Compare commits
663 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| d836d7187e | |||
| b0ecb5b62d | |||
| 09febce4ce | |||
| c5621ff44b | |||
| d58f3114cc | |||
| e1caaed3cf | |||
| 11959f5023 | |||
| 197e5f920d | |||
| e1300a9342 | |||
| 524d2572aa | |||
| 340bab73f5 | |||
| 8d1529cc48 | |||
| c501a73251 | |||
| 6b1c02526f | |||
| d8d7284c35 | |||
| a5a8b93a2e | |||
| a72fd0ebdd | |||
| d5bd1f5aea | |||
| 17c27d1176 | |||
| df698b9433 | |||
| 2ea59ac83a | |||
| 4264e5bee3 | |||
| 411bcc58c5 | |||
| f02cd717bc | |||
| 91f40ac779 | |||
| 04ffee8e82 | |||
| 54253ba8a3 | |||
| ddd533ee9c | |||
| 46133c76b2 | |||
| d4e9ace354 | |||
| 88dd914a31 | |||
| ca68d32a47 | |||
| 3c86dbe28c | |||
| 400bac868e | |||
| 7e765db562 | |||
| a993e179ab | |||
| 5253ff35f1 | |||
| cba0ec4de5 | |||
| ed0354dd06 | |||
| d255d6aeeb | |||
| 94abd0ee79 | |||
| 6a3cd9c0d7 | |||
| 81be16d058 | |||
| 3efdc963d8 | |||
| a4525bf88c | |||
| d7c7ff3dad | |||
| 987aec3fd6 | |||
| d5661c24bd | |||
| c3ee1111f9 | |||
| 9c1509b8c3 | |||
| 1020cdd7a6 | |||
| bff2f53996 | |||
| d5bf831f60 | |||
| 6c423be36f | |||
| 3c33e2c046 | |||
| 253ff41819 | |||
| 24d95b410d | |||
| db5aacf984 | |||
| 111a56dd8a | |||
| d1d0d61b4f | |||
| 640f279abe | |||
| 874191bd8d | |||
| 2066af9f28 | |||
| ef7b3c1715 | |||
| 6eb96851f9 | |||
| a42ef9de77 | |||
| fb23fe3084 | |||
| 57f0150a23 | |||
| 9b31a986b6 | |||
| 8fa46a1f9e | |||
| d805f5ceff | |||
| b4242e562d | |||
| 2effa810c1 | |||
| a78af6acc2 | |||
| fc084c84f4 | |||
| a846ab7443 | |||
| 9f53272d34 | |||
| aa53aac7be | |||
| db984fcad9 | |||
| 607713cdae | |||
| 7de0a61de3 | |||
| 1838460c38 | |||
| 3a4e00d0f5 | |||
| a9bd82150b | |||
| de5c3733d0 | |||
| 3ff662e710 | |||
| 669571799b | |||
| 81a98fc0d3 | |||
| f10157fb24 | |||
| 7d94508257 | |||
| 262a8607d0 | |||
| fd44a9552a | |||
| 8e2d6d8cb2 | |||
| 13b73cb51f | |||
| 5f730ba360 | |||
| 79dbbadf2d | |||
| cd150c265f | |||
| 7a50a91eab | |||
| b5561ee5d4 | |||
| 8dcda7fe35 | |||
| 9b679cc8dd | |||
| 674f8cc936 | |||
| 51a43ef45b | |||
| acc55d588a | |||
| d4990b30e9 | |||
| 920a8d34ea | |||
| c8dfcf4b39 | |||
| aa93632707 | |||
| cc55262cbc | |||
| f887b62a85 | |||
| 5b20781080 | |||
| 98a1efc123 | |||
| a628c1f5e4 | |||
| 6588e8fabf | |||
| 52d349538e | |||
| aad2b3a492 | |||
| 93180abf7b | |||
| e30c8d8949 | |||
| a90c5d71ad | |||
| 54f56813a5 | |||
| 8d29229c0f | |||
| dc498128be | |||
| 6d5b71b663 | |||
| 122fcbb40b | |||
| 4fc28bb65e | |||
| a7f92a3187 | |||
| dd16b68623 | |||
| df24d87245 | |||
| 6000e04c78 | |||
| 87181a8ecb | |||
| 7d0731754c | |||
| 962e63ab52 | |||
| 9f4b43f3f2 | |||
| ef722200c9 | |||
| 784f47fa86 | |||
| 90cdc28707 | |||
| 62844b321c | |||
| 8a6c7f5538 | |||
| 8c3eeb5201 | |||
| 5998fabadd | |||
| 97be02356f | |||
| e59867d479 | |||
| 8e1bcaed37 | |||
| f3c864c178 | |||
| 947923509e | |||
| 4e0f77c0f4 | |||
| 6f0505f19c | |||
| 98bf66cb25 | |||
| f9b641b24d | |||
| 3894314ab2 | |||
| edc9d38680 | |||
| ce5f72207e | |||
| ff8d009022 | |||
| 589c33ec05 | |||
| 28fe5b0df5 | |||
| 5a3dfe598f | |||
| d0c132ccd4 | |||
| 826541548c | |||
| e3adc76a72 | |||
| 2ae2d7ee1a | |||
| e28b50e8d6 | |||
| 9c78d86f58 | |||
| a6b23a751e | |||
| 34d5f1f9fe | |||
| 43ad15dc0e | |||
| d20147c79f | |||
| 7cc014cf9e | |||
| 9e735fc940 | |||
| 4fecf6c50d | |||
| c31c14e46b | |||
| 349dbb98a6 | |||
| f4fa5bb0fc | |||
| 4cdf75dc72 | |||
| 53eb39e033 | |||
| 57ae43890c | |||
| 1c59574cbf | |||
| 7ddef03aba | |||
| 4258738b89 | |||
| 594864e117 | |||
| a5698ce480 | |||
| 1a2c9011e6 | |||
| 600ac72a3d | |||
| 1118eed080 | |||
| e42c66bd0e | |||
| ff8fae377c | |||
| 6931252ed9 | |||
| ef8e549d86 | |||
| a5470029a8 | |||
| 13fb23d59d | |||
| a3197578d6 | |||
| ebc14b35f5 | |||
| b0235a2805 | |||
| d0069e0e1d | |||
| 878f136951 | |||
| bf364bf74c | |||
| 03c2850c59 | |||
| 4eddc7131d | |||
| 14be1935e8 | |||
| f08029354a | |||
| c18600b67f | |||
| 2acc0a6844 | |||
| 8ffba3a52f | |||
| 0fb2f35b10 | |||
| f8270b9cec | |||
| d3311ee231 | |||
| 21eb2c8dad | |||
| a11fd7a792 | |||
| a2ad9f8b10 | |||
| 9a0e2f3395 | |||
| cd9196ddb9 | |||
| c10fe673a2 | |||
| 105f8a1720 | |||
| 050f47daf1 | |||
| 683abd2029 | |||
| d08f937932 | |||
| 2f51742311 | |||
| b926d2f0bd | |||
| 89d1d36e79 | |||
| 999cd8cd11 | |||
| fd8b281731 | |||
| d8481b4528 | |||
| 6d93fa046c | |||
| c75672fd44 | |||
| 5484796745 | |||
| 4ed45e0515 | |||
| 9956c04526 | |||
| b74af71312 | |||
| 44640422f2 | |||
| be91f378ac | |||
| bdca18cc9f | |||
| 76cb15f545 | |||
| 4f9e754a51 | |||
| 955774a91a | |||
| e8a9485d5e | |||
| 0736c141b9 | |||
| 204549f55b | |||
| 82a5f307ed | |||
| 7a4650a1a9 | |||
| 518980d9ed | |||
| 5cc1e2e42d | |||
| c599385c8b | |||
| 1d37d3fdf7 | |||
| f3db64af05 | |||
| 3217372720 | |||
| 7a50654f3b | |||
| 9893921d76 | |||
| 5574f35473 | |||
| fd42e493c0 | |||
| 7843e6a709 | |||
| 4c129ec208 | |||
| 1bf44561da | |||
| ad612864ce | |||
| 1707436cad | |||
| b011d508f8 | |||
| f67a477f65 | |||
| 3573b97bfc | |||
| 37a42a3fb7 | |||
| 2d13ddc70c | |||
| 0be01f3c24 | |||
| eb492724c7 | |||
| 3b05d03220 | |||
| 4c04233a20 | |||
| 2b6d2fc117 | |||
| f64ef39687 | |||
| c1fb392333 | |||
| de60d5467c | |||
| c1274e24b0 | |||
| 7f593d3999 | |||
| 3a6a6097a7 | |||
| 69989e4e64 | |||
| 88999b34d3 | |||
| 582732918d | |||
| f1f69c607e | |||
| 8e82fee494 | |||
| a51475a094 | |||
| f25e2d48bd | |||
| 2bbff64a12 | |||
| 70b4503187 | |||
| 912bd4458f | |||
| d3f4494925 | |||
| 464467ae8b | |||
| 8e579ec8e0 | |||
| 4ef6cbf4fb | |||
| 68dfcddbe9 | |||
| 907761f14e | |||
| be7917c8d8 | |||
| 2e25f09ae4 | |||
| ea95d8604a | |||
| 35def3ab2e | |||
| 5527c12a8d | |||
| fb1cc72013 | |||
| 1f34883a27 | |||
| 724262651f | |||
| d7b2247878 | |||
| 372e7b6312 | |||
| 323a2d83fa | |||
| 03c3393616 | |||
| cbff011e3c | |||
| 2ba6fad633 | |||
| bc4878d71e | |||
| e991ae504b | |||
| c18181042f | |||
| 3de80d3b20 | |||
| 39dcd0a352 | |||
| 199e31ea3f | |||
| dce2247925 | |||
| 89e78c0276 | |||
| 9a57c11348 | |||
| 1dbe8b2a79 | |||
| 29fd0caf58 | |||
| d30701ed59 | |||
| e39550e77f | |||
| a21e7a5eee | |||
| 927b5ae707 | |||
| f59626004c | |||
| 2ece2719d0 | |||
| 78ee542d8d | |||
| cea9b38815 | |||
| cb8f6db68d | |||
| 85038c2b46 | |||
| 1e8055f504 | |||
| a7a5f20d1c | |||
| 0d744a4e74 | |||
| 216ec60dc1 | |||
| 3d9047bec4 | |||
| 08d65beb26 | |||
| 5cab66fb18 | |||
| 9466624f9d | |||
| 80b842a704 | |||
| d513a9fe5c | |||
| c98081cb04 | |||
| 17a1dc18be | |||
| b22ff229db | |||
| 23b03fd6ab | |||
| 97b273905a | |||
| e759c4d27a | |||
| 76685ae2d9 | |||
| 3fad3ceb35 | |||
| dede9e8549 | |||
| 97c018118d | |||
| 8b1ce36402 | |||
| 7931f315b1 | |||
| abb6404ab2 | |||
| c434542c65 | |||
| 42b7aa6450 | |||
| f2ce9cf857 | |||
| 56134d0202 | |||
| f33bbe2d5d | |||
| 59a478bdc5 | |||
| 141b332d4f | |||
| d4a312d6cb | |||
| 31d688b34c | |||
| fbef9ea600 | |||
| 0688491e1b | |||
| 434161687e | |||
| 4b3709b96b | |||
| 1fa993303d | |||
| 01897e7755 | |||
| 7040b2178d | |||
| edf23c4c18 | |||
| b0b9e66fad | |||
| 89488a43b9 | |||
| 798e13f70d | |||
| e758391a23 | |||
| 00d1e01e12 | |||
| 4f265a52a2 | |||
| 560717de76 | |||
| 0f40894317 | |||
| 3915e882a8 | |||
| c5caa23a63 | |||
| 36978d2ddc | |||
| 3f90c895b9 | |||
| 2ada171806 | |||
| 5dc683c968 | |||
| 7026cfe140 | |||
| b7cd1dd764 | |||
| 09bb8fc4f4 | |||
| 746ab49d36 | |||
| 1614dc975a | |||
| ba7598d90d | |||
| 92fc4872e8 | |||
| 30dbfc33a4 | |||
| b3de5aa08e | |||
| ba4773e448 | |||
| a713ee852c | |||
| a65accd412 | |||
| 1dc9583e06 | |||
| 3afe02ac1f | |||
| 57aa61f1ba | |||
| 121ea14fe4 | |||
| 9d457dc0ab | |||
| befd836ab4 | |||
| 044c301d64 | |||
| 94fd0df2e2 | |||
| e5087ca3db | |||
| 819a9da599 | |||
| fb02e55424 | |||
| 70e86434ef | |||
| c41b1e2f06 | |||
| 64641c28ef | |||
| 69e9f4ada2 | |||
| d28cf632e4 | |||
| b466bfa6c8 | |||
| 1c06f4cf06 | |||
| 25f40566ed | |||
| e8fa2cbc4d | |||
| 779c441e0a | |||
| e33031ee7d | |||
| ae63313b55 | |||
| ae50b8d839 | |||
| 10a27156c2 | |||
| 94057886a3 | |||
| 2d9bcb6e4f | |||
| 249bcd9e1a | |||
| b2679b7648 | |||
| 9995b8714b | |||
| 7b4dd2f7f5 | |||
| cc6b01cf88 | |||
| 3568ff72bf | |||
| e20614660b | |||
| c5a69f073c | |||
| 3025671b1a | |||
| 74da0043b4 | |||
| c0ddca12df | |||
| bf55e610b9 | |||
| 4e775a4090 | |||
| 9f7b31b5c5 | |||
| 279641df73 | |||
| 9e1fd16329 | |||
| d6ff5f0239 | |||
| 3f5d3fa0c6 | |||
| 51dc2b109e | |||
| 2358ff6f07 | |||
| 11788d2f39 | |||
| 541f7467c6 | |||
| 411c9707ee | |||
| ee0ba17c03 | |||
| 64bc850d8f | |||
| 154f64dae3 | |||
| 7fa758358f | |||
| f135881bd6 | |||
| 839301f81e | |||
| 04f4ca9772 | |||
| 525328fba1 | |||
| 471c125c1a | |||
| 8ef99137c6 | |||
| 404cad062a | |||
| d4be813f2e | |||
| ab3c0b2f03 | |||
| defcfc2962 | |||
| 267cfdf54b | |||
| a7b0231b3c | |||
| 7c19958840 | |||
| 34c3bb7d2c | |||
| b37545ee6c | |||
| c1e924c894 | |||
| 200e9e28ea | |||
| b95f958890 | |||
| fe9666bdaf | |||
| 948de5dc79 | |||
| 8800fd8250 | |||
| b1e5d8c915 | |||
| 02aec8b091 | |||
| 50517f6aa6 | |||
| a752473280 | |||
| 7e1972d483 | |||
| de48bf04bc | |||
| 228bf66cac | |||
| c986c1d26a | |||
| b0f7ea5b16 | |||
| 8b2e2ff1f8 | |||
| d00166223f | |||
| 4701b4bfc2 | |||
| e4c74c727f | |||
| f626ce29c4 | |||
| 768d8e5811 | |||
| 2ac3a4a103 | |||
| bb512f3fc0 | |||
| d6e7a89c97 | |||
| a5455da909 | |||
| 8dadc698cc | |||
| 2127712115 | |||
| d5b635027e | |||
| 9b2aeda51e | |||
| 5aba9b539f | |||
| b82020722b | |||
| b62a8fe65a | |||
| a5d85e3281 | |||
| e699bcf5a3 | |||
| 7ef5e079fd | |||
| 4076461347 | |||
| d610486c1e | |||
| 1891e2ad68 | |||
| f1e060902b | |||
| 7dbd920912 | |||
| 05ab9e3836 | |||
| a4e0f1f7aa | |||
| a8f27d13e6 | |||
| 05d425ea88 | |||
| 3cb12b5a60 | |||
| 8f1237e629 | |||
| 2c7f44f78d | |||
| a9447aa8c7 | |||
| 9b61b350fe | |||
| e3cf65fbdf | |||
| e51d43568e | |||
| 1bb6b7acdd | |||
| adc7a3ba4a | |||
| 94ec6cc362 | |||
| bbdb5eb6e3 | |||
| e487ca8bd8 | |||
| f5b0e20f78 | |||
| 6116eebbad | |||
| 8619705e44 | |||
| c216ed2d1f | |||
| e17dc25bba | |||
| d311915f9d | |||
| 3a95826b42 | |||
| dcc1009162 | |||
| d61e01ff4f | |||
| 51b9d8e7ad | |||
| 90eb5e9c31 | |||
| 17c34c88dc | |||
| ff6f658f9d | |||
| fb798a4150 | |||
| 4213bb3a62 | |||
| 8a34f91172 | |||
| 764ddd4773 | |||
| ea0dcc8ebd | |||
| 3f5db9f7f9 | |||
| a6a0bba1b7 | |||
| 5ec785e2f7 | |||
| f7d9f1f69d | |||
| 42efd2d005 | |||
| d32e13daee | |||
| e82c21e944 | |||
| 33f835a437 | |||
| 59d8110801 | |||
| d028b381fa | |||
| a1a3f810f0 | |||
| c96f0f2396 | |||
| 46c8985661 | |||
| c588639503 | |||
| b3c6f559b2 | |||
| 85544d109c | |||
| 4aba595b2b | |||
| b2241dca72 | |||
| 4ffe742b69 | |||
| 5979b8e385 | |||
| 955bd5a6d1 | |||
| 1eb8191519 | |||
| 396bda5611 | |||
| cb334be8c4 | |||
| 8845cc0556 | |||
| e34800ad49 | |||
| 5b574901b3 | |||
| 59b68154e1 | |||
| 5a501c8e48 | |||
| f927c15adf | |||
| d08157f7db | |||
| 8a9ac4f01f | |||
| 39df5f3b15 | |||
| 981bf328ae | |||
| 1f8e9727b0 | |||
| f604bcb557 | |||
| eccf9eb4a4 | |||
| 39403fa885 | |||
| 5e7cc30564 | |||
| f942b4c657 | |||
| f5aeb5b068 | |||
| 7f6cb9b07b | |||
| db3657d411 | |||
| 38e5da724d | |||
| 24a63eb304 | |||
| c1f5ae1c5a | |||
| 009211c740 | |||
| 1a208a1612 | |||
| b867e51c6c | |||
| 7693b93c50 | |||
| c3d7158669 | |||
| 9f5e50f25e | |||
| a091ab76d7 | |||
| d5eb242295 | |||
| b21e65fc5f | |||
| 1b07e81936 | |||
| 962b2d45ef | |||
| 7894b41277 | |||
| 51d0b8d2b5 | |||
| 7b992a1dc4 | |||
| 2f8615c6c4 | |||
| aee6d9d01c | |||
| fd4a0dbedf | |||
| 14381ac68a | |||
| c00a98fed4 | |||
| aab7581909 | |||
| 74dcc1b9d5 | |||
| 17241b3543 | |||
| a4a859f47b | |||
| b66ed8bc41 | |||
| 754feff5e7 | |||
| cd1b425a80 | |||
| 187947e8d8 | |||
| 6b38927123 | |||
| f46e4049b6 | |||
| 0ea8299fa7 | |||
| 5d793193e0 | |||
| 62337f75b8 | |||
| 4d4fdfff70 | |||
| b63d0a3138 | |||
| 7949c09183 | |||
| 3f535aca8c | |||
| 9f44809164 | |||
| f7ccb18af5 | |||
| cca9945867 | |||
| f23c6b0c2f | |||
| 6d22b8c6ed | |||
| 245ce7259c | |||
| f36cd60fdb | |||
| 8467e2d376 | |||
| 2529918d5f | |||
| e2711a6121 | |||
| 89d22e5f94 | |||
| f13fda9be5 | |||
| 49f6a63a06 | |||
| e078fea846 | |||
| 048c8b1670 | |||
| 3b5c38d861 | |||
| 90fb075e34 | |||
| 08c6d9ce96 | |||
| 76ccb8c31f | |||
| 3dfc502814 | |||
| df0f626283 | |||
| 1909ce9220 | |||
| 15bef82e1e | |||
| 60a45241e6 | |||
| d403e92315 | |||
| eed7ede376 | |||
| d20f49b58b | |||
| 37091df142 | |||
| 21081cf80f | |||
| c213b37e96 | |||
| d1ca84aa43 | |||
| 0f7fbc411a | |||
| f4b2b1b03f | |||
| 0ecc36c4a5 | |||
| a48eace90a | |||
| 7a2a51ad44 | |||
| f56fcb0a14 | |||
| 7816652078 | |||
| 20aacc7026 | |||
| 49938cfd09 | |||
| 53a4ed6b24 | |||
| 534000b49d | |||
| 7e2ccbf909 | |||
| b0b6968185 | |||
| 94963b5b3a | |||
| 77fa61e6fc | |||
| 94c450ad16 | |||
| a292bf7c83 | |||
| b24ee1c44f | |||
| 981b22ba49 | |||
| e1eedd3bba | |||
| b949fd4d43 |
+1
-1
@@ -14,7 +14,7 @@ default:
|
||||
##########################################################################
|
||||
# The variable CI_COMMIT_BEFORE_SHA is not available in normal merge requests
|
||||
# so we must build the commit hash ourselves, see:
|
||||
# https://gitlab.com/gitlab-org/gitlab/issues/12850
|
||||
# https://gitlab.com/gitlab-org/gitlab/-/issues/12850
|
||||
test_formatting:
|
||||
stage: test
|
||||
needs: []
|
||||
|
||||
+1
-1
@@ -7,7 +7,7 @@ build_doxygen_docker:
|
||||
- docker
|
||||
before_script:
|
||||
- docker info
|
||||
- docker login -u gitlab-ci-token -p "$CI_BUILD_TOKEN" "$CI_REGISTRY"
|
||||
- docker login -u gitlab-ci-token -p "$CI_JOB_TOKEN" "$CI_REGISTRY"
|
||||
script:
|
||||
- docker build -t "${CI_REGISTRY_IMAGE}/doxygen:$CI_COMMIT_BRANCH" -f ./doxygen/doxygen.Dockerfile .
|
||||
- docker push "${CI_REGISTRY_IMAGE}/doxygen:$CI_COMMIT_BRANCH"
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
<!-- --------Before Creating a New Issue-----------
|
||||
* Limit report to a single issue.
|
||||
* Search the issue tracker to verify the issue has not already been reported.
|
||||
* Complete all instructions between `template comment markers <>.
|
||||
* Keep report contents limited to the necessary information required to fix the issue.
|
||||
* When creating an issue against the stable version of KiCad, make sure the latest available stable version is installed as issues may have already been resolved in later stable versions. -->
|
||||
# Description
|
||||
<!-- What is the current behavior and what is the expected behavior? -->
|
||||
<!-- If the issue is visual/graphical, please attach screenshots of the problem. -->
|
||||
<!-- Add the issue details below this line and before the "Steps to reproduce" heading. -->
|
||||
|
||||
# Steps to reproduce
|
||||
<!-- If there are multiple steps to reproduce it or it is a visual issue, then providing a screen recording as an attachment to this report is recommended. -->
|
||||
<!-- If this issue is specific to a project, please attach the necessary files to this issue. -->
|
||||
<!-- Add the steps to reproduce using the numbers below -->
|
||||
<!-- Add new step numbers before the "KiCad Version" heading. -->
|
||||
1.
|
||||
|
||||
# KiCad Version
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
##########################################################################
|
||||
# Test the formatting in a merge request using clang-format
|
||||
##########################################################################
|
||||
# The variable CI_COMMIT_BEFORE_SHA is not available in normal merge requests
|
||||
# so we must build the commit hash ourselves, see:
|
||||
# https://gitlab.com/gitlab-org/gitlab/-/issues/12850
|
||||
test_formatting:
|
||||
stage: test
|
||||
needs: []
|
||||
rules:
|
||||
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
|
||||
allow_failure: true
|
||||
before_script:
|
||||
# We must manually add the KiCad remote to ensure it is named sensibly
|
||||
- git remote add product https://gitlab.com/kicad/code/kicad.git
|
||||
- git remote add source ${CI_MERGE_REQUEST_SOURCE_PROJECT_URL}.git
|
||||
- git fetch -n product
|
||||
- git fetch -n source
|
||||
# Get the SHAs of the commits
|
||||
- "TARGET_HEAD_SHA=$(git rev-parse product/${CI_MERGE_REQUEST_TARGET_BRANCH_NAME})"
|
||||
- "SOURCE_HEAD_SHA=$(git rev-parse source/${CI_MERGE_REQUEST_SOURCE_BRANCH_NAME})"
|
||||
- "MERGE_BASE_SHA=$(git merge-base ${TARGET_HEAD_SHA} ${SOURCE_HEAD_SHA})"
|
||||
script:
|
||||
- echo "Testing formatting from commit ${MERGE_BASE_SHA}"
|
||||
- ./tools/check_coding.sh --diff --ci --commit ${MERGE_BASE_SHA}
|
||||
@@ -28,7 +28,7 @@
|
||||
# GitLab supports displaying the results in the GUI through JUNIT artifacts
|
||||
# (https://docs.gitlab.com/ee/ci/junit_test_reports.html)
|
||||
# so we upload the JUNIT results. Note that there is a bug with how paths
|
||||
# are processed in the junit report (https://gitlab.com/gitlab-org/gitlab/issues/23835)
|
||||
# are processed in the junit report (https://gitlab.com/gitlab-org/gitlab/-/issues/23835)
|
||||
# so we can't use a glob and have to list out each hierarchy separately.
|
||||
artifacts:
|
||||
reports:
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2015-2022 Mario Luzeiro <mrluzeiro@ua.pt>
|
||||
* Copyright (C) 1992-2022 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
* Copyright (C) 1992-2023 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
@@ -36,6 +36,7 @@
|
||||
#include <pgm_base.h>
|
||||
#include <settings/settings_manager.h>
|
||||
#include <wx/log.h>
|
||||
#include <pcbnew_settings.h>
|
||||
#include <advanced_config.h>
|
||||
|
||||
|
||||
@@ -92,8 +93,7 @@ BOARD_ADAPTER::BOARD_ADAPTER() :
|
||||
{
|
||||
wxLogTrace( m_logTrace, wxT( "BOARD_ADAPTER::BOARD_ADAPTER" ) );
|
||||
|
||||
if( PgmOrNull() )
|
||||
m_colors = Pgm().GetSettingsManager().GetColorSettings();
|
||||
ReloadColorSettings();
|
||||
|
||||
m_boardPos = VECTOR2I();
|
||||
m_boardSize = VECTOR2I();
|
||||
@@ -208,6 +208,15 @@ BOARD_ADAPTER::~BOARD_ADAPTER()
|
||||
}
|
||||
|
||||
|
||||
void BOARD_ADAPTER::ReloadColorSettings() noexcept
|
||||
{
|
||||
wxASSERT( PgmOrNull() );
|
||||
|
||||
PCBNEW_SETTINGS* settings = Pgm().GetSettingsManager().GetAppSettings<PCBNEW_SETTINGS>();
|
||||
m_colors = Pgm().GetSettingsManager().GetColorSettings( settings->m_ColorTheme );
|
||||
}
|
||||
|
||||
|
||||
bool BOARD_ADAPTER::Is3dLayerEnabled( PCB_LAYER_ID aLayer ) const
|
||||
{
|
||||
wxASSERT( aLayer < PCB_LAYER_ID_COUNT );
|
||||
@@ -251,7 +260,8 @@ bool BOARD_ADAPTER::Is3dLayerEnabled( PCB_LAYER_ID aLayer ) const
|
||||
|
||||
case B_Cu:
|
||||
case F_Cu:
|
||||
return !m_board || m_board->IsLayerVisible( aLayer ) || m_Cfg->m_Render.realistic;
|
||||
return !m_board || m_board->IsLayerVisible( aLayer ) || m_Cfg->m_Render.realistic
|
||||
|| m_board->IsFootprintHolder();
|
||||
|
||||
default:
|
||||
// the layer is an internal copper layer, used the visibility
|
||||
@@ -671,7 +681,8 @@ bool BOARD_ADAPTER::createBoardPolygon( wxString* aErrorMsg )
|
||||
return false;
|
||||
}
|
||||
|
||||
int chainingEpsilon = pcbIUScale.mmToIU( 0.02 ); // max dist from one endPt to next startPt
|
||||
// max dist from one endPt to next startPt
|
||||
int chainingEpsilon = m_board->GetOutlinesChainingEpsilon();
|
||||
|
||||
success = BuildFootprintPolygonOutlines( m_board, m_board_poly,
|
||||
m_board->GetDesignSettings().m_MaxError,
|
||||
|
||||
@@ -100,7 +100,7 @@ public:
|
||||
void SetBoard( BOARD* aBoard ) noexcept { m_board = aBoard; }
|
||||
const BOARD* GetBoard() const noexcept { return m_board; }
|
||||
|
||||
void SetColorSettings( COLOR_SETTINGS* aSettings ) noexcept { m_colors = aSettings; }
|
||||
void ReloadColorSettings() noexcept;
|
||||
|
||||
/**
|
||||
* Function to be called by the render when it need to reload the settings for the board.
|
||||
@@ -342,8 +342,7 @@ private:
|
||||
OBJECT_2D* createPadWithDrill( const PAD* aPad, int aInflateValue );
|
||||
|
||||
void addPads( const FOOTPRINT* aFootprint, CONTAINER_2D_BASE* aDstContainer,
|
||||
PCB_LAYER_ID aLayerId, bool aSkipNPTHPadsWihNoCopper, bool aSkipPlatedPads,
|
||||
bool aSkipNonPlatedPads );
|
||||
PCB_LAYER_ID aLayerId, bool aSkipPlatedPads, bool aSkipNonPlatedPads );
|
||||
|
||||
void addFootprintShapes( const FOOTPRINT* aFootprint, CONTAINER_2D_BASE* aDstContainer,
|
||||
PCB_LAYER_ID aLayerId );
|
||||
|
||||
@@ -91,7 +91,7 @@ void BOARD_ADAPTER::addText( const EDA_TEXT* aText, CONTAINER_2D_BASE* aContaine
|
||||
callback_gal.SetIsFill( font->IsOutline() );
|
||||
callback_gal.SetIsStroke( font->IsStroke() );
|
||||
callback_gal.SetLineWidth( attrs.m_StrokeWidth );
|
||||
font->Draw( &callback_gal, aText->GetShownText(), aText->GetDrawPos(), attrs );
|
||||
font->Draw( &callback_gal, aText->GetShownText( true ), aText->GetDrawPos(), attrs );
|
||||
|
||||
SHAPE_POLY_SET finalPoly;
|
||||
int margin = attrs.m_StrokeWidth * 1.5 +
|
||||
@@ -137,7 +137,7 @@ void BOARD_ADAPTER::addText( const EDA_TEXT* aText, CONTAINER_2D_BASE* aContaine
|
||||
|
||||
attrs.m_Angle = aText->GetDrawRotation();
|
||||
|
||||
font->Draw( &callback_gal, aText->GetShownText(), aText->GetDrawPos(), attrs );
|
||||
font->Draw( &callback_gal, aText->GetShownText( true ), aText->GetDrawPos(), attrs );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -145,7 +145,7 @@ void BOARD_ADAPTER::addText( const EDA_TEXT* aText, CONTAINER_2D_BASE* aContaine
|
||||
void BOARD_ADAPTER::addShape( const PCB_DIMENSION_BASE* aDimension, CONTAINER_2D_BASE* aContainer,
|
||||
const BOARD_ITEM* aOwner )
|
||||
{
|
||||
addText( &aDimension->Text(), aContainer, aDimension );
|
||||
addText( aDimension, aContainer, aDimension );
|
||||
|
||||
const int linewidth = aDimension->GetLineThickness();
|
||||
|
||||
@@ -275,6 +275,10 @@ void BOARD_ADAPTER::createTrack( const PCB_TRACK* aTrack, CONTAINER_2D_BASE* aDs
|
||||
int arcsegcount = GetArcToSegmentCount( radius, ARC_HIGH_DEF, arc_angle );
|
||||
int circlesegcount;
|
||||
|
||||
// Avoid arcs that cannot be drawn
|
||||
if( radius < std::numeric_limits<double>::min() || arc_angle.IsZero() )
|
||||
break;
|
||||
|
||||
// We need a circle to segment count. However, the arc angle can be small, and the
|
||||
// radius very big. so we calculate a reasonable value for circlesegcount.
|
||||
if( arcsegcount <= 1 ) // The arc will be approximated by a segment
|
||||
@@ -488,41 +492,24 @@ OBJECT_2D* BOARD_ADAPTER::createPadWithDrill( const PAD* aPad, int aInflateValue
|
||||
|
||||
|
||||
void BOARD_ADAPTER::addPads( const FOOTPRINT* aFootprint, CONTAINER_2D_BASE* aContainer,
|
||||
PCB_LAYER_ID aLayerId, bool aSkipNPTHPadsWihNoCopper,
|
||||
bool aSkipPlatedPads, bool aSkipNonPlatedPads )
|
||||
PCB_LAYER_ID aLayerId, bool aSkipPlatedPads, bool aSkipNonPlatedPads )
|
||||
{
|
||||
for( PAD* pad : aFootprint->Pads() )
|
||||
{
|
||||
if( !pad->IsOnLayer( aLayerId ) )
|
||||
continue;
|
||||
|
||||
// Skip pad annulus when not connected on this layer (if removing is enabled)
|
||||
if( !pad->FlashLayer( aLayerId ) && IsCopperLayer( aLayerId ) )
|
||||
continue;
|
||||
|
||||
// NPTH pads are not drawn on layers if the shape size and pos is the same as their hole:
|
||||
if( aSkipNPTHPadsWihNoCopper && ( pad->GetAttribute() == PAD_ATTRIB::NPTH ) )
|
||||
if( IsCopperLayer( aLayerId ) )
|
||||
{
|
||||
if( pad->GetDrillSize() == pad->GetSize() && pad->GetOffset() == wxPoint( 0, 0 ) )
|
||||
{
|
||||
switch( pad->GetShape() )
|
||||
{
|
||||
case PAD_SHAPE::CIRCLE:
|
||||
if( pad->GetDrillShape() == PAD_DRILL_SHAPE_CIRCLE )
|
||||
continue;
|
||||
// Skip pad annulus when there isn't one (note: this is more discerning than
|
||||
// pad->IsOnLayer(), which doesn't check for NPTH pads with holes that consume
|
||||
// the entire pad).
|
||||
if( !pad->IsOnCopperLayer() )
|
||||
continue;
|
||||
|
||||
break;
|
||||
|
||||
case PAD_SHAPE::OVAL:
|
||||
if( pad->GetDrillShape() != PAD_DRILL_SHAPE_CIRCLE )
|
||||
continue;
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Skip pad annulus when not connected on this layer (if removing is enabled)
|
||||
if( !pad->FlashLayer( aLayerId ) )
|
||||
continue;
|
||||
}
|
||||
|
||||
VECTOR2I margin( 0, 0 );
|
||||
|
||||
@@ -525,9 +525,7 @@ void BOARD_ADAPTER::createLayers( REPORTER* aStatusReporter )
|
||||
// ADD PADS
|
||||
for( FOOTPRINT* footprint : m_board->Footprints() )
|
||||
{
|
||||
// Note: NPTH pads are not drawn on copper layers when the pad has the same shape
|
||||
// as its hole
|
||||
addPads( footprint, layerContainer, layer, true, renderPlatedPadsAsPlated, false );
|
||||
addPads( footprint, layerContainer, layer, renderPlatedPadsAsPlated, false );
|
||||
|
||||
// Micro-wave footprints may have items on copper layers
|
||||
addFootprintShapes( footprint, layerContainer, layer );
|
||||
@@ -539,8 +537,8 @@ void BOARD_ADAPTER::createLayers( REPORTER* aStatusReporter )
|
||||
// ADD PLATED PADS
|
||||
for( FOOTPRINT* footprint : m_board->Footprints() )
|
||||
{
|
||||
addPads( footprint, m_platedPadsFront, F_Cu, true, false, true );
|
||||
addPads( footprint, m_platedPadsBack, B_Cu, true, false, true );
|
||||
addPads( footprint, m_platedPadsFront, F_Cu, false, true );
|
||||
addPads( footprint, m_platedPadsBack, B_Cu, false, true );
|
||||
}
|
||||
|
||||
m_platedPadsFront->BuildBVH();
|
||||
@@ -995,7 +993,7 @@ void BOARD_ADAPTER::createLayers( REPORTER* aStatusReporter )
|
||||
}
|
||||
else
|
||||
{
|
||||
addPads( footprint, layerContainer, layer, false, false, false );
|
||||
addPads( footprint, layerContainer, layer, false, false );
|
||||
}
|
||||
|
||||
addFootprintShapes( footprint, layerContainer, layer );
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
#include <3d_rendering/raytracing/render_3d_raytrace.h>
|
||||
#include <3d_rendering/opengl/render_3d_opengl.h>
|
||||
#include <3d_viewer_id.h>
|
||||
#include <advanced_config.h>
|
||||
#include <board.h>
|
||||
#include <reporter.h>
|
||||
#include <gl_context_mgr.h>
|
||||
@@ -140,7 +141,7 @@ EDA_3D_CANVAS::EDA_3D_CANVAS( wxWindow* aParent, const int* aAttribList,
|
||||
// long calculation time)
|
||||
m_3d_render = m_3d_render_opengl;
|
||||
|
||||
m_boardAdapter.SetColorSettings( Pgm().GetSettingsManager().GetColorSettings() );
|
||||
m_boardAdapter.ReloadColorSettings();
|
||||
|
||||
wxASSERT( a3DCachePointer != nullptr );
|
||||
m_boardAdapter.Set3dCacheManager( a3DCachePointer );
|
||||
@@ -303,7 +304,7 @@ void EDA_3D_CANVAS::ReloadRequest( BOARD* aBoard , S3D_CACHE* aCachePointer )
|
||||
if( aBoard != nullptr )
|
||||
m_boardAdapter.SetBoard( aBoard );
|
||||
|
||||
m_boardAdapter.SetColorSettings( Pgm().GetSettingsManager().GetColorSettings() );
|
||||
m_boardAdapter.ReloadColorSettings();
|
||||
|
||||
if( m_3d_render )
|
||||
m_3d_render->ReloadRequest();
|
||||
@@ -383,6 +384,15 @@ void EDA_3D_CANVAS::DoRePaint()
|
||||
if( m_glRC == nullptr )
|
||||
m_glRC = GL_CONTEXT_MANAGER::Get().CreateCtx( this );
|
||||
|
||||
// CreateCtx could and does fail per sentry crash events, lets be graceful
|
||||
if( m_glRC == nullptr )
|
||||
{
|
||||
warningReporter.Report( _( "OpenGL context creation error" ), RPT_SEVERITY_ERROR );
|
||||
warningReporter.Finalize();
|
||||
m_is_currently_painting.clear();
|
||||
return;
|
||||
}
|
||||
|
||||
GL_CONTEXT_MANAGER::Get().LockCtx( m_glRC, this );
|
||||
|
||||
// Set the OpenGL viewport according to the client size of this canvas.
|
||||
@@ -522,13 +532,11 @@ void EDA_3D_CANVAS::DoRePaint()
|
||||
render_pivot( curtime_delta_s, scale );
|
||||
}
|
||||
|
||||
#if defined( KICAD_USE_3DCONNEXION )
|
||||
if( m_render3dmousePivot )
|
||||
if( m_render3dmousePivot && ADVANCED_CFG::GetCfg().m_Use3DConnexionDriver )
|
||||
{
|
||||
const float scale = glm::min( m_camera.GetZoom(), 1.0f );
|
||||
render3dmousePivot( scale );
|
||||
}
|
||||
#endif
|
||||
|
||||
// "Swaps the double-buffer of this window, making the back-buffer the
|
||||
// front-buffer and vice versa, so that the output of the previous OpenGL
|
||||
|
||||
@@ -178,8 +178,6 @@ public:
|
||||
*/
|
||||
void SetRenderPivot( bool aValue ) { m_render_pivot = aValue; }
|
||||
|
||||
|
||||
#if defined( KICAD_USE_3DCONNEXION )
|
||||
/**
|
||||
* Get a value indicating whether to render the 3dmouse pivot.
|
||||
*/
|
||||
@@ -209,7 +207,6 @@ public:
|
||||
{
|
||||
m_3dmousePivotPos = aPos;
|
||||
}
|
||||
#endif
|
||||
|
||||
private:
|
||||
/**
|
||||
@@ -278,14 +275,12 @@ private:
|
||||
*/
|
||||
void render_pivot( float t, float aScale );
|
||||
|
||||
#if defined( KICAD_USE_3DCONNEXION )
|
||||
/**
|
||||
* Render the 3dmouse pivot cursor.
|
||||
*
|
||||
* @param aScale scale to apply on the cursor.
|
||||
*/
|
||||
void render3dmousePivot( float aScale );
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @return true if OpenGL initialization succeeded.
|
||||
@@ -331,10 +326,8 @@ private:
|
||||
|
||||
BOARD_ITEM* m_currentRollOverItem;
|
||||
|
||||
#if defined( KICAD_USE_3DCONNEXION )
|
||||
bool m_render3dmousePivot = false; // Render the 3dmouse pivot
|
||||
SFVEC3F m_3dmousePivotPos; // The position of the 3dmouse pivot
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Trace mask used to enable or disable the trace output of this class.
|
||||
|
||||
@@ -120,7 +120,6 @@ void EDA_3D_CANVAS::render_pivot( float t, float aScale )
|
||||
}
|
||||
|
||||
|
||||
#if defined( KICAD_USE_3DCONNEXION )
|
||||
void EDA_3D_CANVAS::render3dmousePivot( float aScale )
|
||||
{
|
||||
wxASSERT( aScale >= 0.0f );
|
||||
@@ -160,4 +159,3 @@ void EDA_3D_CANVAS::render3dmousePivot( float aScale )
|
||||
glDisable( GL_BLEND );
|
||||
glDisable( GL_POINT_SMOOTH );
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -257,6 +257,13 @@ void EDA_3D_MODEL_VIEWER::OnPaint( wxPaintEvent& event )
|
||||
if( m_glRC == nullptr )
|
||||
m_glRC = GL_CONTEXT_MANAGER::Get().CreateCtx( this );
|
||||
|
||||
// CreateCtx could and does fail per sentry crash events, lets be graceful
|
||||
if( m_glRC == nullptr )
|
||||
{
|
||||
wxLogTrace( m_logTrace, wxT( "EDA_3D_MODEL_VIEWER::OnPaint creating gl context failed" ) );
|
||||
return;
|
||||
}
|
||||
|
||||
GL_CONTEXT_MANAGER::Get().LockCtx( m_glRC, this );
|
||||
|
||||
// Set the OpenGL viewport according to the client size of this canvas.
|
||||
@@ -323,8 +330,16 @@ void EDA_3D_MODEL_VIEWER::OnPaint( wxPaintEvent& event )
|
||||
m_ogl_3dmodel->BeginDrawMulti( true );
|
||||
|
||||
m_ogl_3dmodel->DrawOpaque( false );
|
||||
|
||||
glDepthMask( GL_FALSE );
|
||||
glEnable( GL_BLEND );
|
||||
glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
|
||||
|
||||
m_ogl_3dmodel->DrawTransparent( 1.0f, false );
|
||||
|
||||
glDisable( GL_BLEND );
|
||||
glDepthMask( GL_TRUE );
|
||||
|
||||
m_ogl_3dmodel->EndDrawMulti();
|
||||
|
||||
glPopMatrix();
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
if( KICAD_USE_3DCONNEXION )
|
||||
add_library(3d-viewer_navlib STATIC
|
||||
"nl_3d_viewer_plugin.cpp"
|
||||
"nl_3d_viewer_plugin_impl.cpp"
|
||||
@@ -23,9 +22,4 @@ if( KICAD_USE_3DCONNEXION )
|
||||
$<TARGET_PROPERTY:3DxWare::Navlib,INTERFACE_LINK_LIBRARIES>
|
||||
3DxWare::Navlib
|
||||
)
|
||||
else()
|
||||
add_library(3d-viewer_navlib STATIC
|
||||
"nl_3d_viewer_plugin.cpp"
|
||||
)
|
||||
endif(KICAD_USE_3DCONNEXION)
|
||||
|
||||
|
||||
@@ -19,14 +19,14 @@
|
||||
*/
|
||||
|
||||
#include "nl_3d_viewer_plugin.h"
|
||||
|
||||
#if defined( KICAD_USE_3DCONNEXION )
|
||||
#include "nl_3d_viewer_plugin_impl.h"
|
||||
#include <advanced_config.h>
|
||||
|
||||
|
||||
NL_3D_VIEWER_PLUGIN::NL_3D_VIEWER_PLUGIN( EDA_3D_CANVAS* aViewport ) :
|
||||
m_impl( new NL_3D_VIEWER_PLUGIN_IMPL( aViewport ) )
|
||||
NL_3D_VIEWER_PLUGIN::NL_3D_VIEWER_PLUGIN( EDA_3D_CANVAS* aViewport )
|
||||
{
|
||||
if( ADVANCED_CFG::GetCfg().m_Use3DConnexionDriver )
|
||||
m_impl = new NL_3D_VIEWER_PLUGIN_IMPL( aViewport );
|
||||
}
|
||||
|
||||
|
||||
@@ -38,22 +38,6 @@ NL_3D_VIEWER_PLUGIN::~NL_3D_VIEWER_PLUGIN()
|
||||
|
||||
void NL_3D_VIEWER_PLUGIN::SetFocus( bool focus )
|
||||
{
|
||||
m_impl->SetFocus( focus );
|
||||
if( ADVANCED_CFG::GetCfg().m_Use3DConnexionDriver )
|
||||
m_impl->SetFocus( focus );
|
||||
}
|
||||
#else
|
||||
|
||||
|
||||
NL_3D_VIEWER_PLUGIN::NL_3D_VIEWER_PLUGIN( EDA_3D_CANVAS* aViewport ) : m_impl( nullptr )
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void NL_3D_VIEWER_PLUGIN::SetFocus( bool focus )
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
NL_3D_VIEWER_PLUGIN::~NL_3D_VIEWER_PLUGIN()
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -27,13 +27,14 @@
|
||||
* @file c_ogl_3dmodel.cpp
|
||||
* @brief
|
||||
*/
|
||||
#include <algorithm>
|
||||
#include <stdexcept>
|
||||
#include <gal/opengl/kiglew.h> // Must be included first
|
||||
|
||||
#include "3d_model.h"
|
||||
#include "opengl_utils.h"
|
||||
#include "../common_ogl/ogl_utils.h"
|
||||
#include "../3d_math.h"
|
||||
#include <utility>
|
||||
#include <wx/debug.h>
|
||||
#include <wx/log.h>
|
||||
#include <chrono>
|
||||
@@ -177,9 +178,11 @@ MODEL_3D::MODEL_3D( const S3DMODEL& a3DModel, MATERIAL_MODE aMaterialMode )
|
||||
// use material color for mesh bounding box or some sort of average vertex color.
|
||||
glm::vec3 avg_color = material.m_Diffuse;
|
||||
|
||||
BBOX_3D &mesh_bbox = m_meshes_bbox[mesh_i];
|
||||
|
||||
for( unsigned int vtx_i = 0; vtx_i < mesh.m_VertexSize; ++vtx_i )
|
||||
{
|
||||
m_meshes_bbox[mesh_i].Union( mesh.m_Positions[vtx_i] );
|
||||
mesh_bbox.Union( mesh.m_Positions[vtx_i] );
|
||||
|
||||
VERTEX& vtx_out = mesh_group.m_vertices[vtx_offset + vtx_i];
|
||||
|
||||
@@ -222,16 +225,19 @@ MODEL_3D::MODEL_3D( const S3DMODEL& a3DModel, MATERIAL_MODE aMaterialMode )
|
||||
}
|
||||
}
|
||||
|
||||
if( m_meshes_bbox[mesh_i].IsInitialized() )
|
||||
if( mesh_bbox.IsInitialized() )
|
||||
{
|
||||
// generate geometry for the bounding box
|
||||
MakeBbox( m_meshes_bbox[mesh_i], ( mesh_i + 1 ) * bbox_vtx_count,
|
||||
MakeBbox( mesh_bbox, ( mesh_i + 1 ) * bbox_vtx_count,
|
||||
&bbox_tmp_vertices[( mesh_i + 1 ) * bbox_vtx_count],
|
||||
&bbox_tmp_indices[( mesh_i + 1 ) * bbox_idx_count],
|
||||
{ avg_color, 1.0f } );
|
||||
|
||||
// bump the outer bounding box
|
||||
m_model_bbox.Union( m_meshes_bbox[mesh_i] );
|
||||
m_model_bbox.Union( mesh_bbox );
|
||||
|
||||
// add to the material group
|
||||
material.m_bbox.Union( mesh_bbox );
|
||||
}
|
||||
|
||||
|
||||
@@ -410,7 +416,9 @@ void MODEL_3D::EndDrawMulti()
|
||||
|
||||
|
||||
void MODEL_3D::Draw( bool aTransparent, float aOpacity, bool aUseSelectedMaterial,
|
||||
SFVEC3F& aSelectionColor ) const
|
||||
const SFVEC3F& aSelectionColor,
|
||||
const glm::mat4 *aModelWorldMatrix,
|
||||
const SFVEC3F *aCameraWorldPos ) const
|
||||
{
|
||||
if( aOpacity <= FLT_EPSILON )
|
||||
return;
|
||||
@@ -439,27 +447,102 @@ void MODEL_3D::Draw( bool aTransparent, float aOpacity, bool aUseSelectedMateria
|
||||
|
||||
glTexEnvfv( GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, (const float*)¶m.x );
|
||||
|
||||
for( const MODEL_3D::MATERIAL& mat : m_materials )
|
||||
std::vector<const MODEL_3D::MATERIAL *> materialsToRender;
|
||||
|
||||
materialsToRender.reserve( m_materials.size() );
|
||||
|
||||
if( aModelWorldMatrix && aCameraWorldPos )
|
||||
{
|
||||
if( ( mat.IsTransparent() != aTransparent )
|
||||
// Sort Material groups
|
||||
|
||||
std::vector<std::pair<const MODEL_3D::MATERIAL*, float>> materialsSorted;
|
||||
|
||||
// Calculate the distance to the camera for each material group
|
||||
for( const MODEL_3D::MATERIAL& mat : m_materials )
|
||||
{
|
||||
if( mat.m_render_idx_count == 0 )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if( ( mat.IsTransparent() != aTransparent )
|
||||
&& ( aOpacity >= 1.0f )
|
||||
&& m_materialMode != MATERIAL_MODE::DIFFUSE_ONLY )
|
||||
{
|
||||
continue;
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
const BBOX_3D& bBox = mat.m_bbox;
|
||||
const SFVEC3F& bBoxCenter = bBox.GetCenter();
|
||||
const SFVEC3F bBoxWorld = *aModelWorldMatrix * glm::vec4( bBoxCenter, 1.0f );
|
||||
|
||||
const float distanceToCamera = glm::length( *aCameraWorldPos - bBoxWorld );
|
||||
|
||||
materialsSorted.emplace_back( &mat, distanceToCamera );
|
||||
}
|
||||
|
||||
// Sort from back to front
|
||||
std::sort( materialsSorted.begin(), materialsSorted.end(),
|
||||
[&]( std::pair<const MODEL_3D::MATERIAL*, float>& a,
|
||||
std::pair<const MODEL_3D::MATERIAL*, float>& b ) {
|
||||
// If A is inside B, then A is rendered first
|
||||
if( b.first->m_bbox.Inside( a.first->m_bbox ) )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if( a.first->m_bbox.Inside( b.first->m_bbox ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return a.second > b.second;
|
||||
} );
|
||||
|
||||
for( const std::pair<const MODEL_3D::MATERIAL*, float>& mat : materialsSorted )
|
||||
{
|
||||
materialsToRender.push_back( mat.first );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for( const MODEL_3D::MATERIAL& mat : m_materials )
|
||||
{
|
||||
// There is at least one default material created in case a mesh has no declared materials.
|
||||
// Most meshes have a material, so usually the first material will have nothing to render and is skip.
|
||||
// See S3D::GetModel for more details.
|
||||
if( mat.m_render_idx_count == 0 )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if( ( mat.IsTransparent() != aTransparent )
|
||||
&& ( aOpacity >= 1.0f )
|
||||
&& m_materialMode != MATERIAL_MODE::DIFFUSE_ONLY )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
materialsToRender.push_back( &mat );
|
||||
}
|
||||
}
|
||||
|
||||
for( const MODEL_3D::MATERIAL* mat : materialsToRender )
|
||||
{
|
||||
switch( m_materialMode )
|
||||
{
|
||||
case MATERIAL_MODE::NORMAL:
|
||||
OglSetMaterial( mat, aOpacity, aUseSelectedMaterial, aSelectionColor );
|
||||
OglSetMaterial( *mat, aOpacity, aUseSelectedMaterial, aSelectionColor );
|
||||
break;
|
||||
|
||||
case MATERIAL_MODE::DIFFUSE_ONLY:
|
||||
OglSetDiffuseMaterial( mat.m_Diffuse, aOpacity, aUseSelectedMaterial, aSelectionColor );
|
||||
OglSetDiffuseMaterial( mat->m_Diffuse, aOpacity, aUseSelectedMaterial, aSelectionColor );
|
||||
break;
|
||||
|
||||
case MATERIAL_MODE::CAD_MODE:
|
||||
OglSetDiffuseMaterial( MaterialDiffuseToColorCAD( mat.m_Diffuse ), aOpacity,
|
||||
OglSetDiffuseMaterial( MaterialDiffuseToColorCAD( mat->m_Diffuse ), aOpacity,
|
||||
aUseSelectedMaterial, aSelectionColor );
|
||||
break;
|
||||
|
||||
@@ -467,9 +550,9 @@ void MODEL_3D::Draw( bool aTransparent, float aOpacity, bool aUseSelectedMateria
|
||||
break;
|
||||
}
|
||||
|
||||
glDrawElements( GL_TRIANGLES, mat.m_render_idx_count, m_index_buffer_type,
|
||||
glDrawElements( GL_TRIANGLES, mat->m_render_idx_count, m_index_buffer_type,
|
||||
reinterpret_cast<const void*>(
|
||||
static_cast<uintptr_t>( mat.m_render_idx_buffer_offset ) ) );
|
||||
static_cast<uintptr_t>( mat->m_render_idx_buffer_offset ) ) );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -54,7 +54,7 @@ public:
|
||||
*/
|
||||
void DrawOpaque( bool aUseSelectedMaterial, SFVEC3F aSelectionColor = SFVEC3F( 0.0f ) ) const
|
||||
{
|
||||
Draw( false, 1.0f, aUseSelectedMaterial, aSelectionColor );
|
||||
Draw( false, 1.0f, aUseSelectedMaterial, aSelectionColor, nullptr, nullptr );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -63,9 +63,19 @@ public:
|
||||
void DrawTransparent( float aOpacity, bool aUseSelectedMaterial,
|
||||
SFVEC3F aSelectionColor = SFVEC3F( 0.0f ) ) const
|
||||
{
|
||||
Draw( true, aOpacity, aUseSelectedMaterial, aSelectionColor );
|
||||
Draw( true, aOpacity, aUseSelectedMaterial, aSelectionColor, nullptr, nullptr );
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the model into the current context.
|
||||
* if aModelWorldMatrix and aCameraWorldPos is provided,
|
||||
* it renders the material groups sorted.
|
||||
*/
|
||||
void Draw( bool aTransparent, float aOpacity, bool aUseSelectedMaterial,
|
||||
const SFVEC3F& aSelectionColor,
|
||||
const glm::mat4 *aModelWorldMatrix,
|
||||
const SFVEC3F *aCameraWorldPos ) const;
|
||||
|
||||
/**
|
||||
* Return true if have opaque meshes to render.
|
||||
*/
|
||||
@@ -136,6 +146,8 @@ private:
|
||||
unsigned int m_render_idx_buffer_offset = 0;
|
||||
unsigned int m_render_idx_count = 0;
|
||||
|
||||
BBOX_3D m_bbox; ///< bounding box for this material group, used for transparent material ordering
|
||||
|
||||
MATERIAL( const SMATERIAL& aOther ) : SMATERIAL( aOther ) { }
|
||||
bool IsTransparent() const { return m_Transparency > FLT_EPSILON; }
|
||||
};
|
||||
@@ -159,9 +171,6 @@ private:
|
||||
|
||||
static void MakeBbox( const BBOX_3D& aBox, unsigned int aIdxOffset, VERTEX* aVtxOut,
|
||||
GLuint* aIdxOut, const glm::vec4& aColor );
|
||||
|
||||
void Draw( bool aTransparent, float aOpacity, bool aUseSelectedMaterial,
|
||||
SFVEC3F& aSelectionColor ) const;
|
||||
};
|
||||
|
||||
#endif // _MODEL_3D_H_
|
||||
|
||||
@@ -912,7 +912,8 @@ void RENDER_3D_OPENGL::load3dModels( REPORTER* aStatusReporter )
|
||||
if( !m_boardAdapter.GetBoard() )
|
||||
return;
|
||||
|
||||
if( !m_boardAdapter.m_Cfg->m_Render.show_footprints_normal
|
||||
if( !m_boardAdapter.m_IsPreviewer
|
||||
&& !m_boardAdapter.m_Cfg->m_Render.show_footprints_normal
|
||||
&& !m_boardAdapter.m_Cfg->m_Render.show_footprints_insert
|
||||
&& !m_boardAdapter.m_Cfg->m_Render.show_footprints_virtual )
|
||||
{
|
||||
|
||||
@@ -22,14 +22,19 @@
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#include <cstdint>
|
||||
#include <gal/opengl/kiglew.h> // Must be included first
|
||||
|
||||
#include "plugins/3dapi/xv3d_types.h"
|
||||
#include "render_3d_opengl.h"
|
||||
#include "opengl_utils.h"
|
||||
#include "common_ogl/ogl_utils.h"
|
||||
#include <footprint.h>
|
||||
#include <3d_math.h>
|
||||
#include <glm/geometric.hpp>
|
||||
#include <math/util.h> // for KiROUND
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include <wx/log.h>
|
||||
|
||||
#include <base_units.h>
|
||||
@@ -858,9 +863,12 @@ bool RENDER_3D_OPENGL::Redraw( bool aIsMoving, REPORTER* aStatusReporter,
|
||||
glPopMatrix();
|
||||
}
|
||||
|
||||
glm::mat4 cameraViewMatrix;
|
||||
|
||||
glGetFloatv( GL_MODELVIEW_MATRIX, glm::value_ptr( cameraViewMatrix ) );
|
||||
|
||||
// Render 3D Models (Non-transparent)
|
||||
render3dModels( false, false );
|
||||
render3dModels( true, false );
|
||||
renderOpaqueModels( cameraViewMatrix );
|
||||
|
||||
// Display board body
|
||||
if( m_boardAdapter.m_Cfg->m_Render.show_board_body )
|
||||
@@ -922,8 +930,7 @@ bool RENDER_3D_OPENGL::Redraw( bool aIsMoving, REPORTER* aStatusReporter,
|
||||
glTexEnvi( GL_TEXTURE_ENV, GL_SRC1_ALPHA, GL_CONSTANT );
|
||||
glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA );
|
||||
|
||||
render3dModels( false, true );
|
||||
render3dModels( true, true );
|
||||
renderTransparentModels( cameraViewMatrix );
|
||||
|
||||
glDisable( GL_BLEND );
|
||||
OglResetTextureState();
|
||||
@@ -1143,14 +1150,15 @@ void RENDER_3D_OPENGL::renderSolderMaskLayer( PCB_LAYER_ID aLayerID, float aZPos
|
||||
}
|
||||
|
||||
|
||||
void RENDER_3D_OPENGL::render3dModelsSelected( bool aRenderTopOrBot, bool aRenderTransparentOnly,
|
||||
bool aRenderSelectedOnly )
|
||||
void RENDER_3D_OPENGL::get3dModelsSelected( std::list<MODELTORENDER> &aDstRenderList,
|
||||
bool aGetTop, bool aGetBot, bool aRenderTransparentOnly,
|
||||
bool aRenderSelectedOnly )
|
||||
{
|
||||
wxASSERT( ( aGetTop == true ) || ( aGetBot == true ) );
|
||||
|
||||
if( !m_boardAdapter.GetBoard() )
|
||||
return;
|
||||
|
||||
MODEL_3D::BeginDrawMulti( !aRenderSelectedOnly );
|
||||
|
||||
// Go for all footprints
|
||||
for( FOOTPRINT* fp : m_boardAdapter.GetBoard()->Footprints() )
|
||||
{
|
||||
@@ -1175,54 +1183,52 @@ void RENDER_3D_OPENGL::render3dModelsSelected( bool aRenderTopOrBot, bool aRende
|
||||
{
|
||||
if( m_boardAdapter.IsFootprintShown( (FOOTPRINT_ATTR_T) fp->GetAttributes() ) )
|
||||
{
|
||||
if( aRenderTopOrBot == !fp->IsFlipped() )
|
||||
renderFootprint( fp, aRenderTransparentOnly, highlight );
|
||||
const bool isFlipped = fp->IsFlipped();
|
||||
|
||||
if( ( aGetTop == !isFlipped ) ||
|
||||
( aGetBot == isFlipped ) )
|
||||
get3dModelsFromFootprint( aDstRenderList, fp, aRenderTransparentOnly, highlight );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MODEL_3D::EndDrawMulti();
|
||||
}
|
||||
|
||||
|
||||
void RENDER_3D_OPENGL::render3dModels( bool aRenderTopOrBot, bool aRenderTransparentOnly )
|
||||
{
|
||||
if( m_boardAdapter.m_IsBoardView )
|
||||
render3dModelsSelected( aRenderTopOrBot, aRenderTransparentOnly, true );
|
||||
|
||||
render3dModelsSelected( aRenderTopOrBot, aRenderTransparentOnly, false );
|
||||
}
|
||||
|
||||
|
||||
void RENDER_3D_OPENGL::renderFootprint( const FOOTPRINT* aFootprint, bool aRenderTransparentOnly,
|
||||
bool aIsSelected )
|
||||
void RENDER_3D_OPENGL::get3dModelsFromFootprint( std::list<MODELTORENDER> &aDstRenderList,
|
||||
const FOOTPRINT* aFootprint, bool aRenderTransparentOnly,
|
||||
bool aIsSelected )
|
||||
{
|
||||
if( !aFootprint->Models().empty() )
|
||||
{
|
||||
const double zpos = m_boardAdapter.GetFootprintZPos( aFootprint->IsFlipped() );
|
||||
SFVEC3F selColor = m_boardAdapter.GetColor( m_boardAdapter.m_Cfg->m_Render.opengl_selection_color );
|
||||
|
||||
|
||||
glPushMatrix();
|
||||
|
||||
VECTOR2I pos = aFootprint->GetPosition();
|
||||
|
||||
glTranslatef( pos.x * m_boardAdapter.BiuTo3dUnits(), -pos.y * m_boardAdapter.BiuTo3dUnits(),
|
||||
zpos );
|
||||
glm::mat4 fpMatrix( 1.0f );
|
||||
|
||||
fpMatrix = glm::translate( fpMatrix,
|
||||
SFVEC3F( pos.x * m_boardAdapter.BiuTo3dUnits(),
|
||||
-pos.y * m_boardAdapter.BiuTo3dUnits(),
|
||||
zpos ) );
|
||||
|
||||
if( !aFootprint->GetOrientation().IsZero() )
|
||||
glRotated( aFootprint->GetOrientation().AsDegrees(), 0.0, 0.0, 1.0 );
|
||||
{
|
||||
fpMatrix = glm::rotate( fpMatrix,
|
||||
(float) aFootprint->GetOrientation().AsRadians(),
|
||||
SFVEC3F( 0.0f, 0.0f, 1.0f ) );
|
||||
}
|
||||
|
||||
if( aFootprint->IsFlipped() )
|
||||
{
|
||||
glRotatef( 180.0f, 0.0f, 1.0f, 0.0f );
|
||||
glRotatef( 180.0f, 0.0f, 0.0f, 1.0f );
|
||||
fpMatrix = glm::rotate( fpMatrix, glm::pi<float>(), SFVEC3F( 0.0f, 1.0f, 0.0f ) );
|
||||
fpMatrix = glm::rotate( fpMatrix, glm::pi<float>(), SFVEC3F( 0.0f, 0.0f, 1.0f ) );
|
||||
}
|
||||
|
||||
double modelunit_to_3d_units_factor = m_boardAdapter.BiuTo3dUnits() * UNITS3D_TO_UNITSPCB;
|
||||
const double modelunit_to_3d_units_factor = m_boardAdapter.BiuTo3dUnits() *
|
||||
UNITS3D_TO_UNITSPCB;
|
||||
|
||||
glScaled( modelunit_to_3d_units_factor, modelunit_to_3d_units_factor,
|
||||
modelunit_to_3d_units_factor );
|
||||
fpMatrix = glm::scale( fpMatrix,
|
||||
SFVEC3F( modelunit_to_3d_units_factor ) );
|
||||
|
||||
// Get the list of model files for this model
|
||||
for( const FP_3DMODEL& sM : aFootprint->Models() )
|
||||
@@ -1243,66 +1249,232 @@ void RENDER_3D_OPENGL::renderFootprint( const FOOTPRINT* aFootprint, bool aRende
|
||||
if( ( !aRenderTransparentOnly && modelPtr->HasOpaqueMeshes() && opaque ) ||
|
||||
( aRenderTransparentOnly && ( modelPtr->HasTransparentMeshes() || !opaque ) ) )
|
||||
{
|
||||
glPushMatrix();
|
||||
glm::mat4 modelworldMatrix = fpMatrix;
|
||||
|
||||
std::vector<double> key = { sM.m_Offset.x, sM.m_Offset.y, sM.m_Offset.z,
|
||||
sM.m_Rotation.x, sM.m_Rotation.y, sM.m_Rotation.z,
|
||||
sM.m_Scale.x, sM.m_Scale.y, sM.m_Scale.z };
|
||||
const SFVEC3F offset = SFVEC3F( sM.m_Offset.x, sM.m_Offset.y, sM.m_Offset.z );
|
||||
const SFVEC3F rotation = SFVEC3F( sM.m_Rotation.x, sM.m_Rotation.y, sM.m_Rotation.z );
|
||||
const SFVEC3F scale = SFVEC3F( sM.m_Scale.x, sM.m_Scale.y, sM.m_Scale.z );
|
||||
|
||||
std::vector<float> key = { offset.x, offset.y, offset.z,
|
||||
rotation.x, rotation.y, rotation.z,
|
||||
scale.x, scale.y, scale.z };
|
||||
|
||||
auto it = m_3dModelMatrixMap.find( key );
|
||||
|
||||
if( it != m_3dModelMatrixMap.end() )
|
||||
{
|
||||
glMultMatrixf( glm::value_ptr( it->second ) );
|
||||
modelworldMatrix *= it->second;
|
||||
}
|
||||
else
|
||||
{
|
||||
glm::mat4 mtx( 1 );
|
||||
mtx = glm::translate( mtx, { sM.m_Offset.x, sM.m_Offset.y, sM.m_Offset.z } );
|
||||
mtx = glm::rotate( mtx, glm::radians( (float) -sM.m_Rotation.z ), { 0.0f, 0.0f, 1.0f } );
|
||||
mtx = glm::rotate( mtx, glm::radians( (float) -sM.m_Rotation.y ), { 0.0f, 1.0f, 0.0f } );
|
||||
mtx = glm::rotate( mtx, glm::radians( (float) -sM.m_Rotation.x ), { 1.0f, 0.0f, 0.0f } );
|
||||
mtx = glm::scale( mtx, { sM.m_Scale.x, sM.m_Scale.y, sM.m_Scale.z } );
|
||||
glm::mat4 mtx( 1.0f );
|
||||
mtx = glm::translate( mtx, offset );
|
||||
mtx = glm::rotate( mtx, glm::radians( -rotation.z ), { 0.0f, 0.0f, 1.0f } );
|
||||
mtx = glm::rotate( mtx, glm::radians( -rotation.y ), { 0.0f, 1.0f, 0.0f } );
|
||||
mtx = glm::rotate( mtx, glm::radians( -rotation.x ), { 1.0f, 0.0f, 0.0f } );
|
||||
mtx = glm::scale( mtx, scale );
|
||||
m_3dModelMatrixMap[ key ] = mtx;
|
||||
|
||||
glMultMatrixf( glm::value_ptr( mtx ) );
|
||||
modelworldMatrix *= mtx;
|
||||
}
|
||||
|
||||
|
||||
if( aRenderTransparentOnly )
|
||||
{
|
||||
modelPtr->DrawTransparent( sM.m_Opacity,
|
||||
aFootprint->IsSelected() || aIsSelected,
|
||||
selColor );
|
||||
aDstRenderList.emplace_back( modelworldMatrix,
|
||||
modelPtr,
|
||||
sM.m_Opacity,
|
||||
true,
|
||||
aFootprint->IsSelected() || aIsSelected );
|
||||
}
|
||||
else
|
||||
{
|
||||
modelPtr->DrawOpaque( aFootprint->IsSelected() || aIsSelected, selColor );
|
||||
aDstRenderList.emplace_back( modelworldMatrix,
|
||||
modelPtr,
|
||||
1.0f,
|
||||
false,
|
||||
aFootprint->IsSelected() || aIsSelected );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( m_boardAdapter.m_Cfg->m_Render.opengl_show_model_bbox )
|
||||
{
|
||||
glEnable( GL_BLEND );
|
||||
glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
|
||||
|
||||
glDisable( GL_LIGHTING );
|
||||
void RENDER_3D_OPENGL::renderOpaqueModels( const glm::mat4 &aCameraViewMatrix )
|
||||
{
|
||||
const SFVEC3F selColor = m_boardAdapter.GetColor( m_boardAdapter.m_Cfg->m_Render.opengl_selection_color );
|
||||
|
||||
glLineWidth( 1 );
|
||||
modelPtr->DrawBboxes();
|
||||
glPushMatrix();
|
||||
|
||||
glLineWidth( 4 );
|
||||
modelPtr->DrawBbox();
|
||||
std::list<MODELTORENDER> renderList;
|
||||
|
||||
glEnable( GL_LIGHTING );
|
||||
glDisable( GL_BLEND );
|
||||
}
|
||||
if( m_boardAdapter.m_IsBoardView )
|
||||
{
|
||||
renderList.clear();
|
||||
|
||||
glPopMatrix();
|
||||
get3dModelsSelected( renderList, true, true, false, true );
|
||||
|
||||
if( !renderList.empty() )
|
||||
{
|
||||
MODEL_3D::BeginDrawMulti( false );
|
||||
|
||||
for( const MODELTORENDER& mtr : renderList )
|
||||
{
|
||||
renderModel( aCameraViewMatrix, mtr, selColor, nullptr );
|
||||
}
|
||||
|
||||
MODEL_3D::EndDrawMulti();
|
||||
}
|
||||
}
|
||||
|
||||
renderList.clear();
|
||||
get3dModelsSelected( renderList, true, true, false, false );
|
||||
|
||||
if( !renderList.empty() )
|
||||
{
|
||||
MODEL_3D::BeginDrawMulti( true );
|
||||
|
||||
for( const MODELTORENDER& mtr : renderList )
|
||||
{
|
||||
renderModel( aCameraViewMatrix, mtr, selColor, nullptr );
|
||||
}
|
||||
|
||||
MODEL_3D::EndDrawMulti();
|
||||
}
|
||||
|
||||
glPopMatrix();
|
||||
}
|
||||
|
||||
|
||||
void RENDER_3D_OPENGL::renderTransparentModels( const glm::mat4 &aCameraViewMatrix )
|
||||
{
|
||||
const SFVEC3F selColor = m_boardAdapter.GetColor( m_boardAdapter.m_Cfg->m_Render.opengl_selection_color );
|
||||
|
||||
std::list<MODELTORENDER> renderListModels; // do not clear it until this function returns
|
||||
|
||||
if( m_boardAdapter.m_IsBoardView )
|
||||
{
|
||||
// Get Transparent Selected
|
||||
get3dModelsSelected( renderListModels, true, true, true, true );
|
||||
}
|
||||
|
||||
// Get Transparent Not Selected
|
||||
get3dModelsSelected( renderListModels, true, true, true, false );
|
||||
|
||||
if( renderListModels.empty() )
|
||||
return;
|
||||
|
||||
std::vector<std::pair<const MODELTORENDER *, float>> transparentModelList;
|
||||
|
||||
transparentModelList.reserve( renderListModels.size() );
|
||||
|
||||
// Calculate the distance to the camera for each model
|
||||
const SFVEC3F &cameraPos = m_camera.GetPos();
|
||||
|
||||
for( const MODELTORENDER& mtr : renderListModels )
|
||||
{
|
||||
const BBOX_3D& bBox = mtr.m_model->GetBBox();
|
||||
const SFVEC3F& bBoxCenter = bBox.GetCenter();
|
||||
const SFVEC3F bBoxWorld = mtr.m_modelWorldMat * glm::vec4( bBoxCenter, 1.0f );
|
||||
|
||||
const float distanceToCamera = glm::length( cameraPos - bBoxWorld );
|
||||
|
||||
transparentModelList.emplace_back( &mtr, distanceToCamera );
|
||||
}
|
||||
|
||||
// Sort from back to front
|
||||
std::sort( transparentModelList.begin(), transparentModelList.end(),
|
||||
[&]( std::pair<const MODELTORENDER *, float>& a,
|
||||
std::pair<const MODELTORENDER *, float>& b ) {
|
||||
return a.second > b.second;
|
||||
} );
|
||||
|
||||
// Start rendering calls
|
||||
glPushMatrix();
|
||||
|
||||
bool isUsingColorInformation = !( transparentModelList.begin()->first->m_isSelected &&
|
||||
m_boardAdapter.m_IsBoardView );
|
||||
|
||||
MODEL_3D::BeginDrawMulti( isUsingColorInformation );
|
||||
|
||||
for( const std::pair<const MODELTORENDER *, float>& mtr : transparentModelList )
|
||||
{
|
||||
if( m_boardAdapter.m_IsBoardView )
|
||||
{
|
||||
// Toggle between using model color or the select color
|
||||
if( !isUsingColorInformation && !mtr.first->m_isSelected )
|
||||
{
|
||||
isUsingColorInformation = true;
|
||||
|
||||
glEnableClientState( GL_COLOR_ARRAY );
|
||||
glEnableClientState( GL_TEXTURE_COORD_ARRAY );
|
||||
glEnable( GL_COLOR_MATERIAL );
|
||||
}
|
||||
else
|
||||
{
|
||||
if( isUsingColorInformation && mtr.first->m_isSelected )
|
||||
{
|
||||
isUsingColorInformation = false;
|
||||
|
||||
glDisableClientState( GL_COLOR_ARRAY );
|
||||
glDisableClientState( GL_TEXTURE_COORD_ARRAY );
|
||||
glDisable( GL_COLOR_MATERIAL );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
glPopMatrix();
|
||||
// Render model, sort each individuall material group
|
||||
// by passing cameraPos
|
||||
renderModel( aCameraViewMatrix, *mtr.first, selColor, &cameraPos );
|
||||
}
|
||||
|
||||
MODEL_3D::EndDrawMulti();
|
||||
|
||||
glPopMatrix();
|
||||
}
|
||||
|
||||
|
||||
void RENDER_3D_OPENGL::renderModel( const glm::mat4 &aCameraViewMatrix,
|
||||
const MODELTORENDER &aModelToRender,
|
||||
const SFVEC3F &aSelColor,
|
||||
const SFVEC3F *aCameraWorldPos )
|
||||
{
|
||||
const glm::mat4 modelviewMatrix = aCameraViewMatrix * aModelToRender.m_modelWorldMat;
|
||||
|
||||
glLoadMatrixf( glm::value_ptr( modelviewMatrix ) );
|
||||
|
||||
aModelToRender.m_model->Draw( aModelToRender.m_isTransparent,
|
||||
aModelToRender.m_opacity,
|
||||
aModelToRender.m_isSelected,
|
||||
aSelColor,
|
||||
&aModelToRender.m_modelWorldMat,
|
||||
aCameraWorldPos );
|
||||
|
||||
if( m_boardAdapter.m_Cfg->m_Render.opengl_show_model_bbox )
|
||||
{
|
||||
const bool wasBlendEnabled = glIsEnabled( GL_BLEND );
|
||||
|
||||
if( !wasBlendEnabled )
|
||||
{
|
||||
glEnable( GL_BLEND );
|
||||
glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
|
||||
}
|
||||
|
||||
glDisable( GL_LIGHTING );
|
||||
|
||||
glLineWidth( 1 );
|
||||
aModelToRender.m_model->DrawBboxes();
|
||||
|
||||
glLineWidth( 4 );
|
||||
aModelToRender.m_model->DrawBbox();
|
||||
|
||||
glEnable( GL_LIGHTING );
|
||||
|
||||
if( !wasBlendEnabled )
|
||||
{
|
||||
glDisable( GL_BLEND );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -129,18 +129,44 @@ private:
|
||||
*/
|
||||
void load3dModels( REPORTER* aStatusReporter );
|
||||
|
||||
/**
|
||||
* @param aRenderTopOrBot true will render Top, false will render bottom
|
||||
* @param aRenderTransparentOnly true will render only the transparent objects, false will
|
||||
* render opaque
|
||||
*/
|
||||
void render3dModels( bool aRenderTopOrBot, bool aRenderTransparentOnly );
|
||||
struct MODELTORENDER
|
||||
{
|
||||
glm::mat4 m_modelWorldMat;
|
||||
const MODEL_3D* m_model;
|
||||
float m_opacity;
|
||||
bool m_isTransparent;
|
||||
bool m_isSelected;
|
||||
|
||||
void render3dModelsSelected( bool aRenderTopOrBot, bool aRenderTransparentOnly,
|
||||
bool aRenderSelectedOnly );
|
||||
MODELTORENDER( glm::mat4 aModelWorldMat,
|
||||
const MODEL_3D* aNodel,
|
||||
float aOpacity,
|
||||
bool aIsTransparent,
|
||||
bool aIsSelected ) :
|
||||
m_modelWorldMat( std::move( aModelWorldMat ) ),
|
||||
m_model( aNodel ),
|
||||
m_opacity( aOpacity ),
|
||||
m_isTransparent( aIsTransparent ),
|
||||
m_isSelected( aIsSelected )
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
void renderFootprint( const FOOTPRINT* aFootprint, bool aRenderTransparentOnly,
|
||||
bool aIsSelected );
|
||||
void renderOpaqueModels( const glm::mat4 &aCameraViewMatrix );
|
||||
void renderTransparentModels( const glm::mat4 &aCameraViewMatrix );
|
||||
|
||||
void renderModel( const glm::mat4 &aCameraViewMatrix,
|
||||
const MODELTORENDER &aModelToRender,
|
||||
const SFVEC3F &aSelColor,
|
||||
const SFVEC3F *aCameraWorldPos );
|
||||
|
||||
|
||||
void get3dModelsSelected( std::list<MODELTORENDER> &aDstRenderList,
|
||||
bool aGetTop, bool aGetBot, bool aRenderTransparentOnly,
|
||||
bool aRenderSelectedOnly );
|
||||
|
||||
void get3dModelsFromFootprint( std::list<MODELTORENDER> &aDstRenderList,
|
||||
const FOOTPRINT* aFootprint, bool aRenderTransparentOnly,
|
||||
bool aIsSelected );
|
||||
|
||||
void setLightFront( bool enabled );
|
||||
void setLightTop( bool enabled );
|
||||
@@ -210,7 +236,7 @@ private:
|
||||
|
||||
// Caches
|
||||
std::map< wxString, MODEL_3D* > m_3dModelMap;
|
||||
std::map< std::vector<double>, glm::mat4 > m_3dModelMatrixMap;
|
||||
std::map< std::vector<float>, glm::mat4 > m_3dModelMatrixMap;
|
||||
|
||||
BOARD_ITEM* m_currentRollOverItem;
|
||||
|
||||
|
||||
@@ -1202,7 +1202,8 @@ void RENDER_3D_RAYTRACE::load3DModels( CONTAINER_3D& aDstContainer, bool aSkipMa
|
||||
if( !m_boardAdapter.GetBoard() )
|
||||
return;
|
||||
|
||||
if( !m_boardAdapter.m_Cfg->m_Render.show_footprints_normal
|
||||
if( !m_boardAdapter.m_IsPreviewer
|
||||
&& !m_boardAdapter.m_Cfg->m_Render.show_footprints_normal
|
||||
&& !m_boardAdapter.m_Cfg->m_Render.show_footprints_insert
|
||||
&& !m_boardAdapter.m_Cfg->m_Render.show_footprints_virtual )
|
||||
{
|
||||
|
||||
@@ -229,6 +229,16 @@ bool BBOX_2D::Inside( const SFVEC2F& aPoint ) const
|
||||
}
|
||||
|
||||
|
||||
bool BBOX_2D::Inside( const BBOX_2D& aBBox ) const
|
||||
{
|
||||
wxASSERT( IsInitialized() );
|
||||
wxASSERT( aBBox.IsInitialized() );
|
||||
|
||||
return Inside( aBBox.Min() ) &&
|
||||
Inside( aBBox.Max() );
|
||||
}
|
||||
|
||||
|
||||
float BBOX_2D::Area() const
|
||||
{
|
||||
SFVEC2F extent = GetExtent();
|
||||
|
||||
@@ -132,6 +132,14 @@ public:
|
||||
*/
|
||||
bool Inside( const SFVEC2F& aPoint ) const;
|
||||
|
||||
/**
|
||||
* Check if a bounding box is inside this bounding box.
|
||||
*
|
||||
* @param aBBox the bounding box to test if it is inside
|
||||
* @return true if aBBox is smaller and all points are inside
|
||||
*/
|
||||
bool Inside( const BBOX_2D& aBBox ) const;
|
||||
|
||||
/**
|
||||
* Calculate the area of a bounding box.
|
||||
*
|
||||
|
||||
@@ -238,6 +238,16 @@ bool BBOX_3D::Inside( const SFVEC3F& aPoint ) const
|
||||
}
|
||||
|
||||
|
||||
bool BBOX_3D::Inside( const BBOX_3D& aBBox ) const
|
||||
{
|
||||
wxASSERT( IsInitialized() );
|
||||
wxASSERT( aBBox.IsInitialized() );
|
||||
|
||||
return Inside( aBBox.Min() ) &&
|
||||
Inside( aBBox.Max() );
|
||||
}
|
||||
|
||||
|
||||
float BBOX_3D::Volume() const
|
||||
{
|
||||
wxASSERT( IsInitialized() );
|
||||
|
||||
@@ -125,6 +125,14 @@ public:
|
||||
*/
|
||||
bool Inside( const SFVEC3F& aPoint ) const;
|
||||
|
||||
/**
|
||||
* Check if a bounding box is inside this bounding box.
|
||||
*
|
||||
* @param aBBox the bounding box to test if it is inside
|
||||
* @return true if aBBox is smaller and all points are inside
|
||||
*/
|
||||
bool Inside( const BBOX_3D& aBBox ) const;
|
||||
|
||||
/**
|
||||
* Apply a transformation matrix to the box points.
|
||||
*
|
||||
|
||||
@@ -39,6 +39,7 @@
|
||||
#include <3d_viewer/tools/eda_3d_actions.h>
|
||||
#include <3d_viewer/tools/eda_3d_controller.h>
|
||||
#include <3d_viewer/tools/eda_3d_conditions.h>
|
||||
#include <advanced_config.h>
|
||||
#include <bitmaps.h>
|
||||
#include <board_design_settings.h>
|
||||
#include <core/arraydim.h>
|
||||
@@ -56,9 +57,7 @@
|
||||
#include <widgets/wx_infobar.h>
|
||||
#include <wildcards_and_files_ext.h>
|
||||
|
||||
#if defined( KICAD_USE_3DCONNEXION )
|
||||
#include <3d_navlib/nl_3d_viewer_plugin.h>
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Flag to enable 3D viewer main frame window debug tracing.
|
||||
@@ -166,16 +165,18 @@ EDA_3D_VIEWER_FRAME::EDA_3D_VIEWER_FRAME( KIWAY* aKiway, PCB_BASE_FRAME* aParent
|
||||
m_canvas->SetInfoBar( m_infoBar );
|
||||
m_canvas->SetStatusBar( status_bar );
|
||||
|
||||
#if defined( KICAD_USE_3DCONNEXION )
|
||||
try
|
||||
|
||||
if( ADVANCED_CFG::GetCfg().m_Use3DConnexionDriver )
|
||||
{
|
||||
m_spaceMouse = new NL_3D_VIEWER_PLUGIN( m_canvas );
|
||||
try
|
||||
{
|
||||
m_spaceMouse = new NL_3D_VIEWER_PLUGIN( m_canvas );
|
||||
}
|
||||
catch( const std::system_error& e )
|
||||
{
|
||||
wxLogTrace( wxT( "KI_TRACE_NAVLIB" ), e.what() );
|
||||
}
|
||||
}
|
||||
catch( const std::system_error& e )
|
||||
{
|
||||
wxLogTrace( wxT( "KI_TRACE_NAVLIB" ), e.what() );
|
||||
}
|
||||
#endif
|
||||
|
||||
// Fixes bug in Windows (XP and possibly others) where the canvas requires the focus
|
||||
// in order to receive mouse events. Otherwise, the user has to click somewhere on
|
||||
@@ -193,12 +194,7 @@ EDA_3D_VIEWER_FRAME::EDA_3D_VIEWER_FRAME( KIWAY* aKiway, PCB_BASE_FRAME* aParent
|
||||
|
||||
EDA_3D_VIEWER_FRAME::~EDA_3D_VIEWER_FRAME()
|
||||
{
|
||||
#if defined( KICAD_USE_3DCONNEXION )
|
||||
if( m_spaceMouse != nullptr )
|
||||
{
|
||||
delete m_spaceMouse;
|
||||
}
|
||||
#endif
|
||||
delete m_spaceMouse;
|
||||
|
||||
Prj().GetProjectFile().m_Viewports3D = GetUserViewports();
|
||||
|
||||
@@ -334,12 +330,11 @@ void EDA_3D_VIEWER_FRAME::handleIconizeEvent( wxIconizeEvent& aEvent )
|
||||
{
|
||||
KIWAY_PLAYER::handleIconizeEvent( aEvent );
|
||||
|
||||
#if defined( KICAD_USE_3DCONNEXION )
|
||||
if( m_spaceMouse != nullptr && aEvent.IsIconized() )
|
||||
if( m_spaceMouse != nullptr && aEvent.IsIconized()
|
||||
&& ADVANCED_CFG::GetCfg().m_Use3DConnexionDriver )
|
||||
{
|
||||
m_spaceMouse->SetFocus( false );
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -655,12 +650,8 @@ void EDA_3D_VIEWER_FRAME::OnActivate( wxActivateEvent &aEvent )
|
||||
m_canvas->SetFocus();
|
||||
}
|
||||
|
||||
#if defined( KICAD_USE_3DCONNEXION )
|
||||
if( m_spaceMouse != nullptr )
|
||||
{
|
||||
if( m_spaceMouse != nullptr && ADVANCED_CFG::GetCfg().m_Use3DConnexionDriver )
|
||||
m_spaceMouse->SetFocus( aEvent.GetActive() );
|
||||
}
|
||||
#endif
|
||||
|
||||
aEvent.Skip(); // required under wxMAC
|
||||
}
|
||||
|
||||
@@ -122,8 +122,6 @@ target_link_libraries( 3d-viewer
|
||||
|
||||
add_subdirectory( 3d_cache )
|
||||
|
||||
if( KICAD_USE_3DCONNEXION )
|
||||
message( STATUS "Including 3Dconnexion SpaceMouse navigation support in 3d-viewer" )
|
||||
add_subdirectory( 3d_navlib )
|
||||
target_link_libraries( 3d-viewer PRIVATE 3d-viewer_navlib)
|
||||
endif()
|
||||
message( STATUS "Including 3Dconnexion SpaceMouse navigation support in 3d-viewer" )
|
||||
add_subdirectory( 3d_navlib )
|
||||
target_link_libraries( 3d-viewer PRIVATE 3d-viewer_navlib)
|
||||
|
||||
@@ -56,20 +56,24 @@ PANEL_PREVIEW_3D_MODEL::PANEL_PREVIEW_3D_MODEL( wxWindow* aParent, PCB_BASE_FRAM
|
||||
m_userUnits = aFrame->GetUserUnits();
|
||||
|
||||
m_dummyBoard = new BOARD();
|
||||
|
||||
m_dummyBoard->SetProject( &aFrame->Prj(), true );
|
||||
|
||||
// This board will only be used to hold a footprint for viewing
|
||||
m_dummyBoard->SetBoardUse( BOARD_USE::FPHOLDER );
|
||||
|
||||
BOARD_DESIGN_SETTINGS parent_bds = aFrame->GetDesignSettings();
|
||||
BOARD_DESIGN_SETTINGS dummy_bds = m_dummyBoard->GetDesignSettings();
|
||||
BOARD_DESIGN_SETTINGS& dummy_bds = m_dummyBoard->GetDesignSettings();
|
||||
dummy_bds.SetBoardThickness( parent_bds.GetBoardThickness() );
|
||||
dummy_bds.SetEnabledLayers( LSET::FrontMask() | LSET::BackMask() );
|
||||
BOARD_STACKUP& dummy_board_stackup = m_dummyBoard->GetDesignSettings().GetStackupDescriptor();
|
||||
dummy_board_stackup.RemoveAll();
|
||||
dummy_board_stackup.BuildDefaultStackupList( &dummy_bds, 2 );
|
||||
|
||||
m_selected = -1;
|
||||
|
||||
m_previewLabel->SetFont( KIUI::GetStatusFont( this ) );
|
||||
|
||||
// Set the bitmap of 3D view buttons:
|
||||
m_bpvTop->SetBitmap( KiBitmap( BITMAPS::axis3d_top ) );
|
||||
m_bpvFront->SetBitmap( KiBitmap( BITMAPS::axis3d_front ) );
|
||||
@@ -140,6 +144,9 @@ PANEL_PREVIEW_3D_MODEL::PANEL_PREVIEW_3D_MODEL( wxWindow* aParent, PCB_BASE_FRAM
|
||||
this );
|
||||
}
|
||||
|
||||
aFrame->Connect( UNITS_CHANGED, wxCommandEventHandler( PANEL_PREVIEW_3D_MODEL::onUnitsChanged ),
|
||||
nullptr, this );
|
||||
|
||||
#ifdef __WXOSX__
|
||||
// Call layout once to get the proper button sizes after the bitmaps have been set
|
||||
Layout();
|
||||
@@ -538,6 +545,29 @@ void PANEL_PREVIEW_3D_MODEL::onMouseWheelOffset( wxMouseEvent& event )
|
||||
}
|
||||
|
||||
|
||||
void PANEL_PREVIEW_3D_MODEL::onUnitsChanged( wxCommandEvent& aEvent )
|
||||
{
|
||||
double xoff_mm = EDA_UNIT_UTILS::UI::DoubleValueFromString( pcbIUScale, m_userUnits,
|
||||
xoff->GetValue() )
|
||||
/ pcbIUScale.IU_PER_MM;
|
||||
double yoff_mm = EDA_UNIT_UTILS::UI::DoubleValueFromString( pcbIUScale, m_userUnits,
|
||||
yoff->GetValue() )
|
||||
/ pcbIUScale.IU_PER_MM;
|
||||
double zoff_mm = EDA_UNIT_UTILS::UI::DoubleValueFromString( pcbIUScale, m_userUnits,
|
||||
zoff->GetValue() )
|
||||
/ pcbIUScale.IU_PER_MM;
|
||||
|
||||
PCB_BASE_FRAME* frame = static_cast<PCB_BASE_FRAME*>( aEvent.GetClientData() );
|
||||
m_userUnits = frame->GetUserUnits();
|
||||
|
||||
xoff->SetValue( formatOffsetValue( xoff_mm ) );
|
||||
yoff->SetValue( formatOffsetValue( yoff_mm ) );
|
||||
zoff->SetValue( formatOffsetValue( zoff_mm ) );
|
||||
|
||||
aEvent.Skip();
|
||||
}
|
||||
|
||||
|
||||
void PANEL_PREVIEW_3D_MODEL::UpdateDummyFootprint( bool aReloadRequired )
|
||||
{
|
||||
m_dummyFootprint->Models().clear();
|
||||
|
||||
@@ -141,6 +141,8 @@ private:
|
||||
void doIncrementRotation( wxSpinEvent& aEvent, double aSign );
|
||||
void doIncrementOffset( wxSpinEvent& aEvent, double aSign );
|
||||
|
||||
void onUnitsChanged( wxCommandEvent& aEvent );
|
||||
|
||||
wxString formatScaleValue( double aValue );
|
||||
wxString formatRotationValue( double aValue );
|
||||
wxString formatOffsetValue( double aValue );
|
||||
|
||||
@@ -183,12 +183,11 @@ PANEL_PREVIEW_3D_MODEL_BASE::PANEL_PREVIEW_3D_MODEL_BASE( wxWindow* parent, wxWi
|
||||
wxBoxSizer* bSizer6;
|
||||
bSizer6 = new wxBoxSizer( wxHORIZONTAL );
|
||||
|
||||
wxStaticText* staticPreviewLabel;
|
||||
staticPreviewLabel = new wxStaticText( this, wxID_ANY, _("Preview"), wxDefaultPosition, wxDefaultSize, 0 );
|
||||
staticPreviewLabel->Wrap( -1 );
|
||||
staticPreviewLabel->SetFont( wxFont( 11, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL, false, wxEmptyString ) );
|
||||
m_previewLabel = new wxStaticText( this, wxID_ANY, _("Preview"), wxDefaultPosition, wxDefaultSize, 0 );
|
||||
m_previewLabel->Wrap( -1 );
|
||||
m_previewLabel->SetFont( wxFont( 11, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL, false, wxEmptyString ) );
|
||||
|
||||
bSizer6->Add( staticPreviewLabel, 0, wxEXPAND|wxLEFT|wxRIGHT, 10 );
|
||||
bSizer6->Add( m_previewLabel, 1, wxEXPAND|wxLEFT|wxRIGHT, 10 );
|
||||
|
||||
|
||||
bSizerRight->Add( bSizer6, 0, wxEXPAND, 5 );
|
||||
@@ -207,7 +206,7 @@ PANEL_PREVIEW_3D_MODEL_BASE::PANEL_PREVIEW_3D_MODEL_BASE( wxWindow* parent, wxWi
|
||||
m_bpvISO = new wxBitmapButton( this, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1,-1 ), wxBU_AUTODRAW|0 );
|
||||
m_bpvISO->SetToolTip( _("Enable/disable orthographic projection") );
|
||||
|
||||
bSizer3DButtons->Add( m_bpvISO, 0, wxTOP|wxBOTTOM, 5 );
|
||||
bSizer3DButtons->Add( m_bpvISO, 0, wxTOP, 14 );
|
||||
|
||||
|
||||
bSizer3DButtons->Add( 0, 0, 1, wxEXPAND, 5 );
|
||||
|
||||
@@ -2089,7 +2089,7 @@
|
||||
<object class="sizeritem" expanded="1">
|
||||
<property name="border">10</property>
|
||||
<property name="flag">wxEXPAND|wxLEFT|wxRIGHT</property>
|
||||
<property name="proportion">0</property>
|
||||
<property name="proportion">1</property>
|
||||
<object class="wxStaticText" expanded="1">
|
||||
<property name="BottomDockable">1</property>
|
||||
<property name="LeftDockable">1</property>
|
||||
@@ -2127,11 +2127,11 @@
|
||||
<property name="minimize_button">0</property>
|
||||
<property name="minimum_size"></property>
|
||||
<property name="moveable">1</property>
|
||||
<property name="name">staticPreviewLabel</property>
|
||||
<property name="name">m_previewLabel</property>
|
||||
<property name="pane_border">1</property>
|
||||
<property name="pane_position"></property>
|
||||
<property name="pane_size"></property>
|
||||
<property name="permission">none</property>
|
||||
<property name="permission">protected</property>
|
||||
<property name="pin_button">1</property>
|
||||
<property name="pos"></property>
|
||||
<property name="resize">Resizable</property>
|
||||
@@ -2172,8 +2172,8 @@
|
||||
<property name="orient">wxVERTICAL</property>
|
||||
<property name="permission">none</property>
|
||||
<object class="sizeritem" expanded="1">
|
||||
<property name="border">5</property>
|
||||
<property name="flag">wxTOP|wxBOTTOM</property>
|
||||
<property name="border">14</property>
|
||||
<property name="flag">wxTOP</property>
|
||||
<property name="proportion">0</property>
|
||||
<object class="wxBitmapButton" expanded="1">
|
||||
<property name="BottomDockable">1</property>
|
||||
|
||||
@@ -68,6 +68,7 @@ class PANEL_PREVIEW_3D_MODEL_BASE : public wxPanel
|
||||
wxSlider* m_opacity;
|
||||
wxTextCtrl* m_boardThicknessCtrl;
|
||||
wxStaticText* m_boardThicknessUnits;
|
||||
wxStaticText* m_previewLabel;
|
||||
wxBoxSizer* m_SizerPanelView;
|
||||
wxBitmapButton* m_bpvISO;
|
||||
wxBitmapButton* m_bpvLeft;
|
||||
|
||||
+6
-2
@@ -350,12 +350,16 @@ endif(USE_DISTCC)
|
||||
# Set flags for GCC, or treat llvm as GCC
|
||||
#================================================
|
||||
|
||||
if( CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang" )
|
||||
|
||||
if( CMAKE_COMPILER_IS_GNUCXX )
|
||||
# Set 32-bit flag for GCC to prevent excess precision
|
||||
# clang des not know this flag, so keep this separate
|
||||
if( CMAKE_SIZEOF_VOID_P EQUAL 4 )
|
||||
set( CMAKE_CXX_FLAGS "-ffloat-store ${CMAKE_CXX_FLAGS}" )
|
||||
endif()
|
||||
endif( CMAKE_COMPILER_IS_GNUCXX )
|
||||
|
||||
|
||||
if( CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang" )
|
||||
|
||||
# Link flags in Debug: -g1 and -ggdb1 or -g1 and -ggdb3 can be used.
|
||||
# Level 1 produces minimal information, enough for making basic backtraces.
|
||||
|
||||
@@ -66,7 +66,7 @@ macro( create_git_version_header _git_src_path )
|
||||
# Check to make sure 'git' command did not fail. Otherwise fallback
|
||||
# to KiCadVersion.cmake as the revision level.
|
||||
if( _git_describe_result EQUAL 0 )
|
||||
set( KICAD_VERSION "(${_git_DESCRIBE})" )
|
||||
set( KICAD_VERSION "${_git_DESCRIBE}" )
|
||||
endif()
|
||||
|
||||
if( _git_rev_parse_head_result EQUAL 0 )
|
||||
|
||||
@@ -926,8 +926,17 @@ if(wxWidgets_FOUND)
|
||||
"\\2" wxWidgets_VERSION_MINOR "${_wx_version_h}" )
|
||||
string(REGEX REPLACE "^(.*\n)?#define +wxRELEASE_NUMBER +([0-9]+).*"
|
||||
"\\2" wxWidgets_VERSION_PATCH "${_wx_version_h}" )
|
||||
set(wxWidgets_VERSION_STRING
|
||||
"${wxWidgets_VERSION_MAJOR}.${wxWidgets_VERSION_MINOR}.${wxWidgets_VERSION_PATCH}" )
|
||||
string(REGEX REPLACE "^(.*\n)?#define +wxSUBRELEASE_NUMBER +([0-9]+).*"
|
||||
"\\2" wxWidgets_VERSION_SUBRELEASE "${_wx_version_h}" )
|
||||
|
||||
if( ${wxWidgets_VERSION_SUBRELEASE} GREATER 0 )
|
||||
set(wxWidgets_VERSION_STRING
|
||||
"${wxWidgets_VERSION_MAJOR}.${wxWidgets_VERSION_MINOR}.${wxWidgets_VERSION_PATCH}.${wxWidgets_VERSION_SUBRELEASE}" )
|
||||
else()
|
||||
set(wxWidgets_VERSION_STRING
|
||||
"${wxWidgets_VERSION_MAJOR}.${wxWidgets_VERSION_MINOR}.${wxWidgets_VERSION_PATCH}" )
|
||||
endif()
|
||||
|
||||
DBG_MSG("wxWidgets_VERSION_STRING: ${wxWidgets_VERSION_STRING}")
|
||||
endif()
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
# KiCad.
|
||||
#
|
||||
# Note: This version string should follow the semantic versioning system
|
||||
set( KICAD_SEMANTIC_VERSION "7.0.0" )
|
||||
set( KICAD_SEMANTIC_VERSION "7.0.4" )
|
||||
|
||||
# Default the version to the semantic version.
|
||||
# This is overridden by the git repository tag though (if using git)
|
||||
|
||||
@@ -620,12 +620,9 @@ target_link_libraries( pcbcommon PUBLIC
|
||||
threadpool
|
||||
)
|
||||
|
||||
if( KICAD_USE_3DCONNEXION )
|
||||
message( STATUS "Including 3Dconnexion SpaceMouse navigation support in pcbcommon" )
|
||||
add_subdirectory( ../pcbnew/navlib ./navlib)
|
||||
target_link_libraries( pcbcommon PUBLIC pcbnew_navlib)
|
||||
endif()
|
||||
|
||||
message( STATUS "Including 3Dconnexion SpaceMouse navigation support in pcbcommon" )
|
||||
add_subdirectory( ../pcbnew/navlib ./navlib)
|
||||
target_link_libraries( pcbcommon PUBLIC pcbnew_navlib)
|
||||
|
||||
add_dependencies( pcbcommon delaunator )
|
||||
|
||||
|
||||
@@ -62,6 +62,16 @@ namespace AC_STACK
|
||||
namespace AC_KEYS
|
||||
{
|
||||
|
||||
/**
|
||||
* Should the schematic use the new incremental connectivity algorithm
|
||||
*/
|
||||
static const wxChar IncrementalConnectivity[] = wxT( "IncrementalConnectivity" );
|
||||
|
||||
/**
|
||||
* Decide whether to attempt usage of the 3DConnexion mouse
|
||||
*/
|
||||
static const wxChar Use3DConnexionDriver[] = wxT( "3DConnexionDriver" );
|
||||
|
||||
/**
|
||||
* When filling zones, we add an extra amount of clearance to each zone to ensure that rounding
|
||||
* errors do not overrun minimum clearance distances. This is the extra in mm.
|
||||
@@ -321,6 +331,15 @@ ADVANCED_CFG::ADVANCED_CFG()
|
||||
|
||||
m_UseClipper2 = true;
|
||||
|
||||
#ifdef _WIN32
|
||||
// spacemouse is largely stable on Windows
|
||||
m_Use3DConnexionDriver = true;
|
||||
#else
|
||||
m_Use3DConnexionDriver = false;
|
||||
#endif
|
||||
|
||||
m_IncrementalConnectivity = false;
|
||||
|
||||
loadFromConfigFile();
|
||||
}
|
||||
|
||||
@@ -463,6 +482,12 @@ void ADVANCED_CFG::loadSettings( wxConfigBase& aCfg )
|
||||
configParams.push_back( new PARAM_CFG_BOOL( true, AC_KEYS::UseClipper2,
|
||||
&m_UseClipper2, m_UseClipper2 ) );
|
||||
|
||||
configParams.push_back( new PARAM_CFG_BOOL( true, AC_KEYS::Use3DConnexionDriver,
|
||||
&m_Use3DConnexionDriver, m_Use3DConnexionDriver ) );
|
||||
|
||||
configParams.push_back( new PARAM_CFG_BOOL( true, AC_KEYS::IncrementalConnectivity,
|
||||
&m_IncrementalConnectivity, m_IncrementalConnectivity ) );
|
||||
|
||||
|
||||
|
||||
// Special case for trace mask setting...we just grab them and set them immediately
|
||||
|
||||
@@ -45,6 +45,7 @@
|
||||
#include <eda_base_frame.h>
|
||||
#include <eda_draw_frame.h>
|
||||
#include <paths.h>
|
||||
#include <kiplatform/ui.h>
|
||||
|
||||
|
||||
static std::unique_ptr<BITMAP_STORE> s_BitmapStore;
|
||||
|
||||
+55
-15
@@ -41,7 +41,8 @@ BITMAP_BASE::BITMAP_BASE( const VECTOR2I& pos )
|
||||
m_ppi = 300; // the bitmap definition. the default is 300PPI
|
||||
m_pixelSizeIu = 254000.0 / m_ppi; // a pixel size value OK for bitmaps using 300 PPI
|
||||
// for Eeschema which uses currently 254000PPI
|
||||
m_isMirrored = false;
|
||||
m_isMirroredX = false;
|
||||
m_isMirroredY = false;
|
||||
m_rotation = ANGLE_0;
|
||||
}
|
||||
|
||||
@@ -51,7 +52,8 @@ BITMAP_BASE::BITMAP_BASE( const BITMAP_BASE& aSchBitmap )
|
||||
m_scale = aSchBitmap.m_scale;
|
||||
m_ppi = aSchBitmap.m_ppi;
|
||||
m_pixelSizeIu = aSchBitmap.m_pixelSizeIu;
|
||||
m_isMirrored = aSchBitmap.m_isMirrored;
|
||||
m_isMirroredX = aSchBitmap.m_isMirroredX;
|
||||
m_isMirroredY = aSchBitmap.m_isMirroredY;
|
||||
m_rotation = aSchBitmap.m_rotation;
|
||||
|
||||
m_image = nullptr;
|
||||
@@ -75,6 +77,7 @@ void BITMAP_BASE::SetImage( wxImage* aImage )
|
||||
delete m_originalImage;
|
||||
m_originalImage = new wxImage( *aImage );
|
||||
rebuildBitmap();
|
||||
updatePPI();
|
||||
}
|
||||
|
||||
|
||||
@@ -90,6 +93,21 @@ void BITMAP_BASE::rebuildBitmap( bool aResetID )
|
||||
}
|
||||
|
||||
|
||||
void BITMAP_BASE::updatePPI()
|
||||
{
|
||||
// Todo: eventually we need to support dpi / scaling in both dimensions
|
||||
int dpiX = m_originalImage->GetOptionInt( wxIMAGE_OPTION_RESOLUTIONX );
|
||||
|
||||
if( dpiX > 1 )
|
||||
{
|
||||
if( m_originalImage->GetOptionInt( wxIMAGE_OPTION_RESOLUTIONUNIT ) == wxIMAGE_RESOLUTION_CM )
|
||||
m_ppi = KiROUND( dpiX * 2.54 );
|
||||
else
|
||||
m_ppi = dpiX;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void BITMAP_BASE::ImportData( BITMAP_BASE* aItem )
|
||||
{
|
||||
*m_image = *aItem->m_image;
|
||||
@@ -99,7 +117,8 @@ void BITMAP_BASE::ImportData( BITMAP_BASE* aItem )
|
||||
m_scale = aItem->m_scale;
|
||||
m_ppi = aItem->m_ppi;
|
||||
m_pixelSizeIu = aItem->m_pixelSizeIu;
|
||||
m_isMirrored = aItem->m_isMirrored;
|
||||
m_isMirroredX = aItem->m_isMirroredX;
|
||||
m_isMirroredY = aItem->m_isMirroredY;
|
||||
m_rotation = aItem->m_rotation;
|
||||
}
|
||||
|
||||
@@ -116,6 +135,7 @@ bool BITMAP_BASE::ReadImageFile( wxInputStream& aInStream )
|
||||
delete m_originalImage;
|
||||
m_originalImage = new wxImage( *m_image );
|
||||
rebuildBitmap();
|
||||
updatePPI();
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -136,17 +156,7 @@ bool BITMAP_BASE::ReadImageFile( const wxString& aFullFilename )
|
||||
delete m_originalImage;
|
||||
m_originalImage = new wxImage( *m_image );
|
||||
rebuildBitmap();
|
||||
|
||||
// Todo: eventually we need to support dpi / scaling in both dimensions
|
||||
int dpiX = m_originalImage->GetOptionInt( wxIMAGE_OPTION_RESOLUTIONX );
|
||||
|
||||
if( dpiX > 1 )
|
||||
{
|
||||
if( m_originalImage->GetOptionInt( wxIMAGE_OPTION_RESOLUTIONUNIT ) == wxIMAGE_RESOLUTION_CM )
|
||||
m_ppi = KiROUND( dpiX * 2.54 );
|
||||
else
|
||||
m_ppi = dpiX;
|
||||
}
|
||||
updatePPI();
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -393,8 +403,25 @@ void BITMAP_BASE::Mirror( bool aVertically )
|
||||
{
|
||||
if( m_image )
|
||||
{
|
||||
// wxImage::Mirror() clear some parameters of the original image.
|
||||
// We need to restore them, especially resolution and unit, to be
|
||||
// sure image parameters saved in file are the right parameters, not
|
||||
// the defualt values
|
||||
int resX = m_image->GetOptionInt( wxIMAGE_OPTION_RESOLUTIONX );
|
||||
int resY = m_image->GetOptionInt( wxIMAGE_OPTION_RESOLUTIONY );
|
||||
int unit = m_image->GetOptionInt( wxIMAGE_OPTION_RESOLUTIONUNIT );
|
||||
|
||||
*m_image = m_image->Mirror( not aVertically );
|
||||
m_isMirrored = !m_isMirrored;
|
||||
|
||||
m_image->SetOption( wxIMAGE_OPTION_RESOLUTIONUNIT , unit);
|
||||
m_image->SetOption( wxIMAGE_OPTION_RESOLUTIONX, resX);
|
||||
m_image->SetOption( wxIMAGE_OPTION_RESOLUTIONY, resY);
|
||||
|
||||
if( aVertically )
|
||||
m_isMirroredY = !m_isMirroredY;
|
||||
else
|
||||
m_isMirroredX = !m_isMirroredX;
|
||||
|
||||
rebuildBitmap( false );
|
||||
}
|
||||
}
|
||||
@@ -404,7 +431,20 @@ void BITMAP_BASE::Rotate( bool aRotateCCW )
|
||||
{
|
||||
if( m_image )
|
||||
{
|
||||
// wxImage::Rotate90() clear some parameters of the original image.
|
||||
// We need to restore them, especially resolution and unit, to be
|
||||
// sure image parameters saved in file are the right parameters, not
|
||||
// the defualt values
|
||||
int resX = m_image->GetOptionInt( wxIMAGE_OPTION_RESOLUTIONX );
|
||||
int resY = m_image->GetOptionInt( wxIMAGE_OPTION_RESOLUTIONY );
|
||||
int unit = m_image->GetOptionInt( wxIMAGE_OPTION_RESOLUTIONUNIT );
|
||||
|
||||
*m_image = m_image->Rotate90( aRotateCCW );
|
||||
|
||||
m_image->SetOption( wxIMAGE_OPTION_RESOLUTIONUNIT , unit);
|
||||
m_image->SetOption( wxIMAGE_OPTION_RESOLUTIONX, resX);
|
||||
m_image->SetOption( wxIMAGE_OPTION_RESOLUTIONY, resY);
|
||||
|
||||
m_rotation += ( aRotateCCW ? -ANGLE_90 : ANGLE_90 );
|
||||
rebuildBitmap( false );
|
||||
}
|
||||
|
||||
@@ -177,12 +177,20 @@ wxString GetVersionInfoData( const wxString& aTitle, bool aHtml, bool aBrief )
|
||||
|
||||
aMsg << eol;
|
||||
|
||||
aMsg << "Platform: "
|
||||
wxString osDescription;
|
||||
|
||||
#if __LINUX__
|
||||
<< wxGetLinuxDistributionInfo().Description << ", "
|
||||
#else
|
||||
<< wxGetOsDescription() << ", "
|
||||
osDescription = wxGetLinuxDistributionInfo().Description;
|
||||
#endif
|
||||
|
||||
// Linux uses the lsb-release program to get the description of the OS, if lsb-release
|
||||
// isn't installed, then the string will be empty and we fallback to the method used on
|
||||
// the other platforms (to at least get the kernel/uname info).
|
||||
if( osDescription.empty() )
|
||||
osDescription = wxGetOsDescription();
|
||||
|
||||
aMsg << "Platform: "
|
||||
<< osDescription << ", "
|
||||
<< GetPlatformGetBitnessName() << ", "
|
||||
<< platform.GetEndiannessName() << ", "
|
||||
<< platform.GetPortIdName();
|
||||
|
||||
+4
-21
@@ -31,30 +31,13 @@
|
||||
#include <dialogs/html_message_box.h>
|
||||
#include <functional>
|
||||
#include <unordered_map>
|
||||
#include <pgm_base.h>
|
||||
#include "cli/cli_names.h"
|
||||
|
||||
// Set of dialogs that have been chosen not to be shown again
|
||||
static std::unordered_map<unsigned long, int> doNotShowAgainDlgs;
|
||||
|
||||
|
||||
bool IsGUI()
|
||||
{
|
||||
if( !wxTheApp )
|
||||
return false;
|
||||
|
||||
#if wxCHECK_VERSION( 3, 1, 6 )
|
||||
return wxTheApp->IsGUI();
|
||||
#else
|
||||
// wxWidgets older than version 3.1.6 do not have a way to know if the app
|
||||
// has a GUI or is a console application.
|
||||
// So the trick is to set the App class name when starting kicad-cli, and when
|
||||
// the app class name is the kicad-cli class name the app is a console app
|
||||
bool run_gui = wxTheApp->GetClassName() != KICAD_CLI_APP_NAME;
|
||||
return run_gui;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
KIDIALOG::KIDIALOG( wxWindow* aParent, const wxString& aMessage, const wxString& aCaption,
|
||||
long aStyle )
|
||||
: wxRichMessageDialog( aParent, aMessage, aCaption, aStyle | wxCENTRE | wxSTAY_ON_TOP ),
|
||||
@@ -305,7 +288,7 @@ void DisplayError( wxWindow* aParent, const wxString& aText, int aDisplayTime )
|
||||
return;
|
||||
}
|
||||
|
||||
if( !IsGUI() )
|
||||
if( !Pgm().IsGUI() )
|
||||
{
|
||||
wxFprintf( stderr, aText );
|
||||
return;
|
||||
@@ -330,7 +313,7 @@ void DisplayErrorMessage( wxWindow* aParent, const wxString& aText, const wxStri
|
||||
return;
|
||||
}
|
||||
|
||||
if( !IsGUI() )
|
||||
if( !Pgm().IsGUI() )
|
||||
{
|
||||
wxFprintf( stderr, aText );
|
||||
return;
|
||||
@@ -357,7 +340,7 @@ void DisplayInfoMessage( wxWindow* aParent, const wxString& aMessage, const wxSt
|
||||
return;
|
||||
}
|
||||
|
||||
if( !IsGUI() )
|
||||
if( !Pgm().IsGUI() )
|
||||
{
|
||||
wxFprintf( stdout, "%s %s", aMessage, aExtraInfo );
|
||||
return;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2022 Jon Evans <jon@craftyjon.com>
|
||||
* Copyright (C) 2022 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
* Copyright (C) 2022-2023 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
@@ -178,7 +178,15 @@ bool DATABASE_CONNECTION::Disconnect()
|
||||
return false;
|
||||
}
|
||||
|
||||
m_conn->disconnect();
|
||||
try
|
||||
{
|
||||
m_conn->disconnect();
|
||||
}
|
||||
catch( boost::locale::conv::conversion_error& exc )
|
||||
{
|
||||
wxLogTrace( traceDatabase, wxT( "Disconnect() error \"%s\" occured." ), exc.what() );
|
||||
return false;
|
||||
}
|
||||
|
||||
return !m_conn->connected();
|
||||
}
|
||||
|
||||
@@ -659,6 +659,10 @@ static void buildKicadAboutBanner( EDA_BASE_FRAME* aParent, ABOUT_APP_INFO& aInf
|
||||
wxEmptyString,
|
||||
wxEmptyString,
|
||||
wxS( "Greek (el_GR)" ) ) );
|
||||
aInfo.AddTranslator( new CONTRIBUTOR( wxS( "aris-kimi" ),
|
||||
wxEmptyString,
|
||||
wxEmptyString,
|
||||
wxS( "Greek (el_GR)" ) ) );
|
||||
|
||||
aInfo.AddTranslator( new CONTRIBUTOR( wxT( "Adolfo Jayme Barrientos" ),
|
||||
wxEmptyString,
|
||||
@@ -688,6 +692,10 @@ static void buildKicadAboutBanner( EDA_BASE_FRAME* aParent, ABOUT_APP_INFO& aInf
|
||||
wxEmptyString,
|
||||
wxEmptyString,
|
||||
wxS( "Spanish (ES)" ) ) );
|
||||
aInfo.AddTranslator( new CONTRIBUTOR( wxT( "VicSanRoPe" ),
|
||||
wxEmptyString,
|
||||
wxEmptyString,
|
||||
wxS( "Spanish - Latin American (ES)" ) ) );
|
||||
|
||||
aInfo.AddTranslator( new CONTRIBUTOR( wxT( "Ulices Avila Hernandez" ),
|
||||
wxEmptyString,
|
||||
@@ -822,14 +830,46 @@ static void buildKicadAboutBanner( EDA_BASE_FRAME* aParent, ABOUT_APP_INFO& aInf
|
||||
wxEmptyString,
|
||||
wxEmptyString,
|
||||
wxS( "Korean (KO)" ) ) );
|
||||
aInfo.AddTranslator( new CONTRIBUTOR( wxT( "김낙환" ),
|
||||
wxEmptyString,
|
||||
wxEmptyString,
|
||||
wxS( "Korean (KO)" ) ) );
|
||||
aInfo.AddTranslator( new CONTRIBUTOR( wxT( "이기형" ),
|
||||
wxEmptyString,
|
||||
wxEmptyString,
|
||||
wxS( "Korean (KO)" ) ) );
|
||||
aInfo.AddTranslator( new CONTRIBUTOR( wxT( "남우근" ),
|
||||
wxEmptyString,
|
||||
wxEmptyString,
|
||||
wxS( "Korean (KO)" ) ) );
|
||||
aInfo.AddTranslator( new CONTRIBUTOR( wxT( "강명구" ),
|
||||
wxEmptyString,
|
||||
wxEmptyString,
|
||||
wxS( "Korean (KO)" ) ) );
|
||||
aInfo.AddTranslator( new CONTRIBUTOR( wxT( "김용재" ),
|
||||
wxEmptyString,
|
||||
wxEmptyString,
|
||||
wxS( "Korean (KO)" ) ) );
|
||||
aInfo.AddTranslator( new CONTRIBUTOR( wxT( "서범기" ),
|
||||
wxEmptyString,
|
||||
wxEmptyString,
|
||||
wxS( "Korean (KO)" ) ) );
|
||||
aInfo.AddTranslator( new CONTRIBUTOR( wxT( "김세영" ),
|
||||
wxEmptyString,
|
||||
wxEmptyString,
|
||||
wxS( "Korean (KO)" ) ) );
|
||||
aInfo.AddTranslator( new CONTRIBUTOR( wxT( "이윤성" ),
|
||||
wxEmptyString,
|
||||
wxEmptyString,
|
||||
wxS( "Korean (KO)" ) ) );
|
||||
aInfo.AddTranslator( new CONTRIBUTOR( wxT( "KwonHyeokbeom" ),
|
||||
wxEmptyString,
|
||||
wxEmptyString,
|
||||
wxS( "Korean (KO)" ) ) );
|
||||
aInfo.AddTranslator( new CONTRIBUTOR( wxT( "Minsu Kim (0xGabriel)" ),
|
||||
wxEmptyString,
|
||||
wxEmptyString,
|
||||
wxS( "Korean (KO)" ) ) );
|
||||
|
||||
aInfo.AddTranslator( new CONTRIBUTOR( wxT( "Henrik Kauhanen" ),
|
||||
wxEmptyString,
|
||||
@@ -860,6 +900,14 @@ static void buildKicadAboutBanner( EDA_BASE_FRAME* aParent, ABOUT_APP_INFO& aInf
|
||||
wxEmptyString,
|
||||
wxEmptyString,
|
||||
wxS( "Dutch (NL)" ) ) );
|
||||
aInfo.AddTranslator( new CONTRIBUTOR( wxT( "Tom Niesse" ),
|
||||
wxEmptyString,
|
||||
wxEmptyString,
|
||||
wxS( "Dutch (NL)" ) ) );
|
||||
aInfo.AddTranslator( new CONTRIBUTOR( wxT( "Christiaan Nieuwlaat" ),
|
||||
wxEmptyString,
|
||||
wxEmptyString,
|
||||
wxS( "Dutch (NL)" ) ) );
|
||||
|
||||
aInfo.AddTranslator( new CONTRIBUTOR( wxT( "Jarl Gjessing" ),
|
||||
wxEmptyString,
|
||||
@@ -932,6 +980,10 @@ static void buildKicadAboutBanner( EDA_BASE_FRAME* aParent, ABOUT_APP_INFO& aInf
|
||||
wxEmptyString,
|
||||
wxEmptyString,
|
||||
wxS( "Portuguese (PT)" ) ) );
|
||||
aInfo.AddTranslator( new CONTRIBUTOR( wxT( "ssantos" ),
|
||||
wxEmptyString,
|
||||
wxEmptyString,
|
||||
wxS( "Portuguese (PT)" ) ) );
|
||||
|
||||
aInfo.AddTranslator( new CONTRIBUTOR( wxT( "Igor Plyatov" ),
|
||||
wxEmptyString,
|
||||
@@ -1129,7 +1181,7 @@ static void buildKicadAboutBanner( EDA_BASE_FRAME* aParent, ABOUT_APP_INFO& aInf
|
||||
#define SYMBOL_LIB_CONTRIBUTION _( "Symbols by" )
|
||||
aInfo.AddLibrarian( new CONTRIBUTOR( wxS( "GitLab contributors" ),
|
||||
wxEmptyString,
|
||||
wxS( "https://gitlab.com/kicad/libraries/kicad-symbols/-/graphs/v7" ),
|
||||
wxS( "https://gitlab.com/kicad/libraries/kicad-symbols/-/graphs/master" ),
|
||||
SYMBOL_LIB_CONTRIBUTION,
|
||||
aInfo.CreateKiBitmap( BITMAPS::add_component ) ) );
|
||||
|
||||
|
||||
+54
-31
@@ -2,7 +2,7 @@
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2012 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
|
||||
* Copyright (C) 2012-2022 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
* Copyright (C) 2012-2023 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
@@ -67,10 +67,6 @@ public:
|
||||
|
||||
|
||||
BEGIN_EVENT_TABLE( DIALOG_SHIM, wxDialog )
|
||||
// If dialog has a grid and the grid has an active cell editor
|
||||
// Esc key closes cell editor, otherwise Esc key closes the dialog.
|
||||
EVT_GRID_EDITOR_SHOWN( DIALOG_SHIM::OnGridEditorShown )
|
||||
EVT_GRID_EDITOR_HIDDEN( DIALOG_SHIM::OnGridEditorHidden )
|
||||
EVT_CHAR_HOOK( DIALOG_SHIM::OnCharHook )
|
||||
END_EVENT_TABLE()
|
||||
|
||||
@@ -325,30 +321,38 @@ bool DIALOG_SHIM::Enable( bool enable )
|
||||
// Recursive descent doing a SelectAll() in wxTextCtrls.
|
||||
// MacOS User Interface Guidelines state that when tabbing to a text control all its
|
||||
// text should be selected. Since wxWidgets fails to implement this, we do it here.
|
||||
static void selectAllInTextCtrls( wxWindowList& children )
|
||||
void DIALOG_SHIM::selectAllInTextCtrls( wxWindowList& children )
|
||||
{
|
||||
for( wxWindow* child : children )
|
||||
{
|
||||
if( wxTextCtrl* childTextCtrl = dynamic_cast<wxTextCtrl*>( child ) )
|
||||
if( wxTextCtrl* textCtrl = dynamic_cast<wxTextCtrl*>( child ) )
|
||||
{
|
||||
m_beforeEditValues[ textCtrl ] = textCtrl->GetValue();
|
||||
textCtrl->Connect( wxEVT_SET_FOCUS, wxFocusEventHandler( DIALOG_SHIM::onChildSetFocus ),
|
||||
nullptr, this );
|
||||
|
||||
// We don't currently run this on GTK because some window managers don't hide the
|
||||
// selection in non-active controls, and other window managers do the selection
|
||||
// automatically anyway.
|
||||
#if defined( __WXMAC__ ) || defined( __WXMSW__ )
|
||||
if( !childTextCtrl->GetStringSelection().IsEmpty() )
|
||||
if( !textCtrl->GetStringSelection().IsEmpty() )
|
||||
{
|
||||
// Respect an existing selection
|
||||
}
|
||||
else
|
||||
else if( textCtrl->IsEditable() )
|
||||
{
|
||||
childTextCtrl->SelectAll();
|
||||
textCtrl->SelectAll();
|
||||
}
|
||||
#else
|
||||
ignore_unused( childTextCtrl );
|
||||
ignore_unused( textCtrl );
|
||||
#endif
|
||||
}
|
||||
else if( wxStyledTextCtrl* scintilla = dynamic_cast<wxStyledTextCtrl*>( child ) )
|
||||
{
|
||||
m_beforeEditValues[ scintilla ] = scintilla->GetText();
|
||||
scintilla->Connect( wxEVT_SET_FOCUS, wxFocusEventHandler( DIALOG_SHIM::onChildSetFocus ),
|
||||
nullptr, this );
|
||||
|
||||
if( !scintilla->GetSelectedText().IsEmpty() )
|
||||
{
|
||||
// Respect an existing selection
|
||||
@@ -533,11 +537,6 @@ void DIALOG_SHIM::OnButton( wxCommandEvent& aEvent )
|
||||
{
|
||||
const int id = aEvent.GetId();
|
||||
|
||||
// If we are pressing a button to exit, we need to enable the escapeID
|
||||
// otherwise the dialog does not process cancel
|
||||
if( id == wxID_CANCEL )
|
||||
SetEscapeId( wxID_ANY );
|
||||
|
||||
if( IsQuasiModal() )
|
||||
{
|
||||
if( id == GetAffirmativeId() )
|
||||
@@ -555,7 +554,7 @@ void DIALOG_SHIM::OnButton( wxCommandEvent& aEvent )
|
||||
ignore_unused( TransferDataFromWindow() );
|
||||
}
|
||||
}
|
||||
else if( id == GetEscapeId() || (id == wxID_CANCEL && GetEscapeId() == wxID_ANY) )
|
||||
else if( id == wxID_CANCEL )
|
||||
{
|
||||
EndQuasiModal( wxID_CANCEL );
|
||||
}
|
||||
@@ -572,6 +571,19 @@ void DIALOG_SHIM::OnButton( wxCommandEvent& aEvent )
|
||||
}
|
||||
|
||||
|
||||
void DIALOG_SHIM::onChildSetFocus( wxFocusEvent& aEvent )
|
||||
{
|
||||
// When setting focus to a text control reset the before-edit value.
|
||||
|
||||
if( wxTextCtrl* textCtrl = dynamic_cast<wxTextCtrl*>( aEvent.GetEventObject() ) )
|
||||
m_beforeEditValues[ textCtrl ] = textCtrl->GetValue();
|
||||
else if( wxStyledTextCtrl* scintilla = dynamic_cast<wxStyledTextCtrl*>( aEvent.GetEventObject() ) )
|
||||
m_beforeEditValues[ scintilla ] = scintilla->GetText();
|
||||
|
||||
aEvent.Skip();
|
||||
}
|
||||
|
||||
|
||||
void DIALOG_SHIM::OnCharHook( wxKeyEvent& aEvt )
|
||||
{
|
||||
if( aEvt.GetKeyCode() == 'U' && aEvt.GetModifiers() == wxMOD_CONTROL )
|
||||
@@ -626,25 +638,36 @@ void DIALOG_SHIM::OnCharHook( wxKeyEvent& aEvt )
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if( aEvt.GetKeyCode() == WXK_ESCAPE )
|
||||
{
|
||||
wxObject* eventSource = aEvt.GetEventObject();
|
||||
|
||||
if( wxTextCtrl* textCtrl = dynamic_cast<wxTextCtrl*>( eventSource ) )
|
||||
{
|
||||
// First escape after an edit cancels edit
|
||||
if( textCtrl->GetValue() != m_beforeEditValues[ textCtrl ] )
|
||||
{
|
||||
textCtrl->SetValue( m_beforeEditValues[ textCtrl ] );
|
||||
textCtrl->SelectAll();
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if( wxStyledTextCtrl* scintilla = dynamic_cast<wxStyledTextCtrl*>( eventSource ) )
|
||||
{
|
||||
// First escape after an edit cancels edit
|
||||
if( scintilla->GetText() != m_beforeEditValues[ scintilla ] )
|
||||
{
|
||||
scintilla->SetText( m_beforeEditValues[ scintilla ] );
|
||||
scintilla->SelectAll();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
aEvt.Skip();
|
||||
}
|
||||
|
||||
|
||||
void DIALOG_SHIM::OnGridEditorShown( wxGridEvent& event )
|
||||
{
|
||||
SetEscapeId( wxID_NONE );
|
||||
event.Skip();
|
||||
}
|
||||
|
||||
|
||||
void DIALOG_SHIM::OnGridEditorHidden( wxGridEvent& event )
|
||||
{
|
||||
SetEscapeId( wxID_ANY );
|
||||
event.Skip();
|
||||
}
|
||||
|
||||
|
||||
static void recursiveDescent( wxSizer* aSizer, std::map<int, wxString>& aLabels )
|
||||
{
|
||||
wxStdDialogButtonSizer* sdbSizer = dynamic_cast<wxStdDialogButtonSizer*>( aSizer );
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2022 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
* Copyright (C) 2022-2023 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
@@ -105,10 +105,7 @@ void DIALOG_ASSIGN_NETCLASS::onPatternText( wxCommandEvent& aEvent )
|
||||
|
||||
for( const wxString& net : m_netCandidates )
|
||||
{
|
||||
int matches;
|
||||
int offset;
|
||||
|
||||
if( matcher.Find( net, matches, offset ) && offset == 0 )
|
||||
if( matcher.StartsWith( net ) )
|
||||
{
|
||||
m_matchingNets->Report( net );
|
||||
matchingNetNames.push_back( net );
|
||||
|
||||
@@ -396,12 +396,12 @@ void DIALOG_COLOR_PICKER::drawRGBPalette()
|
||||
|
||||
// Use Y axis from bottom to top and origin to center
|
||||
bitmapDC.SetAxisOrientation( true, true );
|
||||
#if wxCHECK_VERSION( 3, 1, 7 )
|
||||
#if wxCHECK_VERSION( 3, 1, 7 ) && defined( __WXMSW__)
|
||||
// For some reason, SetDeviceOrigin has changed in wxWidgets 3.1.6 or 3.1.7
|
||||
bitmapDC.SetDeviceOrigin( half_size, -half_size );
|
||||
#else
|
||||
#else
|
||||
bitmapDC.SetDeviceOrigin( half_size, half_size );
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Reserve room to draw cursors inside the bitmap
|
||||
half_size -= m_cursorsSize/2;
|
||||
@@ -466,12 +466,12 @@ void DIALOG_COLOR_PICKER::drawHSVPalette()
|
||||
|
||||
// Use Y axis from bottom to top and origin to center
|
||||
bitmapDC.SetAxisOrientation( true, true );
|
||||
#if wxCHECK_VERSION( 3, 1, 7 )
|
||||
#if wxCHECK_VERSION( 3, 1, 7 ) && defined( __WXMSW__)
|
||||
// For some reason, SetDeviceOrigin has changed in wxWidgets 3.1.6 or 3.1.7
|
||||
bitmapDC.SetDeviceOrigin( half_size, -half_size );
|
||||
#else
|
||||
#else
|
||||
bitmapDC.SetDeviceOrigin( half_size, half_size );
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Reserve room to draw cursors inside the bitmap
|
||||
half_size -= m_cursorsSize / 2;
|
||||
@@ -701,11 +701,13 @@ void DIALOG_COLOR_PICKER::onHSVMouseDrag( wxMouseEvent& event )
|
||||
|
||||
void DIALOG_COLOR_PICKER::OnColorValueText( wxCommandEvent& event )
|
||||
{
|
||||
m_newColor4D.SetFromHexString( m_colorValue->GetValue() );
|
||||
m_newColor4D.ToHSV( m_hue, m_sat, m_val, true );
|
||||
if( m_newColor4D.SetFromHexString( m_colorValue->GetValue() ) )
|
||||
{
|
||||
m_newColor4D.ToHSV( m_hue, m_sat, m_val, true );
|
||||
|
||||
SetEditVals( HEX_CHANGED, true );
|
||||
drawAll();
|
||||
SetEditVals( HEX_CHANGED, false );
|
||||
drawAll();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -223,7 +223,7 @@ bool DIALOG_PAGES_SETTINGS::TransferDataFromWindow()
|
||||
m_screen->SetContentModified();
|
||||
|
||||
if( LocalPrjConfigChanged() )
|
||||
m_parent->SaveProjectSettings();
|
||||
m_parent->OnModify();
|
||||
|
||||
// Call the post processing (if any) after changes
|
||||
m_parent->OnPageSettingsChange();
|
||||
@@ -674,9 +674,9 @@ void DIALOG_PAGES_SETTINGS::UpdateDrawingSheetExample()
|
||||
|
||||
GRFilledRect( &memDC, VECTOR2I( 0, 0 ), m_layout_size, 0, bgColor, bgColor );
|
||||
|
||||
PrintDrawingSheet( &renderSettings, pageDUMMY, emptyString, emptyString, m_tb,
|
||||
nullptr, m_screen->GetPageCount(), m_screen->GetPageNumber(), 1,
|
||||
&Prj(), wxEmptyString, m_screen->GetVirtualPageNumber() == 1 );
|
||||
PrintDrawingSheet( &renderSettings, pageDUMMY, emptyString, emptyString, emptyString,
|
||||
m_tb, nullptr, m_screen->GetPageCount(), m_screen->GetPageNumber(),
|
||||
1, &Prj(), wxEmptyString, m_screen->GetVirtualPageNumber() == 1 );
|
||||
|
||||
memDC.SelectObject( wxNullBitmap );
|
||||
m_PageLayoutExampleBitmap->SetBitmap( *m_pageBitmap );
|
||||
|
||||
@@ -117,8 +117,7 @@ void PANEL_COLOR_SETTINGS::OnThemeChanged( wxCommandEvent& event )
|
||||
|
||||
if( idx == static_cast<int>( m_cbTheme->GetCount() ) - 2 )
|
||||
{
|
||||
// separator; re-select active theme
|
||||
m_cbTheme->SetStringSelection( m_currentSettings->GetName() );
|
||||
m_cbTheme->SetStringSelection( GetSettingsDropdownName( m_currentSettings ) );
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -217,10 +216,7 @@ void PANEL_COLOR_SETTINGS::createThemeList( const wxString& aCurrent )
|
||||
|
||||
for( COLOR_SETTINGS* settings : Pgm().GetSettingsManager().GetColorSettingsList() )
|
||||
{
|
||||
wxString name = settings->GetName();
|
||||
|
||||
if( settings->IsReadOnly() )
|
||||
name += wxS( " " ) + _( "(read-only)" );
|
||||
wxString name = GetSettingsDropdownName( settings );
|
||||
|
||||
int pos = m_cbTheme->Append( name, static_cast<void*>( settings ) );
|
||||
|
||||
@@ -262,8 +258,11 @@ void PANEL_COLOR_SETTINGS::createSwatch( int aLayer, const wxString& aName )
|
||||
defaultColor, SWATCH_MEDIUM );
|
||||
swatch->SetForegroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOW ) );
|
||||
|
||||
m_colorsGridSizer->Add( label, 0, wxALIGN_CENTER_VERTICAL | wxALIGN_LEFT | wxLEFT, 5 );
|
||||
// Display the swatches in the left column and the layer name in the right column
|
||||
// The right column is sometimes (depending on the translation) truncated for long texts.
|
||||
// We cannot allow swatches to be truncated or not shown
|
||||
m_colorsGridSizer->Add( swatch, 0, wxALIGN_CENTER_VERTICAL | wxALL, 3 );
|
||||
m_colorsGridSizer->Add( label, 0, wxALIGN_CENTER_VERTICAL | wxALIGN_LEFT | wxLEFT, 5 );
|
||||
|
||||
m_labels[aLayer] = label;
|
||||
m_swatches[aLayer] = swatch;
|
||||
@@ -283,6 +282,8 @@ void PANEL_COLOR_SETTINGS::ShowColorContextMenu( wxMouseEvent& aEvent, int aLaye
|
||||
auto selected =
|
||||
static_cast<COLOR_SETTINGS*>( m_cbTheme->GetClientData( m_cbTheme->GetSelection() ) );
|
||||
|
||||
wxCHECK_RET( selected, wxT( "Invalid color theme selected" ) );
|
||||
|
||||
COLOR4D current = m_currentSettings->GetColor( aLayer );
|
||||
COLOR4D saved = selected->GetColor( aLayer );
|
||||
bool readOnly = m_currentSettings->IsReadOnly();
|
||||
@@ -376,3 +377,14 @@ bool PANEL_COLOR_SETTINGS::saveCurrentTheme( bool aValidate )
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
wxString PANEL_COLOR_SETTINGS::GetSettingsDropdownName(COLOR_SETTINGS* aSettings)
|
||||
{
|
||||
wxString name = aSettings->GetName();
|
||||
|
||||
if( aSettings->IsReadOnly() )
|
||||
name += wxS( " " ) + _( "(read-only)" );
|
||||
|
||||
return name;
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
* This program source code file is part of KICAD, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2018 jean-pierre.charras
|
||||
* Copyright (C) 2011-2020 Kicad Developers, see AUTHORS.txt for contributors.
|
||||
* Copyright (C) 2011-2023 Kicad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
@@ -110,12 +110,19 @@ bool PANEL_IMAGE_EDITOR::TransferDataFromWindow()
|
||||
void PANEL_IMAGE_EDITOR::OnRedrawPanel( wxPaintEvent& event )
|
||||
{
|
||||
wxPaintDC dc( m_panelDraw );
|
||||
wxSize size = m_panelDraw->GetClientSize();
|
||||
dc.SetDeviceOrigin( size.x / 2, size.y / 2 );
|
||||
wxSize display_size = m_panelDraw->GetClientSize();
|
||||
|
||||
double scale = 1.0 / m_workingImage->GetScalingFactor();
|
||||
dc.SetUserScale( scale, scale );
|
||||
m_workingImage->DrawBitmap( &dc, wxPoint( 0, 0 ) );
|
||||
double img_scale = 1.0 / m_workingImage->GetScalingFactor();
|
||||
VECTOR2I img_size_pixels = m_workingImage->GetSizePixels();
|
||||
|
||||
// Adjust the display scale to use the full available display area
|
||||
double scale_X = (double)display_size.x/img_size_pixels.x;
|
||||
double scale_Y = (double)display_size.y/img_size_pixels.y;
|
||||
|
||||
double display_scale = img_scale * std::min( scale_X, scale_Y );
|
||||
|
||||
dc.SetUserScale( display_scale, display_scale );
|
||||
m_workingImage->DrawBitmap( &dc, VECTOR2I( m_workingImage->GetSize()/2 ) );
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// C++ code generated with wxFormBuilder (version 3.10.1-133-g388db8e4)
|
||||
// C++ code generated with wxFormBuilder (version 3.10.1-282-g1fa54006)
|
||||
// http://www.wxformbuilder.org/
|
||||
//
|
||||
// PLEASE DO *NOT* EDIT THIS FILE!
|
||||
|
||||
@@ -0,0 +1,368 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
|
||||
<wxFormBuilder_Project>
|
||||
<FileVersion major="1" minor="16" />
|
||||
<object class="Project" expanded="1">
|
||||
<property name="class_decoration"></property>
|
||||
<property name="code_generation">C++</property>
|
||||
<property name="disconnect_events">1</property>
|
||||
<property name="disconnect_mode">source_name</property>
|
||||
<property name="disconnect_php_events">0</property>
|
||||
<property name="disconnect_python_events">0</property>
|
||||
<property name="embedded_files_path">res</property>
|
||||
<property name="encoding">UTF-8</property>
|
||||
<property name="event_generation">connect</property>
|
||||
<property name="file">panel_image_editor_base</property>
|
||||
<property name="first_id">1000</property>
|
||||
<property name="help_provider">none</property>
|
||||
<property name="image_path_wrapper_function_name"></property>
|
||||
<property name="indent_with_spaces"></property>
|
||||
<property name="internationalize">1</property>
|
||||
<property name="name">panel_image_editor_base</property>
|
||||
<property name="namespace"></property>
|
||||
<property name="path">.</property>
|
||||
<property name="precompiled_header"></property>
|
||||
<property name="relative_path">1</property>
|
||||
<property name="skip_lua_events">1</property>
|
||||
<property name="skip_php_events">1</property>
|
||||
<property name="skip_python_events">1</property>
|
||||
<property name="ui_table">UI</property>
|
||||
<property name="use_array_enum">0</property>
|
||||
<property name="use_enum">0</property>
|
||||
<property name="use_microsoft_bom">0</property>
|
||||
<object class="Panel" expanded="1">
|
||||
<property name="aui_managed">0</property>
|
||||
<property name="aui_manager_style">wxAUI_MGR_DEFAULT</property>
|
||||
<property name="bg"></property>
|
||||
<property name="context_help"></property>
|
||||
<property name="context_menu">1</property>
|
||||
<property name="drag_accept_files">0</property>
|
||||
<property name="enabled">1</property>
|
||||
<property name="event_handler">impl_virtual</property>
|
||||
<property name="fg"></property>
|
||||
<property name="font"></property>
|
||||
<property name="hidden">0</property>
|
||||
<property name="id">wxID_ANY</property>
|
||||
<property name="maximum_size"></property>
|
||||
<property name="minimum_size"></property>
|
||||
<property name="name">PANEL_IMAGE_EDITOR_BASE</property>
|
||||
<property name="pos"></property>
|
||||
<property name="size">500,300</property>
|
||||
<property name="subclass">; ; forward_declare</property>
|
||||
<property name="tooltip"></property>
|
||||
<property name="two_step_creation">0</property>
|
||||
<property name="window_extra_style"></property>
|
||||
<property name="window_name"></property>
|
||||
<property name="window_style">wxTAB_TRAVERSAL</property>
|
||||
<object class="wxBoxSizer" expanded="1">
|
||||
<property name="minimum_size"></property>
|
||||
<property name="name">bSizerMain</property>
|
||||
<property name="orient">wxVERTICAL</property>
|
||||
<property name="permission">none</property>
|
||||
<object class="sizeritem" expanded="1">
|
||||
<property name="border">5</property>
|
||||
<property name="flag">wxEXPAND</property>
|
||||
<property name="proportion">1</property>
|
||||
<object class="wxBoxSizer" expanded="1">
|
||||
<property name="minimum_size"></property>
|
||||
<property name="name">bUpperSizer</property>
|
||||
<property name="orient">wxVERTICAL</property>
|
||||
<property name="permission">none</property>
|
||||
<object class="sizeritem" expanded="1">
|
||||
<property name="border">5</property>
|
||||
<property name="flag">wxEXPAND</property>
|
||||
<property name="proportion">1</property>
|
||||
<object class="wxBoxSizer" expanded="1">
|
||||
<property name="minimum_size"></property>
|
||||
<property name="name">bSizerLeft</property>
|
||||
<property name="orient">wxHORIZONTAL</property>
|
||||
<property name="permission">none</property>
|
||||
<object class="sizeritem" expanded="1">
|
||||
<property name="border">5</property>
|
||||
<property name="flag">wxEXPAND | wxALL</property>
|
||||
<property name="proportion">1</property>
|
||||
<object class="wxPanel" expanded="1">
|
||||
<property name="BottomDockable">1</property>
|
||||
<property name="LeftDockable">1</property>
|
||||
<property name="RightDockable">1</property>
|
||||
<property name="TopDockable">1</property>
|
||||
<property name="aui_layer"></property>
|
||||
<property name="aui_name"></property>
|
||||
<property name="aui_position"></property>
|
||||
<property name="aui_row"></property>
|
||||
<property name="best_size"></property>
|
||||
<property name="bg"></property>
|
||||
<property name="caption"></property>
|
||||
<property name="caption_visible">1</property>
|
||||
<property name="center_pane">0</property>
|
||||
<property name="close_button">1</property>
|
||||
<property name="context_help"></property>
|
||||
<property name="context_menu">1</property>
|
||||
<property name="default_pane">0</property>
|
||||
<property name="dock">Dock</property>
|
||||
<property name="dock_fixed">0</property>
|
||||
<property name="docking">Left</property>
|
||||
<property name="drag_accept_files">0</property>
|
||||
<property name="enabled">1</property>
|
||||
<property name="fg"></property>
|
||||
<property name="floatable">1</property>
|
||||
<property name="font"></property>
|
||||
<property name="gripper">0</property>
|
||||
<property name="hidden">0</property>
|
||||
<property name="id">wxID_ANY</property>
|
||||
<property name="max_size"></property>
|
||||
<property name="maximize_button">0</property>
|
||||
<property name="maximum_size"></property>
|
||||
<property name="min_size"></property>
|
||||
<property name="minimize_button">0</property>
|
||||
<property name="minimum_size">256,256</property>
|
||||
<property name="moveable">1</property>
|
||||
<property name="name">m_panelDraw</property>
|
||||
<property name="pane_border">1</property>
|
||||
<property name="pane_position"></property>
|
||||
<property name="pane_size"></property>
|
||||
<property name="permission">protected</property>
|
||||
<property name="pin_button">1</property>
|
||||
<property name="pos"></property>
|
||||
<property name="resize">Resizable</property>
|
||||
<property name="show">1</property>
|
||||
<property name="size"></property>
|
||||
<property name="subclass"></property>
|
||||
<property name="toolbar_pane">0</property>
|
||||
<property name="tooltip"></property>
|
||||
<property name="window_extra_style"></property>
|
||||
<property name="window_name"></property>
|
||||
<property name="window_style">wxFULL_REPAINT_ON_RESIZE|wxTAB_TRAVERSAL|wxBORDER_SIMPLE</property>
|
||||
<event name="OnPaint">OnRedrawPanel</event>
|
||||
</object>
|
||||
</object>
|
||||
<object class="sizeritem" expanded="1">
|
||||
<property name="border">5</property>
|
||||
<property name="flag">wxEXPAND|wxALL</property>
|
||||
<property name="proportion">0</property>
|
||||
<object class="wxBoxSizer" expanded="1">
|
||||
<property name="minimum_size"></property>
|
||||
<property name="name">bSizerRight</property>
|
||||
<property name="orient">wxVERTICAL</property>
|
||||
<property name="permission">none</property>
|
||||
<object class="sizeritem" expanded="1">
|
||||
<property name="border">5</property>
|
||||
<property name="flag">wxEXPAND|wxTOP|wxRIGHT|wxLEFT</property>
|
||||
<property name="proportion">0</property>
|
||||
<object class="wxButton" expanded="1">
|
||||
<property name="BottomDockable">1</property>
|
||||
<property name="LeftDockable">1</property>
|
||||
<property name="RightDockable">1</property>
|
||||
<property name="TopDockable">1</property>
|
||||
<property name="aui_layer"></property>
|
||||
<property name="aui_name"></property>
|
||||
<property name="aui_position"></property>
|
||||
<property name="aui_row"></property>
|
||||
<property name="auth_needed">0</property>
|
||||
<property name="best_size"></property>
|
||||
<property name="bg"></property>
|
||||
<property name="bitmap"></property>
|
||||
<property name="caption"></property>
|
||||
<property name="caption_visible">1</property>
|
||||
<property name="center_pane">0</property>
|
||||
<property name="close_button">1</property>
|
||||
<property name="context_help"></property>
|
||||
<property name="context_menu">1</property>
|
||||
<property name="current"></property>
|
||||
<property name="default">0</property>
|
||||
<property name="default_pane">0</property>
|
||||
<property name="disabled"></property>
|
||||
<property name="dock">Dock</property>
|
||||
<property name="dock_fixed">0</property>
|
||||
<property name="docking">Left</property>
|
||||
<property name="drag_accept_files">0</property>
|
||||
<property name="enabled">1</property>
|
||||
<property name="fg"></property>
|
||||
<property name="floatable">1</property>
|
||||
<property name="focus"></property>
|
||||
<property name="font"></property>
|
||||
<property name="gripper">0</property>
|
||||
<property name="hidden">0</property>
|
||||
<property name="id">wxID_ANY</property>
|
||||
<property name="label">Grey</property>
|
||||
<property name="margins"></property>
|
||||
<property name="markup">0</property>
|
||||
<property name="max_size"></property>
|
||||
<property name="maximize_button">0</property>
|
||||
<property name="maximum_size"></property>
|
||||
<property name="min_size"></property>
|
||||
<property name="minimize_button">0</property>
|
||||
<property name="minimum_size"></property>
|
||||
<property name="moveable">1</property>
|
||||
<property name="name">m_buttonGrey</property>
|
||||
<property name="pane_border">1</property>
|
||||
<property name="pane_position"></property>
|
||||
<property name="pane_size"></property>
|
||||
<property name="permission">protected</property>
|
||||
<property name="pin_button">1</property>
|
||||
<property name="pos"></property>
|
||||
<property name="position"></property>
|
||||
<property name="pressed"></property>
|
||||
<property name="resize">Resizable</property>
|
||||
<property name="show">1</property>
|
||||
<property name="size"></property>
|
||||
<property name="style"></property>
|
||||
<property name="subclass"></property>
|
||||
<property name="toolbar_pane">0</property>
|
||||
<property name="tooltip"></property>
|
||||
<property name="validator_data_type"></property>
|
||||
<property name="validator_style">wxFILTER_NONE</property>
|
||||
<property name="validator_type">wxDefaultValidator</property>
|
||||
<property name="validator_variable"></property>
|
||||
<property name="window_extra_style"></property>
|
||||
<property name="window_name"></property>
|
||||
<property name="window_style"></property>
|
||||
<event name="OnButtonClick">OnGreyScaleConvert</event>
|
||||
</object>
|
||||
</object>
|
||||
<object class="sizeritem" expanded="1">
|
||||
<property name="border">10</property>
|
||||
<property name="flag">wxEXPAND|wxTOP|wxBOTTOM</property>
|
||||
<property name="proportion">0</property>
|
||||
<object class="spacer" expanded="1">
|
||||
<property name="height">0</property>
|
||||
<property name="permission">protected</property>
|
||||
<property name="width">0</property>
|
||||
</object>
|
||||
</object>
|
||||
<object class="sizeritem" expanded="1">
|
||||
<property name="border">5</property>
|
||||
<property name="flag">wxTOP|wxRIGHT|wxLEFT</property>
|
||||
<property name="proportion">0</property>
|
||||
<object class="wxStaticText" expanded="1">
|
||||
<property name="BottomDockable">1</property>
|
||||
<property name="LeftDockable">1</property>
|
||||
<property name="RightDockable">1</property>
|
||||
<property name="TopDockable">1</property>
|
||||
<property name="aui_layer"></property>
|
||||
<property name="aui_name"></property>
|
||||
<property name="aui_position"></property>
|
||||
<property name="aui_row"></property>
|
||||
<property name="best_size"></property>
|
||||
<property name="bg"></property>
|
||||
<property name="caption"></property>
|
||||
<property name="caption_visible">1</property>
|
||||
<property name="center_pane">0</property>
|
||||
<property name="close_button">1</property>
|
||||
<property name="context_help"></property>
|
||||
<property name="context_menu">1</property>
|
||||
<property name="default_pane">0</property>
|
||||
<property name="dock">Dock</property>
|
||||
<property name="dock_fixed">0</property>
|
||||
<property name="docking">Left</property>
|
||||
<property name="drag_accept_files">0</property>
|
||||
<property name="enabled">1</property>
|
||||
<property name="fg"></property>
|
||||
<property name="floatable">1</property>
|
||||
<property name="font"></property>
|
||||
<property name="gripper">0</property>
|
||||
<property name="hidden">0</property>
|
||||
<property name="id">wxID_ANY</property>
|
||||
<property name="label">Image Scale:</property>
|
||||
<property name="markup">0</property>
|
||||
<property name="max_size"></property>
|
||||
<property name="maximize_button">0</property>
|
||||
<property name="maximum_size"></property>
|
||||
<property name="min_size"></property>
|
||||
<property name="minimize_button">0</property>
|
||||
<property name="minimum_size"></property>
|
||||
<property name="moveable">1</property>
|
||||
<property name="name">m_staticTextScale</property>
|
||||
<property name="pane_border">1</property>
|
||||
<property name="pane_position"></property>
|
||||
<property name="pane_size"></property>
|
||||
<property name="permission">protected</property>
|
||||
<property name="pin_button">1</property>
|
||||
<property name="pos"></property>
|
||||
<property name="resize">Resizable</property>
|
||||
<property name="show">1</property>
|
||||
<property name="size"></property>
|
||||
<property name="style"></property>
|
||||
<property name="subclass"></property>
|
||||
<property name="toolbar_pane">0</property>
|
||||
<property name="tooltip"></property>
|
||||
<property name="window_extra_style"></property>
|
||||
<property name="window_name"></property>
|
||||
<property name="window_style"></property>
|
||||
<property name="wrap">-1</property>
|
||||
</object>
|
||||
</object>
|
||||
<object class="sizeritem" expanded="1">
|
||||
<property name="border">5</property>
|
||||
<property name="flag">wxBOTTOM|wxRIGHT|wxLEFT|wxEXPAND</property>
|
||||
<property name="proportion">0</property>
|
||||
<object class="wxTextCtrl" expanded="1">
|
||||
<property name="BottomDockable">1</property>
|
||||
<property name="LeftDockable">1</property>
|
||||
<property name="RightDockable">1</property>
|
||||
<property name="TopDockable">1</property>
|
||||
<property name="aui_layer"></property>
|
||||
<property name="aui_name"></property>
|
||||
<property name="aui_position"></property>
|
||||
<property name="aui_row"></property>
|
||||
<property name="best_size"></property>
|
||||
<property name="bg"></property>
|
||||
<property name="caption"></property>
|
||||
<property name="caption_visible">1</property>
|
||||
<property name="center_pane">0</property>
|
||||
<property name="close_button">1</property>
|
||||
<property name="context_help"></property>
|
||||
<property name="context_menu">1</property>
|
||||
<property name="default_pane">0</property>
|
||||
<property name="dock">Dock</property>
|
||||
<property name="dock_fixed">0</property>
|
||||
<property name="docking">Left</property>
|
||||
<property name="drag_accept_files">0</property>
|
||||
<property name="enabled">1</property>
|
||||
<property name="fg"></property>
|
||||
<property name="floatable">1</property>
|
||||
<property name="font"></property>
|
||||
<property name="gripper">0</property>
|
||||
<property name="hidden">0</property>
|
||||
<property name="id">wxID_ANY</property>
|
||||
<property name="max_size"></property>
|
||||
<property name="maximize_button">0</property>
|
||||
<property name="maximum_size"></property>
|
||||
<property name="maxlength">0</property>
|
||||
<property name="min_size"></property>
|
||||
<property name="minimize_button">0</property>
|
||||
<property name="minimum_size"></property>
|
||||
<property name="moveable">1</property>
|
||||
<property name="name">m_textCtrlScale</property>
|
||||
<property name="pane_border">1</property>
|
||||
<property name="pane_position"></property>
|
||||
<property name="pane_size"></property>
|
||||
<property name="permission">protected</property>
|
||||
<property name="pin_button">1</property>
|
||||
<property name="pos"></property>
|
||||
<property name="resize">Resizable</property>
|
||||
<property name="show">1</property>
|
||||
<property name="size"></property>
|
||||
<property name="style"></property>
|
||||
<property name="subclass"></property>
|
||||
<property name="toolbar_pane">0</property>
|
||||
<property name="tooltip"></property>
|
||||
<property name="validator_data_type"></property>
|
||||
<property name="validator_style">wxFILTER_NONE</property>
|
||||
<property name="validator_type">wxDefaultValidator</property>
|
||||
<property name="validator_variable"></property>
|
||||
<property name="value"></property>
|
||||
<property name="window_extra_style"></property>
|
||||
<property name="window_name"></property>
|
||||
<property name="window_style"></property>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
</wxFormBuilder_Project>
|
||||
@@ -1,5 +1,5 @@
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// C++ code generated with wxFormBuilder (version 3.10.1-133-g388db8e4)
|
||||
// C++ code generated with wxFormBuilder (version 3.10.1-282-g1fa54006)
|
||||
// http://www.wxformbuilder.org/
|
||||
//
|
||||
// PLEASE DO *NOT* EDIT THIS FILE!
|
||||
|
||||
@@ -708,10 +708,7 @@ void PANEL_SETUP_NETCLASSES::OnUpdateUI( wxUpdateUIEvent& event )
|
||||
|
||||
for( const wxString& net : m_netNames )
|
||||
{
|
||||
int matches;
|
||||
int offset;
|
||||
|
||||
if( matcher.Find( net, matches, offset ) && offset == 0 )
|
||||
if( matcher.StartsWith( net ) )
|
||||
m_matchingNets->Report( net );
|
||||
}
|
||||
}
|
||||
|
||||
+10
-11
@@ -58,7 +58,13 @@ EDA_DRAW_PANEL_GAL::EDA_DRAW_PANEL_GAL( wxWindow* aParentWindow, wxWindowID aWin
|
||||
const wxPoint& aPosition, const wxSize& aSize,
|
||||
KIGFX::GAL_DISPLAY_OPTIONS& aOptions, GAL_TYPE aGalType ) :
|
||||
wxScrolledCanvas( aParentWindow, aWindowId, aPosition, aSize ),
|
||||
m_MouseCapturedLost( false ),
|
||||
m_parent( aParentWindow ),
|
||||
m_edaFrame( nullptr ),
|
||||
m_lastRefresh( 0 ),
|
||||
m_pendingRefresh( false ),
|
||||
m_drawing( false ),
|
||||
m_drawingEnabled( false ),
|
||||
m_gal( nullptr ),
|
||||
m_view( nullptr ),
|
||||
m_painter( nullptr ),
|
||||
@@ -70,11 +76,10 @@ EDA_DRAW_PANEL_GAL::EDA_DRAW_PANEL_GAL( wxWindow* aParentWindow, wxWindowID aWin
|
||||
m_stealsFocus( true ),
|
||||
m_statusPopup( nullptr )
|
||||
{
|
||||
m_parent = aParentWindow;
|
||||
m_MouseCapturedLost = false;
|
||||
|
||||
m_PaintEventCounter = std::make_unique<PROF_COUNTER>( "Draw panel paint events" );
|
||||
|
||||
m_minRefreshPeriod = 13; // 77 FPS (minus render time) by default
|
||||
|
||||
SetLayoutDirection( wxLayout_LeftToRight );
|
||||
|
||||
m_edaFrame = dynamic_cast<EDA_DRAW_FRAME*>( m_parent );
|
||||
@@ -146,12 +151,6 @@ EDA_DRAW_PANEL_GAL::EDA_DRAW_PANEL_GAL( wxWindow* aParentWindow, wxWindowID aWin
|
||||
Connect( eventType, wxEventHandler( EDA_DRAW_PANEL_GAL::OnEvent ), nullptr,
|
||||
m_eventDispatcher );
|
||||
|
||||
m_pendingRefresh = false;
|
||||
m_drawing = false;
|
||||
m_drawingEnabled = false;
|
||||
|
||||
m_minRefreshPeriod = 13; // 77 FPS (minus render time) by default
|
||||
|
||||
// Set up timer that prevents too frequent redraw commands
|
||||
m_refreshTimer.SetOwner( this );
|
||||
Connect( m_refreshTimer.GetId(), wxEVT_TIMER,
|
||||
@@ -212,7 +211,7 @@ void EDA_DRAW_PANEL_GAL::DoRePaint()
|
||||
if( !m_drawingEnabled )
|
||||
return;
|
||||
|
||||
if( !m_gal->IsVisible() )
|
||||
if( !m_gal->IsInitialized() || !m_gal->IsVisible() )
|
||||
return;
|
||||
|
||||
m_pendingRefresh = false;
|
||||
@@ -627,7 +626,7 @@ void EDA_DRAW_PANEL_GAL::onRefreshTimer( wxTimerEvent& aEvent )
|
||||
|
||||
void EDA_DRAW_PANEL_GAL::onShowTimer( wxTimerEvent& aEvent )
|
||||
{
|
||||
if( m_gal && m_gal->IsVisible() )
|
||||
if( m_gal && m_gal->IsInitialized() && m_gal->IsVisible() )
|
||||
{
|
||||
m_onShowTimer.Stop();
|
||||
OnShow();
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 1992-2013 Jean-Pierre Charras <jp.charras at wanadoo.fr>.
|
||||
* Copyright (C) 1992-2022 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
* Copyright (C) 1992-2023 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
@@ -118,8 +118,12 @@ void DS_DRAW_ITEM_BASE::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame,
|
||||
break;
|
||||
|
||||
case DS_DATA_ITEM::DS_TEXT:
|
||||
aList.emplace_back( _( "Text" ), static_cast<DS_DRAW_ITEM_TEXT*>( this )->GetShownText() );
|
||||
{
|
||||
DS_DRAW_ITEM_TEXT* textItem = static_cast<DS_DRAW_ITEM_TEXT*>( this );
|
||||
// Don't use GetShownText(); we want to see the variable references here
|
||||
aList.emplace_back( _( "Text" ), KIUI::EllipsizeStatusText( aFrame, textItem->GetText() ) );
|
||||
break;
|
||||
}
|
||||
|
||||
case DS_DATA_ITEM::DS_POLYPOLYGON:
|
||||
aList.emplace_back( _( "Imported Shape" ), wxEmptyString );
|
||||
@@ -190,7 +194,7 @@ bool DS_DRAW_ITEM_TEXT::HitTest( const BOX2I& aRect, bool aContains, int aAccura
|
||||
|
||||
wxString DS_DRAW_ITEM_TEXT::GetItemDescription( UNITS_PROVIDER* aUnitsProvider ) const
|
||||
{
|
||||
return wxString::Format( _( "Text '%s'" ), GetShownText() );
|
||||
return wxString::Format( _( "Text '%s'" ), KIUI::EllipsizeMenuText( GetText() ) );
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -270,7 +270,7 @@ void KIGFX::DS_PAINTER::draw( const DS_DRAW_ITEM_TEXT* aItem, int aLayer ) const
|
||||
attrs.m_StrokeWidth = std::max( aItem->GetEffectiveTextPenWidth(),
|
||||
m_renderSettings.GetDefaultPenWidth() );
|
||||
|
||||
font->Draw( m_gal, aItem->GetShownText(), aItem->GetTextPos(), attrs );
|
||||
font->Draw( m_gal, aItem->GetShownText( true ), aItem->GetTextPos(), attrs );
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -55,6 +55,7 @@
|
||||
#include <widgets/paged_dialog.h>
|
||||
#include <widgets/wx_infobar.h>
|
||||
#include <widgets/wx_aui_art_providers.h>
|
||||
#include <widgets/wx_grid.h>
|
||||
#include <wx/app.h>
|
||||
#include <wx/config.h>
|
||||
#include <wx/display.h>
|
||||
@@ -219,6 +220,10 @@ void EDA_BASE_FRAME::windowClosing( wxCloseEvent& event )
|
||||
if( canCloseWindow( event ) )
|
||||
{
|
||||
m_isClosing = true;
|
||||
|
||||
if( m_infoBar )
|
||||
m_infoBar->Dismiss();
|
||||
|
||||
APP_SETTINGS_BASE* cfg = config();
|
||||
|
||||
if( cfg )
|
||||
@@ -399,6 +404,8 @@ void EDA_BASE_FRAME::HandleUpdateUIEvent( wxUpdateUIEvent& aEvent, EDA_BASE_FRAM
|
||||
enableRes = true;
|
||||
else if( textEntry && isPaste && textEntry->CanPaste() )
|
||||
enableRes = true;
|
||||
else if( dynamic_cast<WX_GRID*>( focus ) )
|
||||
enableRes = false; // Must disable menu in order to get command as CharHook event
|
||||
}
|
||||
|
||||
aEvent.Enable( enableRes );
|
||||
@@ -1230,7 +1237,7 @@ bool EDA_BASE_FRAME::IsWritable( const wxFileName& aFileName, bool aVerbose )
|
||||
|
||||
void EDA_BASE_FRAME::CheckForAutoSaveFile( const wxFileName& aFileName )
|
||||
{
|
||||
if( !IsGUI() )
|
||||
if( !Pgm().IsGUI() )
|
||||
return;
|
||||
|
||||
wxCHECK_RET( aFileName.IsOk(), wxT( "Invalid file name!" ) );
|
||||
|
||||
@@ -144,6 +144,10 @@ bool GetAssociatedDocument( wxWindow* aParent, const wxString& aDocName, PROJECT
|
||||
|
||||
wxFileName currentFileName( fullfilename );
|
||||
|
||||
// Use wxWidgets to resolve any "." and ".." in the path
|
||||
currentFileName.MakeAbsolute();
|
||||
fullfilename = currentFileName.GetFullPath();
|
||||
|
||||
wxString file_ext = currentFileName.GetExt();
|
||||
|
||||
if( file_ext.Lower() == wxT( "pdf" ) )
|
||||
|
||||
+43
-42
@@ -3,7 +3,7 @@
|
||||
*
|
||||
* Copyright (C) 2004-2017 Jean-Pierre Charras, jp.charras at wanadoo.fr
|
||||
* Copyright (C) 2008 Wayne Stambaugh <stambaughw@gmail.com>
|
||||
* Copyright (C) 2004-2022 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
* Copyright (C) 2004-2023 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
@@ -27,6 +27,7 @@
|
||||
#include <bitmaps.h>
|
||||
#include <confirm.h>
|
||||
#include <core/arraydim.h>
|
||||
#include <core/kicad_algo.h>
|
||||
#include <dialog_shim.h>
|
||||
#include <eda_draw_frame.h>
|
||||
#include <file_history.h>
|
||||
@@ -78,12 +79,16 @@ BEGIN_EVENT_TABLE( EDA_DRAW_FRAME, KIWAY_PLAYER )
|
||||
EVT_ACTIVATE( EDA_DRAW_FRAME::onActivate )
|
||||
END_EVENT_TABLE()
|
||||
|
||||
|
||||
bool EDA_DRAW_FRAME::m_openGLFailureOccured = false;
|
||||
|
||||
|
||||
EDA_DRAW_FRAME::EDA_DRAW_FRAME( KIWAY* aKiway, wxWindow* aParent, FRAME_T aFrameType,
|
||||
const wxString& aTitle, const wxPoint& aPos, const wxSize& aSize,
|
||||
long aStyle, const wxString& aFrameName, const EDA_IU_SCALE& aIuScale ) :
|
||||
KIWAY_PLAYER( aKiway, aParent, aFrameType, aTitle, aPos, aSize, aStyle, aFrameName, aIuScale )
|
||||
long aStyle, const wxString& aFrameName,
|
||||
const EDA_IU_SCALE& aIuScale ) :
|
||||
KIWAY_PLAYER( aKiway, aParent, aFrameType, aTitle, aPos, aSize, aStyle, aFrameName, aIuScale ),
|
||||
m_socketServer( nullptr )
|
||||
{
|
||||
m_socketServer = nullptr;
|
||||
m_mainToolBar = nullptr;
|
||||
@@ -171,8 +176,8 @@ EDA_DRAW_FRAME::EDA_DRAW_FRAME( KIWAY* aKiway, wxWindow* aParent, FRAME_T aFrame
|
||||
OnMove( dummy );
|
||||
|
||||
// we need to kludge the msg panel to the correct size again
|
||||
// especially important even for first launches as the constructor of the window here usually doesn't
|
||||
// have the correct dpi awareness yet
|
||||
// especially important even for first launches as the constructor of the window
|
||||
// here usually doesn't have the correct dpi awareness yet
|
||||
m_frameSize.y += m_msgFrameHeight;
|
||||
m_msgFrameHeight = EDA_MSG_PANEL::GetRequiredHeight( this );
|
||||
m_frameSize.y -= m_msgFrameHeight;
|
||||
@@ -285,7 +290,7 @@ void EDA_DRAW_FRAME::ToggleUserUnits()
|
||||
else
|
||||
{
|
||||
SetUserUnits( GetUserUnits() == EDA_UNITS::INCHES ? EDA_UNITS::MILLIMETRES
|
||||
: EDA_UNITS::INCHES );
|
||||
: EDA_UNITS::INCHES );
|
||||
unitsChangeRefresh();
|
||||
|
||||
wxCommandEvent e( UNITS_CHANGED );
|
||||
@@ -609,7 +614,8 @@ void EDA_DRAW_FRAME::DisplayGridMsg()
|
||||
{
|
||||
wxString msg;
|
||||
|
||||
msg.Printf( wxS( "grid %s" ), MessageTextFromValue( GetCanvas()->GetGAL()->GetGridSize().x, false ) );
|
||||
msg.Printf( _( "grid %s" ), MessageTextFromValue( GetCanvas()->GetGAL()->GetGridSize().x,
|
||||
false ) );
|
||||
|
||||
SetStatusText( msg, 4 );
|
||||
}
|
||||
@@ -736,21 +742,21 @@ void EDA_DRAW_FRAME::SaveSettings( APP_SETTINGS_BASE* aCfg )
|
||||
void EDA_DRAW_FRAME::AppendMsgPanel( const wxString& aTextUpper, const wxString& aTextLower,
|
||||
int aPadding )
|
||||
{
|
||||
if( m_messagePanel )
|
||||
if( m_messagePanel && !m_isClosing )
|
||||
m_messagePanel->AppendMessage( aTextUpper, aTextLower, aPadding );
|
||||
}
|
||||
|
||||
|
||||
void EDA_DRAW_FRAME::ClearMsgPanel()
|
||||
{
|
||||
if( m_messagePanel )
|
||||
if( m_messagePanel && !m_isClosing )
|
||||
m_messagePanel->EraseMsgBox();
|
||||
}
|
||||
|
||||
|
||||
void EDA_DRAW_FRAME::SetMsgPanel( const std::vector<MSG_PANEL_ITEM>& aList )
|
||||
{
|
||||
if( m_messagePanel )
|
||||
if( m_messagePanel && !m_isClosing )
|
||||
{
|
||||
m_messagePanel->EraseMsgBox();
|
||||
|
||||
@@ -763,10 +769,9 @@ void EDA_DRAW_FRAME::SetMsgPanel( const std::vector<MSG_PANEL_ITEM>& aList )
|
||||
void EDA_DRAW_FRAME::SetMsgPanel( const wxString& aTextUpper, const wxString& aTextLower,
|
||||
int aPadding )
|
||||
{
|
||||
if( m_messagePanel )
|
||||
if( m_messagePanel && !m_isClosing )
|
||||
{
|
||||
m_messagePanel->EraseMsgBox();
|
||||
|
||||
m_messagePanel->AppendMessage( aTextUpper, aTextLower, aPadding );
|
||||
}
|
||||
}
|
||||
@@ -837,26 +842,15 @@ bool EDA_DRAW_FRAME::saveCanvasTypeSetting( EDA_DRAW_PANEL_GAL::GAL_TYPE aCanvas
|
||||
// Not all classes derived from EDA_DRAW_FRAME can save the canvas type, because some
|
||||
// have a fixed type, or do not have a option to set the canvas type (they inherit from
|
||||
// a parent frame)
|
||||
FRAME_T allowed_frames[] =
|
||||
{
|
||||
FRAME_SCH, FRAME_SCH_SYMBOL_EDITOR,
|
||||
FRAME_PCB_EDITOR, FRAME_FOOTPRINT_EDITOR,
|
||||
FRAME_GERBER,
|
||||
FRAME_PL_EDITOR
|
||||
};
|
||||
static std::vector<FRAME_T> s_allowedFrames =
|
||||
{
|
||||
FRAME_SCH, FRAME_SCH_SYMBOL_EDITOR,
|
||||
FRAME_PCB_EDITOR, FRAME_FOOTPRINT_EDITOR,
|
||||
FRAME_GERBER,
|
||||
FRAME_PL_EDITOR
|
||||
};
|
||||
|
||||
bool allow_save = false;
|
||||
|
||||
for( unsigned ii = 0; ii < arrayDim( allowed_frames ); ii++ )
|
||||
{
|
||||
if( m_ident == allowed_frames[ii] )
|
||||
{
|
||||
allow_save = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if( !allow_save )
|
||||
if( !alg::contains( s_allowedFrames, m_ident ) )
|
||||
return false;
|
||||
|
||||
if( aCanvasType < EDA_DRAW_PANEL_GAL::GAL_TYPE_NONE
|
||||
@@ -866,9 +860,7 @@ bool EDA_DRAW_FRAME::saveCanvasTypeSetting( EDA_DRAW_PANEL_GAL::GAL_TYPE aCanvas
|
||||
return false;
|
||||
}
|
||||
|
||||
APP_SETTINGS_BASE* cfg = Kiface().KifaceSettings();
|
||||
|
||||
if( cfg )
|
||||
if( APP_SETTINGS_BASE* cfg = Kiface().KifaceSettings() )
|
||||
cfg->m_Graphics.canvas_type = static_cast<int>( aCanvasType );
|
||||
|
||||
return false;
|
||||
@@ -878,7 +870,7 @@ bool EDA_DRAW_FRAME::saveCanvasTypeSetting( EDA_DRAW_PANEL_GAL::GAL_TYPE aCanvas
|
||||
VECTOR2I EDA_DRAW_FRAME::GetNearestGridPosition( const VECTOR2I& aPosition ) const
|
||||
{
|
||||
const VECTOR2I& gridOrigin = GetGridOrigin();
|
||||
VECTOR2D gridSize = GetCanvas()->GetGAL()->GetGridSize();
|
||||
VECTOR2D gridSize = GetCanvas()->GetGAL()->GetGridSize();
|
||||
|
||||
double xOffset = fmod( gridOrigin.x, gridSize.x );
|
||||
int x = KiROUND( (aPosition.x - xOffset) / gridSize.x );
|
||||
@@ -892,7 +884,7 @@ VECTOR2I EDA_DRAW_FRAME::GetNearestGridPosition( const VECTOR2I& aPosition ) con
|
||||
VECTOR2I EDA_DRAW_FRAME::GetNearestHalfGridPosition( const VECTOR2I& aPosition ) const
|
||||
{
|
||||
const VECTOR2I& gridOrigin = GetGridOrigin();
|
||||
VECTOR2D gridSize = GetCanvas()->GetGAL()->GetGridSize() / 2.0;
|
||||
VECTOR2D gridSize = GetCanvas()->GetGAL()->GetGridSize() / 2.0;
|
||||
|
||||
double xOffset = fmod( gridOrigin.x, gridSize.x );
|
||||
int x = KiROUND( (aPosition.x - xOffset) / gridSize.x );
|
||||
@@ -985,8 +977,8 @@ static const wxString productName = wxT( "KiCad E.D.A. " );
|
||||
|
||||
|
||||
void PrintDrawingSheet( const RENDER_SETTINGS* aSettings, const PAGE_INFO& aPageInfo,
|
||||
const wxString& aFullSheetName, const wxString& aFileName,
|
||||
const TITLE_BLOCK& aTitleBlock,
|
||||
const wxString& aSheetName, const wxString& aSheetPath,
|
||||
const wxString& aFileName, const TITLE_BLOCK& aTitleBlock,
|
||||
const std::map<wxString, wxString>* aProperties, int aSheetCount,
|
||||
const wxString& aPageNumber, double aMils2Iu, const PROJECT* aProject,
|
||||
const wxString& aSheetLayer, bool aIsFirstPage )
|
||||
@@ -998,7 +990,8 @@ void PrintDrawingSheet( const RENDER_SETTINGS* aSettings, const PAGE_INFO& aPage
|
||||
drawList.SetPageNumber( aPageNumber );
|
||||
drawList.SetSheetCount( aSheetCount );
|
||||
drawList.SetFileName( aFileName );
|
||||
drawList.SetSheetName( aFullSheetName );
|
||||
drawList.SetSheetName( aSheetName );
|
||||
drawList.SetSheetPath( aSheetPath );
|
||||
drawList.SetSheetLayer( aSheetLayer );
|
||||
drawList.SetProject( aProject );
|
||||
drawList.SetIsFirstPage( aIsFirstPage );
|
||||
@@ -1028,9 +1021,10 @@ void EDA_DRAW_FRAME::PrintDrawingSheet( const RENDER_SETTINGS* aSettings, BASE_S
|
||||
DC->SetAxisOrientation( true, false );
|
||||
}
|
||||
|
||||
::PrintDrawingSheet( aSettings, GetPageSettings(), GetScreenDesc(), aFilename, GetTitleBlock(),
|
||||
aProperties, aScreen->GetPageCount(), aScreen->GetPageNumber(), aMils2Iu,
|
||||
&Prj(), aSheetLayer, aScreen->GetVirtualPageNumber() == 1 );
|
||||
::PrintDrawingSheet( aSettings, GetPageSettings(), GetScreenDesc(), GetFullScreenDesc(),
|
||||
aFilename, GetTitleBlock(), aProperties, aScreen->GetPageCount(),
|
||||
aScreen->GetPageNumber(), aMils2Iu, &Prj(), aSheetLayer,
|
||||
aScreen->GetVirtualPageNumber() == 1 );
|
||||
|
||||
if( origin.y > 0 )
|
||||
{
|
||||
@@ -1047,6 +1041,13 @@ wxString EDA_DRAW_FRAME::GetScreenDesc() const
|
||||
}
|
||||
|
||||
|
||||
wxString EDA_DRAW_FRAME::GetFullScreenDesc() const
|
||||
{
|
||||
// Virtual function. Base class implementation returns an empty string.
|
||||
return wxEmptyString;
|
||||
}
|
||||
|
||||
|
||||
bool EDA_DRAW_FRAME::LibraryFileBrowser( bool doOpen, wxFileName& aFilename,
|
||||
const wxString& wildcard, const wxString& ext,
|
||||
bool isDirectory, bool aIsGlobal,
|
||||
|
||||
+3
-4
@@ -392,10 +392,9 @@ static struct EDA_ITEM_DESC
|
||||
PROPERTY_MANAGER& propMgr = PROPERTY_MANAGER::Instance();
|
||||
REGISTER_TYPE( EDA_ITEM );
|
||||
|
||||
auto typeProp = new PROPERTY_ENUM<EDA_ITEM, KICAD_T>( wxS( "Type" ),
|
||||
NO_SETTER( EDA_ITEM, KICAD_T ), &EDA_ITEM::Type );
|
||||
typeProp->SetIsInternal( true );
|
||||
propMgr.AddProperty( typeProp );
|
||||
propMgr.AddProperty( new PROPERTY_ENUM<EDA_ITEM, KICAD_T>( wxS( "Type" ),
|
||||
NO_SETTER( EDA_ITEM, KICAD_T ), &EDA_ITEM::Type ) )
|
||||
.SetIsHiddenFromPropertiesManager();
|
||||
}
|
||||
} _EDA_ITEM_DESC;
|
||||
|
||||
|
||||
@@ -412,6 +412,30 @@ bool EDA_COMBINED_MATCHER::Find( const wxString& aTerm, int& aMatchersTriggered,
|
||||
}
|
||||
|
||||
|
||||
bool EDA_COMBINED_MATCHER::Find( const wxString& aTerm )
|
||||
{
|
||||
for( const std::unique_ptr<EDA_PATTERN_MATCH>& matcher : m_matchers )
|
||||
{
|
||||
if( matcher->Find( aTerm ).start >= 0 )
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool EDA_COMBINED_MATCHER::StartsWith( const wxString& aTerm )
|
||||
{
|
||||
for( const std::unique_ptr<EDA_PATTERN_MATCH>& matcher : m_matchers )
|
||||
{
|
||||
if( matcher->Find( aTerm ).start == 0 )
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
wxString const& EDA_COMBINED_MATCHER::GetPattern() const
|
||||
{
|
||||
return m_pattern;
|
||||
|
||||
+30
-5
@@ -1687,21 +1687,36 @@ static struct EDA_SHAPE_DESC
|
||||
|
||||
PROPERTY_MANAGER& propMgr = PROPERTY_MANAGER::Instance();
|
||||
REGISTER_TYPE( EDA_SHAPE );
|
||||
|
||||
auto isNotPolygon =
|
||||
[]( INSPECTABLE* aItem ) -> bool
|
||||
{
|
||||
// Polygons, unlike other shapes, have no meaningful start or end coordinates
|
||||
if( EDA_SHAPE* shape = dynamic_cast<EDA_SHAPE*>( aItem ) )
|
||||
return shape->GetShape() != SHAPE_T::POLY;
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
auto shape = new PROPERTY_ENUM<EDA_SHAPE, SHAPE_T>( _HKI( "Shape" ),
|
||||
NO_SETTER( EDA_SHAPE, SHAPE_T ), &EDA_SHAPE::GetShape );
|
||||
propMgr.AddProperty( shape );
|
||||
propMgr.AddProperty( new PROPERTY<EDA_SHAPE, int>( _HKI( "Start X" ),
|
||||
&EDA_SHAPE::SetStartX, &EDA_SHAPE::GetStartX, PROPERTY_DISPLAY::PT_COORD,
|
||||
ORIGIN_TRANSFORMS::ABS_X_COORD ) );
|
||||
ORIGIN_TRANSFORMS::ABS_X_COORD ) )
|
||||
.SetAvailableFunc( isNotPolygon );
|
||||
propMgr.AddProperty( new PROPERTY<EDA_SHAPE, int>( _HKI( "Start Y" ),
|
||||
&EDA_SHAPE::SetStartY, &EDA_SHAPE::GetStartY, PROPERTY_DISPLAY::PT_COORD,
|
||||
ORIGIN_TRANSFORMS::ABS_Y_COORD ) );
|
||||
ORIGIN_TRANSFORMS::ABS_Y_COORD ) )
|
||||
.SetAvailableFunc( isNotPolygon );
|
||||
propMgr.AddProperty( new PROPERTY<EDA_SHAPE, int>( _HKI( "End X" ),
|
||||
&EDA_SHAPE::SetEndX, &EDA_SHAPE::GetEndX, PROPERTY_DISPLAY::PT_COORD,
|
||||
ORIGIN_TRANSFORMS::ABS_X_COORD ) );
|
||||
ORIGIN_TRANSFORMS::ABS_X_COORD ) )
|
||||
.SetAvailableFunc( isNotPolygon );
|
||||
propMgr.AddProperty( new PROPERTY<EDA_SHAPE, int>( _HKI( "End Y" ),
|
||||
&EDA_SHAPE::SetEndY, &EDA_SHAPE::GetEndY, PROPERTY_DISPLAY::PT_COORD,
|
||||
ORIGIN_TRANSFORMS::ABS_Y_COORD ) );
|
||||
ORIGIN_TRANSFORMS::ABS_Y_COORD ) )
|
||||
.SetAvailableFunc( isNotPolygon );
|
||||
// TODO: m_arcCenter, m_bezierC1, m_bezierC2, m_poly
|
||||
propMgr.AddProperty( new PROPERTY<EDA_SHAPE, int>( _HKI( "Line Width" ),
|
||||
&EDA_SHAPE::SetWidth, &EDA_SHAPE::GetWidth, PROPERTY_DISPLAY::PT_SIZE ) );
|
||||
@@ -1721,7 +1736,17 @@ static struct EDA_SHAPE_DESC
|
||||
filled->SetAvailableFunc(
|
||||
[=]( INSPECTABLE* aItem ) -> bool
|
||||
{
|
||||
SHAPE_T itemShape = aItem->Get<SHAPE_T>( shape );
|
||||
SHAPE_T itemShape;
|
||||
|
||||
try
|
||||
{
|
||||
itemShape = aItem->Get<SHAPE_T>( shape );
|
||||
}
|
||||
catch( std::runtime_error& err )
|
||||
{
|
||||
wxFAIL_MSG( err.what() );
|
||||
return false;
|
||||
}
|
||||
|
||||
switch( itemShape )
|
||||
{
|
||||
|
||||
+24
-12
@@ -2,7 +2,7 @@
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2016 Jean-Pierre Charras, jp.charras at wanadoo.fr
|
||||
* Copyright (C) 2004-2022 KiCad Developers, see change_log.txt for contributors.
|
||||
* Copyright (C) 2004-2023 KiCad Developers, see change_log.txt for contributors.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
@@ -37,6 +37,7 @@
|
||||
#include <callback_gal.h>
|
||||
#include <eda_text.h> // for EDA_TEXT, TEXT_EFFECTS, GR_TEXT_VJUSTIF...
|
||||
#include <gal/color4d.h> // for COLOR4D, COLOR4D::BLACK
|
||||
#include <font/glyph.h>
|
||||
#include <gr_text.h>
|
||||
#include <string_utils.h> // for UnescapeString
|
||||
#include <math/util.h> // for KiROUND
|
||||
@@ -117,8 +118,10 @@ EDA_TEXT::EDA_TEXT( const EDA_TEXT& aText ) :
|
||||
|
||||
for( const std::unique_ptr<KIFONT::GLYPH>& glyph : aText.m_render_cache )
|
||||
{
|
||||
KIFONT::OUTLINE_GLYPH* outline_glyph = static_cast<KIFONT::OUTLINE_GLYPH*>( glyph.get() );
|
||||
m_render_cache.emplace_back( std::make_unique<KIFONT::OUTLINE_GLYPH>( *outline_glyph ) );
|
||||
if( KIFONT::OUTLINE_GLYPH* outline = dynamic_cast<KIFONT::OUTLINE_GLYPH*>( glyph.get() ) )
|
||||
m_render_cache.emplace_back( std::make_unique<KIFONT::OUTLINE_GLYPH>( *outline ) );
|
||||
else if( KIFONT::STROKE_GLYPH* stroke = dynamic_cast<KIFONT::STROKE_GLYPH*>( glyph.get() ) )
|
||||
m_render_cache.emplace_back( std::make_unique<KIFONT::STROKE_GLYPH>( *stroke ) );
|
||||
}
|
||||
|
||||
m_bounding_box_cache_valid = aText.m_bounding_box_cache_valid;
|
||||
@@ -149,8 +152,10 @@ EDA_TEXT& EDA_TEXT::operator=( const EDA_TEXT& aText )
|
||||
|
||||
for( const std::unique_ptr<KIFONT::GLYPH>& glyph : aText.m_render_cache )
|
||||
{
|
||||
KIFONT::OUTLINE_GLYPH* outline_glyph = static_cast<KIFONT::OUTLINE_GLYPH*>( glyph.get() );
|
||||
m_render_cache.emplace_back( std::make_unique<KIFONT::OUTLINE_GLYPH>( *outline_glyph ) );
|
||||
if( KIFONT::OUTLINE_GLYPH* outline = dynamic_cast<KIFONT::OUTLINE_GLYPH*>( glyph.get() ) )
|
||||
m_render_cache.emplace_back( std::make_unique<KIFONT::OUTLINE_GLYPH>( *outline ) );
|
||||
else if( KIFONT::STROKE_GLYPH* stroke = dynamic_cast<KIFONT::STROKE_GLYPH*>( glyph.get() ) )
|
||||
m_render_cache.emplace_back( std::make_unique<KIFONT::STROKE_GLYPH>( *stroke ) );
|
||||
}
|
||||
|
||||
m_bounding_box_cache_valid = aText.m_bounding_box_cache_valid;
|
||||
@@ -391,7 +396,12 @@ void EDA_TEXT::Offset( const VECTOR2I& aOffset )
|
||||
m_pos += aOffset;
|
||||
|
||||
for( std::unique_ptr<KIFONT::GLYPH>& glyph : m_render_cache )
|
||||
static_cast<KIFONT::OUTLINE_GLYPH*>( glyph.get() )->Move( aOffset );
|
||||
{
|
||||
if( KIFONT::OUTLINE_GLYPH* outline = dynamic_cast<KIFONT::OUTLINE_GLYPH*>( glyph.get() ) )
|
||||
outline->Move( aOffset );
|
||||
else if( KIFONT::STROKE_GLYPH* stroke = dynamic_cast<KIFONT::STROKE_GLYPH*>( glyph.get() ) )
|
||||
glyph = stroke->Transform( { 1.0, 1.0 }, aOffset, 0, ANGLE_0, false, { 0, 0 } );
|
||||
}
|
||||
|
||||
m_bounding_box_cache_valid = false;
|
||||
}
|
||||
@@ -467,7 +477,8 @@ EDA_TEXT::GetRenderCache( const KIFONT::FONT* aFont, const wxString& forResolved
|
||||
|
||||
attrs.m_Angle = resolvedAngle;
|
||||
|
||||
font->GetLinesAsGlyphs( &m_render_cache, GetShownText(), GetDrawPos() + aOffset, attrs );
|
||||
font->GetLinesAsGlyphs( &m_render_cache, forResolvedText, GetDrawPos() + aOffset,
|
||||
attrs );
|
||||
m_render_cache_angle = resolvedAngle;
|
||||
m_render_cache_text = forResolvedText;
|
||||
m_render_cache_offset = aOffset;
|
||||
@@ -514,7 +525,7 @@ BOX2I EDA_TEXT::GetTextBox( int aLine, bool aInvertY ) const
|
||||
|
||||
BOX2I bbox;
|
||||
wxArrayString strings;
|
||||
wxString text = GetShownText();
|
||||
wxString text = GetShownText( true );
|
||||
int thickness = GetEffectiveTextPenWidth();
|
||||
|
||||
if( IsMultilineAllowed() )
|
||||
@@ -652,7 +663,7 @@ void EDA_TEXT::Print( const RENDER_SETTINGS* aSettings, const VECTOR2I& aOffset,
|
||||
{
|
||||
std::vector<VECTOR2I> positions;
|
||||
wxArrayString strings;
|
||||
wxStringSplit( GetShownText(), strings, '\n' );
|
||||
wxStringSplit( GetShownText( true ), strings, '\n' );
|
||||
|
||||
positions.reserve( strings.Count() );
|
||||
|
||||
@@ -663,7 +674,8 @@ void EDA_TEXT::Print( const RENDER_SETTINGS* aSettings, const VECTOR2I& aOffset,
|
||||
}
|
||||
else
|
||||
{
|
||||
printOneLineOfText( aSettings, aOffset, aColor, aFillMode, GetShownText(), GetDrawPos() );
|
||||
printOneLineOfText( aSettings, aOffset, aColor, aFillMode, GetShownText( true ),
|
||||
GetDrawPos() );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -884,7 +896,7 @@ std::shared_ptr<SHAPE_COMPOUND> EDA_TEXT::GetEffectiveTextShape( bool aTriangula
|
||||
shape->AddShape( triShape );
|
||||
} );
|
||||
|
||||
font->Draw( &callback_gal, GetShownText(), GetDrawPos(), attrs );
|
||||
font->Draw( &callback_gal, GetShownText( true ), GetDrawPos(), attrs );
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -901,7 +913,7 @@ std::shared_ptr<SHAPE_COMPOUND> EDA_TEXT::GetEffectiveTextShape( bool aTriangula
|
||||
shape->AddShape( aPoly.Clone() );
|
||||
} );
|
||||
|
||||
font->Draw( &callback_gal, GetShownText(), GetDrawPos(), attrs );
|
||||
font->Draw( &callback_gal, GetShownText( true ), GetDrawPos(), attrs );
|
||||
}
|
||||
|
||||
return shape;
|
||||
|
||||
@@ -65,7 +65,7 @@ int EDA_UNIT_UTILS::Mils2mm( double aVal )
|
||||
}
|
||||
|
||||
|
||||
void EDA_UNIT_UTILS::FetchUnitsFromString( const wxString& aTextValue, EDA_UNITS& aUnits )
|
||||
bool EDA_UNIT_UTILS::FetchUnitsFromString( const wxString& aTextValue, EDA_UNITS& aUnits )
|
||||
{
|
||||
wxString buf( aTextValue.Strip( wxString::both ) );
|
||||
unsigned brk_point = 0;
|
||||
@@ -92,6 +92,9 @@ void EDA_UNIT_UTILS::FetchUnitsFromString( const wxString& aTextValue, EDA_UNITS
|
||||
aUnits = EDA_UNITS::INCHES;
|
||||
else if( unit == wxT( "de" ) || unit == wxT( "ra" ) ) // "deg" or "rad"
|
||||
aUnits = EDA_UNITS::DEGREES;
|
||||
else
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
+135
-38
@@ -2,7 +2,7 @@
|
||||
* This program source code file is part of KICAD, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2021 Ola Rinta-Koski
|
||||
* Copyright (C) 2021-2022 Kicad Developers, see AUTHORS.txt for contributors.
|
||||
* Copyright (C) 2021-2023 Kicad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* Font abstract base class
|
||||
*
|
||||
@@ -35,6 +35,7 @@
|
||||
// The "official" name of the building Kicad stroke font (always existing)
|
||||
#include <font/kicad_font_name.h>
|
||||
#include "macros.h"
|
||||
#include "wx/tokenzr.h"
|
||||
|
||||
|
||||
// markup_parser.h includes pegtl.hpp which includes windows.h... which leaks #define DrawText
|
||||
@@ -120,6 +121,13 @@ void FONT::getLinePositions( const wxString& aText, const VECTOR2I& aPosition,
|
||||
VECTOR2I offset( 0, 0 );
|
||||
offset.y += aAttrs.m_Size.y;
|
||||
|
||||
if( IsStroke() )
|
||||
{
|
||||
// Fudge factors to match 6.0 positioning
|
||||
offset.x += aAttrs.m_StrokeWidth / 1.52;
|
||||
offset.y -= aAttrs.m_StrokeWidth * 0.052;
|
||||
}
|
||||
|
||||
switch( aAttrs.m_Valign )
|
||||
{
|
||||
case GR_TEXT_V_ALIGN_TOP: break;
|
||||
@@ -138,7 +146,7 @@ void FONT::getLinePositions( const wxString& aText, const VECTOR2I& aPosition,
|
||||
{
|
||||
case GR_TEXT_H_ALIGN_LEFT: break;
|
||||
case GR_TEXT_H_ALIGN_CENTER: lineOffset.x = -lineSize.x / 2; break;
|
||||
case GR_TEXT_H_ALIGN_RIGHT: lineOffset.x = -lineSize.x; break;
|
||||
case GR_TEXT_H_ALIGN_RIGHT: lineOffset.x = -( lineSize.x + offset.x ); break;
|
||||
}
|
||||
|
||||
aPositions.push_back( aPosition + lineOffset );
|
||||
@@ -191,6 +199,8 @@ VECTOR2I drawMarkup( BOX2I* aBoundingBox, std::vector<std::unique_ptr<GLYPH>>* a
|
||||
bool aMirror, const VECTOR2I& aOrigin, TEXT_STYLE_FLAGS aTextStyle )
|
||||
{
|
||||
VECTOR2I nextPosition = aPosition;
|
||||
bool drawUnderline = false;
|
||||
bool drawOverbar = false;
|
||||
|
||||
if( aNode )
|
||||
{
|
||||
@@ -199,30 +209,79 @@ VECTOR2I drawMarkup( BOX2I* aBoundingBox, std::vector<std::unique_ptr<GLYPH>>* a
|
||||
if( !aNode->is_root() )
|
||||
{
|
||||
if( aNode->isSubscript() )
|
||||
textStyle = TEXT_STYLE::SUBSCRIPT;
|
||||
textStyle |= TEXT_STYLE::SUBSCRIPT;
|
||||
else if( aNode->isSuperscript() )
|
||||
textStyle = TEXT_STYLE::SUPERSCRIPT;
|
||||
textStyle |= TEXT_STYLE::SUPERSCRIPT;
|
||||
|
||||
if( aNode->isOverbar() )
|
||||
textStyle |= TEXT_STYLE::OVERBAR;
|
||||
drawOverbar = true;
|
||||
|
||||
if( aNode->has_content() )
|
||||
{
|
||||
BOX2I bbox;
|
||||
|
||||
nextPosition = aFont->GetTextAsGlyphs( &bbox, aGlyphs, aNode->asWxString(), aSize,
|
||||
aPosition, aAngle, aMirror, aOrigin,
|
||||
nextPosition, aAngle, aMirror, aOrigin,
|
||||
textStyle );
|
||||
|
||||
if( aBoundingBox )
|
||||
aBoundingBox->Merge( bbox );
|
||||
}
|
||||
}
|
||||
else if( aTextStyle & TEXT_STYLE::UNDERLINE )
|
||||
{
|
||||
drawUnderline = true;
|
||||
}
|
||||
|
||||
for( const std::unique_ptr<MARKUP::NODE>& child : aNode->children )
|
||||
{
|
||||
nextPosition = drawMarkup( aBoundingBox, aGlyphs, child, nextPosition, aFont, aSize,
|
||||
aAngle, aMirror, aOrigin, textStyle );
|
||||
aAngle, aMirror, aOrigin, textStyle );
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if( drawUnderline )
|
||||
{
|
||||
// Shorten the bar a little so its rounded ends don't make it over-long
|
||||
double barTrim = aSize.x * 0.1;
|
||||
double barOffset = aFont->ComputeUnderlineVerticalPosition( aSize.y );
|
||||
|
||||
VECTOR2D barStart( aPosition.x + barTrim, aPosition.y - barOffset );
|
||||
VECTOR2D barEnd( nextPosition.x - barTrim, nextPosition.y - barOffset );
|
||||
|
||||
if( aGlyphs )
|
||||
{
|
||||
STROKE_GLYPH barGlyph;
|
||||
|
||||
barGlyph.AddPoint( barStart );
|
||||
barGlyph.AddPoint( barEnd );
|
||||
barGlyph.Finalize();
|
||||
|
||||
aGlyphs->push_back( barGlyph.Transform( { 1.0, 1.0 }, { 0, 0 }, false, aAngle, aMirror,
|
||||
aOrigin ) );
|
||||
}
|
||||
}
|
||||
|
||||
if( drawOverbar )
|
||||
{
|
||||
// Shorten the bar a little so its rounded ends don't make it over-long
|
||||
double barTrim = aSize.x * 0.1;
|
||||
double barOffset = aFont->ComputeOverbarVerticalPosition( aSize.y );
|
||||
|
||||
VECTOR2D barStart( aPosition.x + barTrim, aPosition.y - barOffset );
|
||||
VECTOR2D barEnd( nextPosition.x - barTrim, nextPosition.y - barOffset );
|
||||
|
||||
if( aGlyphs )
|
||||
{
|
||||
STROKE_GLYPH barGlyph;
|
||||
|
||||
barGlyph.AddPoint( barStart );
|
||||
barGlyph.AddPoint( barEnd );
|
||||
barGlyph.Finalize();
|
||||
|
||||
aGlyphs->push_back( barGlyph.Transform( { 1.0, 1.0 }, { 0, 0 }, false, aAngle, aMirror,
|
||||
aOrigin ) );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -253,6 +312,7 @@ void FONT::drawSingleLineText( KIGFX::GAL* aGal, BOX2I* aBoundingBox, const wxSt
|
||||
|
||||
TEXT_STYLE_FLAGS textStyle = 0;
|
||||
|
||||
|
||||
if( aItalic )
|
||||
textStyle |= TEXT_STYLE::ITALIC;
|
||||
|
||||
@@ -281,8 +341,8 @@ VECTOR2I FONT::StringBoundaryLimits( const wxString& aText, const VECTOR2I& aSiz
|
||||
if( aItalic )
|
||||
textStyle |= TEXT_STYLE::ITALIC;
|
||||
|
||||
(void) drawMarkup( &boundingBox, nullptr, aText, VECTOR2I(), aSize, ANGLE_0, false,
|
||||
VECTOR2I(), textStyle );
|
||||
(void) drawMarkup( &boundingBox, nullptr, aText, VECTOR2I(), aSize, ANGLE_0, false, VECTOR2I(),
|
||||
textStyle );
|
||||
|
||||
if( IsStroke() )
|
||||
{
|
||||
@@ -308,7 +368,7 @@ VECTOR2I FONT::boundingBoxSingleLine( BOX2I* aBBox, const wxString& aText,
|
||||
textStyle |= TEXT_STYLE::ITALIC;
|
||||
|
||||
VECTOR2I extents = drawMarkup( aBBox, nullptr, aText, aPosition, aSize, ANGLE_0, false,
|
||||
VECTOR2I(), textStyle );
|
||||
VECTOR2I(), textStyle );
|
||||
|
||||
return extents;
|
||||
}
|
||||
@@ -376,20 +436,22 @@ void wordbreakMarkup( std::vector<std::pair<wxString, int>>* aWords,
|
||||
}
|
||||
else
|
||||
{
|
||||
wxString textRun = aNode->asWxString();
|
||||
wxArrayString words;
|
||||
wxString textRun = aNode->asWxString();
|
||||
wxStringTokenizer tokenizer( textRun, " ", wxTOKEN_RET_DELIMS );
|
||||
std::vector<wxString> words;
|
||||
|
||||
wxStringSplit( textRun, words, ' ' );
|
||||
while( tokenizer.HasMoreTokens() )
|
||||
words.emplace_back( tokenizer.GetNextToken() );
|
||||
|
||||
if( textRun.EndsWith( wxS( " " ) ) )
|
||||
words.Add( wxS( " " ) );
|
||||
|
||||
for( size_t ii = 0; ii < words.size(); ++ii )
|
||||
for( const wxString& word : words )
|
||||
{
|
||||
int w = aFont->GetTextAsGlyphs( nullptr, nullptr, words[ii], aSize, { 0, 0 },
|
||||
wxString chars = word;
|
||||
chars.Trim();
|
||||
|
||||
int w = aFont->GetTextAsGlyphs( nullptr, nullptr, chars, aSize, { 0, 0 },
|
||||
ANGLE_0, false, { 0, 0 }, textStyle ).x;
|
||||
|
||||
aWords->emplace_back( std::make_pair( words[ii], w ) );
|
||||
aWords->emplace_back( std::make_pair( word, w ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -441,35 +503,70 @@ void FONT::LinebreakText( wxString& aText, int aColumnWidth, const VECTOR2I& aSi
|
||||
|
||||
for( size_t ii = 0; ii < textLines.Count(); ++ii )
|
||||
{
|
||||
bool virginLine = true;
|
||||
int lineWidth = 0;
|
||||
std::vector<std::pair<wxString, int>> markup;
|
||||
std::vector<std::pair<wxString, int>> words;
|
||||
|
||||
wordbreakMarkup( &words, textLines[ii], aSize, textStyle );
|
||||
wordbreakMarkup( &markup, textLines[ii], aSize, textStyle );
|
||||
|
||||
for( size_t jj = 0; jj < words.size(); /* advance in loop */ )
|
||||
for( const auto& [ run, runWidth ] : markup )
|
||||
{
|
||||
if( virginLine )
|
||||
if( !words.empty() && !words.back().first.EndsWith( ' ' ) )
|
||||
{
|
||||
// First word is always placed, even when wider than columnWidth.
|
||||
aText += words[jj].first;
|
||||
lineWidth += words[jj].second;
|
||||
jj++;
|
||||
|
||||
virginLine = false;
|
||||
}
|
||||
else if( lineWidth + spaceWidth + words[jj].second < aColumnWidth - aThickness )
|
||||
{
|
||||
aText += " " + words[jj].first;
|
||||
lineWidth += spaceWidth + words[jj].second;
|
||||
jj++;
|
||||
words.back().first += run;
|
||||
words.back().second += runWidth;
|
||||
}
|
||||
else
|
||||
{
|
||||
aText += '\n';
|
||||
words.emplace_back( std::make_pair( run, runWidth ) );
|
||||
}
|
||||
}
|
||||
|
||||
bool buryMode = false;
|
||||
int lineWidth = 0;
|
||||
wxString pendingSpaces;
|
||||
|
||||
for( const auto& [ word, wordWidth ] : words )
|
||||
{
|
||||
int pendingSpaceWidth = (int) pendingSpaces.Length() * spaceWidth;
|
||||
bool overflow = lineWidth + pendingSpaceWidth + wordWidth > aColumnWidth - aThickness;
|
||||
|
||||
if( overflow && pendingSpaces.Length() > 0 )
|
||||
{
|
||||
aText += '\n';
|
||||
lineWidth = 0;
|
||||
virginLine = true;
|
||||
pendingSpaces = wxEmptyString;
|
||||
pendingSpaceWidth = 0;
|
||||
buryMode = true;
|
||||
}
|
||||
|
||||
if( word == wxS( " " ) )
|
||||
{
|
||||
pendingSpaces += word;
|
||||
}
|
||||
else
|
||||
{
|
||||
if( buryMode )
|
||||
{
|
||||
buryMode = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
aText += pendingSpaces;
|
||||
lineWidth += pendingSpaceWidth;
|
||||
}
|
||||
|
||||
if( word.EndsWith( ' ' ) )
|
||||
{
|
||||
aText += word.Left( word.Length() - 1 );
|
||||
pendingSpaces = wxS( " " );
|
||||
}
|
||||
else
|
||||
{
|
||||
aText += word;
|
||||
pendingSpaces = wxEmptyString;
|
||||
}
|
||||
|
||||
lineWidth += wordWidth;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+148
-33
@@ -18,23 +18,25 @@
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <fontconfig/fontconfig.h>
|
||||
|
||||
#include <font/fontconfig.h>
|
||||
#include <pgm_base.h>
|
||||
#include <wx/log.h>
|
||||
#include <trace_helpers.h>
|
||||
#include <string_utils.h>
|
||||
#include <macros.h>
|
||||
#include <font/fontconfig.h>
|
||||
|
||||
using namespace fontconfig;
|
||||
|
||||
static FONTCONFIG* g_config = nullptr;
|
||||
|
||||
|
||||
inline static FcChar8* wxStringToFcChar8( const wxString& str )
|
||||
/**
|
||||
* A simple wrapper to avoid exporing fontconfig in the header
|
||||
*/
|
||||
struct fontconfig::FONTCONFIG_PAT
|
||||
{
|
||||
wxScopedCharBuffer const fcBuffer = str.ToUTF8();
|
||||
return (FcChar8*) fcBuffer.data();
|
||||
}
|
||||
FcPattern* pat;
|
||||
};
|
||||
|
||||
|
||||
wxString FONTCONFIG::Version()
|
||||
@@ -61,19 +63,112 @@ FONTCONFIG* Fontconfig()
|
||||
}
|
||||
|
||||
|
||||
bool FONTCONFIG::isLanguageMatch( const wxString& aSearchLang, const wxString& aSupportedLang )
|
||||
{
|
||||
if( aSearchLang.Lower() == aSupportedLang.Lower() )
|
||||
return true;
|
||||
|
||||
if( aSupportedLang.empty() )
|
||||
return false;
|
||||
|
||||
if( aSearchLang.empty() )
|
||||
return false;
|
||||
|
||||
wxArrayString supportedLangBits;
|
||||
wxStringSplit( aSupportedLang.Lower(), supportedLangBits, wxS( '-' ) );
|
||||
|
||||
wxArrayString searhcLangBits;
|
||||
wxStringSplit( aSearchLang.Lower(), searhcLangBits, wxS( '-' ) );
|
||||
|
||||
// if either side of the comparison have only one section, then its a broad match but fine
|
||||
// i.e. the haystack is declaring broad support or the search language is broad
|
||||
if( searhcLangBits.size() == 1 || supportedLangBits.size() == 1 )
|
||||
{
|
||||
return searhcLangBits[0] == supportedLangBits[0];
|
||||
}
|
||||
|
||||
// the full two part comparison should have passed the initial shortcut
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
std::string FONTCONFIG::getFcString( FONTCONFIG_PAT& aPat, const char* aObj, int aIdx )
|
||||
{
|
||||
FcChar8* str;
|
||||
std::string res;
|
||||
|
||||
if( FcPatternGetString( aPat.pat, aObj, aIdx, &str ) == FcResultMatch )
|
||||
res = std::string( reinterpret_cast<char*>( str ) );
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
void FONTCONFIG::getAllFamilyStrings( FONTCONFIG_PAT& aPat,
|
||||
std::unordered_map<std::string, std::string>& aFamStringMap )
|
||||
{
|
||||
std::string famLang;
|
||||
std::string fam;
|
||||
|
||||
int langIdx = 0;
|
||||
do
|
||||
{
|
||||
famLang = getFcString( aPat, FC_FAMILYLANG, langIdx );
|
||||
|
||||
if( famLang.empty() && langIdx != 0 )
|
||||
break;
|
||||
else
|
||||
{
|
||||
fam = getFcString( aPat, FC_FAMILY, langIdx );
|
||||
aFamStringMap.insert_or_assign( famLang, fam );
|
||||
}
|
||||
} while( langIdx++ < std::numeric_limits<
|
||||
int8_t>::max() ); //arbitrary to avoid getting stuck for any reason
|
||||
}
|
||||
|
||||
|
||||
std::string FONTCONFIG::getFamilyStringByLang( FONTCONFIG_PAT& aPat, const wxString& aDesiredLang )
|
||||
{
|
||||
std::unordered_map<std::string, std::string> famStrings;
|
||||
getAllFamilyStrings( aPat, famStrings );
|
||||
|
||||
if( famStrings.empty() )
|
||||
return "";
|
||||
|
||||
for( auto const& [key, val] : famStrings )
|
||||
{
|
||||
if( isLanguageMatch( aDesiredLang, FROM_UTF8( key.c_str() ) ) )
|
||||
{
|
||||
return val;
|
||||
}
|
||||
}
|
||||
|
||||
// fall back to the first and maybe only available name
|
||||
// most fonts by review don't even bother declaring more than one font family name
|
||||
// and they don't even bother declare the language tag either, they just leave it blank
|
||||
return famStrings.begin()->second;
|
||||
}
|
||||
|
||||
|
||||
FONTCONFIG::FF_RESULT FONTCONFIG::FindFont( const wxString &aFontName, wxString &aFontFile,
|
||||
bool aBold, bool aItalic )
|
||||
int& aFaceIndex, bool aBold, bool aItalic )
|
||||
{
|
||||
FF_RESULT retval = FF_RESULT::FF_ERROR;
|
||||
wxString qualifiedFontName = aFontName;
|
||||
|
||||
wxScopedCharBuffer const fcBuffer = qualifiedFontName.ToUTF8();
|
||||
|
||||
FcPattern* pat = FcPatternCreate();
|
||||
|
||||
if( aBold )
|
||||
qualifiedFontName << wxS( ":Bold" );
|
||||
FcPatternAddString( pat, FC_STYLE, (const FcChar8*) "Bold" );
|
||||
|
||||
if( aItalic )
|
||||
qualifiedFontName << wxS( ":Italic" );
|
||||
FcPatternAddString( pat, FC_STYLE, (const FcChar8*) "Italic" );
|
||||
|
||||
FcPatternAddString( pat, FC_FAMILY, (FcChar8*) fcBuffer.data() );
|
||||
|
||||
FcPattern* pat = FcNameParse( wxStringToFcChar8( qualifiedFontName ) );
|
||||
FcConfigSubstitute( nullptr, pat, FcMatchPattern );
|
||||
FcDefaultSubstitute( pat );
|
||||
|
||||
@@ -89,14 +184,23 @@ FONTCONFIG::FF_RESULT FONTCONFIG::FindFont( const wxString &aFontName, wxString
|
||||
if( FcPatternGetString( font, FC_FILE, 0, &file ) == FcResultMatch )
|
||||
{
|
||||
aFontFile = wxString::FromUTF8( (char*) file );
|
||||
aFaceIndex = 0;
|
||||
|
||||
wxString styleStr;
|
||||
FcChar8* family = nullptr;
|
||||
FcChar8* style = nullptr;
|
||||
|
||||
retval = FF_RESULT::FF_SUBSTITUTE;
|
||||
|
||||
std::unordered_map<std::string, std::string> famStrings;
|
||||
FONTCONFIG_PAT patHolder{ font };
|
||||
|
||||
getAllFamilyStrings( patHolder, famStrings );
|
||||
|
||||
if( FcPatternGetString( font, FC_FAMILY, 0, &family ) == FcResultMatch )
|
||||
{
|
||||
FcPatternGetInteger( font, FC_INDEX, 0, &aFaceIndex );
|
||||
|
||||
fontName = wxString::FromUTF8( (char*) family );
|
||||
|
||||
if( FcPatternGetString( font, FC_STYLE, 0, &style ) == FcResultMatch )
|
||||
@@ -129,18 +233,26 @@ FONTCONFIG::FF_RESULT FONTCONFIG::FindFont( const wxString &aFontName, wxString
|
||||
has_ital = true;
|
||||
}
|
||||
|
||||
if( fontName.Lower().StartsWith( aFontName.Lower() ) )
|
||||
for( auto const& [key, val] : famStrings )
|
||||
{
|
||||
if( ( aBold && !has_bold ) && ( aItalic && !has_ital ) )
|
||||
retval = FF_RESULT::FF_MISSING_BOLD_ITAL;
|
||||
else if( aBold && !has_bold )
|
||||
retval = FF_RESULT::FF_MISSING_BOLD;
|
||||
else if( aItalic && !has_ital )
|
||||
retval = FF_RESULT::FF_MISSING_ITAL;
|
||||
else if( ( aBold != has_bold ) || ( aItalic != has_ital ) )
|
||||
retval = FF_RESULT::FF_SUBSTITUTE;
|
||||
else
|
||||
retval = FF_RESULT::FF_OK;
|
||||
wxString searchFont;
|
||||
searchFont = wxString::FromUTF8( (char*) val.data() );
|
||||
|
||||
if( searchFont.Lower().StartsWith( aFontName.Lower() ) )
|
||||
{
|
||||
if( ( aBold && !has_bold ) && ( aItalic && !has_ital ) )
|
||||
retval = FF_RESULT::FF_MISSING_BOLD_ITAL;
|
||||
else if( aBold && !has_bold )
|
||||
retval = FF_RESULT::FF_MISSING_BOLD;
|
||||
else if( aItalic && !has_ital )
|
||||
retval = FF_RESULT::FF_MISSING_ITAL;
|
||||
else if( ( aBold != has_bold ) || ( aItalic != has_ital ) )
|
||||
retval = FF_RESULT::FF_SUBSTITUTE;
|
||||
else
|
||||
retval = FF_RESULT::FF_OK;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -158,13 +270,14 @@ FONTCONFIG::FF_RESULT FONTCONFIG::FindFont( const wxString &aFontName, wxString
|
||||
}
|
||||
|
||||
|
||||
void FONTCONFIG::ListFonts( std::vector<std::string>& aFonts )
|
||||
void FONTCONFIG::ListFonts( std::vector<std::string>& aFonts, const std::string& aDesiredLang )
|
||||
{
|
||||
if( m_fonts.empty() )
|
||||
// be sure to cache bust if the language changed
|
||||
if( m_fontInfoCache.empty() || m_fontCacheLastLang != aDesiredLang )
|
||||
{
|
||||
FcPattern* pat = FcPatternCreate();
|
||||
FcObjectSet* os = FcObjectSetBuild( FC_FAMILY, FC_STYLE, FC_LANG, FC_FILE, FC_OUTLINE,
|
||||
nullptr );
|
||||
FcObjectSet* os = FcObjectSetBuild( FC_FAMILY, FC_FAMILYLANG, FC_STYLE, FC_LANG, FC_FILE,
|
||||
FC_OUTLINE, nullptr );
|
||||
FcFontSet* fs = FcFontList( nullptr, pat, os );
|
||||
|
||||
for( int i = 0; fs && i < fs->nfont; ++i )
|
||||
@@ -172,12 +285,10 @@ void FONTCONFIG::ListFonts( std::vector<std::string>& aFonts )
|
||||
FcPattern* font = fs->fonts[i];
|
||||
FcChar8* file;
|
||||
FcChar8* style;
|
||||
FcChar8* family;
|
||||
FcLangSet* langSet;
|
||||
FcBool outline;
|
||||
|
||||
if( FcPatternGetString( font, FC_FILE, 0, &file ) == FcResultMatch
|
||||
&& FcPatternGetString( font, FC_FAMILY, 0, &family ) == FcResultMatch
|
||||
&& FcPatternGetString( font, FC_STYLE, 0, &style ) == FcResultMatch
|
||||
&& FcPatternGetLangSet( font, FC_LANG, 0, &langSet ) == FcResultMatch
|
||||
&& FcPatternGetBool( font, FC_OUTLINE, 0, &outline ) == FcResultMatch )
|
||||
@@ -185,7 +296,9 @@ void FONTCONFIG::ListFonts( std::vector<std::string>& aFonts )
|
||||
if( !outline )
|
||||
continue;
|
||||
|
||||
std::string theFamily( reinterpret_cast<char *>( family ) );
|
||||
FONTCONFIG_PAT patHolder{ font };
|
||||
std::string theFamily =
|
||||
getFamilyStringByLang( patHolder, FROM_UTF8( aDesiredLang.c_str() ) );
|
||||
|
||||
#ifdef __WXMAC__
|
||||
// On Mac (at least) some of the font names are in their own language. If
|
||||
@@ -238,10 +351,10 @@ void FONTCONFIG::ListFonts( std::vector<std::string>& aFonts )
|
||||
if( theFamily.length() > 0 && theFamily.front() == '.' )
|
||||
continue;
|
||||
|
||||
std::map<std::string, FONTINFO>::iterator it = m_fonts.find( theFamily );
|
||||
std::map<std::string, FONTINFO>::iterator it = m_fontInfoCache.find( theFamily );
|
||||
|
||||
if( it == m_fonts.end() )
|
||||
m_fonts.emplace( theFamily, fontInfo );
|
||||
if( it == m_fontInfoCache.end() )
|
||||
m_fontInfoCache.emplace( theFamily, fontInfo );
|
||||
else
|
||||
it->second.Children().push_back( fontInfo );
|
||||
}
|
||||
@@ -249,8 +362,10 @@ void FONTCONFIG::ListFonts( std::vector<std::string>& aFonts )
|
||||
|
||||
if( fs )
|
||||
FcFontSetDestroy( fs );
|
||||
|
||||
m_fontCacheLastLang = aDesiredLang;
|
||||
}
|
||||
|
||||
for( const std::pair<const std::string, FONTINFO>& entry : m_fonts )
|
||||
for( const std::pair<const std::string, FONTINFO>& entry : m_fontInfoCache )
|
||||
aFonts.push_back( entry.second.Family() );
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* This program source code file is part of KICAD, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2021 Ola Rinta-Koski <gitlab@rinta-koski.net>
|
||||
* Copyright (C) 2021-2022 Kicad Developers, see AUTHORS.txt for contributors.
|
||||
* Copyright (C) 2021-2023 Kicad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* Outline font class
|
||||
*
|
||||
@@ -44,6 +44,7 @@ using namespace KIFONT;
|
||||
|
||||
|
||||
FT_Library OUTLINE_FONT::m_freeType = nullptr;
|
||||
std::mutex OUTLINE_FONT::m_freeTypeMutex;
|
||||
|
||||
OUTLINE_FONT::OUTLINE_FONT() :
|
||||
m_face(NULL),
|
||||
@@ -51,6 +52,8 @@ OUTLINE_FONT::OUTLINE_FONT() :
|
||||
m_fakeBold( false ),
|
||||
m_fakeItal( false )
|
||||
{
|
||||
std::lock_guard<std::mutex> guard( m_freeTypeMutex );
|
||||
|
||||
if( !m_freeType )
|
||||
FT_Init_FreeType( &m_freeType );
|
||||
}
|
||||
@@ -58,6 +61,8 @@ OUTLINE_FONT::OUTLINE_FONT() :
|
||||
|
||||
wxString OUTLINE_FONT::FreeTypeVersion()
|
||||
{
|
||||
std::lock_guard<std::mutex> guard( m_freeTypeMutex );
|
||||
|
||||
if( !m_freeType )
|
||||
FT_Init_FreeType( &m_freeType );
|
||||
|
||||
@@ -90,12 +95,16 @@ wxString OUTLINE_FONT::FontLibraryVersion()
|
||||
|
||||
OUTLINE_FONT* OUTLINE_FONT::LoadFont( const wxString& aFontName, bool aBold, bool aItalic )
|
||||
{
|
||||
OUTLINE_FONT* font = new OUTLINE_FONT();
|
||||
std::unique_ptr<OUTLINE_FONT> font = std::make_unique<OUTLINE_FONT>();
|
||||
|
||||
wxString fontFile;
|
||||
int faceIndex;
|
||||
using fc = fontconfig::FONTCONFIG;
|
||||
|
||||
fc::FF_RESULT retval = Fontconfig()->FindFont( aFontName, fontFile, aBold, aItalic );
|
||||
fc::FF_RESULT retval = Fontconfig()->FindFont( aFontName, fontFile, faceIndex, aBold, aItalic );
|
||||
|
||||
if( retval == fc::FF_RESULT::FF_ERROR )
|
||||
return nullptr;
|
||||
|
||||
if( retval == fc::FF_RESULT::FF_MISSING_BOLD || retval == fc::FF_RESULT::FF_MISSING_BOLD_ITAL )
|
||||
font->SetFakeBold();
|
||||
@@ -103,21 +112,23 @@ OUTLINE_FONT* OUTLINE_FONT::LoadFont( const wxString& aFontName, bool aBold, boo
|
||||
if( retval == fc::FF_RESULT::FF_MISSING_ITAL || retval == fc::FF_RESULT::FF_MISSING_BOLD_ITAL )
|
||||
font->SetFakeItal();
|
||||
|
||||
if( retval != fc::FF_RESULT::FF_ERROR )
|
||||
(void) font->loadFace( fontFile );
|
||||
if( font->loadFace( fontFile, faceIndex ) != 0 )
|
||||
return nullptr;
|
||||
|
||||
font->m_fontName = aFontName; // Keep asked-for name, even if we substituted.
|
||||
font->m_fontFileName = fontFile;
|
||||
|
||||
return font;
|
||||
return font.release();
|
||||
}
|
||||
|
||||
|
||||
FT_Error OUTLINE_FONT::loadFace( const wxString& aFontFileName )
|
||||
FT_Error OUTLINE_FONT::loadFace( const wxString& aFontFileName, int aFaceIndex )
|
||||
{
|
||||
std::lock_guard<std::mutex> guard( m_freeTypeMutex );
|
||||
|
||||
// TODO: check that going from wxString to char* with UTF-8
|
||||
// conversion for filename makes sense on any/all platforms
|
||||
FT_Error e = FT_New_Face( m_freeType, aFontFileName.mb_str( wxConvUTF8 ), 0, &m_face );
|
||||
FT_Error e = FT_New_Face( m_freeType, aFontFileName.mb_str( wxConvUTF8 ), aFaceIndex, &m_face );
|
||||
|
||||
if( !e )
|
||||
{
|
||||
@@ -302,27 +313,24 @@ VECTOR2I OUTLINE_FONT::GetTextAsGlyphs( BOX2I* aBBox, std::vector<std::unique_pt
|
||||
}
|
||||
|
||||
|
||||
double OUTLINE_FONT::getOverbarOffset( int ascender, int height, int thickness ) const
|
||||
{
|
||||
double thicknessRatio = abs( (double) thickness ) / (double) height;
|
||||
double ascenderRatio = (double) ascender / (double) height;
|
||||
|
||||
if( thicknessRatio < 0.05 )
|
||||
return 0.04;
|
||||
else if( ascenderRatio < 0.78 )
|
||||
return 0.00;
|
||||
else if( ascenderRatio < 0.80 )
|
||||
return -0.03;
|
||||
else
|
||||
return -0.06;
|
||||
}
|
||||
|
||||
|
||||
VECTOR2I OUTLINE_FONT::getTextAsGlyphs( BOX2I* aBBox, std::vector<std::unique_ptr<GLYPH>>* aGlyphs,
|
||||
const wxString& aText, const VECTOR2I& aSize,
|
||||
const VECTOR2I& aPosition, const EDA_ANGLE& aAngle,
|
||||
bool aMirror, const VECTOR2I& aOrigin,
|
||||
TEXT_STYLE_FLAGS aTextStyle ) const
|
||||
{
|
||||
std::lock_guard<std::mutex> guard( m_freeTypeMutex );
|
||||
|
||||
return getTextAsGlyphsUnlocked( aBBox, aGlyphs, aText, aSize, aPosition, aAngle, aMirror,
|
||||
aOrigin, aTextStyle );
|
||||
}
|
||||
|
||||
VECTOR2I OUTLINE_FONT::getTextAsGlyphsUnlocked( BOX2I* aBBox,
|
||||
std::vector<std::unique_ptr<GLYPH>>* aGlyphs,
|
||||
const wxString& aText, const VECTOR2I& aSize,
|
||||
const VECTOR2I& aPosition, const EDA_ANGLE& aAngle,
|
||||
bool aMirror, const VECTOR2I& aOrigin,
|
||||
TEXT_STYLE_FLAGS aTextStyle ) const
|
||||
{
|
||||
VECTOR2D glyphSize = aSize;
|
||||
FT_Face face = m_face;
|
||||
@@ -366,7 +374,7 @@ VECTOR2I OUTLINE_FONT::getTextAsGlyphs( BOX2I* aBBox, std::vector<std::unique_pt
|
||||
{
|
||||
FT_Matrix matrix;
|
||||
// Create a 12 degree slant
|
||||
const float angle = ( -M_PI * 12 ) / 180.0f;
|
||||
const float angle = (float)( -M_PI * 12.0f ) / 180.0f;
|
||||
matrix.xx = (FT_Fixed) ( cos( angle ) * 0x10000L );
|
||||
matrix.xy = (FT_Fixed) ( -sin( angle ) * 0x10000L );
|
||||
matrix.yx = (FT_Fixed) ( 0 * 0x10000L ); // Don't rotate in the y direction
|
||||
@@ -455,75 +463,9 @@ VECTOR2I OUTLINE_FONT::getTextAsGlyphs( BOX2I* aBBox, std::vector<std::unique_pt
|
||||
}
|
||||
|
||||
int ascender = abs( face->size->metrics.ascender * GLYPH_SIZE_SCALER );
|
||||
int height = abs( face->size->metrics.height * GLYPH_SIZE_SCALER );
|
||||
int descender = abs( face->size->metrics.descender * GLYPH_SIZE_SCALER );
|
||||
VECTOR2I extents( cursor.x * scaleFactor.x, ( ascender + descender ) * abs( scaleFactor.y ) );
|
||||
|
||||
// Font metrics don't include all descenders and diacriticals, so beef them up just a little.
|
||||
extents.y *= 1.05;
|
||||
|
||||
if( IsOverbar( aTextStyle ) )
|
||||
{
|
||||
std::vector<std::unique_ptr<GLYPH>> underscoreGlyphs;
|
||||
|
||||
getTextAsGlyphs( nullptr, &underscoreGlyphs, wxT( "_" ), aSize, { 0, 0 }, ANGLE_0, false,
|
||||
{ 0, 0 }, aTextStyle & ~TEXT_STYLE::OVERBAR );
|
||||
|
||||
OUTLINE_GLYPH* underscoreGlyph = static_cast<OUTLINE_GLYPH*>( underscoreGlyphs[0].get() );
|
||||
BOX2I underscoreBBox;
|
||||
|
||||
for( const VECTOR2I& pt : underscoreGlyph->Outline( 0 ).CPoints() )
|
||||
underscoreBBox.Merge( pt );
|
||||
|
||||
int barThickness = underscoreBBox.GetHeight();
|
||||
|
||||
// Shorten the bar a little so its rounded ends don't make it over-long
|
||||
double barTrim = barThickness / 2.0;
|
||||
double barOffset = getOverbarOffset( ascender, height, barThickness / scaleFactor.y );
|
||||
|
||||
VECTOR2I topLeft( aPosition );
|
||||
VECTOR2I topRight( aPosition );
|
||||
|
||||
topLeft.y += ascender * scaleFactor.y * ( 1.0 + barOffset );
|
||||
topRight.y = topLeft.y;
|
||||
|
||||
topLeft.x += barTrim;
|
||||
topRight.x += extents.x - barTrim;
|
||||
|
||||
extents.y *= ( 1.0 + barOffset + barOffset );
|
||||
extents.x += barTrim;
|
||||
|
||||
if( IsItalic() )
|
||||
{
|
||||
topLeft.x += aSize.y * ITALIC_TILT;
|
||||
topRight.x += aSize.y * ITALIC_TILT;
|
||||
extents.x += aSize.y * ITALIC_TILT;
|
||||
}
|
||||
|
||||
if( aMirror )
|
||||
{
|
||||
topLeft.x = aOrigin.x - ( topLeft.x - aOrigin.x );
|
||||
topRight.x = aOrigin.x - ( topRight.x - aOrigin.x );
|
||||
}
|
||||
|
||||
if( !aAngle.IsZero() )
|
||||
{
|
||||
RotatePoint( topLeft, aOrigin, aAngle );
|
||||
RotatePoint( topRight, aOrigin, aAngle );
|
||||
}
|
||||
|
||||
if( aGlyphs )
|
||||
{
|
||||
int maxError = KiROUND( barThickness / 48 );
|
||||
SHAPE_POLY_SET poly;
|
||||
|
||||
TransformOvalToPolygon( poly, topLeft, topRight, barThickness, maxError, ERROR_INSIDE );
|
||||
|
||||
std::unique_ptr<OUTLINE_GLYPH> overbarGlyph = std::make_unique<OUTLINE_GLYPH>( poly );
|
||||
aGlyphs->push_back( std::move( overbarGlyph ) );
|
||||
}
|
||||
}
|
||||
|
||||
hb_buffer_destroy( buf );
|
||||
hb_font_destroy( referencedFont );
|
||||
|
||||
@@ -552,6 +494,9 @@ void OUTLINE_FONT::RenderToOpenGLCanvas( KIGFX::OPENGL_GAL& aGal, const wxString
|
||||
unsigned int glyphCount;
|
||||
hb_glyph_info_t* glyphInfo = hb_buffer_get_glyph_infos( buf, &glyphCount );
|
||||
hb_glyph_position_t* glyphPos = hb_buffer_get_glyph_positions( buf, &glyphCount );
|
||||
|
||||
std::lock_guard<std::mutex> guard( m_freeTypeMutex );
|
||||
|
||||
hb_font_t* referencedFont = hb_ft_font_create_referenced( m_face );
|
||||
|
||||
hb_ft_font_set_funcs( referencedFont );
|
||||
|
||||
+25
-71
@@ -4,7 +4,7 @@
|
||||
* Copyright (C) 2012 Torsten Hueter, torstenhtr <at> gmx.de
|
||||
* Copyright (C) 2013 CERN
|
||||
* @author Maciej Suminski <maciej.suminski@cern.ch>
|
||||
* Copyright (C) 2016-2022 Kicad Developers, see AUTHORS.txt for contributors.
|
||||
* Copyright (C) 2016-2023 Kicad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* Stroke font class
|
||||
*
|
||||
@@ -44,7 +44,7 @@ using namespace KIFONT;
|
||||
|
||||
|
||||
///< Factor that determines relative vertical position of the overbar.
|
||||
static constexpr double OVERBAR_POSITION_FACTOR = 1.40;
|
||||
static constexpr double OVERBAR_POSITION_FACTOR = 1.23;
|
||||
|
||||
///< Factor that determines relative vertical position of the underline.
|
||||
static constexpr double UNDERLINE_POSITION_FACTOR = -0.16;
|
||||
@@ -52,7 +52,8 @@ static constexpr double UNDERLINE_POSITION_FACTOR = -0.16;
|
||||
///< Scale factor for a glyph
|
||||
static constexpr double STROKE_FONT_SCALE = 1.0 / 21.0;
|
||||
|
||||
static constexpr int FONT_OFFSET = -10;
|
||||
///< Offset (in stroke font units) to move the origin to the baseline.
|
||||
static constexpr int FONT_OFFSET = -8;
|
||||
|
||||
|
||||
bool g_defaultFontInitialized = false;
|
||||
@@ -127,7 +128,6 @@ void STROKE_FONT::loadNewStrokeFont( const char* const aNewStrokeFont[], int aNe
|
||||
|
||||
while( aNewStrokeFont[j][i] )
|
||||
{
|
||||
|
||||
if( aNewStrokeFont[j][i] == ' ' && aNewStrokeFont[j][i+1] == 'R' )
|
||||
strokes++;
|
||||
|
||||
@@ -225,18 +225,17 @@ VECTOR2I STROKE_FONT::GetTextAsGlyphs( BOX2I* aBBox, std::vector<std::unique_ptr
|
||||
bool aMirror, const VECTOR2I& aOrigin,
|
||||
TEXT_STYLE_FLAGS aTextStyle ) const
|
||||
{
|
||||
constexpr double SPACE_WIDTH = 0.6;
|
||||
constexpr int TAB_WIDTH = 4;
|
||||
constexpr double INTER_CHAR = 0.2;
|
||||
constexpr double TAB_WIDTH = 4 * 0.82; // Not quite as wide as 5.1/6.0 tab formatting, but
|
||||
// a better match for Scintilla, and closer to the
|
||||
// nominal SPACE_WIDTH + INTER_CHAR
|
||||
constexpr double SUPER_SUB_SIZE_MULTIPLIER = 0.7;
|
||||
constexpr double SUPER_HEIGHT_OFFSET = 0.5;
|
||||
constexpr double SUB_HEIGHT_OFFSET = 0.3;
|
||||
constexpr double SUPER_SUB_SIZE_MULTIPLIER = 0.8;
|
||||
constexpr double SUPER_HEIGHT_OFFSET = 0.35;
|
||||
constexpr double SUB_HEIGHT_OFFSET = 0.15;
|
||||
|
||||
VECTOR2I cursor( aPosition );
|
||||
VECTOR2D glyphSize( aSize );
|
||||
double tilt = ( aTextStyle & TEXT_STYLE::ITALIC ) ? ITALIC_TILT : 0.0;
|
||||
double space_width = m_glyphBoundingBoxes->front().GetWidth(); // First char is space
|
||||
int char_count = 0;
|
||||
|
||||
if( aTextStyle & TEXT_STYLE::SUBSCRIPT || aTextStyle & TEXT_STYLE::SUPERSCRIPT )
|
||||
{
|
||||
@@ -250,18 +249,26 @@ VECTOR2I STROKE_FONT::GetTextAsGlyphs( BOX2I* aBBox, std::vector<std::unique_ptr
|
||||
|
||||
for( wxUniChar c : aText )
|
||||
{
|
||||
// Handle tabs as locked to the nearest 4th column (in space-widths).
|
||||
// Handle tabs as locked to the next 4th column (in base-widths).
|
||||
if( c == '\t' )
|
||||
{
|
||||
int tabWidth = KiROUND( glyphSize.x * TAB_WIDTH );
|
||||
int currentIntrusion = ( cursor.x - aOrigin.x ) % tabWidth;
|
||||
char_count = ( char_count / TAB_WIDTH + 1 ) * TAB_WIDTH - 1;
|
||||
|
||||
cursor.x += tabWidth - currentIntrusion;
|
||||
int new_cursor = aPosition.x + aSize.x * char_count
|
||||
+ aSize.x * space_width;
|
||||
|
||||
while( new_cursor <= cursor.x )
|
||||
{
|
||||
char_count += TAB_WIDTH;
|
||||
new_cursor += aSize.x * TAB_WIDTH;
|
||||
}
|
||||
|
||||
cursor.x = new_cursor;
|
||||
}
|
||||
else if( c == ' ' )
|
||||
{
|
||||
// 'space' character - draw nothing, advance cursor position
|
||||
cursor.x += KiROUND( glyphSize.x * SPACE_WIDTH );
|
||||
cursor.x += KiROUND( glyphSize.x * space_width );
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -287,69 +294,16 @@ VECTOR2I STROKE_FONT::GetTextAsGlyphs( BOX2I* aBBox, std::vector<std::unique_ptr
|
||||
|
||||
glyphExtents *= glyphSize;
|
||||
|
||||
if( tilt > 0.0 )
|
||||
glyphExtents.x -= glyphExtents.y * tilt;
|
||||
|
||||
cursor.x += KiROUND( glyphExtents.x );
|
||||
}
|
||||
}
|
||||
|
||||
VECTOR2D barOffset( 0.0, 0.0 );
|
||||
|
||||
// Shorten the bar a little so its rounded ends don't make it over-long
|
||||
double barTrim = glyphSize.x * 0.1;
|
||||
|
||||
if( aTextStyle & TEXT_STYLE::OVERBAR )
|
||||
{
|
||||
barOffset.y = ComputeOverbarVerticalPosition( glyphSize.y );
|
||||
|
||||
if( aTextStyle & TEXT_STYLE::ITALIC )
|
||||
barOffset.x = barOffset.y * ITALIC_TILT;
|
||||
|
||||
VECTOR2D barStart( aPosition.x + barOffset.x + barTrim, cursor.y - barOffset.y );
|
||||
VECTOR2D barEnd( cursor.x + barOffset.x - barTrim, cursor.y - barOffset.y );
|
||||
|
||||
if( aGlyphs )
|
||||
{
|
||||
STROKE_GLYPH overbarGlyph;
|
||||
|
||||
overbarGlyph.AddPoint( barStart );
|
||||
overbarGlyph.AddPoint( barEnd );
|
||||
overbarGlyph.Finalize();
|
||||
|
||||
aGlyphs->push_back( overbarGlyph.Transform( { 1.0, 1.0 }, { 0, 0 }, false,
|
||||
aAngle, aMirror, aOrigin ) );
|
||||
}
|
||||
}
|
||||
|
||||
if( aTextStyle & TEXT_STYLE::UNDERLINE )
|
||||
{
|
||||
barOffset.y = ComputeUnderlineVerticalPosition( glyphSize.y );
|
||||
|
||||
if( aTextStyle & TEXT_STYLE::ITALIC )
|
||||
barOffset.x = barOffset.y * ITALIC_TILT;
|
||||
|
||||
VECTOR2D barStart( aPosition.x + barOffset.x + barTrim, cursor.y - barOffset.y );
|
||||
VECTOR2D barEnd( cursor.x + barOffset.x - barTrim, cursor.y - barOffset.y );
|
||||
|
||||
if( aGlyphs )
|
||||
{
|
||||
STROKE_GLYPH underlineGlyph;
|
||||
|
||||
underlineGlyph.AddPoint( barStart );
|
||||
underlineGlyph.AddPoint( barEnd );
|
||||
underlineGlyph.Finalize();
|
||||
|
||||
aGlyphs->push_back( underlineGlyph.Transform( { 1.0, 1.0 }, { 0, 0 }, false,
|
||||
aAngle, aMirror, aOrigin ) );
|
||||
}
|
||||
++char_count;
|
||||
}
|
||||
|
||||
if( aBBox )
|
||||
{
|
||||
aBBox->SetOrigin( aPosition );
|
||||
aBBox->SetEnd( cursor.x + barOffset.x - KiROUND( glyphSize.x * INTER_CHAR ),
|
||||
cursor.y + std::max( glyphSize.y, barOffset.y * OVERBAR_POSITION_FACTOR ) );
|
||||
aBBox->SetEnd( cursor.x - KiROUND( glyphSize.x * INTER_CHAR ), cursor.y + glyphSize.y );
|
||||
aBBox->Normalize();
|
||||
}
|
||||
|
||||
|
||||
@@ -86,12 +86,11 @@ void FOOTPRINT_FILTER_IT::increment()
|
||||
candidate.GetLibNickname(),
|
||||
candidate.GetFootprintName(),
|
||||
candidate.GetSearchText() );
|
||||
int matches, position;
|
||||
bool exclude = false;
|
||||
bool exclude = false;
|
||||
|
||||
for( std::unique_ptr<EDA_COMBINED_MATCHER>& matcher : m_filter->m_pattern_filters )
|
||||
{
|
||||
if( !matcher->Find( searchStr.Lower(), matches, position ) )
|
||||
if( !matcher->Find( searchStr.Lower() ) )
|
||||
{
|
||||
exclude = true;
|
||||
break;
|
||||
|
||||
@@ -596,6 +596,7 @@ bool FP_LIB_TABLE::LoadGlobalTable( FP_LIB_TABLE& aTable )
|
||||
}
|
||||
}
|
||||
|
||||
aTable.Clear();
|
||||
aTable.Load( fn.GetFullPath() );
|
||||
|
||||
SETTINGS_MANAGER& mgr = Pgm().GetSettingsManager();
|
||||
|
||||
@@ -180,7 +180,7 @@ bool COLOR4D::SetFromHexString( const wxString& aColorString )
|
||||
str.Trim( true );
|
||||
str.Trim( false );
|
||||
|
||||
if( str.length() < 7 || str.GetChar( 0 ) != '#' )
|
||||
if( str.length() < 7 || !str.StartsWith( '#' ) )
|
||||
return false;
|
||||
|
||||
unsigned long tmp;
|
||||
|
||||
+47
-13
@@ -57,11 +57,6 @@ static std::optional<double> getKiCadConfiguredScale( const COMMON_SETTINGS& aCo
|
||||
scale = canvas_scale;
|
||||
}
|
||||
|
||||
if( scale )
|
||||
{
|
||||
wxLogTrace( traceHiDpi, wxS( "Scale factor (configured): %f" ), *scale );
|
||||
}
|
||||
|
||||
return scale;
|
||||
}
|
||||
|
||||
@@ -83,11 +78,6 @@ static std::optional<double> getEnvironmentScale()
|
||||
scale = ENV_VAR::GetEnvVar<double>( wxS( "GDK_SCALE" ) );
|
||||
}
|
||||
|
||||
if( scale )
|
||||
{
|
||||
wxLogTrace( traceHiDpi, wxS( "Scale factor (environment): %f" ), *scale );
|
||||
}
|
||||
|
||||
return scale;
|
||||
}
|
||||
|
||||
@@ -101,15 +91,18 @@ DPI_SCALING::DPI_SCALING( COMMON_SETTINGS* aConfig, const wxWindow* aWindow )
|
||||
double DPI_SCALING::GetScaleFactor() const
|
||||
{
|
||||
std::optional<double> val;
|
||||
wxString src;
|
||||
|
||||
if( m_config )
|
||||
{
|
||||
val = getKiCadConfiguredScale( *m_config );
|
||||
src = wxS( "config" );
|
||||
}
|
||||
|
||||
if( !val )
|
||||
{
|
||||
val = getEnvironmentScale();
|
||||
src = wxS( "env" );
|
||||
}
|
||||
|
||||
if( !val && m_window )
|
||||
@@ -117,17 +110,58 @@ double DPI_SCALING::GetScaleFactor() const
|
||||
// Use the native WX reporting.
|
||||
// On Linux, this will not work until WX 3.2 and GTK >= 3.10
|
||||
// Otherwise it returns 1.0
|
||||
val = KIPLATFORM::UI::GetSystemScaleFactor( m_window );
|
||||
wxLogTrace( traceHiDpi, wxS( "Scale factor (WX): %f" ), *val );
|
||||
val = KIPLATFORM::UI::GetPixelScaleFactor( m_window );
|
||||
src = wxS( "platform" );
|
||||
}
|
||||
|
||||
if( !val )
|
||||
{
|
||||
// Nothing else we can do, give it a default value
|
||||
val = GetDefaultScaleFactor();
|
||||
wxLogTrace( traceHiDpi, wxS( "Scale factor (default): %f" ), *val );
|
||||
src = wxS( "default" );
|
||||
}
|
||||
|
||||
wxLogTrace( traceHiDpi, wxS( "Scale factor (%s): %f" ), src, *val );
|
||||
|
||||
return *val;
|
||||
}
|
||||
|
||||
|
||||
double DPI_SCALING::GetContentScaleFactor() const
|
||||
{
|
||||
std::optional<double> val;
|
||||
wxString src;
|
||||
|
||||
if( m_config )
|
||||
{
|
||||
val = getKiCadConfiguredScale( *m_config );
|
||||
src = wxS( "config" );
|
||||
}
|
||||
|
||||
if( !val )
|
||||
{
|
||||
val = getEnvironmentScale();
|
||||
src = wxS( "env" );
|
||||
}
|
||||
|
||||
if( !val && m_window )
|
||||
{
|
||||
// Use the native WX reporting.
|
||||
// On Linux, this will not work until WX 3.2 and GTK >= 3.10
|
||||
// Otherwise it returns 1.0
|
||||
val = KIPLATFORM::UI::GetContentScaleFactor( m_window );
|
||||
src = wxS( "platform" );
|
||||
}
|
||||
|
||||
if( !val )
|
||||
{
|
||||
// Nothing else we can do, give it a default value
|
||||
val = GetDefaultScaleFactor();
|
||||
src = wxS( "default" );
|
||||
}
|
||||
|
||||
wxLogTrace( traceHiDpi, wxS( "Content scale factor (%s): %f" ), src, *val );
|
||||
|
||||
return *val;
|
||||
}
|
||||
|
||||
|
||||
@@ -169,14 +169,6 @@ GLuint GL_BITMAP_CACHE::cacheBitmap( const BITMAP_BASE* aBitmap )
|
||||
bmp.w = imgData.GetSize().x;
|
||||
bmp.h = imgData.GetSize().y;
|
||||
|
||||
// The bitmap size needs to be a multiple of 4.
|
||||
// This is easiest to achieve by ensuring that each row
|
||||
// has a multiple of 4 pixels
|
||||
int extra_w = bmp.w % 4;
|
||||
|
||||
if( extra_w )
|
||||
extra_w = 4 - extra_w;
|
||||
|
||||
GLuint textureID;
|
||||
|
||||
if( m_freedTextureIds.empty() )
|
||||
@@ -189,15 +181,14 @@ GLuint GL_BITMAP_CACHE::cacheBitmap( const BITMAP_BASE* aBitmap )
|
||||
m_freedTextureIds.pop_front();
|
||||
}
|
||||
|
||||
// make_unique initializes this to 0, so extra pixels are transparent
|
||||
bmp.size = ( bmp.w + extra_w ) * bmp.h * 4;
|
||||
bmp.size = bmp.w * bmp.h * 4;
|
||||
auto buf = std::make_unique<uint8_t[]>( bmp.size );
|
||||
|
||||
for( int y = 0; y < bmp.h; y++ )
|
||||
{
|
||||
for( int x = 0; x < bmp.w; x++ )
|
||||
{
|
||||
uint8_t* p = buf.get() + ( ( bmp.w + extra_w ) * y + x ) * 4;
|
||||
uint8_t* p = buf.get() + ( bmp.w * y + x ) * 4;
|
||||
|
||||
p[0] = imgData.GetRed( x, y );
|
||||
p[1] = imgData.GetGreen( x, y );
|
||||
@@ -214,7 +205,7 @@ GLuint GL_BITMAP_CACHE::cacheBitmap( const BITMAP_BASE* aBitmap )
|
||||
}
|
||||
|
||||
glBindTexture( GL_TEXTURE_2D, textureID );
|
||||
glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA8, bmp.w + extra_w, bmp.h, 0, GL_RGBA, GL_UNSIGNED_BYTE,
|
||||
glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA8, bmp.w, bmp.h, 0, GL_RGBA, GL_UNSIGNED_BYTE,
|
||||
buf.get() );
|
||||
|
||||
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
|
||||
@@ -1427,21 +1418,23 @@ void OPENGL_GAL::DrawBitmap( const BITMAP_BASE& aBitmap, double alphaBlend )
|
||||
glActiveTexture( GL_TEXTURE0 );
|
||||
glBindTexture( GL_TEXTURE_2D, texture_id );
|
||||
|
||||
float texStartX = aBitmap.IsMirrored() ? 1.0 : 0.0;
|
||||
float texEndX = aBitmap.IsMirrored() ? 0.0 : 1.0;
|
||||
float texStartX = aBitmap.IsMirroredX() ? 1.0 : 0.0;
|
||||
float texEndX = aBitmap.IsMirroredX() ? 0.0 : 1.0;
|
||||
float texStartY = aBitmap.IsMirroredY() ? 1.0 : 0.0;
|
||||
float texEndY = aBitmap.IsMirroredY() ? 0.0 : 1.0;
|
||||
|
||||
glBegin( GL_QUADS );
|
||||
glColor4f( 1.0, 1.0, 1.0, alpha );
|
||||
glTexCoord2f( texStartX, 0.0 );
|
||||
glTexCoord2f( texStartX, texStartY );
|
||||
glVertex3f( v0.x, v0.y, m_layerDepth );
|
||||
glColor4f( 1.0, 1.0, 1.0, alpha );
|
||||
glTexCoord2f( texEndX, 0.0 );
|
||||
glTexCoord2f( texEndX, texStartY);
|
||||
glVertex3f( v1.x, v0.y, m_layerDepth );
|
||||
glColor4f( 1.0, 1.0, 1.0, alpha );
|
||||
glTexCoord2f( texEndX, 1.0 );
|
||||
glTexCoord2f( texEndX, texEndY);
|
||||
glVertex3f( v1.x, v1.y, m_layerDepth );
|
||||
glColor4f( 1.0, 1.0, 1.0, alpha );
|
||||
glTexCoord2f( texStartX, 1.0 );
|
||||
glTexCoord2f( texStartX, texEndY);
|
||||
glVertex3f( v0.x, v1.y, m_layerDepth );
|
||||
glEnd();
|
||||
|
||||
|
||||
@@ -91,6 +91,11 @@ void GRSetColorPen( wxDC* DC, const COLOR4D& Color, int width, wxPenStyle style
|
||||
if( s_ForceBlackPen )
|
||||
color = COLOR4D::BLACK;
|
||||
|
||||
// wxWidgets will enforce a minimum pen width when printing, so we have to make the pen
|
||||
// transparent when we don't want the object stroked.
|
||||
if( width == 0 )
|
||||
color = COLOR4D::UNSPECIFIED;
|
||||
|
||||
const wxPen& curr_pen = DC->GetPen();
|
||||
|
||||
if( !curr_pen.IsOk() || curr_pen.GetColour() != color.ToColour()
|
||||
|
||||
+18
-2
@@ -418,12 +418,20 @@ void GRID_TRICKS::onCharHook( wxKeyEvent& ev )
|
||||
{
|
||||
bool handled = false;
|
||||
|
||||
if( ev.GetKeyCode() == WXK_RETURN && m_grid->GetGridCursorRow() == m_grid->GetNumberRows() - 1 )
|
||||
if( ( ev.GetKeyCode() == WXK_RETURN || ev.GetKeyCode() == WXK_NUMPAD_ENTER )
|
||||
&& ev.GetModifiers() == wxMOD_NONE
|
||||
&& m_grid->GetGridCursorRow() == m_grid->GetNumberRows() - 1 )
|
||||
{
|
||||
if( m_grid->CommitPendingChanges() )
|
||||
if( m_grid->IsCellEditControlShown() )
|
||||
{
|
||||
if( m_grid->CommitPendingChanges() )
|
||||
handled = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
wxCommandEvent dummy;
|
||||
m_addHandler( dummy );
|
||||
handled = true;
|
||||
}
|
||||
}
|
||||
else if( ev.GetModifiers() == wxMOD_CONTROL && ev.GetKeyCode() == 'V' )
|
||||
@@ -448,6 +456,14 @@ void GRID_TRICKS::onCharHook( wxKeyEvent& ev )
|
||||
m_grid->ForceRefresh();
|
||||
}
|
||||
}
|
||||
else if( ev.GetKeyCode() == WXK_ESCAPE )
|
||||
{
|
||||
if( m_grid->IsCellEditControlShown() )
|
||||
{
|
||||
m_grid->CancelPendingChanges();
|
||||
handled = true;
|
||||
}
|
||||
}
|
||||
|
||||
if( !handled )
|
||||
ev.Skip( true );
|
||||
|
||||
@@ -27,109 +27,21 @@
|
||||
// conflicts for some defines, at least on Windows
|
||||
#include <kicad_curl/kicad_curl.h>
|
||||
|
||||
#include <mutex>
|
||||
#include <ki_exception.h> // THROW_IO_ERROR
|
||||
|
||||
|
||||
|
||||
// These are even more private than class members, and since there is only
|
||||
// one instance of KICAD_CURL ever, these statics are hidden here to simplify the
|
||||
// client (API) header file.
|
||||
static volatile bool s_initialized;
|
||||
|
||||
static std::mutex s_lock; // for s_initialized
|
||||
|
||||
/// At process termination, using atexit() keeps the CURL stuff out of the
|
||||
/// singletops and PGM_BASE.
|
||||
static void at_terminate()
|
||||
{
|
||||
KICAD_CURL::Cleanup();
|
||||
}
|
||||
|
||||
|
||||
void KICAD_CURL::Init()
|
||||
{
|
||||
// We test s_initialized twice in an effort to avoid
|
||||
// unnecessarily locking s_lock. This understands that the common case
|
||||
// will not need to lock.
|
||||
if( !s_initialized )
|
||||
if( curl_global_init( CURL_GLOBAL_ALL ) != CURLE_OK )
|
||||
{
|
||||
std::lock_guard<std::mutex> lock( s_lock );
|
||||
|
||||
if( !s_initialized )
|
||||
{
|
||||
if( curl_global_init( CURL_GLOBAL_ALL ) != CURLE_OK )
|
||||
{
|
||||
THROW_IO_ERROR( "curl_global_init() failed." );
|
||||
}
|
||||
|
||||
s_initialized = true;
|
||||
}
|
||||
THROW_IO_ERROR( "curl_global_init() failed." );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void KICAD_CURL::Cleanup()
|
||||
{
|
||||
/*
|
||||
|
||||
Calling lock_guard() from a static destructor will typically be bad, since the
|
||||
s_lock may already have been statically destroyed itself leading to a boost
|
||||
exception. (Remember C++ does not provide certain sequencing of static
|
||||
destructor invocation.)
|
||||
|
||||
To prevent this we test s_initialized twice, which ensures that the lock_guard
|
||||
is only instantiated on the first call, which should be from
|
||||
PGM_BASE::destroy() which is first called earlier than static destruction.
|
||||
Then when called again from the actual PGM_BASE::~PGM_BASE() function,
|
||||
lock_guard will not be instantiated because s_initialized will be false.
|
||||
|
||||
*/
|
||||
|
||||
if( s_initialized )
|
||||
{
|
||||
std::lock_guard<std::mutex> lock( s_lock );
|
||||
|
||||
if( s_initialized )
|
||||
{
|
||||
curl_global_cleanup();
|
||||
|
||||
atexit( &at_terminate );
|
||||
|
||||
s_initialized = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
std::string KICAD_CURL::GetSimpleVersion()
|
||||
{
|
||||
if( !s_initialized )
|
||||
Init();
|
||||
|
||||
curl_version_info_data* info = curl_version_info( CURLVERSION_NOW );
|
||||
|
||||
std::string res;
|
||||
|
||||
if( info->version )
|
||||
{
|
||||
res += "libcurl version: " + std::string( info->version );
|
||||
}
|
||||
|
||||
res += " (";
|
||||
|
||||
if( info->features & CURL_VERSION_SSL )
|
||||
{
|
||||
res += "with SSL - ";
|
||||
res += std::string( info->ssl_version );
|
||||
}
|
||||
else
|
||||
{
|
||||
res += "without SSL";
|
||||
}
|
||||
res += ")";
|
||||
|
||||
return res;
|
||||
curl_global_cleanup();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2015 Mark Roszko <mark.roszko@gmail.com>
|
||||
* Copyright (C) 2015-2021 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
* Copyright (C) 2015-2023 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
@@ -100,23 +100,18 @@ static int xferinfo( void* aProgress, curl_off_t aDLtotal, curl_off_t aDLnow, cu
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
|
||||
#if LIBCURL_VERSION_NUM < 0x072000 // 7.32.0
|
||||
static int progressinfo( void* aProgress, double aDLtotal, double aDLnow, double aULtotal, double aULnow )
|
||||
{
|
||||
return xferinfo( aProgress, static_cast<curl_off_t>( aDLtotal ), static_cast<curl_off_t>( aDLnow ),
|
||||
static_cast<curl_off_t>( aULtotal ), static_cast<curl_off_t>( aULnow ) );
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
KICAD_CURL_EASY::KICAD_CURL_EASY() :
|
||||
m_headers( nullptr )
|
||||
{
|
||||
// Call KICAD_CURL::Init() from in here every time, but only the first time
|
||||
// will incur any overhead. This strategy ensures that libcurl is never loaded
|
||||
// unless it is needed.
|
||||
|
||||
KICAD_CURL::Init();
|
||||
|
||||
m_CURL = curl_easy_init();
|
||||
|
||||
if( !m_CURL )
|
||||
@@ -126,7 +121,11 @@ KICAD_CURL_EASY::KICAD_CURL_EASY() :
|
||||
curl_easy_setopt( m_CURL, CURLOPT_WRITEDATA, static_cast<void*>( &m_buffer ) );
|
||||
|
||||
// Only allow HTTP and HTTPS protocols
|
||||
#if LIBCURL_VERSION_NUM >= 0x075500 // version 7.85.0
|
||||
curl_easy_setopt(m_CURL, CURLOPT_PROTOCOLS_STR, "http,https");
|
||||
#else
|
||||
curl_easy_setopt( m_CURL, CURLOPT_PROTOCOLS, CURLPROTO_HTTP | CURLPROTO_HTTPS );
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
// We need this to use the Windows Certificate store
|
||||
@@ -264,7 +263,7 @@ bool KICAD_CURL_EASY::SetTransferCallback( const TRANSFER_CALLBACK& aCallback, s
|
||||
{
|
||||
progress = std::make_unique<CURL_PROGRESS>( this, aCallback,
|
||||
static_cast<curl_off_t>( aInterval ) );
|
||||
#ifdef CURLOPT_XFERINFOFUNCTION
|
||||
#if LIBCURL_VERSION_NUM >= 0x072000 // 7.32.0
|
||||
setOption( CURLOPT_XFERINFOFUNCTION, xferinfo );
|
||||
setOption( CURLOPT_XFERINFODATA, progress.get() );
|
||||
#else
|
||||
@@ -286,7 +285,7 @@ bool KICAD_CURL_EASY::SetOutputStream( const std::ostream* aOutput )
|
||||
|
||||
int KICAD_CURL_EASY::GetTransferTotal( uint64_t& aDownloadedBytes ) const
|
||||
{
|
||||
#ifdef CURLINFO_SIZE_DOWNLOAD_T
|
||||
#if LIBCURL_VERSION_NUM >= 0x073700 // 7.55.0
|
||||
curl_off_t dl;
|
||||
int result = curl_easy_getinfo( m_CURL, CURLINFO_SIZE_DOWNLOAD_T, &dl );
|
||||
aDownloadedBytes = static_cast<uint64_t>( dl );
|
||||
|
||||
+6
-4
@@ -431,15 +431,17 @@ KIWAY_PLAYER* KIWAY::Player( FRAME_T aFrameType, bool doCreate, wxTopLevelWindow
|
||||
}
|
||||
catch( const IO_ERROR& ioe )
|
||||
{
|
||||
DisplayErrorMessage( nullptr, _( "Error loading editor." ), ioe.What() );
|
||||
wxLogError( ioe.What() );
|
||||
wxLogError( _( "Error loading editor." ) );
|
||||
}
|
||||
catch( const std::exception& e)
|
||||
catch( const std::exception& e )
|
||||
{
|
||||
DisplayErrorMessage( nullptr, _( "Error loading editor." ), e.what() );
|
||||
wxLogError( e.what() );
|
||||
wxLogError( _( "Error loading editor." ) );
|
||||
}
|
||||
catch( ... )
|
||||
{
|
||||
DisplayErrorMessage( nullptr, _( "Error loading editor." ) );
|
||||
wxLogError( _( "Error loading editor." ) );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -193,6 +193,8 @@ LIB_TABLE_ROW* LIB_TABLE::findRow( const wxString& aNickName, bool aCheckIfEnabl
|
||||
{
|
||||
cur->ensureIndex();
|
||||
|
||||
std::shared_lock<std::shared_mutex> lock( cur->m_nickIndexMutex );
|
||||
|
||||
for( const std::pair<const wxString, int>& entry : cur->m_nickIndex )
|
||||
{
|
||||
if( entry.first == aNickName )
|
||||
@@ -303,7 +305,7 @@ bool LIB_TABLE::InsertRow( LIB_TABLE_ROW* aRow, bool doReplace )
|
||||
{
|
||||
ensureIndex();
|
||||
|
||||
std::lock_guard<std::mutex> lock( m_nickIndexMutex );
|
||||
std::lock_guard<std::shared_mutex> lock( m_nickIndexMutex );
|
||||
|
||||
INDEX_CITER it = m_nickIndex.find( aRow->GetNickName() );
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2017-2022 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
* Copyright (C) 2017-2023 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
@@ -24,12 +24,16 @@ LIB_TABLE_GRID_TRICKS::LIB_TABLE_GRID_TRICKS( WX_GRID* aGrid ) : GRID_TRICKS( aG
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void LIB_TABLE_GRID_TRICKS::showPopupMenu( wxMenu& menu )
|
||||
{
|
||||
bool showActivate = false;
|
||||
bool showDeactivate = false;
|
||||
LIB_TABLE_GRID* tbl = static_cast<LIB_TABLE_GRID*>( m_grid->GetTable() );
|
||||
|
||||
// Ensure selection parameters are up to date
|
||||
getSelectedArea();
|
||||
|
||||
for( int row = m_sel_row_start; row < m_sel_row_start + m_sel_row_count; ++row )
|
||||
{
|
||||
if( tbl->GetValueAsBool( row, 0 ) )
|
||||
@@ -49,10 +53,14 @@ void LIB_TABLE_GRID_TRICKS::showPopupMenu( wxMenu& menu )
|
||||
menu.Append( LIB_TABLE_GRID_TRICKS_ACTIVATE_SELECTED, _( "Activate selected" ) );
|
||||
if( showDeactivate )
|
||||
menu.Append( LIB_TABLE_GRID_TRICKS_DEACTIVATE_SELECTED, _( "Deactivate selected" ) );
|
||||
menu.AppendSeparator();
|
||||
|
||||
if( showActivate || showDeactivate )
|
||||
menu.AppendSeparator();
|
||||
|
||||
GRID_TRICKS::showPopupMenu( menu );
|
||||
}
|
||||
|
||||
|
||||
void LIB_TABLE_GRID_TRICKS::doPopupSelection( wxCommandEvent& event )
|
||||
{
|
||||
int menu_id = event.GetId();
|
||||
@@ -61,10 +69,13 @@ void LIB_TABLE_GRID_TRICKS::doPopupSelection( wxCommandEvent& event )
|
||||
{
|
||||
LIB_TABLE_GRID* tbl = (LIB_TABLE_GRID*) m_grid->GetTable();
|
||||
|
||||
bool selected_state = menu_id == LIB_TABLE_GRID_TRICKS_ACTIVATE_SELECTED;
|
||||
|
||||
for( int row = m_sel_row_start; row < m_sel_row_start + m_sel_row_count; ++row )
|
||||
{
|
||||
tbl->SetValueAsBool( row, 0, menu_id == LIB_TABLE_GRID_TRICKS_ACTIVATE_SELECTED );
|
||||
}
|
||||
tbl->SetValueAsBool( row, 0, selected_state );
|
||||
|
||||
// Ensure the new state (on/off) of the widgets is immediately shown:
|
||||
m_grid->Refresh();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
*lib_tree_model
|
||||
* Copyright (C) 2017 Chris Pavlina <pavlina.chris@gmail.com>
|
||||
* Copyright (C) 2014 Henner Zeller <h.zeller@acm.org>
|
||||
* Copyright (C) 2014-2019 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
* Copyright (C) 2014-2023 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
@@ -24,14 +24,12 @@
|
||||
#include <algorithm>
|
||||
#include <eda_pattern_match.h>
|
||||
#include <lib_tree_item.h>
|
||||
#include <utility>
|
||||
#include <pgm_base.h>
|
||||
#include <string_utils.h>
|
||||
|
||||
// Each node gets this lowest score initially, without any matches applied.
|
||||
// Matches will then increase this score depending on match quality. This way,
|
||||
// an empty search string will result in all components being displayed as they
|
||||
// have the minimum score. However, in that case, we avoid expanding all the
|
||||
// Each node gets this lowest score initially, without any matches applied. Matches will then
|
||||
// increase this score. This way, an empty search string will result in all components being
|
||||
// displayed as they have the minimum score. However, in that case, we avoid expanding all the
|
||||
// nodes asd the result is very unspecific.
|
||||
static const unsigned kLowestDefaultScore = 1;
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
*
|
||||
* Copyright (C) 2017 Chris Pavlina <pavlina.chris@gmail.com>
|
||||
* Copyright (C) 2014 Henner Zeller <h.zeller@acm.org>
|
||||
* Copyright (C) 2014-2022 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
* Copyright (C) 2014-2023 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
@@ -213,17 +213,11 @@ void LIB_TREE_MODEL_ADAPTER::UpdateSearchString( const wxString& aSearch, bool a
|
||||
Thaw();
|
||||
}
|
||||
|
||||
LIB_TREE_NODE* bestMatch = ShowResults();
|
||||
const LIB_TREE_NODE* firstMatch = ShowResults();
|
||||
|
||||
if( !bestMatch )
|
||||
bestMatch = ShowPreselect();
|
||||
|
||||
if( !bestMatch )
|
||||
bestMatch = ShowSingleLibrary();
|
||||
|
||||
if( bestMatch )
|
||||
if( firstMatch )
|
||||
{
|
||||
wxDataViewItem item = wxDataViewItem( bestMatch );
|
||||
wxDataViewItem item = ToItem( firstMatch );
|
||||
m_widget->Select( item );
|
||||
|
||||
// Make sure the *parent* item is visible. The selected item is the
|
||||
@@ -269,7 +263,7 @@ void LIB_TREE_MODEL_ADAPTER::recreateColumns()
|
||||
for( const wxString& colName : m_shownColumns )
|
||||
{
|
||||
if( !m_colNameMap.count( colName ) )
|
||||
doAddColumn( colName, false );
|
||||
doAddColumn( colName, colName == wxT( "Description" ) );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -619,93 +613,85 @@ bool LIB_TREE_MODEL_ADAPTER::GetAttr( const wxDataViewItem& aItem,
|
||||
}
|
||||
|
||||
|
||||
void LIB_TREE_MODEL_ADAPTER::Find( LIB_TREE_NODE& aNode,
|
||||
std::function<bool( const LIB_TREE_NODE* )> aFunc,
|
||||
LIB_TREE_NODE** aHighScore )
|
||||
void recursiveDescent( LIB_TREE_NODE& aNode, const std::function<bool( const LIB_TREE_NODE* )>& f )
|
||||
{
|
||||
for( std::unique_ptr<LIB_TREE_NODE>& node: aNode.m_Children )
|
||||
{
|
||||
if( aFunc( &*node ) )
|
||||
{
|
||||
if( !(*aHighScore) || node->m_Score > (*aHighScore)->m_Score )
|
||||
(*aHighScore) = &*node;
|
||||
}
|
||||
if( !f( node.get() ) )
|
||||
break;
|
||||
|
||||
Find( *node, aFunc, aHighScore );
|
||||
recursiveDescent( *node, f );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
LIB_TREE_NODE* LIB_TREE_MODEL_ADAPTER::ShowResults()
|
||||
const LIB_TREE_NODE* LIB_TREE_MODEL_ADAPTER::ShowResults()
|
||||
{
|
||||
LIB_TREE_NODE* highScore = nullptr;
|
||||
const LIB_TREE_NODE* firstMatch = nullptr;
|
||||
|
||||
Find( m_tree,
|
||||
[]( LIB_TREE_NODE const* n )
|
||||
{
|
||||
// return leaf nodes with some level of matching
|
||||
return n->m_Type == LIB_TREE_NODE::TYPE::LIBID && n->m_Score > 1;
|
||||
},
|
||||
&highScore );
|
||||
|
||||
if( highScore)
|
||||
{
|
||||
wxDataViewItem item = wxDataViewItem( highScore );
|
||||
m_widget->ExpandAncestors( item );
|
||||
}
|
||||
|
||||
return highScore;
|
||||
}
|
||||
|
||||
|
||||
LIB_TREE_NODE* LIB_TREE_MODEL_ADAPTER::ShowPreselect()
|
||||
{
|
||||
LIB_TREE_NODE* highScore = nullptr;
|
||||
|
||||
if( !m_preselect_lib_id.IsValid() )
|
||||
return highScore;
|
||||
|
||||
Find( m_tree,
|
||||
[&]( LIB_TREE_NODE const* n )
|
||||
// Expand parents of leaf nodes with some level of matching
|
||||
recursiveDescent( m_tree,
|
||||
[&]( const LIB_TREE_NODE* n )
|
||||
{
|
||||
if( n->m_Type == LIB_TREE_NODE::LIBID && ( n->m_Children.empty() ||
|
||||
!m_preselect_unit ) )
|
||||
return m_preselect_lib_id == n->m_LibId;
|
||||
else if( n->m_Type == LIB_TREE_NODE::UNIT && m_preselect_unit )
|
||||
return m_preselect_lib_id == n->m_Parent->m_LibId &&
|
||||
m_preselect_unit == n->m_Unit;
|
||||
else
|
||||
return false;
|
||||
},
|
||||
&highScore );
|
||||
if( n->m_Type == LIB_TREE_NODE::TYPE::LIBID && n->m_Score > 1 )
|
||||
{
|
||||
if( !firstMatch )
|
||||
firstMatch = n;
|
||||
else if( n->m_Score > firstMatch->m_Score )
|
||||
firstMatch = n;
|
||||
|
||||
if( highScore)
|
||||
m_widget->ExpandAncestors( ToItem( n ) );
|
||||
}
|
||||
|
||||
return true; // keep going to expand ancestors of all found items
|
||||
} );
|
||||
|
||||
// If no matches, find and show the preselect node
|
||||
if( !firstMatch && m_preselect_lib_id.IsValid() )
|
||||
{
|
||||
wxDataViewItem item = wxDataViewItem( highScore );
|
||||
m_widget->ExpandAncestors( item );
|
||||
recursiveDescent( m_tree,
|
||||
[&]( const LIB_TREE_NODE* n )
|
||||
{
|
||||
if( n->m_Type == LIB_TREE_NODE::LIBID
|
||||
&& ( n->m_Children.empty() || !m_preselect_unit )
|
||||
&& m_preselect_lib_id == n->m_LibId )
|
||||
{
|
||||
firstMatch = n;
|
||||
m_widget->ExpandAncestors( ToItem( n ) );
|
||||
return false;
|
||||
}
|
||||
else if( n->m_Type == LIB_TREE_NODE::UNIT
|
||||
&& ( m_preselect_unit && m_preselect_unit == n->m_Unit )
|
||||
&& m_preselect_lib_id == n->m_Parent->m_LibId )
|
||||
{
|
||||
firstMatch = n;
|
||||
m_widget->ExpandAncestors( ToItem( n ) );
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
} );
|
||||
}
|
||||
|
||||
return highScore;
|
||||
// If still no matches expand a single library if there is only one
|
||||
if( !firstMatch )
|
||||
{
|
||||
recursiveDescent( m_tree,
|
||||
[&]( const LIB_TREE_NODE* n )
|
||||
{
|
||||
if( n->m_Type == LIB_TREE_NODE::TYPE::LIBID
|
||||
&& n->m_Parent->m_Parent->m_Children.size() == 1 )
|
||||
{
|
||||
firstMatch = n;
|
||||
m_widget->ExpandAncestors( ToItem( n ) );
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
} );
|
||||
}
|
||||
|
||||
return firstMatch;
|
||||
}
|
||||
|
||||
|
||||
LIB_TREE_NODE* LIB_TREE_MODEL_ADAPTER::ShowSingleLibrary()
|
||||
{
|
||||
LIB_TREE_NODE* highScore = nullptr;
|
||||
|
||||
Find( m_tree,
|
||||
[]( LIB_TREE_NODE const* n )
|
||||
{
|
||||
return n->m_Type == LIB_TREE_NODE::TYPE::LIBID &&
|
||||
n->m_Parent->m_Parent->m_Children.size() == 1;
|
||||
},
|
||||
&highScore );
|
||||
|
||||
if( highScore)
|
||||
{
|
||||
wxDataViewItem item = wxDataViewItem( highScore );
|
||||
m_widget->ExpandAncestors( item );
|
||||
}
|
||||
|
||||
return highScore;
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* This file is part of libeval, a simple math expression evaluator
|
||||
*
|
||||
* Copyright (C) 2017 Michael Geselbracht, mgeselbracht3@gmail.com
|
||||
* Copyright (C) 2019-2022 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
* Copyright (C) 2019-2023 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -356,10 +356,11 @@ void COMPILER::newString( const wxString& aString )
|
||||
m_parseFinished = false;
|
||||
}
|
||||
|
||||
|
||||
T_TOKEN COMPILER::getToken()
|
||||
{
|
||||
T_TOKEN rv;
|
||||
rv.value.str = nullptr;
|
||||
rv.value = defaultTokenValue;
|
||||
|
||||
bool done = false;
|
||||
|
||||
|
||||
+45
-1
@@ -43,6 +43,7 @@
|
||||
#include <wx/tooltip.h>
|
||||
|
||||
#include <advanced_config.h>
|
||||
#include <cli/cli_names.h> // Needed for the pre wx 3.2 cli workaround
|
||||
#include <common.h>
|
||||
#include <config_params.h>
|
||||
#include <confirm.h>
|
||||
@@ -51,6 +52,7 @@
|
||||
#include <eda_draw_frame.h>
|
||||
#include <gestfich.h>
|
||||
#include <id.h>
|
||||
#include <kicad_curl/kicad_curl.h>
|
||||
#include <kiplatform/policy.h>
|
||||
#include <lockfile.h>
|
||||
#include <menus_helpers.h>
|
||||
@@ -110,7 +112,7 @@ LANGUAGE_DESCR LanguagesList[] =
|
||||
{ wxLANGUAGE_SWEDISH, ID_LANGUAGE_SWEDISH, wxT( "Svenska" ), true },
|
||||
// { wxLANGUAGE_VIETNAMESE, ID_LANGUAGE_VIETNAMESE, wxT( "Tiếng Việt" ), true },
|
||||
// { wxLANGUAGE_TURKISH, ID_LANGUAGE_TURKISH, wxT( "Türkçe" ), true },
|
||||
{ wxLANGUAGE_UKRAINIAN, ID_LANGUAGE_UKRANIAN, wxT( "Українець" ), true },
|
||||
{ wxLANGUAGE_UKRAINIAN, ID_LANGUAGE_UKRANIAN, wxT( "Українська" ), true },
|
||||
{ wxLANGUAGE_CHINESE_SIMPLIFIED, ID_LANGUAGE_CHINESE_SIMPLIFIED,
|
||||
wxT( "简体中文" ), true },
|
||||
{ wxLANGUAGE_CHINESE_TRADITIONAL, ID_LANGUAGE_CHINESE_TRADITIONAL,
|
||||
@@ -150,6 +152,8 @@ PGM_BASE::~PGM_BASE()
|
||||
|
||||
void PGM_BASE::Destroy()
|
||||
{
|
||||
KICAD_CURL::Cleanup();
|
||||
|
||||
#ifdef KICAD_USE_SENTRY
|
||||
sentry_close();
|
||||
#endif
|
||||
@@ -408,6 +412,8 @@ bool PGM_BASE::InitPgm( bool aHeadless, bool aSkipPyInit, bool aIsUnitTest )
|
||||
// In particular, the user cache path is the most likely to be hit by startup code
|
||||
PATHS::EnsureUserPathsExist();
|
||||
|
||||
KICAD_CURL::Init();
|
||||
|
||||
#ifdef KICAD_USE_SENTRY
|
||||
sentryInit();
|
||||
#endif
|
||||
@@ -775,6 +781,26 @@ void PGM_BASE::SetLanguageIdentifier( int menu_id )
|
||||
}
|
||||
|
||||
|
||||
wxString PGM_BASE::GetLanguageTag()
|
||||
{
|
||||
const wxLanguageInfo* langInfo = wxLocale::GetLanguageInfo( m_language_id );
|
||||
|
||||
if( !langInfo )
|
||||
return "";
|
||||
else
|
||||
{
|
||||
#if wxCHECK_VERSION( 3, 1, 6 )
|
||||
wxString str = langInfo->GetCanonicalWithRegion();
|
||||
#else
|
||||
wxString str = langInfo->CanonicalName;
|
||||
#endif
|
||||
str.Replace( "_", "-" );
|
||||
|
||||
return str;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void PGM_BASE::SetLanguagePath()
|
||||
{
|
||||
wxLocale::AddCatalogLookupPathPrefix( PATHS::GetLocaleDataPath() );
|
||||
@@ -837,3 +863,21 @@ ENV_VAR_MAP& PGM_BASE::GetLocalEnvVariables() const
|
||||
{
|
||||
return GetCommonSettings()->m_Env.vars;
|
||||
}
|
||||
|
||||
|
||||
bool PGM_BASE::IsGUI()
|
||||
{
|
||||
if( !wxTheApp )
|
||||
return false;
|
||||
|
||||
#if wxCHECK_VERSION( 3, 1, 6 )
|
||||
return wxTheApp->IsGUI();
|
||||
#else
|
||||
// wxWidgets older than version 3.1.6 do not have a way to know if the app
|
||||
// has a GUI or is a console application.
|
||||
// So the trick is to set the App class name when starting kicad-cli, and when
|
||||
// the app class name is the kicad-cli class name the app is a console app
|
||||
bool run_gui = wxTheApp->GetClassName() != KICAD_CLI_APP_NAME;
|
||||
return run_gui;
|
||||
#endif
|
||||
}
|
||||
+180
-139
@@ -861,145 +861,186 @@ void DXF_PLOTTER::Text( const VECTOR2I& aPos,
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Emit text as a text entity. This loses formatting and shape but it's
|
||||
more useful as a CAD object */
|
||||
VECTOR2D origin_dev = userToDeviceCoordinates( aPos );
|
||||
SetColor( aColor );
|
||||
wxString cname = getDXFColorName( m_currentColor );
|
||||
VECTOR2D size_dev = userToDeviceSize( aSize );
|
||||
int h_code = 0, v_code = 0;
|
||||
|
||||
switch( aH_justify )
|
||||
{
|
||||
case GR_TEXT_H_ALIGN_LEFT: h_code = 0; break;
|
||||
case GR_TEXT_H_ALIGN_CENTER: h_code = 1; break;
|
||||
case GR_TEXT_H_ALIGN_RIGHT: h_code = 2; break;
|
||||
}
|
||||
|
||||
switch( aV_justify )
|
||||
{
|
||||
case GR_TEXT_V_ALIGN_TOP: v_code = 3; break;
|
||||
case GR_TEXT_V_ALIGN_CENTER: v_code = 2; break;
|
||||
case GR_TEXT_V_ALIGN_BOTTOM: v_code = 1; break;
|
||||
}
|
||||
|
||||
// Position, size, rotation and alignment
|
||||
// The two alignment point usages is somewhat idiot (see the DXF ref)
|
||||
// Anyway since we don't use the fit/aligned options, they're the same
|
||||
fprintf( m_outputFile,
|
||||
" 0\n"
|
||||
"TEXT\n"
|
||||
" 7\n"
|
||||
"%s\n" // Text style
|
||||
" 8\n"
|
||||
"%s\n" // Layer name
|
||||
" 10\n"
|
||||
"%g\n" // First point X
|
||||
" 11\n"
|
||||
"%g\n" // Second point X
|
||||
" 20\n"
|
||||
"%g\n" // First point Y
|
||||
" 21\n"
|
||||
"%g\n" // Second point Y
|
||||
" 40\n"
|
||||
"%g\n" // Text height
|
||||
" 41\n"
|
||||
"%g\n" // Width factor
|
||||
" 50\n"
|
||||
"%g\n" // Rotation
|
||||
" 51\n"
|
||||
"%g\n" // Oblique angle
|
||||
" 71\n"
|
||||
"%d\n" // Mirror flags
|
||||
" 72\n"
|
||||
"%d\n" // H alignment
|
||||
" 73\n"
|
||||
"%d\n", // V alignment
|
||||
aBold ? (aItalic ? "KICADBI" : "KICADB") : (aItalic ? "KICADI" : "KICAD"),
|
||||
TO_UTF8( cname ),
|
||||
origin_dev.x, origin_dev.x,
|
||||
origin_dev.y, origin_dev.y,
|
||||
size_dev.y, fabs( size_dev.x / size_dev.y ),
|
||||
aOrient.AsDegrees(),
|
||||
aItalic ? DXF_OBLIQUE_ANGLE : 0,
|
||||
size_dev.x < 0 ? 2 : 0, // X mirror flag
|
||||
h_code, v_code );
|
||||
|
||||
/* There are two issue in emitting the text:
|
||||
- Our overline character (~) must be converted to the appropriate
|
||||
control sequence %%O or %%o
|
||||
- Text encoding in DXF is more or less unspecified since depends on
|
||||
the DXF declared version, the acad version reading it *and* some
|
||||
system variables to be put in the header handled only by newer acads
|
||||
Also before R15 unicode simply is not supported (you need to use
|
||||
bigfonts which are a massive PITA). Common denominator solution:
|
||||
use Latin1 (and however someone could choke on it, anyway). Sorry
|
||||
for the extended latin people. If somewant want to try fixing this
|
||||
recent version seems to use UTF-8 (and not UCS2 like the rest of
|
||||
Windows)
|
||||
|
||||
XXX Actually there is a *third* issue: older DXF formats are limited
|
||||
to 255 bytes records (it was later raised to 2048); since I'm lazy
|
||||
and text so long is not probable I just don't implement this rule.
|
||||
If someone is interested in fixing this, you have to emit the first
|
||||
partial lines with group code 3 (max 250 bytes each) and then finish
|
||||
with a group code 1 (less than 250 bytes). The DXF refs explains it
|
||||
in no more details...
|
||||
*/
|
||||
|
||||
int braceNesting = 0;
|
||||
int overbarDepth = -1;
|
||||
|
||||
fputs( " 1\n", m_outputFile );
|
||||
|
||||
for( unsigned int i = 0; i < aText.length(); i++ )
|
||||
{
|
||||
/* Here I do a bad thing: writing the output one byte at a time!
|
||||
but today I'm lazy and I have no idea on how to coerce a Unicode
|
||||
wxString to spit out latin1 encoded text ...
|
||||
|
||||
At least stdio is *supposed* to do output buffering, so there is
|
||||
hope is not too slow */
|
||||
wchar_t ch = aText[i];
|
||||
|
||||
if( ch > 255 )
|
||||
{
|
||||
// I can't encode this...
|
||||
putc( '?', m_outputFile );
|
||||
}
|
||||
else
|
||||
{
|
||||
if( aText[i] == '~' && i+1 < aText.length() && aText[i+1] == '{' )
|
||||
{
|
||||
fputs( "%%o", m_outputFile );
|
||||
overbarDepth = braceNesting;
|
||||
|
||||
// Skip the '{'
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
else if( aText[i] == '{' )
|
||||
{
|
||||
braceNesting++;
|
||||
}
|
||||
else if( aText[i] == '}' )
|
||||
{
|
||||
if( braceNesting > 0 )
|
||||
braceNesting--;
|
||||
|
||||
if( braceNesting == overbarDepth )
|
||||
{
|
||||
fputs( "%%O", m_outputFile );
|
||||
overbarDepth = -1;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
putc( ch, m_outputFile );
|
||||
}
|
||||
}
|
||||
|
||||
putc( '\n', m_outputFile );
|
||||
TEXT_ATTRIBUTES attrs;
|
||||
attrs.m_Halign = aH_justify;
|
||||
attrs.m_Valign =aV_justify;
|
||||
attrs.m_StrokeWidth = aWidth;
|
||||
attrs.m_Angle = aOrient;
|
||||
attrs.m_Italic = aItalic;
|
||||
attrs.m_Bold = aBold;
|
||||
attrs.m_Mirrored = aSize.x < 0;
|
||||
attrs.m_Multiline = false;
|
||||
plotOneLineOfText( aPos, aColor, aText, attrs );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void DXF_PLOTTER::PlotText( const VECTOR2I& aPos, const COLOR4D& aColor,
|
||||
const wxString& aText,
|
||||
const TEXT_ATTRIBUTES& aAttributes,
|
||||
KIFONT::FONT* aFont,
|
||||
void* aData )
|
||||
{
|
||||
TEXT_ATTRIBUTES attrs = aAttributes;
|
||||
// Fix me: see how to use DXF text mode for multiline texts
|
||||
if( attrs.m_Multiline && !aText.Contains( wxT( "\n" ) ) )
|
||||
attrs.m_Multiline = false; // the text has only one line.
|
||||
|
||||
bool processSuperSub = aText.Contains( wxT( "^{" ) ) || aText.Contains( wxT( "_{" ) );
|
||||
|
||||
if( m_textAsLines || containsNonAsciiChars( aText ) || attrs.m_Multiline || processSuperSub )
|
||||
{
|
||||
// output text as graphics.
|
||||
// Perhaps multiline texts could be handled as DXF text entity
|
||||
// but I do not want spend time about that (JPC)
|
||||
PLOTTER::PlotText( aPos, aColor, aText, aAttributes, aFont, aData );
|
||||
}
|
||||
else
|
||||
plotOneLineOfText( aPos, aColor, aText, attrs );
|
||||
}
|
||||
|
||||
void DXF_PLOTTER::plotOneLineOfText( const VECTOR2I& aPos, const COLOR4D& aColor,
|
||||
const wxString& aText,
|
||||
const TEXT_ATTRIBUTES& aAttributes )
|
||||
{
|
||||
/* Emit text as a text entity. This loses formatting and shape but it's
|
||||
more useful as a CAD object */
|
||||
VECTOR2D origin_dev = userToDeviceCoordinates( aPos );
|
||||
SetColor( aColor );
|
||||
wxString cname = getDXFColorName( m_currentColor );
|
||||
VECTOR2D size_dev = userToDeviceSize( aAttributes.m_Size );
|
||||
int h_code = 0, v_code = 0;
|
||||
|
||||
switch( aAttributes.m_Halign )
|
||||
{
|
||||
case GR_TEXT_H_ALIGN_LEFT: h_code = 0; break;
|
||||
case GR_TEXT_H_ALIGN_CENTER: h_code = 1; break;
|
||||
case GR_TEXT_H_ALIGN_RIGHT: h_code = 2; break;
|
||||
}
|
||||
|
||||
switch( aAttributes.m_Valign )
|
||||
{
|
||||
case GR_TEXT_V_ALIGN_TOP: v_code = 3; break;
|
||||
case GR_TEXT_V_ALIGN_CENTER: v_code = 2; break;
|
||||
case GR_TEXT_V_ALIGN_BOTTOM: v_code = 1; break;
|
||||
}
|
||||
|
||||
// Position, size, rotation and alignment
|
||||
// The two alignment point usages is somewhat idiot (see the DXF ref)
|
||||
// Anyway since we don't use the fit/aligned options, they're the same
|
||||
fprintf( m_outputFile,
|
||||
" 0\n"
|
||||
"TEXT\n"
|
||||
" 7\n"
|
||||
"%s\n" // Text style
|
||||
" 8\n"
|
||||
"%s\n" // Layer name
|
||||
" 10\n"
|
||||
"%g\n" // First point X
|
||||
" 11\n"
|
||||
"%g\n" // Second point X
|
||||
" 20\n"
|
||||
"%g\n" // First point Y
|
||||
" 21\n"
|
||||
"%g\n" // Second point Y
|
||||
" 40\n"
|
||||
"%g\n" // Text height
|
||||
" 41\n"
|
||||
"%g\n" // Width factor
|
||||
" 50\n"
|
||||
"%g\n" // Rotation
|
||||
" 51\n"
|
||||
"%g\n" // Oblique angle
|
||||
" 71\n"
|
||||
"%d\n" // Mirror flags
|
||||
" 72\n"
|
||||
"%d\n" // H alignment
|
||||
" 73\n"
|
||||
"%d\n", // V alignment
|
||||
aAttributes.m_Bold ?
|
||||
(aAttributes.m_Italic ? "KICADBI" : "KICADB")
|
||||
: (aAttributes.m_Italic ? "KICADI" : "KICAD"), TO_UTF8( cname ),
|
||||
origin_dev.x, origin_dev.x,
|
||||
origin_dev.y, origin_dev.y,
|
||||
size_dev.y, fabs( size_dev.x / size_dev.y ),
|
||||
aAttributes.m_Angle.AsDegrees(),
|
||||
aAttributes.m_Italic ? DXF_OBLIQUE_ANGLE : 0,
|
||||
aAttributes.m_Mirrored ? 2 : 0, // X mirror flag
|
||||
h_code, v_code );
|
||||
|
||||
/* There are two issue in emitting the text:
|
||||
- Our overline character (~) must be converted to the appropriate
|
||||
control sequence %%O or %%o
|
||||
- Text encoding in DXF is more or less unspecified since depends on
|
||||
the DXF declared version, the acad version reading it *and* some
|
||||
system variables to be put in the header handled only by newer acads
|
||||
Also before R15 unicode simply is not supported (you need to use
|
||||
bigfonts which are a massive PITA). Common denominator solution:
|
||||
use Latin1 (and however someone could choke on it, anyway). Sorry
|
||||
for the extended latin people. If somewant want to try fixing this
|
||||
recent version seems to use UTF-8 (and not UCS2 like the rest of
|
||||
Windows)
|
||||
|
||||
XXX Actually there is a *third* issue: older DXF formats are limited
|
||||
to 255 bytes records (it was later raised to 2048); since I'm lazy
|
||||
and text so long is not probable I just don't implement this rule.
|
||||
If someone is interested in fixing this, you have to emit the first
|
||||
partial lines with group code 3 (max 250 bytes each) and then finish
|
||||
with a group code 1 (less than 250 bytes). The DXF refs explains it
|
||||
in no more details...
|
||||
*/
|
||||
|
||||
int braceNesting = 0;
|
||||
int overbarDepth = -1;
|
||||
|
||||
fputs( " 1\n", m_outputFile );
|
||||
|
||||
for( unsigned int i = 0; i < aText.length(); i++ )
|
||||
{
|
||||
/* Here I do a bad thing: writing the output one byte at a time!
|
||||
but today I'm lazy and I have no idea on how to coerce a Unicode
|
||||
wxString to spit out latin1 encoded text ...
|
||||
|
||||
At least stdio is *supposed* to do output buffering, so there is
|
||||
hope is not too slow */
|
||||
wchar_t ch = aText[i];
|
||||
|
||||
if( ch > 255 )
|
||||
{
|
||||
// I can't encode this...
|
||||
putc( '?', m_outputFile );
|
||||
}
|
||||
else
|
||||
{
|
||||
if( aText[i] == '~' && i+1 < aText.length() && aText[i+1] == '{' )
|
||||
{
|
||||
fputs( "%%o", m_outputFile );
|
||||
overbarDepth = braceNesting;
|
||||
|
||||
// Skip the '{'
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
else if( aText[i] == '{' )
|
||||
{
|
||||
braceNesting++;
|
||||
}
|
||||
else if( aText[i] == '}' )
|
||||
{
|
||||
if( braceNesting > 0 )
|
||||
braceNesting--;
|
||||
|
||||
if( braceNesting == overbarDepth )
|
||||
{
|
||||
fputs( "%%O", m_outputFile );
|
||||
overbarDepth = -1;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
putc( ch, m_outputFile );
|
||||
}
|
||||
}
|
||||
|
||||
putc( '\n', m_outputFile );
|
||||
}
|
||||
|
||||
@@ -154,7 +154,6 @@ void GERBER_PLOTTER::SetGerberCoordinatesFormat( int aResolution, bool aUseInche
|
||||
|
||||
void GERBER_PLOTTER::emitDcode( const VECTOR2D& pt, int dcode )
|
||||
{
|
||||
|
||||
fprintf( m_outputFile, "X%dY%dD%02d*\n", KiROUND( pt.x ), KiROUND( pt.y ), dcode );
|
||||
}
|
||||
|
||||
@@ -849,11 +848,16 @@ void GERBER_PLOTTER::plotArc( const SHAPE_ARC& aArc, bool aPlotInRegion )
|
||||
LineTo( start );
|
||||
|
||||
VECTOR2D devEnd = userToDeviceCoordinates( end );
|
||||
VECTOR2D devCenter = userToDeviceCoordinates( center - start );
|
||||
|
||||
// devRelCenter is the position on arc center relative to the arc start, in Gerber coord.
|
||||
// Warning: it is **not** userToDeviceCoordinates( center - start ) when the plotter
|
||||
// has an offset.
|
||||
VECTOR2D devRelCenter = userToDeviceCoordinates( center ) - userToDeviceCoordinates( start );
|
||||
|
||||
// We need to know if the arc is CW or CCW in device coordinates, so build this arc.
|
||||
SHAPE_ARC deviceArc( userToDeviceCoordinates( start ),
|
||||
userToDeviceCoordinates( aArc.GetArcMid() ), devEnd, 0 );
|
||||
userToDeviceCoordinates( aArc.GetArcMid() ),
|
||||
devEnd, 0 );
|
||||
|
||||
fprintf( m_outputFile, "G75*\n" ); // Multiquadrant (360 degrees) mode
|
||||
|
||||
@@ -864,7 +868,7 @@ void GERBER_PLOTTER::plotArc( const SHAPE_ARC& aArc, bool aPlotInRegion )
|
||||
|
||||
fprintf( m_outputFile, "X%dY%dI%dJ%dD01*\n",
|
||||
KiROUND( devEnd.x ), KiROUND( devEnd.y ),
|
||||
KiROUND( devCenter.x ), KiROUND( devCenter.y ) );
|
||||
KiROUND( devRelCenter.x ), KiROUND( devRelCenter.y ) );
|
||||
|
||||
fprintf( m_outputFile, "G01*\n" ); // Back to linear interpolate (perhaps useless here).
|
||||
}
|
||||
@@ -885,7 +889,8 @@ void GERBER_PLOTTER::plotArc( const VECTOR2I& aCenter, const EDA_ANGLE& aStartAn
|
||||
end.x = aCenter.x + KiROUND( aRadius * aEndAngle.Cos() );
|
||||
end.y = aCenter.y - KiROUND( aRadius * aEndAngle.Sin() );
|
||||
VECTOR2D devEnd = userToDeviceCoordinates( end );
|
||||
VECTOR2D devCenter = userToDeviceCoordinates( aCenter ) - userToDeviceCoordinates( start );
|
||||
// devRelCenter is the position on arc center relative to the arc start, in Gerber coord.
|
||||
VECTOR2D devRelCenter = userToDeviceCoordinates( aCenter ) - userToDeviceCoordinates( start );
|
||||
|
||||
fprintf( m_outputFile, "G75*\n" ); // Multiquadrant (360 degrees) mode
|
||||
|
||||
@@ -896,24 +901,22 @@ void GERBER_PLOTTER::plotArc( const VECTOR2I& aCenter, const EDA_ANGLE& aStartAn
|
||||
|
||||
fprintf( m_outputFile, "X%dY%dI%dJ%dD01*\n",
|
||||
KiROUND( devEnd.x ), KiROUND( devEnd.y ),
|
||||
KiROUND( devCenter.x ), KiROUND( devCenter.y ) );
|
||||
KiROUND( devRelCenter.x ), KiROUND( devRelCenter.y ) );
|
||||
|
||||
fprintf( m_outputFile, "G01*\n" ); // Back to linear interpolate (perhaps useless here).
|
||||
}
|
||||
|
||||
|
||||
void GERBER_PLOTTER::PlotGerberRegion( const SHAPE_LINE_CHAIN& aPoly, void* aData )
|
||||
void GERBER_PLOTTER::PlotGerberRegion( const SHAPE_LINE_CHAIN& aPoly, GBR_METADATA* aGbrMetadata )
|
||||
{
|
||||
if( aPoly.PointCount() <= 2 )
|
||||
return;
|
||||
|
||||
GBR_METADATA* gbr_metadata = static_cast<GBR_METADATA*>( aData );
|
||||
|
||||
bool clearTA_AperFunction = false; // true if a TA.AperFunction is used
|
||||
|
||||
if( gbr_metadata )
|
||||
if( aGbrMetadata )
|
||||
{
|
||||
std::string attrib = gbr_metadata->m_ApertureMetadata.FormatAttribute( !m_useX2format );
|
||||
std::string attrib = aGbrMetadata->m_ApertureMetadata.FormatAttribute( !m_useX2format );
|
||||
|
||||
if( !attrib.empty() )
|
||||
{
|
||||
@@ -922,7 +925,7 @@ void GERBER_PLOTTER::PlotGerberRegion( const SHAPE_LINE_CHAIN& aPoly, void* aDat
|
||||
}
|
||||
}
|
||||
|
||||
PlotPoly( aPoly, FILL_T::FILLED_SHAPE, 0 , gbr_metadata );
|
||||
PlotPoly( aPoly, FILL_T::FILLED_SHAPE, 0 , aGbrMetadata );
|
||||
|
||||
// Clear the TA attribute, to avoid the next item to inherit it:
|
||||
if( clearTA_AperFunction )
|
||||
@@ -939,18 +942,17 @@ void GERBER_PLOTTER::PlotGerberRegion( const SHAPE_LINE_CHAIN& aPoly, void* aDat
|
||||
}
|
||||
|
||||
|
||||
void GERBER_PLOTTER::PlotGerberRegion( const std::vector<VECTOR2I>& aCornerList, void* aData )
|
||||
void GERBER_PLOTTER::PlotGerberRegion( const std::vector<VECTOR2I>& aCornerList,
|
||||
GBR_METADATA* aGbrMetadata )
|
||||
{
|
||||
if( aCornerList.size() <= 2 )
|
||||
return;
|
||||
|
||||
GBR_METADATA* gbr_metadata = static_cast<GBR_METADATA*>( aData );
|
||||
|
||||
bool clearTA_AperFunction = false; // true if a TA.AperFunction is used
|
||||
|
||||
if( gbr_metadata )
|
||||
if( aGbrMetadata )
|
||||
{
|
||||
std::string attrib = gbr_metadata->m_ApertureMetadata.FormatAttribute( !m_useX2format );
|
||||
std::string attrib = aGbrMetadata->m_ApertureMetadata.FormatAttribute( !m_useX2format );
|
||||
|
||||
if( !attrib.empty() )
|
||||
{
|
||||
@@ -959,7 +961,7 @@ void GERBER_PLOTTER::PlotGerberRegion( const std::vector<VECTOR2I>& aCornerList,
|
||||
}
|
||||
}
|
||||
|
||||
PlotPoly( aCornerList, FILL_T::FILLED_SHAPE, 0, gbr_metadata );
|
||||
PlotPoly( aCornerList, FILL_T::FILLED_SHAPE, 0, aGbrMetadata );
|
||||
|
||||
// Clear the TA attribute, to avoid the next item to inherit it:
|
||||
if( clearTA_AperFunction )
|
||||
@@ -976,6 +978,19 @@ void GERBER_PLOTTER::PlotGerberRegion( const std::vector<VECTOR2I>& aCornerList,
|
||||
}
|
||||
|
||||
|
||||
void GERBER_PLOTTER::PlotPolyAsRegion( const SHAPE_LINE_CHAIN& aPoly, FILL_T aFill,
|
||||
int aWidth, GBR_METADATA* aGbrMetadata )
|
||||
{
|
||||
// plot a filled polygon using Gerber region, therefore adding X2 attributes
|
||||
// to the solid polygon
|
||||
if( aWidth )
|
||||
PlotPoly( aPoly, FILL_T::NO_FILL, aWidth, aGbrMetadata );
|
||||
|
||||
if( aFill != FILL_T::NO_FILL )
|
||||
PlotGerberRegion( aPoly, aGbrMetadata );
|
||||
}
|
||||
|
||||
|
||||
void GERBER_PLOTTER::PlotPoly( const SHAPE_LINE_CHAIN& aPoly, FILL_T aFill, int aWidth,
|
||||
void* aData )
|
||||
{
|
||||
@@ -1011,7 +1026,7 @@ void GERBER_PLOTTER::PlotPoly( const SHAPE_LINE_CHAIN& aPoly, FILL_T aFill, int
|
||||
{
|
||||
const SHAPE_ARC& arc = aPoly.Arc( arcindex );
|
||||
|
||||
plotArc( arc, ii > 0 );
|
||||
plotArc( arc, true );
|
||||
|
||||
// skip points on arcs, since we plot the arc itself
|
||||
while( ii+1 < aPoly.PointCount() && arcindex == aPoly.ArcIndex( ii+1 ) )
|
||||
@@ -1045,7 +1060,7 @@ void GERBER_PLOTTER::PlotPoly( const SHAPE_LINE_CHAIN& aPoly, FILL_T aFill, int
|
||||
{
|
||||
const SHAPE_ARC& arc = aPoly.Arc( arcindex );
|
||||
|
||||
plotArc( arc, ii > 0 );
|
||||
plotArc( arc, true );
|
||||
|
||||
// skip points on arcs, since we plot the arc itself
|
||||
while( ii+1 < aPoly.PointCount() && arcindex == aPoly.ArcIndex( ii+1 ) )
|
||||
@@ -1322,7 +1337,7 @@ void GERBER_PLOTTER::FlashPadOval( const VECTOR2I& aPos, const VECTOR2I& aSize,
|
||||
if( orient.IsCardinal90() )
|
||||
std::swap( size.x, size.y );
|
||||
|
||||
VECTOR2I pos_device = userToDeviceCoordinates( aPos );
|
||||
VECTOR2D pos_device = userToDeviceCoordinates( aPos );
|
||||
int aperture_attrib = gbr_metadata ? gbr_metadata->GetApertureAttrib() : 0;
|
||||
selectAperture( size, 0, ANGLE_0, APERTURE::AT_OVAL, aperture_attrib );
|
||||
|
||||
@@ -1353,7 +1368,7 @@ void GERBER_PLOTTER::FlashPadOval( const VECTOR2I& aPos, const VECTOR2I& aSize,
|
||||
orient -= ANGLE_180;
|
||||
}
|
||||
|
||||
VECTOR2I pos_device = userToDeviceCoordinates( aPos );
|
||||
VECTOR2D pos_device = userToDeviceCoordinates( aPos );
|
||||
int aperture_attrib = gbr_metadata ? gbr_metadata->GetApertureAttrib() : 0;
|
||||
selectAperture( size, 0, orient, APERTURE::AM_ROTATED_OVAL, aperture_attrib );
|
||||
|
||||
@@ -1416,7 +1431,7 @@ void GERBER_PLOTTER::FlashPadRect( const VECTOR2I& pos, const VECTOR2I& aSize,
|
||||
}
|
||||
else
|
||||
{
|
||||
VECTOR2I pos_device = userToDeviceCoordinates( pos );
|
||||
VECTOR2D pos_device = userToDeviceCoordinates( pos );
|
||||
int aperture_attrib = gbr_metadata ? gbr_metadata->GetApertureAttrib() : 0;
|
||||
selectAperture( size, 0, ANGLE_0, APERTURE::AT_RECT, aperture_attrib );
|
||||
|
||||
@@ -1433,7 +1448,7 @@ void GERBER_PLOTTER::FlashPadRect( const VECTOR2I& pos, const VECTOR2I& aSize,
|
||||
{
|
||||
m_hasApertureRotRect = true;
|
||||
|
||||
VECTOR2I pos_device = userToDeviceCoordinates( pos );
|
||||
VECTOR2D pos_device = userToDeviceCoordinates( pos );
|
||||
int aperture_attrib = gbr_metadata ? gbr_metadata->GetApertureAttrib() : 0;
|
||||
selectAperture( size, 0, aOrient, APERTURE::AM_ROT_RECT, aperture_attrib );
|
||||
|
||||
@@ -1755,7 +1770,7 @@ void GERBER_PLOTTER::FlashPadChamferRoundRect( const VECTOR2I& aShapePos, const
|
||||
if( aData )
|
||||
gbr_metadata = *static_cast<GBR_METADATA*>( aData );
|
||||
|
||||
VECTOR2I pos_device = userToDeviceCoordinates( aShapePos );
|
||||
VECTOR2D pos_device = userToDeviceCoordinates( aShapePos );
|
||||
SHAPE_POLY_SET outline;
|
||||
std::vector<VECTOR2I> cornerList;
|
||||
|
||||
@@ -1994,6 +2009,20 @@ void GERBER_PLOTTER::Text( const VECTOR2I& aPos,
|
||||
}
|
||||
|
||||
|
||||
void GERBER_PLOTTER::PlotText( const VECTOR2I& aPos, const COLOR4D& aColor,
|
||||
const wxString& aText,
|
||||
const TEXT_ATTRIBUTES& aAttributes,
|
||||
KIFONT::FONT* aFont,
|
||||
void* aData )
|
||||
{
|
||||
GBR_METADATA* gbr_metadata = static_cast<GBR_METADATA*>( aData );
|
||||
|
||||
if( gbr_metadata )
|
||||
formatNetAttribute( &gbr_metadata->m_NetlistMetadata );
|
||||
|
||||
PLOTTER::PlotText( aPos, aColor, aText, aAttributes, aFont, aData );
|
||||
}
|
||||
|
||||
void GERBER_PLOTTER::SetLayerPolarity( bool aPositive )
|
||||
{
|
||||
if( aPositive )
|
||||
|
||||
@@ -513,10 +513,11 @@ void PDF_PLOTTER::PlotImage( const wxImage& aImage, const VECTOR2I& aPos, double
|
||||
|
||||
if( alpha < 0xFF )
|
||||
{
|
||||
float a = 1.0 - ( (float) alpha / 255.0 );
|
||||
r = ( int )( r + ( a * 0xFF ) ) & 0xFF;
|
||||
g = ( int )( g + ( a * 0xFF ) ) & 0xFF;
|
||||
b = ( int )( b + ( a * 0xFF ) ) & 0xFF;
|
||||
float d = alpha / 255.0;
|
||||
float a = 1.0 - d;
|
||||
r = std::min( KiROUND( r * d + ( a * 0xFF ) ), 0xFF );
|
||||
g = std::min( KiROUND( g * d + ( a * 0xFF ) ), 0xFF );
|
||||
b = std::min( KiROUND( b * d + ( a * 0xFF ) ), 0xFF );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1376,7 +1377,9 @@ void PDF_PLOTTER::Text( const VECTOR2I& aPos,
|
||||
double ctm_a, ctm_b, ctm_c, ctm_d, ctm_e, ctm_f;
|
||||
double wideningFactor, heightFactor;
|
||||
|
||||
computeTextParameters( aPos, aText, aOrient, aSize, m_plotMirror, aH_justify,
|
||||
VECTOR2I t_size( std::abs( aSize.x ), std::abs( aSize.y ) );
|
||||
|
||||
computeTextParameters( aPos, aText, aOrient, t_size, m_plotMirror, aH_justify,
|
||||
aV_justify, aWidth, aItalic, aBold, &wideningFactor, &ctm_a,
|
||||
&ctm_b, &ctm_c, &ctm_d, &ctm_e, &ctm_f, &heightFactor );
|
||||
|
||||
@@ -1389,7 +1392,7 @@ void PDF_PLOTTER::Text( const VECTOR2I& aPos,
|
||||
if( !aFont )
|
||||
aFont = KIFONT::FONT::GetFont();
|
||||
|
||||
VECTOR2I full_box( aFont->StringBoundaryLimits( aText, aSize, aWidth, aBold, aItalic ) );
|
||||
VECTOR2I full_box( aFont->StringBoundaryLimits( aText, t_size, aWidth, aBold, aItalic ) );
|
||||
VECTOR2I box_x( full_box.x, 0 );
|
||||
VECTOR2I box_y( 0, full_box.y );
|
||||
|
||||
@@ -1410,13 +1413,13 @@ void PDF_PLOTTER::Text( const VECTOR2I& aPos,
|
||||
{
|
||||
wxString word = str_tok.GetNextToken();
|
||||
|
||||
computeTextParameters( pos, word, aOrient, aSize, m_plotMirror, GR_TEXT_H_ALIGN_LEFT,
|
||||
computeTextParameters( pos, word, aOrient, t_size, m_plotMirror, GR_TEXT_H_ALIGN_LEFT,
|
||||
GR_TEXT_V_ALIGN_BOTTOM, aWidth, aItalic, aBold, &wideningFactor, &ctm_a,
|
||||
&ctm_b, &ctm_c, &ctm_d, &ctm_e, &ctm_f, &heightFactor );
|
||||
|
||||
// Extract the changed width and rotate by the orientation to get the offset for the
|
||||
// next word
|
||||
VECTOR2I bbox( aFont->StringBoundaryLimits( word, aSize, aWidth, aBold, aItalic ).x, 0 );
|
||||
VECTOR2I bbox( aFont->StringBoundaryLimits( word, t_size, aWidth, aBold, aItalic ).x, 0 );
|
||||
RotatePoint( bbox, aOrient );
|
||||
pos += bbox;
|
||||
|
||||
@@ -1444,6 +1447,30 @@ void PDF_PLOTTER::Text( const VECTOR2I& aPos,
|
||||
}
|
||||
|
||||
|
||||
void PDF_PLOTTER::PlotText( const VECTOR2I& aPos, const COLOR4D& aColor,
|
||||
const wxString& aText,
|
||||
const TEXT_ATTRIBUTES& aAttributes,
|
||||
KIFONT::FONT* aFont,
|
||||
void* aData )
|
||||
{
|
||||
VECTOR2I size = aAttributes.m_Size;
|
||||
|
||||
// PDF files do not like 0 sized texts which create broken files.
|
||||
if( size.x == 0 || size.y == 0 )
|
||||
return;
|
||||
|
||||
if( aAttributes.m_Mirrored )
|
||||
size.x = -size.x;
|
||||
|
||||
PDF_PLOTTER::Text( aPos, aColor, aText, aAttributes.m_Angle, size,
|
||||
aAttributes.m_Halign, aAttributes.m_Valign,
|
||||
aAttributes.m_StrokeWidth,
|
||||
aAttributes.m_Italic, aAttributes.m_Bold,
|
||||
aAttributes.m_Multiline,
|
||||
aFont, aData );
|
||||
}
|
||||
|
||||
|
||||
void PDF_PLOTTER::HyperlinkBox( const BOX2I& aBox, const wxString& aDestinationURL )
|
||||
{
|
||||
m_hyperlinksInPage.push_back( std::make_pair( aBox, aDestinationURL ) );
|
||||
|
||||
@@ -967,6 +967,28 @@ void PS_PLOTTER::Text( const VECTOR2I& aPos,
|
||||
}
|
||||
|
||||
|
||||
void PS_PLOTTER::PlotText( const VECTOR2I& aPos,
|
||||
const COLOR4D& aColor,
|
||||
const wxString& aText,
|
||||
const TEXT_ATTRIBUTES& aAttributes,
|
||||
KIFONT::FONT* aFont,
|
||||
void* aData )
|
||||
{
|
||||
SetCurrentLineWidth( aAttributes.m_StrokeWidth );
|
||||
SetColor( aColor );
|
||||
|
||||
// Draw the hidden postscript text (if requested)
|
||||
if( m_textMode == PLOT_TEXT_MODE::PHANTOM )
|
||||
{
|
||||
std::string ps_test = encodeStringForPlotter( aText );
|
||||
VECTOR2D pos_dev = userToDeviceCoordinates( aPos );
|
||||
fprintf( m_outputFile, "%s %g %g phantomshow\n", ps_test.c_str(), pos_dev.x, pos_dev.y );
|
||||
}
|
||||
|
||||
PLOTTER::PlotText( aPos, aColor, aText, aAttributes, aFont, aData );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Character widths for Helvetica
|
||||
*/
|
||||
|
||||
@@ -633,7 +633,13 @@ void SVG_PLOTTER::PlotImage( const wxImage& aImage, const VECTOR2I& aPos, double
|
||||
{
|
||||
wxMemoryOutputStream img_stream;
|
||||
|
||||
aImage.SaveFile( img_stream, wxBITMAP_TYPE_PNG );
|
||||
if( m_colorMode )
|
||||
aImage.SaveFile( img_stream, wxBITMAP_TYPE_PNG );
|
||||
else // Plot in B&W
|
||||
{
|
||||
wxImage image = aImage.ConvertToGreyscale();
|
||||
image.SaveFile( img_stream, wxBITMAP_TYPE_PNG );
|
||||
}
|
||||
size_t input_len = img_stream.GetOutputStreamBuffer()->GetBufferSize();
|
||||
std::vector<uint8_t> buffer( input_len );
|
||||
std::vector<uint8_t> encoded;
|
||||
@@ -847,3 +853,23 @@ void SVG_PLOTTER::Text( const VECTOR2I& aPos,
|
||||
|
||||
fputs( "</g>", m_outputFile );
|
||||
}
|
||||
|
||||
|
||||
void SVG_PLOTTER::PlotText( const VECTOR2I& aPos, const COLOR4D& aColor,
|
||||
const wxString& aText,
|
||||
const TEXT_ATTRIBUTES& aAttributes,
|
||||
KIFONT::FONT* aFont,
|
||||
void* aData )
|
||||
{
|
||||
VECTOR2I size = aAttributes.m_Size;
|
||||
|
||||
if( aAttributes.m_Mirrored )
|
||||
size.x = -size.x;
|
||||
|
||||
SVG_PLOTTER::Text( aPos, aColor, aText, aAttributes.m_Angle, size,
|
||||
aAttributes.m_Halign, aAttributes.m_Valign,
|
||||
aAttributes.m_StrokeWidth,
|
||||
aAttributes.m_Italic, aAttributes.m_Bold,
|
||||
aAttributes.m_Multiline,
|
||||
aFont, aData );
|
||||
}
|
||||
|
||||
@@ -139,10 +139,10 @@ void PlotDrawingSheet( PLOTTER* plotter, const PROJECT* aProject, const TITLE_BL
|
||||
|
||||
int penWidth = std::max( text->GetEffectiveTextPenWidth(), defaultPenWidth );
|
||||
|
||||
plotter->Text( text->GetTextPos(), color, text->GetShownText(), text->GetTextAngle(),
|
||||
text->GetTextSize(), text->GetHorizJustify(), text->GetVertJustify(),
|
||||
penWidth, text->IsItalic(), text->IsBold(), text->IsMultilineAllowed(),
|
||||
font );
|
||||
plotter->Text( text->GetTextPos(), color, text->GetShownText( true ),
|
||||
text->GetTextAngle(), text->GetTextSize(), text->GetHorizJustify(),
|
||||
text->GetVertJustify(), penWidth, text->IsItalic(), text->IsBold(),
|
||||
text->IsMultilineAllowed(), font );
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
+50
-18
@@ -2,7 +2,7 @@
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2017 Jean-Pierre Charras, jp.charras at wanadoo.fr
|
||||
* Copyright (C) 2017-2022 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
* Copyright (C) 2017-2023 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
@@ -694,23 +694,6 @@ void PLOTTER::PlotPoly( const SHAPE_LINE_CHAIN& aCornerList, FILL_T aFill, int a
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Same as GRText, but plot graphic text instead of draw it.
|
||||
*
|
||||
* @param aPos is the text position (according to aH_justify, aV_justify).
|
||||
* @param aColor is the text color.
|
||||
* @param aText is the text to draw.
|
||||
* @param aOrient is the angle.
|
||||
* @param aSize is the text size (size.x or size.y can be < 0 for mirrored texts).
|
||||
* @param aH_justify is the horizontal justification (Left, center, right).
|
||||
* @param aV_justify is the vertical justification (bottom, center, top).
|
||||
* @param aPenWidth is the line width (if = 0, use plot default line width).
|
||||
* @param aItalic is the true to simulate an italic font.
|
||||
* @param aBold use true to use a bold font Useful only with default width value (aPenWidth = 0).
|
||||
* @param aMultilineAllowed use true to plot text as multiline, otherwise single line.
|
||||
* @param aData is a parameter used by some plotters in SetCurrentLineWidth(),
|
||||
* not directly used here.
|
||||
*/
|
||||
void PLOTTER::Text( const VECTOR2I& aPos,
|
||||
const COLOR4D& aColor,
|
||||
const wxString& aText,
|
||||
@@ -759,6 +742,55 @@ void PLOTTER::Text( const VECTOR2I& aPos,
|
||||
attributes.m_Valign = aV_justify;
|
||||
attributes.m_Size = aSize;
|
||||
|
||||
// if Size.x is < 0, the text is mirrored (we have no other param to know a text is mirrored)
|
||||
if( attributes.m_Size.x < 0 )
|
||||
{
|
||||
attributes.m_Size.x = -attributes.m_Size.x;
|
||||
attributes.m_Mirrored = true;
|
||||
}
|
||||
|
||||
if( !aFont )
|
||||
aFont = KIFONT::FONT::GetFont();
|
||||
|
||||
aFont->Draw( &callback_gal, aText, aPos, attributes );
|
||||
}
|
||||
|
||||
void PLOTTER::PlotText( const VECTOR2I& aPos, const COLOR4D& aColor,
|
||||
const wxString& aText,
|
||||
const TEXT_ATTRIBUTES& aAttributes,
|
||||
KIFONT::FONT* aFont,
|
||||
void* aData )
|
||||
{
|
||||
KIGFX::GAL_DISPLAY_OPTIONS empty_opts;
|
||||
|
||||
TEXT_ATTRIBUTES attributes = aAttributes;
|
||||
int penWidth = attributes.m_StrokeWidth;
|
||||
|
||||
SetColor( aColor );
|
||||
SetCurrentLineWidth( penWidth, aData );
|
||||
|
||||
if( penWidth == 0 && attributes.m_Bold ) // Use default values if aPenWidth == 0
|
||||
penWidth = GetPenSizeForBold( std::min( attributes.m_Size.x, attributes.m_Size.y ) );
|
||||
|
||||
if( penWidth < 0 )
|
||||
penWidth = -penWidth;
|
||||
|
||||
attributes.m_StrokeWidth = penWidth;
|
||||
|
||||
CALLBACK_GAL callback_gal( empty_opts,
|
||||
// Stroke callback
|
||||
[&]( const VECTOR2I& aPt1, const VECTOR2I& aPt2 )
|
||||
{
|
||||
MoveTo( aPt1 );
|
||||
LineTo( aPt2 );
|
||||
PenFinish();
|
||||
},
|
||||
// Polygon callback
|
||||
[&]( const SHAPE_LINE_CHAIN& aPoly )
|
||||
{
|
||||
PlotPoly( aPoly, FILL_T::FILLED_SHAPE, 0, aData );
|
||||
} );
|
||||
|
||||
if( !aFont )
|
||||
aFont = KIFONT::FONT::GetFont();
|
||||
|
||||
|
||||
@@ -193,7 +193,7 @@ void CADSTAR_ARCHIVE_PARSER::LINECODE::Parse( XNODE* aNode, PARSER_CONTEXT* aCon
|
||||
|
||||
XNODE* cNode = aNode->GetChildren();
|
||||
|
||||
if( cNode->GetName() != wxT( "STYLE" ) )
|
||||
if( !cNode || cNode->GetName() != wxT( "STYLE" ) )
|
||||
THROW_UNKNOWN_NODE_IO_ERROR( cNode->GetName(), wxString::Format( "LINECODE -> %s", Name ) );
|
||||
|
||||
wxString styleStr = GetXmlAttributeIDString( cNode, 0 );
|
||||
@@ -486,18 +486,28 @@ void CADSTAR_ARCHIVE_PARSER::VERTEX::AppendToChain( SHAPE_LINE_CHAIN* aChainToAp
|
||||
const std::function<VECTOR2I( const VECTOR2I& )> aCadstarToKicadPointCallback,
|
||||
double aAccuracy ) const
|
||||
{
|
||||
VECTOR2I endPoint = aCadstarToKicadPointCallback( End );
|
||||
|
||||
if( Type == VERTEX_TYPE::POINT )
|
||||
{
|
||||
aChainToAppendTo->Append( endPoint );
|
||||
aChainToAppendTo->Append( aCadstarToKicadPointCallback( End ) );
|
||||
return;
|
||||
}
|
||||
|
||||
wxCHECK_MSG( aChainToAppendTo->PointCount() > 0, /*void*/,
|
||||
"Can't append an arc to vertex to an empty chain" );
|
||||
|
||||
VECTOR2I startPoint = aChainToAppendTo->GetPoint( -1 );
|
||||
aChainToAppendTo->Append( BuildArc( aChainToAppendTo->GetPoint( -1 ), aCadstarToKicadPointCallback),
|
||||
aAccuracy );
|
||||
}
|
||||
|
||||
|
||||
SHAPE_ARC CADSTAR_ARCHIVE_PARSER::VERTEX::BuildArc( const VECTOR2I& aPrevPoint,
|
||||
const std::function<VECTOR2I( const VECTOR2I& )> aCadstarToKicadPointCallback ) const
|
||||
{
|
||||
wxCHECK_MSG( Type != VERTEX_TYPE::POINT, SHAPE_ARC(),
|
||||
"Can't build an arc for a straight segment!" );
|
||||
|
||||
VECTOR2I startPoint = aPrevPoint;
|
||||
VECTOR2I endPoint = aCadstarToKicadPointCallback( End );
|
||||
VECTOR2I centerPoint;
|
||||
|
||||
if( Type == VERTEX_TYPE::ANTICLOCKWISE_SEMICIRCLE || Type == VERTEX_TYPE::CLOCKWISE_SEMICIRCLE )
|
||||
@@ -516,9 +526,8 @@ void CADSTAR_ARCHIVE_PARSER::VERTEX::AppendToChain( SHAPE_LINE_CHAIN* aChainToAp
|
||||
clockwise = !clockwise;
|
||||
|
||||
SHAPE_ARC arc;
|
||||
arc.ConstructFromStartEndCenter( startPoint, endPoint, centerPoint, clockwise );
|
||||
|
||||
aChainToAppendTo->Append( arc, aAccuracy );
|
||||
return arc.ConstructFromStartEndCenter( startPoint, endPoint, centerPoint, clockwise );
|
||||
}
|
||||
|
||||
|
||||
@@ -2419,7 +2428,9 @@ XNODE* CADSTAR_ARCHIVE_PARSER::LoadArchiveFile( const wxString& aFileName,
|
||||
const wxString& aFileTypeIdentifier, PROGRESS_REPORTER* aProgressReporter )
|
||||
{
|
||||
KEYWORD emptyKeywords[1] = {};
|
||||
XNODE * iNode = nullptr, *cNode = nullptr;
|
||||
XNODE* rootNode = nullptr;
|
||||
XNODE* cNode = nullptr;
|
||||
XNODE* iNode = nullptr;
|
||||
int tok;
|
||||
bool cadstarFileCheckDone = false;
|
||||
wxString str;
|
||||
@@ -2451,7 +2462,10 @@ XNODE* CADSTAR_ARCHIVE_PARSER::LoadArchiveFile( const wxString& aFileName,
|
||||
if( aProgressReporter && ( currentProgress() - previousReportedProgress ) > 0.01 )
|
||||
{
|
||||
if( !aProgressReporter->KeepRefreshing() )
|
||||
{
|
||||
delete rootNode;
|
||||
THROW_IO_ERROR( _( "File import cancelled by user." ) );
|
||||
}
|
||||
|
||||
aProgressReporter->SetCurrentProgress( currentProgress() );
|
||||
previousReportedProgress = currentProgress();
|
||||
@@ -2467,6 +2481,7 @@ XNODE* CADSTAR_ARCHIVE_PARSER::LoadArchiveFile( const wxString& aFileName,
|
||||
else
|
||||
{
|
||||
//too many closing brackets
|
||||
delete rootNode;
|
||||
THROW_IO_ERROR( _( "The selected file is not valid or might be corrupt!" ) );
|
||||
}
|
||||
}
|
||||
@@ -2476,6 +2491,9 @@ XNODE* CADSTAR_ARCHIVE_PARSER::LoadArchiveFile( const wxString& aFileName,
|
||||
str = wxString( lexer.CurText(), *conv );
|
||||
cNode = new XNODE( wxXML_ELEMENT_NODE, str );
|
||||
|
||||
if( !rootNode )
|
||||
rootNode = cNode;
|
||||
|
||||
if( iNode )
|
||||
{
|
||||
//we will add it as attribute as well as child node
|
||||
@@ -2485,7 +2503,10 @@ XNODE* CADSTAR_ARCHIVE_PARSER::LoadArchiveFile( const wxString& aFileName,
|
||||
else if( !cadstarFileCheckDone )
|
||||
{
|
||||
if( cNode->GetName() != aFileTypeIdentifier )
|
||||
{
|
||||
delete rootNode;
|
||||
THROW_IO_ERROR( _( "The selected file is not valid or might be corrupt!" ) );
|
||||
}
|
||||
|
||||
cadstarFileCheckDone = true;
|
||||
}
|
||||
@@ -2501,19 +2522,28 @@ XNODE* CADSTAR_ARCHIVE_PARSER::LoadArchiveFile( const wxString& aFileName,
|
||||
else
|
||||
{
|
||||
//not enough closing brackets
|
||||
delete rootNode;
|
||||
THROW_IO_ERROR( _( "The selected file is not valid or might be corrupt!" ) );
|
||||
}
|
||||
}
|
||||
|
||||
// Not enough closing brackets
|
||||
if( iNode != nullptr )
|
||||
{
|
||||
delete rootNode;
|
||||
THROW_IO_ERROR( _( "The selected file is not valid or might be corrupt!" ) );
|
||||
}
|
||||
|
||||
// Throw if no data was parsed
|
||||
if( cNode )
|
||||
return cNode;
|
||||
if( rootNode )
|
||||
{
|
||||
return rootNode;
|
||||
}
|
||||
else
|
||||
{
|
||||
delete rootNode;
|
||||
THROW_IO_ERROR( _( "The selected file is not valid or might be corrupt!" ) );
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -83,6 +83,7 @@ class wxXmlAttribute;
|
||||
class PROGRESS_REPORTER;
|
||||
class SHAPE_LINE_CHAIN;
|
||||
class SHAPE_POLY_SET;
|
||||
class SHAPE_ARC;
|
||||
|
||||
/**
|
||||
* @brief Helper functions and common structures for CADSTAR PCB and Schematic archive files.
|
||||
@@ -92,6 +93,8 @@ class CADSTAR_ARCHIVE_PARSER
|
||||
public:
|
||||
CADSTAR_ARCHIVE_PARSER() { m_progressReporter = nullptr; }
|
||||
|
||||
virtual ~CADSTAR_ARCHIVE_PARSER() {}
|
||||
|
||||
|
||||
typedef wxString LINECODE_ID;
|
||||
typedef wxString HATCHCODE_ID;
|
||||
@@ -451,6 +454,10 @@ public:
|
||||
void AppendToChain( SHAPE_LINE_CHAIN* aChainToAppendTo,
|
||||
const std::function<VECTOR2I( const VECTOR2I& )> aCadstarToKicadPointCallback,
|
||||
double aAccuracy ) const;
|
||||
|
||||
SHAPE_ARC BuildArc( const VECTOR2I& aPrevPoint,
|
||||
const std::function<VECTOR2I( const VECTOR2I& )>
|
||||
aCadstarToKicadPointCallback ) const;
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -49,7 +49,7 @@ wxString escapeName( const wxString& aNetName )
|
||||
|
||||
wxString interpretText( const wxString& aText )
|
||||
{
|
||||
wxString token = aText.Upper();
|
||||
wxString token = aText;
|
||||
|
||||
if( substituteVariable( &token ) )
|
||||
return token;
|
||||
@@ -116,25 +116,32 @@ wxString interpretText( const wxString& aText )
|
||||
|
||||
bool substituteVariable( wxString* aText )
|
||||
{
|
||||
if ( *aText == wxT( ">NAME" ) ) *aText = wxT( "${REFERENCE}" );
|
||||
else if( *aText == wxT( ">VALUE" ) ) *aText = wxT( "${VALUE}" );
|
||||
else if( *aText == wxT( ">PART" ) ) *aText = wxT( "${REFERENCE}" );
|
||||
else if( *aText == wxT( ">GATE" ) ) *aText = wxT( "${UNIT}" );
|
||||
else if( *aText == wxT( ">MODULE" ) ) *aText = wxT( "${FOOTPRINT_NAME}" );
|
||||
else if( *aText == wxT( ">SHEETNR" ) ) *aText = wxT( "${#}" );
|
||||
else if( *aText == wxT( ">SHEETS" ) ) *aText = wxT( "${##}" );
|
||||
else if( *aText == wxT( ">SHEET" ) ) *aText = wxT( "${#}/${##}" );
|
||||
else if( *aText == wxT( ">SHEETNR_TOTAL" ) ) *aText = wxT( "${#}" );
|
||||
else if( *aText == wxT( ">SHEETS_TOTAL" ) ) *aText = wxT( "${##}" );
|
||||
else if( *aText == wxT( ">SHEET_TOTAL" ) ) *aText = wxT( "${#}/${##}" );
|
||||
else if( *aText == wxT( ">SHEET_HEADLINE" ) ) *aText = wxT( "${SHEETNAME}" );
|
||||
else if( *aText == wxT( ">ASSEMBLY_VARIANT" ) ) *aText = wxT( "${ASSEMBLY_VARIANT}" );
|
||||
else if( *aText == wxT( ">DRAWING_NAME" ) ) *aText = wxT( "${PROJECTNAME}" );
|
||||
else if( *aText == wxT( ">LAST_DATE_TIME" ) ) *aText = wxT( "${CURRENT_DATE}" );
|
||||
else if( *aText == wxT( ">PLOT_DATE_TIME" ) ) *aText = wxT( "${CURRENT_DATE}" );
|
||||
else return false;
|
||||
if( aText->StartsWith( '>' ) && aText->AfterFirst( ' ' ).IsEmpty() )
|
||||
{
|
||||
wxString token = aText->Upper();
|
||||
|
||||
return true;
|
||||
if ( token == wxT( ">NAME" ) ) *aText = wxT( "${REFERENCE}" );
|
||||
else if( token == wxT( ">VALUE" ) ) *aText = wxT( "${VALUE}" );
|
||||
else if( token == wxT( ">PART" ) ) *aText = wxT( "${REFERENCE}" );
|
||||
else if( token == wxT( ">GATE" ) ) *aText = wxT( "${UNIT}" );
|
||||
else if( token == wxT( ">MODULE" ) ) *aText = wxT( "${FOOTPRINT_NAME}" );
|
||||
else if( token == wxT( ">SHEETNR" ) ) *aText = wxT( "${#}" );
|
||||
else if( token == wxT( ">SHEETS" ) ) *aText = wxT( "${##}" );
|
||||
else if( token == wxT( ">SHEET" ) ) *aText = wxT( "${#}/${##}" );
|
||||
else if( token == wxT( ">SHEETNR_TOTAL" ) ) *aText = wxT( "${#}" );
|
||||
else if( token == wxT( ">SHEETS_TOTAL" ) ) *aText = wxT( "${##}" );
|
||||
else if( token == wxT( ">SHEET_TOTAL" ) ) *aText = wxT( "${#}/${##}" );
|
||||
else if( token == wxT( ">SHEET_HEADLINE" ) ) *aText = wxT( "${SHEETNAME}" );
|
||||
else if( token == wxT( ">ASSEMBLY_VARIANT" ) ) *aText = wxT( "${ASSEMBLY_VARIANT}" );
|
||||
else if( token == wxT( ">DRAWING_NAME" ) ) *aText = wxT( "${PROJECTNAME}" );
|
||||
else if( token == wxT( ">LAST_DATE_TIME" ) ) *aText = wxT( "${CURRENT_DATE}" );
|
||||
else if( token == wxT( ">PLOT_DATE_TIME" ) ) *aText = wxT( "${CURRENT_DATE}" );
|
||||
else *aText = wxString::Format( wxS( "${%s}" ), aText->Mid( 1 ).Trim() );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -47,7 +47,6 @@ struct EPART;
|
||||
struct ETEXT;
|
||||
|
||||
typedef std::unordered_map<wxString, wxXmlNode*> NODE_MAP;
|
||||
typedef std::map<wxString, FOOTPRINT*> FOOTPRINT_MAP;
|
||||
typedef std::map<wxString, EINSTANCE*> EINSTANCE_MAP;
|
||||
typedef std::map<wxString, std::unique_ptr<EPART>> EPART_MAP;
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2020 CERN
|
||||
* Copyright (C) 2021-2022 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
* Copyright (C) 2021-2023 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
* @author Jon Evans <jon@craftyjon.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
@@ -393,10 +393,7 @@ std::shared_ptr<NETCLASS> NET_SETTINGS::GetEffectiveNetClass( const wxString& aN
|
||||
|
||||
for( const auto& [ matcher, netclassName ] : m_NetClassPatternAssignments )
|
||||
{
|
||||
int matches;
|
||||
int offset;
|
||||
|
||||
if( matcher->Find( aNetName, matches, offset ) && offset == 0 )
|
||||
if( matcher->StartsWith( aNetName ) )
|
||||
return getNetclass( netclassName );
|
||||
}
|
||||
|
||||
|
||||
@@ -210,6 +210,8 @@ PROJECT_LOCAL_SETTINGS::PROJECT_LOCAL_SETTINGS( PROJECT* aProject, const wxStrin
|
||||
return;
|
||||
}
|
||||
|
||||
m_files.clear();
|
||||
|
||||
for( const nlohmann::json& file : aVal )
|
||||
{
|
||||
PROJECT_FILE_STATE fileState;
|
||||
|
||||
@@ -73,9 +73,14 @@ wxPGWindowList PG_UNIT_EDITOR::CreateControls( wxPropertyGrid* aPropGrid, wxPGPr
|
||||
m_unitBinder->SetUnits( m_frame->GetUserUnits() );
|
||||
|
||||
if( PGPROPERTY_DISTANCE* prop = dynamic_cast<PGPROPERTY_DISTANCE*>( aProperty ) )
|
||||
{
|
||||
m_unitBinder->SetCoordType( prop->CoordType() );
|
||||
}
|
||||
else if( dynamic_cast<PGPROPERTY_ANGLE*>( aProperty ) != nullptr )
|
||||
{
|
||||
m_unitBinder->SetCoordType( ORIGIN_TRANSFORMS::NOT_A_COORD );
|
||||
m_unitBinder->SetUnits( EDA_UNITS::DEGREES );
|
||||
}
|
||||
|
||||
UpdateControl( aProperty, win );
|
||||
|
||||
|
||||
@@ -130,7 +130,7 @@ const void* PROPERTY_MANAGER::TypeCast( const void* aSource, TYPE_ID aBase, TYPE
|
||||
}
|
||||
|
||||
|
||||
void PROPERTY_MANAGER::AddProperty( PROPERTY_BASE* aProperty, const wxString& aGroup )
|
||||
PROPERTY_BASE& PROPERTY_MANAGER::AddProperty( PROPERTY_BASE* aProperty, const wxString& aGroup )
|
||||
{
|
||||
const wxString& name = aProperty->Name();
|
||||
TYPE_ID hash = aProperty->OwnerHash();
|
||||
@@ -147,15 +147,16 @@ void PROPERTY_MANAGER::AddProperty( PROPERTY_BASE* aProperty, const wxString& aG
|
||||
}
|
||||
|
||||
m_dirty = true;
|
||||
return *aProperty;
|
||||
}
|
||||
|
||||
|
||||
void PROPERTY_MANAGER::ReplaceProperty( size_t aBase, const wxString& aName, PROPERTY_BASE* aNew,
|
||||
const wxString& aGroup )
|
||||
PROPERTY_BASE& PROPERTY_MANAGER::ReplaceProperty( size_t aBase, const wxString& aName,
|
||||
PROPERTY_BASE* aNew, const wxString& aGroup )
|
||||
{
|
||||
CLASS_DESC& classDesc = getClass( aNew->OwnerHash() );
|
||||
classDesc.m_replaced.insert( std::make_pair( aBase, aName ) );
|
||||
AddProperty( aNew, aGroup );
|
||||
return AddProperty( aNew, aGroup );
|
||||
}
|
||||
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user