Compare commits
546 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 8ad2755ae3 | |||
| c90d9b7ebe | |||
| 613f13c576 | |||
| 4d8269c5fd | |||
| 99ac73630a | |||
| bec70ff39d | |||
| cd5827a694 | |||
| a32e7a44e3 | |||
| 8c3c82153d | |||
| 28e433cc54 | |||
| 3fd353d837 | |||
| f238e09990 | |||
| b0b523bfdb | |||
| e5ef33d227 | |||
| f67945aae9 | |||
| f74e4fa73e | |||
| efaa3b5ca8 | |||
| 0ad919d043 | |||
| dc2b87aa75 | |||
| b65d3c80a3 | |||
| 12e03b0fcf | |||
| e964ccb6b5 | |||
| 994cabf4c0 | |||
| 5f9f31605f | |||
| db2b94e1c6 | |||
| a37ffabd27 | |||
| de8b22ac10 | |||
| 30f6135ad6 | |||
| 9e50e37fdd | |||
| 50d8178482 | |||
| e4cf45edce | |||
| b6b85fa652 | |||
| dad2e485da | |||
| 63999f25fa | |||
| f23f43961f | |||
| 16594a65a2 | |||
| de32417df1 | |||
| bb779c87f3 | |||
| 3dedd899f7 | |||
| 5eb265080f | |||
| 3329affc12 | |||
| fce66a0372 | |||
| 780df7262b | |||
| 8a3a11e2f8 | |||
| 5878ac5aaf | |||
| 22cebd8e71 | |||
| 0f2f953476 | |||
| 205db57971 | |||
| d607249e81 | |||
| 5b9b49cf2b | |||
| 045b00bac7 | |||
| c297a4e2b3 | |||
| 4c9273206a | |||
| 8530b71833 | |||
| 67cca8db25 | |||
| 84cc67c9df | |||
| 044a7ca39e | |||
| 1d09917e3e | |||
| b5658962be | |||
| 0a1d209255 | |||
| dbf0150cec | |||
| 8871b0385d | |||
| 9f20816b24 | |||
| f3566a987d | |||
| a6210da126 | |||
| ebad7dfc0d | |||
| ab82dc5839 | |||
| cfc1f14282 | |||
| 479b3e6c72 | |||
| 27c573ca42 | |||
| e28381841a | |||
| 37ac2ee0a3 | |||
| 42397a6ce1 | |||
| e29131f265 | |||
| b4d03e2eeb | |||
| 5bd565211b | |||
| dd654ddd9a | |||
| 303a90eb65 | |||
| 7be9021ba3 | |||
| 843d01f27b | |||
| bdc1cbda27 | |||
| 51e094eb34 | |||
| ccec31da71 | |||
| fe3bbee807 | |||
| 12cb6fc043 | |||
| 1c3efdf212 | |||
| 5d4f66a613 | |||
| 711184ef62 | |||
| 9b4809e10f | |||
| 9109c4cd27 | |||
| 20c68f9c8d | |||
| 9950d046cb | |||
| ff44242682 | |||
| f671f4db51 | |||
| 406e7acaac | |||
| a3eca13ad3 | |||
| 73053a2177 | |||
| 5992d7331a | |||
| 9767a083cc | |||
| 07c9aee1ea | |||
| fc0911f55e | |||
| b74fef1b10 | |||
| 127874a7b9 | |||
| ecce28a472 | |||
| e93dacb788 | |||
| 6c4734c370 | |||
| 93a63a61ec | |||
| 57b9c1bdaf | |||
| b166e866e0 | |||
| 9fa2549d7a | |||
| f9cb5a26a3 | |||
| cbd40cb5e4 | |||
| 352672f8bf | |||
| 6dc5c2b24a | |||
| fa63bd24f4 | |||
| 10750bc460 | |||
| afb4b1411d | |||
| 74d7711e37 | |||
| 585693f0b3 | |||
| 186f5e65a7 | |||
| 1fd1cde3bf | |||
| dcadff46b7 | |||
| 62bb553460 | |||
| 0f32217cf0 | |||
| 0ec479c17f | |||
| 4ede3b3f2b | |||
| 22feba7bbf | |||
| b6eef921a4 | |||
| 567d0dca95 | |||
| 7a869fc503 | |||
| 8b6274af16 | |||
| 581715f7aa | |||
| 1c7a64b0ea | |||
| 8fb25f5577 | |||
| 88ae436249 | |||
| bf6bcba7bb | |||
| 10205bb432 | |||
| aa1fc43048 | |||
| 9c12ba60aa | |||
| 3c21938295 | |||
| 8d9e254e0c | |||
| e52dafcaaf | |||
| 676b7d1739 | |||
| 490d3152ab | |||
| 1b68a4f98e | |||
| 58fac19a5c | |||
| 65850682a8 | |||
| 6c4df9aca9 | |||
| b110861ba1 | |||
| 13fcb571f7 | |||
| 9738a71922 | |||
| f45e3ca339 | |||
| c579e11db4 | |||
| 819f75e17c | |||
| 0828ee3b10 | |||
| 35094a786d | |||
| add2215e5a | |||
| efa99b1e71 | |||
| 1ebc66b9e2 | |||
| c852055ae1 | |||
| 8fb2cecd64 | |||
| 5d2952cd24 | |||
| 4a1fe267ca | |||
| 694b37b852 | |||
| 253f7deb62 | |||
| 3e62bbf561 | |||
| 0f9c75749d | |||
| 9c7f1d261f | |||
| 44a4800383 | |||
| 2e6f01b871 | |||
| 41bb627ef2 | |||
| b2fa06b5f5 | |||
| 69e9aa917a | |||
| 507bebda80 | |||
| e4a66c8a11 | |||
| ecdee78368 | |||
| 763ee75856 | |||
| 07fb0804ac | |||
| ced1c742c8 | |||
| 029b0e709a | |||
| 43ffccc67f | |||
| 23e9b733ee | |||
| f4ffa8123b | |||
| fd9e976346 | |||
| 85db61b8d3 | |||
| a2e1ac3972 | |||
| 0c3f2fd4b4 | |||
| b71f32e1b4 | |||
| f478643411 | |||
| 39cf1fea22 | |||
| f967d6ab43 | |||
| 448da01cea | |||
| a25888b4ba | |||
| 7f3508b8b3 | |||
| 1d880cdcf6 | |||
| c855702918 | |||
| 51023a1ae4 | |||
| 35364bd8ad | |||
| 0f715223e9 | |||
| 9ceace2a47 | |||
| 6e93c08ff2 | |||
| 3744cfd987 | |||
| 245abd5f16 | |||
| f559b49f44 | |||
| 8e9f50f465 | |||
| ae39cfb1be | |||
| 259c34d12b | |||
| fbeeadfd0f | |||
| 9ed89a324b | |||
| 49c17a0ce5 | |||
| a11211ecd1 | |||
| 8d2c04b287 | |||
| 7834fc9214 | |||
| 6bebfdc65d | |||
| c35f4a0988 | |||
| 86660d055c | |||
| 59dae982d4 | |||
| 8a3bf672e7 | |||
| cc05e9d8fb | |||
| ada4f107e7 | |||
| 3db58c533b | |||
| 480e4290a0 | |||
| 89c96d50ef | |||
| dfc3a7bf5c | |||
| 10f0fa65f3 | |||
| d23a449d57 | |||
| 753c7ae666 | |||
| ac7fa777a6 | |||
| 2b63d9f175 | |||
| 744a3463b2 | |||
| f70fdad9ae | |||
| 42df6cbca2 | |||
| c2e39cbc5d | |||
| ed0046fcd0 | |||
| 5e2f979f36 | |||
| 0b1065ff55 | |||
| 7db48b81b6 | |||
| f0ce3167c0 | |||
| ace6439758 | |||
| e38b948f0b | |||
| 2f74d1466e | |||
| 85c324b5d7 | |||
| edddf8a660 | |||
| 193e7f894d | |||
| 32cc486d89 | |||
| 0aec789659 | |||
| f92cedab9a | |||
| f84f93b167 | |||
| d33fbd8e47 | |||
| 3ab23201b4 | |||
| 39236ae68f | |||
| 5ee89b41ac | |||
| ec0ff4ffc2 | |||
| 1b6b2d7896 | |||
| 036241c819 | |||
| 2dc81999ef | |||
| 3f8a5874e6 | |||
| 838674c4a7 | |||
| 98a8781d70 | |||
| 85f4ab3944 | |||
| 25db3032ee | |||
| d638f4cad0 | |||
| 32fe612045 | |||
| 76d463dcc8 | |||
| 2daa432261 | |||
| d7b2c81db5 | |||
| b597a4559f | |||
| 18e3227c9a | |||
| 41b847b3c9 | |||
| ae2aea8fc0 | |||
| 567c5bc8db | |||
| 1fdf7d0cf4 | |||
| 5ffe28eec2 | |||
| 4e855b4cb0 | |||
| ae886c824c | |||
| 46b5442214 | |||
| c3deafd271 | |||
| de2da52941 | |||
| 8aa3d183ef | |||
| 6623b19b70 | |||
| 7a40b6e484 | |||
| d63dc32e71 | |||
| 54aa3bc5d4 | |||
| 6ebd616049 | |||
| c0439feef8 | |||
| 0e550322db | |||
| 7398d47728 | |||
| 9f0f7e8641 | |||
| f26e36440d | |||
| 8ff0aca6b4 | |||
| d4b564ee7a | |||
| 22a6bf999f | |||
| 09bae9bb14 | |||
| 874f7fbdff | |||
| 6d17d7d7a1 | |||
| 98dc21360a | |||
| 0d330051ed | |||
| f17c4cceac | |||
| a3072ffade | |||
| f60c544478 | |||
| fc320e0ab4 | |||
| 91c861e8d6 | |||
| 2640f4ad41 | |||
| 06f5828990 | |||
| 85604e1707 | |||
| ad7bc215d0 | |||
| f005676c90 | |||
| 17961165cf | |||
| 6ba2230804 | |||
| cacfaac52e | |||
| 4f09e18894 | |||
| 05f1912d19 | |||
| e15306464f | |||
| 28f75d5ad3 | |||
| 3021764401 | |||
| 2766e90fe0 | |||
| 10d5baa862 | |||
| 28a8997603 | |||
| 83d4771e6b | |||
| 0f4cd449b9 | |||
| 27843728d7 | |||
| 676ad491fe | |||
| 9a91537968 | |||
| 3eba0d9bab | |||
| b4995aa711 | |||
| 55353536e5 | |||
| e3d45fb37b | |||
| e3369608fd | |||
| 1c6390f829 | |||
| df64a6c583 | |||
| 59c638c64c | |||
| 9850541433 | |||
| 5140fd7819 | |||
| 5ae1b271e7 | |||
| c5cdff6213 | |||
| e05b3955a5 | |||
| e1c0bddff3 | |||
| 62297e63a2 | |||
| 54c325a631 | |||
| af99c9da34 | |||
| dbf5455656 | |||
| 4cb9edd9f0 | |||
| 60d23b14e7 | |||
| 12fdeac31c | |||
| 69a1a4611b | |||
| a46501b279 | |||
| bc1953dded | |||
| 789a695737 | |||
| 5f8a0b0728 | |||
| 9fdda223f5 | |||
| 1ff4b2b4eb | |||
| 0751a3ae7f | |||
| e6e08c111b | |||
| 004b96ec21 | |||
| 7cb98f6856 | |||
| fc86de34f8 | |||
| fe69da4cb8 | |||
| 27434e38f9 | |||
| 60ddafa4ff | |||
| ef8b6bf9e1 | |||
| 59cc7b2d3e | |||
| 6245bbff50 | |||
| 6331a0ab7a | |||
| c43ae314e0 | |||
| 250720ca4a | |||
| a5ac1fc34f | |||
| 1740aeca5e | |||
| 4f060d9384 | |||
| acd244f873 | |||
| dfef20658c | |||
| 8255e091f0 | |||
| 96037591c5 | |||
| 692949fd0a | |||
| 4bf75de6fd | |||
| 05890480e2 | |||
| 70d7bc2099 | |||
| e2d8d53a10 | |||
| 402c139957 | |||
| 31e79ef54f | |||
| 39788e7e6c | |||
| 932c908075 | |||
| 443da9943a | |||
| cc1071fe7a | |||
| 3ac4fd59c5 | |||
| 5e93814283 | |||
| d29c07a663 | |||
| a558a67fbd | |||
| 153e1190ea | |||
| a80a641427 | |||
| acd7d5ad2f | |||
| 81ba4fa9a6 | |||
| 57f007c46e | |||
| d513640572 | |||
| 8c695e5044 | |||
| 395a966802 | |||
| 643894c882 | |||
| c7c28c0471 | |||
| 20ada81d43 | |||
| 07736e59bd | |||
| 3195ba646f | |||
| 2deee01592 | |||
| 890b09499e | |||
| 01c5fab84b | |||
| e9b7737692 | |||
| fe1072a06b | |||
| 59f308850e | |||
| e775a7581a | |||
| ec99e10b31 | |||
| 240d7921ba | |||
| 9ac006b114 | |||
| c3fef1cae2 | |||
| ca1c99a0d1 | |||
| 06ae7a20df | |||
| f536ecdc00 | |||
| a4bdd38367 | |||
| 6fb6d3e444 | |||
| a3952c37bf | |||
| c24ee72fe3 | |||
| f988b807c4 | |||
| cb1a596b10 | |||
| c41cd75b62 | |||
| 0df48f3002 | |||
| 2d58184080 | |||
| 1ef6e69d83 | |||
| dbd4af16c6 | |||
| 2263535d3a | |||
| 3ce4a5bf7f | |||
| f62c3431ff | |||
| a652084922 | |||
| ed30599db8 | |||
| d8752970e9 | |||
| 57a4c93cf5 | |||
| a116f5783d | |||
| 2730098c42 | |||
| 836d17359f | |||
| a4406bb137 | |||
| bbb67b415a | |||
| 0842360dbb | |||
| e58b23a54b | |||
| 72342bd8a5 | |||
| fa77fc3310 | |||
| 53fe2a7203 | |||
| 480dfafb4f | |||
| f5e13c5ceb | |||
| eadc902f84 | |||
| b461a3b64d | |||
| 75c758e5f4 | |||
| 05912b0381 | |||
| fb387a2c09 | |||
| 1380feef72 | |||
| 6c91a3022e | |||
| e55989120e | |||
| 14f12ccf51 | |||
| 82a1b02b4a | |||
| e99a2fbc56 | |||
| d3d23d18fb | |||
| cbf1b2af47 | |||
| 4f5fca4e67 | |||
| e0158a8ed7 | |||
| 40e7ba67d1 | |||
| e664605c90 | |||
| 5a51a6b179 | |||
| eb7929ccb6 | |||
| e85eec2e6b | |||
| 121394c0c0 | |||
| 5ad74d58f8 | |||
| afe2516d57 | |||
| ccf6e78cd5 | |||
| fef91fc8b9 | |||
| 4156587abe | |||
| 629eccaf09 | |||
| f89803eb64 | |||
| da12746a3a | |||
| b023019b0d | |||
| 1fdaa1083e | |||
| 2f8e846b9e | |||
| e42db52d14 | |||
| d4ec455ce0 | |||
| 0547c7ba91 | |||
| 8f4b809599 | |||
| 8432fb4fea | |||
| 84df2c86ae | |||
| 49ced23ba8 | |||
| 00bf2ca36f | |||
| b92861c7e3 | |||
| a189102628 | |||
| 58a6eb653b | |||
| 9159f5a004 | |||
| f1c570d793 | |||
| 832af39f34 | |||
| 9260f58803 | |||
| 1a5c515e45 | |||
| 87c8688f70 | |||
| d13179f9e4 | |||
| 75de21314c | |||
| 239f8e0905 | |||
| f4ac624bb3 | |||
| 2be0b98135 | |||
| 36c5719535 | |||
| 1f870bf76c | |||
| d5cc334e20 | |||
| fd98188ee4 | |||
| c3446f9c2d | |||
| e6e29b6c4c | |||
| 6096b5c4d8 | |||
| 838eadd47f | |||
| afb43531e8 | |||
| 3533e8b119 | |||
| 0e6ad13db8 | |||
| 0d725fcc2c | |||
| 7e747085d3 | |||
| f1376396c2 | |||
| 4eb9281f4d | |||
| c895816cb0 | |||
| 9f814c0f6a | |||
| e14aef9bd5 | |||
| 2b106a2b34 | |||
| f6494d2980 | |||
| 78a6c1a909 | |||
| c858643100 | |||
| 17b0bdc9fe | |||
| 2e0cdebb0c | |||
| a5f8955d78 | |||
| 0eca698a39 | |||
| 16f259da81 | |||
| c3ee477a1b | |||
| 33da35db04 | |||
| 533be1ec70 | |||
| b64573f5d4 | |||
| 1d6caa9a35 | |||
| c74b0943f3 | |||
| bb579294a0 | |||
| ad9f5f4dd7 | |||
| bf2e34f32e | |||
| bd57957df7 | |||
| 093db600ff | |||
| 131013f291 | |||
| 909d199379 | |||
| 5f16f4ab99 | |||
| fff95fa4e6 | |||
| a38327a39c | |||
| 686048dcce | |||
| 330c0f86de | |||
| 83317f1b80 | |||
| a416eb2cf6 | |||
| 2959c94bd3 |
@@ -49,6 +49,7 @@
|
||||
#include <dialogs/dialog_color_picker.h>
|
||||
|
||||
class COLOR_SETTINGS;
|
||||
class PCB_TEXTBOX;
|
||||
|
||||
/// A type that stores a container of 2d objects for each layer id
|
||||
typedef std::map<PCB_LAYER_ID, BVH_CONTAINER_2D*> MAP_CONTAINER_2D_BASE;
|
||||
@@ -356,6 +357,9 @@ private:
|
||||
void addShape( const PCB_DIMENSION_BASE* aDimension, CONTAINER_2D_BASE* aDstContainer,
|
||||
const BOARD_ITEM* aOwner );
|
||||
|
||||
void addShape( const PCB_TEXTBOX* aTextBox, CONTAINER_2D_BASE* aContainer,
|
||||
const BOARD_ITEM* aOwner );
|
||||
|
||||
void addSolidAreasShapes( const ZONE* aZone, CONTAINER_2D_BASE* aDstContainer,
|
||||
PCB_LAYER_ID aLayerId );
|
||||
|
||||
|
||||
@@ -44,6 +44,7 @@
|
||||
#include <pcb_painter.h> // for PCB_RENDER_SETTINGS
|
||||
#include <zone.h>
|
||||
#include <fp_text.h>
|
||||
#include <pcb_textbox.h>
|
||||
#include <convert_basic_shapes_to_polygon.h>
|
||||
#include <trigo.h>
|
||||
#include <geometry/shape_segment.h>
|
||||
@@ -720,6 +721,11 @@ void BOARD_ADAPTER::addShape( const PCB_SHAPE* aShape, CONTAINER_2D_BASE* aConta
|
||||
aShape->TransformShapeToPolygon( polyList, UNDEFINED_LAYER, 0, ARC_HIGH_DEF,
|
||||
ERROR_INSIDE );
|
||||
|
||||
// Some polygons can be a bit complex (especially when coming from a
|
||||
// picture ot a text converted to a polygon
|
||||
// So call Simplify before calling ConvertPolygonToTriangles, just in case.
|
||||
polyList.Simplify( SHAPE_POLY_SET::PM_FAST );
|
||||
|
||||
if( polyList.IsEmpty() ) // Just for caution
|
||||
break;
|
||||
|
||||
@@ -767,6 +773,32 @@ void BOARD_ADAPTER::addShape( const PCB_SHAPE* aShape, CONTAINER_2D_BASE* aConta
|
||||
}
|
||||
|
||||
|
||||
void BOARD_ADAPTER::addShape( const PCB_TEXTBOX* aTextBox, CONTAINER_2D_BASE* aContainer,
|
||||
const BOARD_ITEM* aOwner )
|
||||
{
|
||||
addText( aTextBox, aContainer, aOwner );
|
||||
|
||||
if( !aTextBox->IsBorderEnabled() )
|
||||
return;
|
||||
|
||||
// We cannot use PCB_TEXTBOX::TransformShapeToPolygon because it convert the textbox
|
||||
// as filled polygon even if there's no background colour.
|
||||
// So for polygon, we use PCB_SHAPE::TransformShapeToPolygon
|
||||
|
||||
if( aTextBox->GetShape() == SHAPE_T::RECT )
|
||||
addShape( static_cast<const PCB_SHAPE*>( aTextBox ), aContainer, aOwner );
|
||||
else
|
||||
{
|
||||
SHAPE_POLY_SET polyList;
|
||||
|
||||
aTextBox->PCB_SHAPE::TransformShapeToPolygon( polyList, UNDEFINED_LAYER, 0,
|
||||
ARC_HIGH_DEF, ERROR_INSIDE );
|
||||
|
||||
ConvertPolygonToTriangles( polyList, *aContainer, m_biuTo3Dunits, *aOwner );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void BOARD_ADAPTER::addSolidAreasShapes( const ZONE* aZone, CONTAINER_2D_BASE* aContainer,
|
||||
PCB_LAYER_ID aLayerId )
|
||||
{
|
||||
@@ -792,7 +824,7 @@ void BOARD_ADAPTER::buildPadOutlineAsSegments( const PAD* aPad, CONTAINER_2D_BAS
|
||||
}
|
||||
|
||||
// For other shapes, add outlines as thick segments in polygon buffer
|
||||
const std::shared_ptr<SHAPE_POLY_SET>& corners = aPad->GetEffectivePolygon();
|
||||
const std::shared_ptr<SHAPE_POLY_SET>& corners = aPad->GetEffectivePolygon( ERROR_INSIDE );
|
||||
const SHAPE_LINE_CHAIN& path = corners->COutline( 0 );
|
||||
|
||||
for( int j = 0; j < path.PointCount(); j++ )
|
||||
|
||||
@@ -604,9 +604,7 @@ void BOARD_ADAPTER::createLayers( REPORTER* aStatusReporter )
|
||||
break;
|
||||
|
||||
case PCB_TEXTBOX_T:
|
||||
addText( static_cast<PCB_TEXTBOX*>( item ), layerContainer, item );
|
||||
if( static_cast<PCB_TEXTBOX*>( item )->IsBorderEnabled() )
|
||||
addShape( static_cast<PCB_TEXTBOX*>( item ), layerContainer, item );
|
||||
addShape( static_cast<PCB_TEXTBOX*>( item ), layerContainer, item );
|
||||
break;
|
||||
|
||||
case PCB_DIM_ALIGNED_T:
|
||||
@@ -924,7 +922,6 @@ void BOARD_ADAPTER::createLayers( REPORTER* aStatusReporter )
|
||||
break;
|
||||
|
||||
case PCB_TEXTBOX_T:
|
||||
addText( static_cast<PCB_TEXTBOX*>( item ), layerContainer, item );
|
||||
addShape( static_cast<PCB_TEXTBOX*>( item ), layerContainer, item );
|
||||
break;
|
||||
|
||||
|
||||
@@ -51,7 +51,7 @@ void BOARD_ADAPTER::buildPadOutlineAsPolygon( const PAD* aPad, SHAPE_POLY_SET& a
|
||||
}
|
||||
|
||||
// For other shapes, add outlines as thick segments in polygon buffer
|
||||
const std::shared_ptr<SHAPE_POLY_SET>& corners = aPad->GetEffectivePolygon();
|
||||
const std::shared_ptr<SHAPE_POLY_SET>& corners = aPad->GetEffectivePolygon( ERROR_INSIDE );
|
||||
const SHAPE_LINE_CHAIN& path = corners->COutline( 0 );
|
||||
|
||||
for( int ii = 0; ii < path.PointCount(); ++ii )
|
||||
|
||||
@@ -637,6 +637,9 @@ void EDA_3D_CANVAS::OnMagnify( wxMouseEvent& event )
|
||||
|
||||
void EDA_3D_CANVAS::OnMouseMove( wxMouseEvent& event )
|
||||
{
|
||||
if( m_3d_render && m_3d_render->IsReloadRequestPending() )
|
||||
return; // Prevents using invalid m_3d_render_raytracing data
|
||||
|
||||
if( m_camera_is_moving )
|
||||
return;
|
||||
|
||||
|
||||
@@ -208,12 +208,6 @@ public:
|
||||
m_3dmousePivotPos = aPos;
|
||||
}
|
||||
|
||||
private:
|
||||
/**
|
||||
* Called by a wxPaintEvent event
|
||||
*/
|
||||
void OnPaint( wxPaintEvent& aEvent );
|
||||
|
||||
/**
|
||||
* The actual function to repaint the canvas.
|
||||
*
|
||||
@@ -222,6 +216,10 @@ private:
|
||||
*/
|
||||
void DoRePaint();
|
||||
|
||||
private:
|
||||
// The wxPaintEvent event. mainly calls DoRePaint()
|
||||
void OnPaint( wxPaintEvent& aEvent );
|
||||
|
||||
void OnEraseBackground( wxEraseEvent& event );
|
||||
|
||||
void OnRefreshRequest( wxEvent& aEvent );
|
||||
|
||||
@@ -483,23 +483,21 @@ void MODEL_3D::Draw( bool aTransparent, float aOpacity, bool aUseSelectedMateria
|
||||
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
[&]( std::pair<const MODEL_3D::MATERIAL*, float>& a,
|
||||
std::pair<const MODEL_3D::MATERIAL*, float>& b )
|
||||
{
|
||||
bool aInsideB = a.first->m_bbox.Inside( b.first->m_bbox );
|
||||
bool bInsideA = b.first->m_bbox.Inside( a.first->m_bbox );
|
||||
|
||||
return a.second > b.second;
|
||||
} );
|
||||
// If A is inside B, then A is rendered first
|
||||
if( aInsideB != bInsideA )
|
||||
return bInsideA;
|
||||
|
||||
if( a.second != b.second )
|
||||
return a.second > b.second;
|
||||
|
||||
return a.first > b.first; // compare pointers as a last resort
|
||||
} );
|
||||
|
||||
for( const std::pair<const MODEL_3D::MATERIAL*, float>& mat : materialsSorted )
|
||||
{
|
||||
|
||||
@@ -1388,10 +1388,14 @@ void RENDER_3D_OPENGL::renderTransparentModels( const glm::mat4 &aCameraViewMatr
|
||||
|
||||
// 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;
|
||||
} );
|
||||
[&]( std::pair<const MODELTORENDER *, float>& a,
|
||||
std::pair<const MODELTORENDER *, float>& b )
|
||||
{
|
||||
if( a.second != b.second )
|
||||
return a.second > b.second;
|
||||
|
||||
return a.first > b.first; // use pointers as a last resort
|
||||
} );
|
||||
|
||||
// Start rendering calls
|
||||
glPushMatrix();
|
||||
|
||||
@@ -1911,9 +1911,19 @@ void RENDER_3D_RAYTRACE::initializeBlockPositions()
|
||||
|
||||
const SFVEC2UI center( m_realBufferSize.x / 2, m_realBufferSize.y / 2 );
|
||||
std::sort( m_blockPositions.begin(), m_blockPositions.end(),
|
||||
[&]( const SFVEC2UI& a, const SFVEC2UI& b ) {
|
||||
[&]( const SFVEC2UI& a, const SFVEC2UI& b )
|
||||
{
|
||||
// Sort order: inside out.
|
||||
return distance( a, center ) < distance( b, center );
|
||||
float distanceA = distance( a, center );
|
||||
float distanceB = distance( b, center );
|
||||
|
||||
if( distanceA != distanceB )
|
||||
return distanceA < distanceB;
|
||||
|
||||
if( a[0] != b[0] )
|
||||
return a[0] < b[0];
|
||||
|
||||
return a[1] < b[1];
|
||||
} );
|
||||
|
||||
// Create m_shader buffer
|
||||
|
||||
@@ -794,8 +794,13 @@ void EDA_3D_VIEWER_FRAME::takeScreenshot( wxCommandEvent& event )
|
||||
}
|
||||
|
||||
// Be sure we have the latest 3D view (remember 3D view is buffered)
|
||||
m_canvas->Request_refresh( true );
|
||||
wxYield();
|
||||
// Also ensure any highlighted item is not highlighted when creating screen shot
|
||||
EDA_3D_VIEWER_SETTINGS::RENDER_SETTINGS& cfg = m_boardAdapter.m_Cfg->m_Render;
|
||||
bool allow_highlight = cfg.opengl_highlight_on_rollover;
|
||||
cfg.opengl_highlight_on_rollover = false;
|
||||
|
||||
m_canvas->DoRePaint(); // init first buffer
|
||||
m_canvas->DoRePaint(); // init second buffer
|
||||
|
||||
// Build image from the 3D buffer
|
||||
wxWindowUpdateLocker noUpdates( this );
|
||||
@@ -805,6 +810,8 @@ void EDA_3D_VIEWER_FRAME::takeScreenshot( wxCommandEvent& event )
|
||||
if( m_canvas )
|
||||
m_canvas->GetScreenshot( screenshotImage );
|
||||
|
||||
cfg.opengl_highlight_on_rollover = allow_highlight;
|
||||
|
||||
if( event.GetId() == ID_TOOL_SCREENCOPY_TOCLIBBOARD )
|
||||
{
|
||||
wxBitmap bitmap( screenshotImage );
|
||||
|
||||
@@ -167,7 +167,11 @@ BM2CMP_FRAME::BM2CMP_FRAME( KIWAY* aKiway, wxWindow* aParent ) :
|
||||
wxIcon icon;
|
||||
wxIconBundle icon_bundle;
|
||||
|
||||
icon.CopyFromBitmap( KiBitmap( BITMAPS::icon_bitmap2component ) );
|
||||
icon.CopyFromBitmap( KiBitmap( BITMAPS::icon_bitmap2component, 48 ) );
|
||||
icon_bundle.AddIcon( icon );
|
||||
icon.CopyFromBitmap( KiBitmap( BITMAPS::icon_bitmap2component, 128 ) );
|
||||
icon_bundle.AddIcon( icon );
|
||||
icon.CopyFromBitmap( KiBitmap( BITMAPS::icon_bitmap2component, 256 ) );
|
||||
icon_bundle.AddIcon( icon );
|
||||
icon.CopyFromBitmap( KiBitmap( BITMAPS::icon_bitmap2component_32 ) );
|
||||
icon_bundle.AddIcon( icon );
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
# KiCad.
|
||||
#
|
||||
# Note: This version string should follow the semantic versioning system
|
||||
set( KICAD_SEMANTIC_VERSION "7.0.8" )
|
||||
set( KICAD_SEMANTIC_VERSION "7.0.11-unknown" )
|
||||
|
||||
# Default the version to the semantic version.
|
||||
# This is overridden by the git repository tag though (if using git)
|
||||
|
||||
@@ -83,6 +83,8 @@
|
||||
/// Allows scripts install directory to be referenced by the program code.
|
||||
#define PYTHON_DEST "@PYTHON_DEST@"
|
||||
|
||||
#define PYTHON_SITE_PACKAGE_PATH "@PYTHON_SITE_PACKAGE_PATH@"
|
||||
|
||||
/// Allows scripts install directory to be referenced by the program code.
|
||||
#define KICAD_DATA "@KICAD_DATA@"
|
||||
|
||||
|
||||
@@ -1013,6 +1013,28 @@ void BuildBitmapInfo( std::unordered_map<BITMAPS, std::vector<BITMAP_INFO>>& aBi
|
||||
aBitmapInfoCache[BITMAPS::icon_pagelayout_editor].emplace_back( BITMAPS::icon_pagelayout_editor, wxT( "icon_pagelayout_editor_dark_128.png" ), 128, wxT( "dark" ) );
|
||||
aBitmapInfoCache[BITMAPS::icon_bitmap2component].emplace_back( BITMAPS::icon_bitmap2component, wxT( "icon_bitmap2component_dark_128.png" ), 128, wxT( "dark" ) );
|
||||
aBitmapInfoCache[BITMAPS::icon_pcbcalculator].emplace_back( BITMAPS::icon_pcbcalculator, wxT( "icon_pcbcalculator_dark_128.png" ), 128, wxT( "dark" ) );
|
||||
aBitmapInfoCache[BITMAPS::icon_cvpcb].emplace_back( BITMAPS::icon_cvpcb, wxT( "icon_cvpcb_256.png" ), 256, wxT( "light" ) );
|
||||
aBitmapInfoCache[BITMAPS::icon_eeschema].emplace_back( BITMAPS::icon_eeschema, wxT( "icon_eeschema_256.png" ), 256, wxT( "light" ) );
|
||||
aBitmapInfoCache[BITMAPS::icon_gerbview].emplace_back( BITMAPS::icon_gerbview, wxT( "icon_gerbview_256.png" ), 256, wxT( "light" ) );
|
||||
aBitmapInfoCache[BITMAPS::icon_kicad].emplace_back( BITMAPS::icon_kicad, wxT( "icon_kicad_256.png" ), 256, wxT( "light" ) );
|
||||
aBitmapInfoCache[BITMAPS::icon_kicad_nightly].emplace_back( BITMAPS::icon_kicad_nightly, wxT( "icon_kicad_nightly_256.png" ), 256, wxT( "light" ) );
|
||||
aBitmapInfoCache[BITMAPS::icon_libedit].emplace_back( BITMAPS::icon_libedit, wxT( "icon_libedit_256.png" ), 256, wxT( "light" ) );
|
||||
aBitmapInfoCache[BITMAPS::icon_modedit].emplace_back( BITMAPS::icon_modedit, wxT( "icon_modedit_256.png" ), 256, wxT( "light" ) );
|
||||
aBitmapInfoCache[BITMAPS::icon_pcbnew].emplace_back( BITMAPS::icon_pcbnew, wxT( "icon_pcbnew_256.png" ), 256, wxT( "light" ) );
|
||||
aBitmapInfoCache[BITMAPS::icon_pagelayout_editor].emplace_back( BITMAPS::icon_pagelayout_editor, wxT( "icon_pagelayout_editor_256.png" ), 256, wxT( "light" ) );
|
||||
aBitmapInfoCache[BITMAPS::icon_bitmap2component].emplace_back( BITMAPS::icon_bitmap2component, wxT( "icon_bitmap2component_256.png" ), 256, wxT( "light" ) );
|
||||
aBitmapInfoCache[BITMAPS::icon_pcbcalculator].emplace_back( BITMAPS::icon_pcbcalculator, wxT( "icon_pcbcalculator_256.png" ), 256, wxT( "light" ) );
|
||||
aBitmapInfoCache[BITMAPS::icon_cvpcb].emplace_back( BITMAPS::icon_cvpcb, wxT( "icon_cvpcb_dark_256.png" ), 256, wxT( "dark" ) );
|
||||
aBitmapInfoCache[BITMAPS::icon_eeschema].emplace_back( BITMAPS::icon_eeschema, wxT( "icon_eeschema_dark_256.png" ), 256, wxT( "dark" ) );
|
||||
aBitmapInfoCache[BITMAPS::icon_gerbview].emplace_back( BITMAPS::icon_gerbview, wxT( "icon_gerbview_dark_256.png" ), 256, wxT( "dark" ) );
|
||||
aBitmapInfoCache[BITMAPS::icon_kicad].emplace_back( BITMAPS::icon_kicad, wxT( "icon_kicad_dark_256.png" ), 256, wxT( "dark" ) );
|
||||
aBitmapInfoCache[BITMAPS::icon_kicad_nightly].emplace_back( BITMAPS::icon_kicad_nightly, wxT( "icon_kicad_nightly_dark_256.png" ), 256, wxT( "dark" ) );
|
||||
aBitmapInfoCache[BITMAPS::icon_libedit].emplace_back( BITMAPS::icon_libedit, wxT( "icon_libedit_dark_256.png" ), 256, wxT( "dark" ) );
|
||||
aBitmapInfoCache[BITMAPS::icon_modedit].emplace_back( BITMAPS::icon_modedit, wxT( "icon_modedit_dark_256.png" ), 256, wxT( "dark" ) );
|
||||
aBitmapInfoCache[BITMAPS::icon_pcbnew].emplace_back( BITMAPS::icon_pcbnew, wxT( "icon_pcbnew_dark_256.png" ), 256, wxT( "dark" ) );
|
||||
aBitmapInfoCache[BITMAPS::icon_pagelayout_editor].emplace_back( BITMAPS::icon_pagelayout_editor, wxT( "icon_pagelayout_editor_dark_256.png" ), 256, wxT( "dark" ) );
|
||||
aBitmapInfoCache[BITMAPS::icon_bitmap2component].emplace_back( BITMAPS::icon_bitmap2component, wxT( "icon_bitmap2component_dark_256.png" ), 256, wxT( "dark" ) );
|
||||
aBitmapInfoCache[BITMAPS::icon_pcbcalculator].emplace_back( BITMAPS::icon_pcbcalculator, wxT( "icon_pcbcalculator_dark_256.png" ), 256, wxT( "dark" ) );
|
||||
aBitmapInfoCache[BITMAPS::dialog_warning].emplace_back( BITMAPS::dialog_warning, wxT( "dialog_warning_48.png" ), 48, wxT( "light" ) );
|
||||
aBitmapInfoCache[BITMAPS::icon_3d].emplace_back( BITMAPS::icon_3d, wxT( "icon_3d_48.png" ), 48, wxT( "light" ) );
|
||||
aBitmapInfoCache[BITMAPS::icon_cvpcb].emplace_back( BITMAPS::icon_cvpcb, wxT( "icon_cvpcb_48.png" ), 48, wxT( "light" ) );
|
||||
|
||||
+1
-1
@@ -155,7 +155,7 @@ long KIDIALOG::getStyle( KD_TYPE aType )
|
||||
}
|
||||
|
||||
|
||||
bool OverrideLock( wxWindow* aParent, const wxString& aMessage )
|
||||
bool AskOverrideLock( wxWindow* aParent, const wxString& aMessage )
|
||||
{
|
||||
#ifdef __APPLE__
|
||||
// wxMessageDialog gets the button spacing wrong on Mac so we have to use wxRichMessageDialog.
|
||||
|
||||
@@ -435,7 +435,31 @@ bool DATABASE_CONNECTION::SelectOne( const std::string& aTable,
|
||||
for( short i = 0; i < results.columns(); ++i )
|
||||
{
|
||||
std::string column = toUTF8( results.column_name( i ) );
|
||||
aResult[ column ] = toUTF8( results.get<nanodbc::string>( i, NANODBC_TEXT( "" ) ) );
|
||||
|
||||
switch( results.column_datatype( i ) )
|
||||
{
|
||||
case SQL_DOUBLE:
|
||||
case SQL_FLOAT:
|
||||
case SQL_REAL:
|
||||
case SQL_DECIMAL:
|
||||
case SQL_NUMERIC:
|
||||
{
|
||||
try
|
||||
{
|
||||
aResult[column] = fmt::format( "{:G}", results.get<double>( i ) );
|
||||
}
|
||||
catch( nanodbc::null_access_error& e )
|
||||
{
|
||||
// Column was empty (null)
|
||||
aResult[column] = std::string();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
aResult[column] = toUTF8( results.get<nanodbc::string>( i, NANODBC_TEXT( "" ) ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
catch( nanodbc::database_error& e )
|
||||
@@ -525,27 +549,92 @@ bool DATABASE_CONNECTION::SelectAll( const std::string& aTable, const std::strin
|
||||
|
||||
timer.Stop();
|
||||
|
||||
try
|
||||
{
|
||||
while( results.next() )
|
||||
{
|
||||
ROW result;
|
||||
|
||||
for( short j = 0; j < results.columns(); ++j )
|
||||
auto handleException =
|
||||
[&]( std::runtime_error& aException, const std::string& aExtraContext = "" )
|
||||
{
|
||||
std::string column = toUTF8( results.column_name( j ) );
|
||||
result[column] = toUTF8( results.get<nanodbc::string>( j, NANODBC_TEXT( "" ) ) );
|
||||
m_lastError = aException.what();
|
||||
std::string extra = aExtraContext.empty() ? "" : ": " + aExtraContext;
|
||||
wxLogTrace( traceDatabase,
|
||||
wxT( "Exception while parsing result %d from SelectAll: %s%s" ),
|
||||
aResults.size(), m_lastError, extra );
|
||||
};
|
||||
|
||||
while( results.next() )
|
||||
{
|
||||
short columnCount = 0;
|
||||
ROW result;
|
||||
|
||||
try
|
||||
{
|
||||
columnCount = results.columns();
|
||||
}
|
||||
catch( nanodbc::database_error& e )
|
||||
{
|
||||
handleException( e );
|
||||
return false;
|
||||
}
|
||||
|
||||
for( short j = 0; j < columnCount; ++j )
|
||||
{
|
||||
std::string column;
|
||||
std::string columnExtraDbgInfo;
|
||||
int datatype = SQL_UNKNOWN_TYPE;
|
||||
|
||||
try
|
||||
{
|
||||
column = toUTF8( results.column_name( j ) );
|
||||
datatype = results.column_datatype( j );
|
||||
columnExtraDbgInfo = fmt::format( "column index {}, name '{}', type {}", j, column,
|
||||
datatype );
|
||||
}
|
||||
catch( nanodbc::index_range_error& e )
|
||||
{
|
||||
handleException( e, columnExtraDbgInfo );
|
||||
return false;
|
||||
}
|
||||
|
||||
aResults.emplace_back( std::move( result ) );
|
||||
switch( datatype )
|
||||
{
|
||||
case SQL_DOUBLE:
|
||||
case SQL_FLOAT:
|
||||
case SQL_REAL:
|
||||
case SQL_DECIMAL:
|
||||
case SQL_NUMERIC:
|
||||
{
|
||||
try
|
||||
{
|
||||
result[column] = fmt::format( "{:G}", results.get<double>( j ) );
|
||||
}
|
||||
catch( nanodbc::null_access_error& e )
|
||||
{
|
||||
// Column was empty (null)
|
||||
result[column] = std::string();
|
||||
}
|
||||
catch( std::runtime_error& e )
|
||||
{
|
||||
handleException( e, columnExtraDbgInfo );
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
try
|
||||
{
|
||||
result[column] = toUTF8( results.get<nanodbc::string>( j,
|
||||
NANODBC_TEXT( "" ) ) );
|
||||
}
|
||||
catch( std::runtime_error& e )
|
||||
{
|
||||
handleException( e, columnExtraDbgInfo );
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch( nanodbc::database_error& e )
|
||||
{
|
||||
m_lastError = e.what();
|
||||
wxLogTrace( traceDatabase, wxT( "Exception while parsing results from SelectAll: %s" ),
|
||||
m_lastError );
|
||||
return false;
|
||||
|
||||
aResults.emplace_back( std::move( result ) );
|
||||
}
|
||||
|
||||
wxLogTrace( traceDatabase, wxT( "SelectAll from %s completed in %0.1f ms" ), aTable,
|
||||
|
||||
+44
-1
@@ -133,12 +133,41 @@ DIALOG_SHIM::DIALOG_SHIM( wxWindow* aParent, wxWindowID id, const wxString& titl
|
||||
Pgm().App().SetTopWindow( (EDA_BASE_FRAME*) kiwayHolder );
|
||||
#endif
|
||||
|
||||
Connect( wxEVT_PAINT, wxPaintEventHandler( DIALOG_SHIM::OnPaint ) );
|
||||
Bind( wxEVT_PAINT, &DIALOG_SHIM::OnPaint, this );
|
||||
}
|
||||
|
||||
|
||||
DIALOG_SHIM::~DIALOG_SHIM()
|
||||
{
|
||||
Unbind( wxEVT_CLOSE_WINDOW, &DIALOG_SHIM::OnCloseWindow, this );
|
||||
Unbind( wxEVT_BUTTON, &DIALOG_SHIM::OnButton, this );
|
||||
Unbind( wxEVT_PAINT, &DIALOG_SHIM::OnPaint, this );
|
||||
|
||||
std::function<void( wxWindowList& )> disconnectFocusHandlers = [&]( wxWindowList& children )
|
||||
{
|
||||
for( wxWindow* child : children )
|
||||
{
|
||||
if( wxTextCtrl* textCtrl = dynamic_cast<wxTextCtrl*>( child ) )
|
||||
{
|
||||
textCtrl->Disconnect( wxEVT_SET_FOCUS,
|
||||
wxFocusEventHandler( DIALOG_SHIM::onChildSetFocus ), nullptr,
|
||||
this );
|
||||
}
|
||||
else if( wxStyledTextCtrl* scintilla = dynamic_cast<wxStyledTextCtrl*>( child ) )
|
||||
{
|
||||
scintilla->Disconnect( wxEVT_SET_FOCUS,
|
||||
wxFocusEventHandler( DIALOG_SHIM::onChildSetFocus ), nullptr,
|
||||
this );
|
||||
}
|
||||
else
|
||||
{
|
||||
disconnectFocusHandlers( child->GetChildren() );
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
disconnectFocusHandlers( GetChildren() );
|
||||
|
||||
// if the dialog is quasi-modal, this will end its event loop
|
||||
if( IsQuasiModal() )
|
||||
EndQuasiModal( wxID_CANCEL );
|
||||
@@ -259,6 +288,14 @@ bool DIALOG_SHIM::Show( bool show )
|
||||
std::max( wxDialog::GetSize().y, savedDialogRect.GetSize().y ),
|
||||
0 );
|
||||
}
|
||||
#ifdef __WXMAC__
|
||||
if( m_parent != nullptr )
|
||||
{
|
||||
if( wxDisplay::GetFromPoint( m_parent->GetPosition() )
|
||||
!= wxDisplay::GetFromPoint( savedDialogRect.GetPosition() ) )
|
||||
Centre();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else if( m_initialSize != wxDefaultSize )
|
||||
SetSize( m_initialSize );
|
||||
@@ -282,6 +319,9 @@ bool DIALOG_SHIM::Show( bool show )
|
||||
ret = wxDialog::Show( show );
|
||||
}
|
||||
|
||||
if( m_parent )
|
||||
m_parent->SetFocus();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -483,6 +523,9 @@ int DIALOG_SHIM::ShowQuasiModal()
|
||||
|
||||
m_qmodal_showing = false;
|
||||
|
||||
if( parent )
|
||||
parent->SetFocus();
|
||||
|
||||
return GetReturnCode();
|
||||
}
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ static PASTE_MODE g_paste_mode = PASTE_MODE::UNIQUE_ANNOTATIONS;
|
||||
|
||||
DIALOG_PASTE_SPECIAL::DIALOG_PASTE_SPECIAL( wxWindow* aParent,
|
||||
PASTE_MODE* aMode,
|
||||
wxString aReplacement ) :
|
||||
const wxString& aReplacement ) :
|
||||
DIALOG_PASTE_SPECIAL_BASE( aParent ),
|
||||
m_mode( aMode )
|
||||
{
|
||||
@@ -45,7 +45,7 @@ DIALOG_PASTE_SPECIAL::DIALOG_PASTE_SPECIAL( wxWindow* aParent,
|
||||
"with '%s'." ),
|
||||
aReplacement ) );
|
||||
|
||||
m_sdbSizerOK->SetFocus();
|
||||
m_pasteOptions->SetFocus();
|
||||
|
||||
// Now all widgets have the size fixed, call FinishDialogSettings
|
||||
finishDialogSettings();
|
||||
@@ -64,3 +64,11 @@ bool DIALOG_PASTE_SPECIAL::TransferDataFromWindow()
|
||||
g_paste_mode = *m_mode = static_cast<PASTE_MODE>( m_pasteOptions->GetSelection() );
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void DIALOG_PASTE_SPECIAL::onRadioBoxEvent( wxCommandEvent& event )
|
||||
{
|
||||
event.Skip();
|
||||
|
||||
m_sdbSizerOK->SetFocus();
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// C++ code generated with wxFormBuilder (version 3.10.1-0-g8feb16b)
|
||||
// C++ code generated with wxFormBuilder (version 4.0.0-0-g0efcecf)
|
||||
// http://www.wxformbuilder.org/
|
||||
//
|
||||
// PLEASE DO *NOT* EDIT THIS FILE!
|
||||
@@ -45,12 +45,12 @@ DIALOG_PASTE_SPECIAL_BASE::DIALOG_PASTE_SPECIAL_BASE( wxWindow* parent, wxWindow
|
||||
this->Centre( wxBOTH );
|
||||
|
||||
// Connect Events
|
||||
m_sdbSizerOK->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_PASTE_SPECIAL_BASE::onOKButton ), NULL, this );
|
||||
m_pasteOptions->Connect( wxEVT_COMMAND_RADIOBOX_SELECTED, wxCommandEventHandler( DIALOG_PASTE_SPECIAL_BASE::onRadioBoxEvent ), NULL, this );
|
||||
}
|
||||
|
||||
DIALOG_PASTE_SPECIAL_BASE::~DIALOG_PASTE_SPECIAL_BASE()
|
||||
{
|
||||
// Disconnect Events
|
||||
m_sdbSizerOK->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_PASTE_SPECIAL_BASE::onOKButton ), NULL, this );
|
||||
m_pasteOptions->Disconnect( wxEVT_COMMAND_RADIOBOX_SELECTED, wxCommandEventHandler( DIALOG_PASTE_SPECIAL_BASE::onRadioBoxEvent ), NULL, this );
|
||||
|
||||
}
|
||||
|
||||
@@ -1,163 +1,165 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
|
||||
<?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">dialog_paste_special_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">dialog_paste_special</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="Dialog" expanded="1">
|
||||
<property name="aui_managed">0</property>
|
||||
<property name="aui_manager_style">wxAUI_MGR_DEFAULT</property>
|
||||
<property name="bg"></property>
|
||||
<property name="center">wxBOTH</property>
|
||||
<property name="context_help"></property>
|
||||
<property name="context_menu">1</property>
|
||||
<property name="enabled">1</property>
|
||||
<property name="event_handler">impl_virtual</property>
|
||||
<property name="extra_style"></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">-1,-1</property>
|
||||
<property name="name">DIALOG_PASTE_SPECIAL_BASE</property>
|
||||
<property name="pos"></property>
|
||||
<property name="size">-1,-1</property>
|
||||
<property name="style">wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER</property>
|
||||
<property name="subclass">DIALOG_SHIM; dialog_shim.h</property>
|
||||
<property name="title">Paste Special</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"></property>
|
||||
<object class="wxBoxSizer" expanded="1">
|
||||
<FileVersion major="1" minor="17"/>
|
||||
<object class="Project" expanded="true">
|
||||
<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">dialog_paste_special_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">dialog_paste_special</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="Dialog" expanded="true">
|
||||
<property name="aui_managed">0</property>
|
||||
<property name="aui_manager_style">wxAUI_MGR_DEFAULT</property>
|
||||
<property name="bg"></property>
|
||||
<property name="center">wxBOTH</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="extra_style"></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">-1,-1</property>
|
||||
<property name="name">DIALOG_PASTE_SPECIAL_BASE</property>
|
||||
<property name="pos"></property>
|
||||
<property name="size">-1,-1</property>
|
||||
<property name="style">wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER</property>
|
||||
<property name="subclass">DIALOG_SHIM; dialog_shim.h</property>
|
||||
<property name="title">Paste Special</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"></property>
|
||||
<object class="wxBoxSizer" expanded="true">
|
||||
<property name="minimum_size"></property>
|
||||
<property name="name">m_mainSizer</property>
|
||||
<property name="orient">wxVERTICAL</property>
|
||||
<property name="permission">none</property>
|
||||
<object class="sizeritem" expanded="true">
|
||||
<property name="border">10</property>
|
||||
<property name="flag">wxALL|wxEXPAND</property>
|
||||
<property name="proportion">1</property>
|
||||
<object class="wxBoxSizer" expanded="true">
|
||||
<property name="minimum_size"></property>
|
||||
<property name="name">optionsSizer</property>
|
||||
<property name="orient">wxVERTICAL</property>
|
||||
<property name="permission">none</property>
|
||||
<object class="sizeritem" expanded="true">
|
||||
<property name="border">5</property>
|
||||
<property name="flag">wxALL</property>
|
||||
<property name="proportion">0</property>
|
||||
<object class="wxRadioBox" expanded="true">
|
||||
<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="choices">"Assign unique reference designators to pasted symbols" "Keep existing reference designators, even if they are duplicated" "Clear reference designators on all pasted symbols"</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">Paste Options</property>
|
||||
<property name="majorDimension">1</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="name">m_mainSizer</property>
|
||||
<property name="orient">wxVERTICAL</property>
|
||||
<property name="permission">none</property>
|
||||
<object class="sizeritem" expanded="1">
|
||||
<property name="border">10</property>
|
||||
<property name="flag">wxALL|wxEXPAND</property>
|
||||
<property name="proportion">1</property>
|
||||
<object class="wxBoxSizer" expanded="1">
|
||||
<property name="minimum_size"></property>
|
||||
<property name="name">optionsSizer</property>
|
||||
<property name="orient">wxVERTICAL</property>
|
||||
<property name="permission">none</property>
|
||||
<object class="sizeritem" expanded="1">
|
||||
<property name="border">5</property>
|
||||
<property name="flag">wxALL</property>
|
||||
<property name="proportion">0</property>
|
||||
<object class="wxRadioBox" 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="choices">"Assign unique reference designators to pasted symbols" "Keep existing reference designators, even if they are duplicated" "Clear reference designators on all pasted symbols"</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="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">Paste Options</property>
|
||||
<property name="majorDimension">1</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_pasteOptions</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="selection">1</property>
|
||||
<property name="show">1</property>
|
||||
<property name="size"></property>
|
||||
<property name="style">wxRA_SPECIFY_COLS</property>
|
||||
<property name="subclass">; ; forward_declare</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>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
<object class="sizeritem" expanded="1">
|
||||
<property name="border">6</property>
|
||||
<property name="flag">wxALL|wxEXPAND</property>
|
||||
<property name="proportion">0</property>
|
||||
<object class="wxStdDialogButtonSizer" expanded="1">
|
||||
<property name="Apply">0</property>
|
||||
<property name="Cancel">1</property>
|
||||
<property name="ContextHelp">0</property>
|
||||
<property name="Help">0</property>
|
||||
<property name="No">0</property>
|
||||
<property name="OK">1</property>
|
||||
<property name="Save">0</property>
|
||||
<property name="Yes">0</property>
|
||||
<property name="minimum_size"></property>
|
||||
<property name="name">m_sdbSizer</property>
|
||||
<property name="permission">protected</property>
|
||||
<event name="OnOKButtonClick">onOKButton</event>
|
||||
</object>
|
||||
</object>
|
||||
<property name="moveable">1</property>
|
||||
<property name="name">m_pasteOptions</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="selection">1</property>
|
||||
<property name="show">1</property>
|
||||
<property name="size"></property>
|
||||
<property name="style">wxRA_SPECIFY_COLS</property>
|
||||
<property name="subclass">; ; forward_declare</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="OnRadioBox">onRadioBoxEvent</event>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
<object class="sizeritem" expanded="true">
|
||||
<property name="border">6</property>
|
||||
<property name="flag">wxALL|wxEXPAND</property>
|
||||
<property name="proportion">0</property>
|
||||
<object class="wxStdDialogButtonSizer" expanded="true">
|
||||
<property name="Apply">0</property>
|
||||
<property name="Cancel">1</property>
|
||||
<property name="ContextHelp">0</property>
|
||||
<property name="Help">0</property>
|
||||
<property name="No">0</property>
|
||||
<property name="OK">1</property>
|
||||
<property name="Save">0</property>
|
||||
<property name="Yes">0</property>
|
||||
<property name="minimum_size"></property>
|
||||
<property name="name">m_sdbSizer</property>
|
||||
<property name="permission">protected</property>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
</wxFormBuilder_Project>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// C++ code generated with wxFormBuilder (version 3.10.1-0-g8feb16b)
|
||||
// C++ code generated with wxFormBuilder (version 4.0.0-0-g0efcecf)
|
||||
// http://www.wxformbuilder.org/
|
||||
//
|
||||
// PLEASE DO *NOT* EDIT THIS FILE!
|
||||
@@ -38,7 +38,7 @@ class DIALOG_PASTE_SPECIAL_BASE : public DIALOG_SHIM
|
||||
wxButton* m_sdbSizerCancel;
|
||||
|
||||
// Virtual event handlers, override them in your derived class
|
||||
virtual void onOKButton( wxCommandEvent& event ) { event.Skip(); }
|
||||
virtual void onRadioBoxEvent( wxCommandEvent& event ) { event.Skip(); }
|
||||
|
||||
|
||||
public:
|
||||
|
||||
@@ -113,7 +113,7 @@ void DS_DRAW_ITEM_LIST::GetTextVars( wxArrayString* aVars )
|
||||
wxString DS_DRAW_ITEM_LIST::BuildFullText( const wxString& aTextbase )
|
||||
{
|
||||
std::function<bool( wxString* )> wsResolver =
|
||||
[ this ]( wxString* token ) -> bool
|
||||
[&]( wxString* token ) -> bool
|
||||
{
|
||||
bool tokenUpdated = false;
|
||||
|
||||
@@ -166,10 +166,24 @@ wxString DS_DRAW_ITEM_LIST::BuildFullText( const wxString& aTextbase )
|
||||
}
|
||||
else if( m_titleBlock )
|
||||
{
|
||||
// no need for tokenUpdated; TITLE_BLOCK::TextVarResolver() does a full
|
||||
// resolve
|
||||
if( m_titleBlock->TextVarResolver( token, m_project ) )
|
||||
{
|
||||
// No need for tokenUpdated; TITLE_BLOCK::TextVarResolver() already goes
|
||||
// up to the project.
|
||||
//
|
||||
// However, the title block may have variables in it itself, so we need
|
||||
// to run the worksheet resolver again.
|
||||
//
|
||||
const TITLE_BLOCK* savedTitleBlock = m_titleBlock;
|
||||
|
||||
m_titleBlock = nullptr;
|
||||
{
|
||||
*token = ExpandTextVars( *token, &wsResolver );
|
||||
}
|
||||
m_titleBlock = savedTitleBlock;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if( m_properties && m_properties->count( *token ) )
|
||||
{
|
||||
@@ -356,5 +370,6 @@ void KIGFX::DS_PAINTER::DrawBorder( const PAGE_INFO* aPageInfo, int aScaleFactor
|
||||
// Use a gray color for the border color
|
||||
m_gal->SetStrokeColor( m_renderSettings.m_pageBorderColor );
|
||||
m_gal->SetIsFill( false );
|
||||
m_gal->SetLineWidth( m_renderSettings.GetDefaultPenWidth() );
|
||||
m_gal->DrawRectangle( origin, end );
|
||||
}
|
||||
|
||||
@@ -106,14 +106,22 @@ void DS_PROXY_VIEW_ITEM::ViewDraw( int aLayer, VIEW* aView ) const
|
||||
|
||||
buildDrawList( aView, m_properties, &drawList );
|
||||
|
||||
BOX2I viewport( aView->GetViewport().GetOrigin(), aView->GetViewport().GetSize() );
|
||||
|
||||
// Draw the title block normally even if the view is flipped
|
||||
bool flipped = gal->IsFlippedX();
|
||||
|
||||
if( flipped )
|
||||
{
|
||||
int pageWidth = m_pageInfo->GetWidthMils() * m_mils2IUscalefactor;
|
||||
|
||||
gal->Save();
|
||||
gal->Translate( VECTOR2D( m_pageInfo->GetWidthMils() * m_mils2IUscalefactor, 0 ) );
|
||||
gal->Translate( VECTOR2D( pageWidth, 0 ) );
|
||||
gal->Scale( VECTOR2D( -1.0, 1.0 ) );
|
||||
|
||||
int right = pageWidth - viewport.GetLeft();
|
||||
int left = right - viewport.GetWidth();
|
||||
viewport.SetOrigin( left, viewport.GetTop() );
|
||||
}
|
||||
|
||||
DS_PAINTER ws_painter( gal );
|
||||
@@ -126,8 +134,6 @@ void DS_PROXY_VIEW_ITEM::ViewDraw( int aLayer, VIEW* aView ) const
|
||||
ws_settings->SetDefaultFont( settings->GetDefaultFont() );
|
||||
|
||||
// Draw all the components that make the drawing sheet
|
||||
BOX2I viewport( aView->GetViewport().GetOrigin(), aView->GetViewport().GetSize() );
|
||||
|
||||
for( DS_DRAW_ITEM_BASE* item = drawList.GetFirst(); item; item = drawList.GetNext() )
|
||||
{
|
||||
if( viewport.Intersects( item->GetApproxBBox() ) )
|
||||
|
||||
@@ -230,6 +230,15 @@ bool EDA_DRAW_FRAME::LockFile( const wxString& aFileName )
|
||||
|
||||
m_file_checker = std::make_unique<LOCKFILE>( aFileName );
|
||||
|
||||
if( !m_file_checker->Valid() && m_file_checker->IsLockedByMe() )
|
||||
{
|
||||
// If we cannot acquire the lock but we appear to be the one who
|
||||
// locked it, check to see if there is another KiCad instance running.
|
||||
// If there is not, then we can override the lock. This could happen if
|
||||
// KiCad crashed or was interrupted
|
||||
if( !Pgm().SingleInstance()->IsAnotherRunning() )
|
||||
m_file_checker->OverrideLock();
|
||||
}
|
||||
// If the file is valid, return true. This could mean that the file is
|
||||
// locked or it could mean that the file is read-only
|
||||
return m_file_checker->Valid();
|
||||
|
||||
+10
-6
@@ -881,7 +881,8 @@ void EDA_TEXT::Format( OUTPUTFORMATTER* aFormatter, int aNestLevel, int aControl
|
||||
|
||||
|
||||
std::shared_ptr<SHAPE_COMPOUND> EDA_TEXT::GetEffectiveTextShape( bool aTriangulate,
|
||||
bool aUseTextRotation ) const
|
||||
const BOX2I& aBBox,
|
||||
const EDA_ANGLE& aAngle ) const
|
||||
{
|
||||
std::shared_ptr<SHAPE_COMPOUND> shape = std::make_shared<SHAPE_COMPOUND>();
|
||||
KIGFX::GAL_DISPLAY_OPTIONS empty_opts;
|
||||
@@ -893,17 +894,20 @@ std::shared_ptr<SHAPE_COMPOUND> EDA_TEXT::GetEffectiveTextShape( bool aTriangula
|
||||
|
||||
std::vector<std::unique_ptr<KIFONT::GLYPH>>* cache = nullptr;
|
||||
|
||||
if( aUseTextRotation )
|
||||
if( aBBox.GetWidth() )
|
||||
{
|
||||
drawPos = aBBox.GetCenter();
|
||||
attrs.m_Halign = GR_TEXT_H_ALIGN_CENTER;
|
||||
attrs.m_Valign = GR_TEXT_V_ALIGN_CENTER;
|
||||
attrs.m_Angle = aAngle;
|
||||
}
|
||||
else
|
||||
{
|
||||
attrs.m_Angle = GetDrawRotation();
|
||||
|
||||
if( font->IsOutline() )
|
||||
cache = GetRenderCache( font, shownText, VECTOR2I() );
|
||||
}
|
||||
else
|
||||
{
|
||||
attrs.m_Angle = ANGLE_0;
|
||||
}
|
||||
|
||||
if( aTriangulate )
|
||||
{
|
||||
|
||||
@@ -253,11 +253,6 @@ wxString FILENAME_RESOLVER::ResolvePath( const wxString& aFileName, const wxStri
|
||||
// first attempt to use the name as specified:
|
||||
wxString tname = aFileName;
|
||||
|
||||
#ifdef _WIN32
|
||||
// translate from KiCad's internal UNIX-like path to MSWin paths
|
||||
tname.Replace( wxT( "/" ), wxT( "\\" ) );
|
||||
#endif
|
||||
|
||||
// Note: variable expansion must preferably be performed via a threadsafe wrapper for the
|
||||
// getenv() system call. If we allow the wxFileName::Normalize() routine to perform expansion
|
||||
// then we will have a race condition since wxWidgets does not assure a threadsafe wrapper
|
||||
|
||||
@@ -26,9 +26,15 @@
|
||||
#include <macros.h>
|
||||
#include <font/fontconfig.h>
|
||||
|
||||
#ifdef __WIN32__
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
using namespace fontconfig;
|
||||
|
||||
static FONTCONFIG* g_config = nullptr;
|
||||
static bool g_fcInitSuccess = false;
|
||||
|
||||
/**
|
||||
* A simple wrapper to avoid exporing fontconfig in the header
|
||||
@@ -50,11 +56,41 @@ FONTCONFIG::FONTCONFIG()
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* This is simply a wrapper to call FcInit() with SEH for Windows
|
||||
* SEH on Windows can only be used in functions without objects that might be unwinded
|
||||
* (basically objects with destructors)
|
||||
* For example, new FONTCONFIG() in Fontconfig() is creating a object with a destructor
|
||||
* that *might* need to be unwinded. MSVC catches this and throws a compile error
|
||||
*/
|
||||
static void bootstrapFc()
|
||||
{
|
||||
#if defined( _MSC_VER )
|
||||
__try
|
||||
{
|
||||
#endif
|
||||
FcInit();
|
||||
g_fcInitSuccess = true;
|
||||
#if defined( _MSC_VER )
|
||||
}
|
||||
__except( GetExceptionCode() == STATUS_IN_PAGE_ERROR ? EXCEPTION_EXECUTE_HANDLER
|
||||
: EXCEPTION_CONTINUE_SEARCH )
|
||||
{
|
||||
g_fcInitSuccess = false;
|
||||
// We have documented cases that fontconfig while trying to cache fonts
|
||||
// ends up using freetype to try and get font info
|
||||
// freetype itself reads fonts through memory mapping instead of normal file APIs
|
||||
// there are crashes reading fonts sometimes as a result that return STATUS_IN_PAGE_ERROR
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
FONTCONFIG* Fontconfig()
|
||||
{
|
||||
if( !g_config )
|
||||
{
|
||||
FcInit();
|
||||
bootstrapFc();
|
||||
g_config = new FONTCONFIG();
|
||||
}
|
||||
|
||||
@@ -154,6 +190,10 @@ FONTCONFIG::FF_RESULT FONTCONFIG::FindFont( const wxString &aFontName, wxString
|
||||
int& aFaceIndex, bool aBold, bool aItalic )
|
||||
{
|
||||
FF_RESULT retval = FF_RESULT::FF_ERROR;
|
||||
|
||||
if( !g_fcInitSuccess )
|
||||
return retval;
|
||||
|
||||
wxString qualifiedFontName = aFontName;
|
||||
|
||||
wxScopedCharBuffer const fcBuffer = qualifiedFontName.ToUTF8();
|
||||
@@ -271,6 +311,9 @@ FONTCONFIG::FF_RESULT FONTCONFIG::FindFont( const wxString &aFontName, wxString
|
||||
|
||||
void FONTCONFIG::ListFonts( std::vector<std::string>& aFonts, const std::string& aDesiredLang )
|
||||
{
|
||||
if( !g_fcInitSuccess )
|
||||
return;
|
||||
|
||||
// be sure to cache bust if the language changed
|
||||
if( m_fontInfoCache.empty() || m_fontCacheLastLang != aDesiredLang )
|
||||
{
|
||||
|
||||
@@ -349,14 +349,14 @@ VECTOR2I OUTLINE_FONT::getTextAsGlyphsUnlocked( BOX2I* aBBox,
|
||||
hb_buffer_guess_segment_properties( buf ); // guess direction, script, and language based on
|
||||
// contents
|
||||
|
||||
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 );
|
||||
|
||||
hb_font_t* referencedFont = hb_ft_font_create_referenced( face );
|
||||
hb_ft_font_set_funcs( referencedFont );
|
||||
hb_shape( referencedFont, buf, nullptr, 0 );
|
||||
|
||||
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 );
|
||||
|
||||
VECTOR2D scaleFactor( glyphSize.x / faceSize(), -glyphSize.y / faceSize() );
|
||||
scaleFactor = scaleFactor * m_outlineFontSizeCompensation;
|
||||
|
||||
|
||||
@@ -94,9 +94,10 @@ public:
|
||||
private:
|
||||
struct CACHED_BITMAP
|
||||
{
|
||||
GLuint id;
|
||||
int w, h;
|
||||
size_t size;
|
||||
GLuint id;
|
||||
int w, h;
|
||||
size_t size;
|
||||
long long int accessTime;
|
||||
};
|
||||
|
||||
GLuint cacheBitmap( const BITMAP_BASE* aBitmap );
|
||||
@@ -105,9 +106,9 @@ private:
|
||||
const size_t m_cacheMaxSize = 256 * 1024 * 1024;
|
||||
|
||||
std::map<const KIID, CACHED_BITMAP> m_bitmaps;
|
||||
std::list<KIID> m_cacheLru;
|
||||
size_t m_cacheSize;
|
||||
std::list<GLuint> m_freedTextureIds;
|
||||
std::list<KIID> m_cacheLru;
|
||||
size_t m_cacheSize;
|
||||
std::list<GLuint> m_freedTextureIds;
|
||||
};
|
||||
|
||||
}; // namespace KIGFX
|
||||
@@ -130,6 +131,7 @@ GLuint GL_BITMAP_CACHE::RequestBitmap( const BITMAP_BASE* aBitmap )
|
||||
// A bitmap is found in cache bitmap. Ensure the associated texture is still valid.
|
||||
if( glIsTexture( it->second.id ) )
|
||||
{
|
||||
it->second.accessTime = wxGetUTCTimeMillis().GetValue();
|
||||
return it->second.id;
|
||||
}
|
||||
else
|
||||
@@ -182,56 +184,115 @@ GLuint GL_BITMAP_CACHE::cacheBitmap( const BITMAP_BASE* aBitmap )
|
||||
m_freedTextureIds.pop_front();
|
||||
}
|
||||
|
||||
bmp.size = bmp.w * bmp.h * 4;
|
||||
auto buf = std::make_unique<uint8_t[]>( bmp.size );
|
||||
glPixelStorei( GL_UNPACK_ALIGNMENT, 1 );
|
||||
|
||||
for( int y = 0; y < bmp.h; y++ )
|
||||
if( imgData.HasAlpha() || imgData.HasMask() )
|
||||
{
|
||||
for( int x = 0; x < bmp.w; x++ )
|
||||
bmp.size = bmp.w * bmp.h * 4;
|
||||
auto buf = std::make_unique<uint8_t[]>( bmp.size );
|
||||
|
||||
uint8_t* dstP = buf.get();
|
||||
uint8_t* srcP = imgData.GetData();
|
||||
|
||||
long long pxCount = static_cast<long long>( bmp.w ) * bmp.h;
|
||||
|
||||
if( imgData.HasAlpha() )
|
||||
{
|
||||
uint8_t* p = buf.get() + ( bmp.w * y + x ) * 4;
|
||||
uint8_t* srcAlpha = imgData.GetAlpha();
|
||||
|
||||
p[0] = imgData.GetRed( x, y );
|
||||
p[1] = imgData.GetGreen( x, y );
|
||||
p[2] = imgData.GetBlue( x, y );
|
||||
for( long long px = 0; px < pxCount; px++ )
|
||||
{
|
||||
memcpy( dstP, srcP, 3 );
|
||||
dstP[3] = *srcAlpha;
|
||||
|
||||
if( imgData.HasAlpha() )
|
||||
p[3] = imgData.GetAlpha( x, y );
|
||||
else if( imgData.HasMask() && p[0] == imgData.GetMaskRed()
|
||||
&& p[1] == imgData.GetMaskGreen() && p[2] == imgData.GetMaskBlue() )
|
||||
p[3] = wxALPHA_TRANSPARENT;
|
||||
else
|
||||
p[3] = wxALPHA_OPAQUE;
|
||||
srcAlpha += 1;
|
||||
srcP += 3;
|
||||
dstP += 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if( imgData.HasMask() )
|
||||
{
|
||||
uint8_t maskRed = imgData.GetMaskRed();
|
||||
uint8_t maskGreen = imgData.GetMaskGreen();
|
||||
uint8_t maskBlue = imgData.GetMaskBlue();
|
||||
|
||||
glBindTexture( GL_TEXTURE_2D, textureID );
|
||||
glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA8, bmp.w, bmp.h, 0, GL_RGBA, GL_UNSIGNED_BYTE,
|
||||
buf.get() );
|
||||
for( long long px = 0; px < pxCount; px++ )
|
||||
{
|
||||
memcpy( dstP, srcP, 3 );
|
||||
|
||||
if( srcP[0] == maskRed && srcP[1] == maskGreen && srcP[2] == maskBlue )
|
||||
dstP[3] = wxALPHA_TRANSPARENT;
|
||||
else
|
||||
dstP[3] = wxALPHA_OPAQUE;
|
||||
|
||||
srcP += 3;
|
||||
dstP += 4;
|
||||
}
|
||||
}
|
||||
|
||||
glBindTexture( GL_TEXTURE_2D, textureID );
|
||||
glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA8, bmp.w, bmp.h, 0, GL_RGBA, GL_UNSIGNED_BYTE,
|
||||
buf.get() );
|
||||
}
|
||||
else
|
||||
{
|
||||
bmp.size = bmp.w * bmp.h * 3;
|
||||
|
||||
uint8_t* srcP = imgData.GetData();
|
||||
|
||||
glBindTexture( GL_TEXTURE_2D, textureID );
|
||||
glTexImage2D( GL_TEXTURE_2D, 0, GL_RGB8, bmp.w, bmp.h, 0, GL_RGB, GL_UNSIGNED_BYTE, srcP );
|
||||
}
|
||||
|
||||
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
|
||||
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
|
||||
|
||||
long long currentTime = wxGetUTCTimeMillis().GetValue();
|
||||
|
||||
bmp.id = textureID;
|
||||
bmp.accessTime = currentTime;
|
||||
|
||||
#ifndef DISABLE_BITMAP_CACHE
|
||||
m_cacheLru.emplace_back( aBitmap->GetImageID() );
|
||||
m_cacheSize += bmp.size;
|
||||
m_bitmaps.emplace( aBitmap->GetImageID(), std::move( bmp ) );
|
||||
|
||||
if( m_cacheLru.size() > m_cacheMaxElements
|
||||
|| m_cacheSize > m_cacheMaxSize )
|
||||
if( m_cacheLru.size() + 1 > m_cacheMaxElements || m_cacheSize + bmp.size > m_cacheMaxSize )
|
||||
{
|
||||
KIID last = m_cacheLru.front();
|
||||
CACHED_BITMAP& cachedBitmap = m_bitmaps[last];
|
||||
KIID toRemove( 0 );
|
||||
auto toRemoveLru = m_cacheLru.end();
|
||||
|
||||
// Remove entries accessed > 1s ago first
|
||||
for( const auto& [kiid, cachedBmp] : m_bitmaps )
|
||||
{
|
||||
const int cacheTimeoutMillis = 1000L;
|
||||
|
||||
if( currentTime - cachedBmp.accessTime > cacheTimeoutMillis )
|
||||
{
|
||||
toRemove = kiid;
|
||||
toRemoveLru = std::find( m_cacheLru.begin(), m_cacheLru.end(), toRemove );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Otherwise, remove the latest entry (it's less likely to be needed soon)
|
||||
if( toRemove == niluuid )
|
||||
{
|
||||
toRemoveLru = m_cacheLru.end();
|
||||
toRemoveLru--;
|
||||
|
||||
toRemove = *toRemoveLru;
|
||||
}
|
||||
|
||||
CACHED_BITMAP& cachedBitmap = m_bitmaps[toRemove];
|
||||
|
||||
m_cacheSize -= cachedBitmap.size;
|
||||
glDeleteTextures( 1, &cachedBitmap.id );
|
||||
m_freedTextureIds.emplace_back( cachedBitmap.id );
|
||||
|
||||
m_bitmaps.erase( last );
|
||||
m_cacheLru.pop_front();
|
||||
m_bitmaps.erase( toRemove );
|
||||
m_cacheLru.erase( toRemoveLru );
|
||||
}
|
||||
|
||||
m_cacheLru.emplace_back( aBitmap->GetImageID() );
|
||||
m_cacheSize += bmp.size;
|
||||
m_bitmaps.emplace( aBitmap->GetImageID(), std::move( bmp ) );
|
||||
#endif
|
||||
|
||||
return textureID;
|
||||
@@ -1111,13 +1172,21 @@ void OPENGL_GAL::DrawRectangle( const VECTOR2D& aStartPoint, const VECTOR2D& aEn
|
||||
m_currentManager->Color( m_strokeColor.r, m_strokeColor.g, m_strokeColor.b,
|
||||
m_strokeColor.a );
|
||||
|
||||
std::deque<VECTOR2D> pointList;
|
||||
pointList.push_back( aStartPoint );
|
||||
pointList.push_back( diagonalPointA );
|
||||
pointList.push_back( aEndPoint );
|
||||
pointList.push_back( diagonalPointB );
|
||||
pointList.push_back( aStartPoint );
|
||||
DrawPolyline( pointList );
|
||||
// DrawLine (and DrawPolyline )
|
||||
// has problem with 0 length lines so enforce minimum
|
||||
if( aStartPoint == aEndPoint )
|
||||
DrawLine( aStartPoint + VECTOR2D( 1.0, 0.0 ), aEndPoint );
|
||||
else
|
||||
{
|
||||
std::deque<VECTOR2D> pointList;
|
||||
|
||||
pointList.push_back( aStartPoint );
|
||||
pointList.push_back( diagonalPointA );
|
||||
pointList.push_back( aEndPoint );
|
||||
pointList.push_back( diagonalPointB );
|
||||
pointList.push_back( aStartPoint );
|
||||
DrawPolyline( pointList );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+77
-17
@@ -38,6 +38,7 @@
|
||||
#include <gestfich.h>
|
||||
#include <string_utils.h>
|
||||
#include <launch_ext.h>
|
||||
#include "wx/tokenzr.h"
|
||||
|
||||
void QuoteString( wxString& string )
|
||||
{
|
||||
@@ -114,39 +115,98 @@ wxString FindKicadFile( const wxString& shortname )
|
||||
|
||||
int ExecuteFile( const wxString& aEditorName, const wxString& aFileName, wxProcess *aCallback )
|
||||
{
|
||||
wxString fullEditorName;
|
||||
wxString param;
|
||||
wxString fullEditorName;
|
||||
std::vector<wxString> params;
|
||||
|
||||
#ifdef __UNIX__
|
||||
int space = aEditorName.Find( ' ' );
|
||||
wxString param;
|
||||
bool inSingleQuotes = false;
|
||||
bool inDoubleQuotes = false;
|
||||
|
||||
if( space > 0 && !aEditorName.Contains( "\"" ) && !aEditorName.Contains( "\'" ) )
|
||||
auto pushParam =
|
||||
[&]()
|
||||
{
|
||||
if( !param.IsEmpty() )
|
||||
{
|
||||
params.push_back( param );
|
||||
param.clear();
|
||||
}
|
||||
};
|
||||
|
||||
for( wxUniChar ch : aEditorName )
|
||||
{
|
||||
fullEditorName = FindKicadFile( aEditorName.Mid( 0, space ) );
|
||||
param = aEditorName.Mid( space + 1 );
|
||||
if( inSingleQuotes )
|
||||
{
|
||||
if( ch == '\'' )
|
||||
{
|
||||
pushParam();
|
||||
inSingleQuotes = false;
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
param += ch;
|
||||
}
|
||||
}
|
||||
else if( inDoubleQuotes )
|
||||
{
|
||||
if( ch == '"' )
|
||||
{
|
||||
pushParam();
|
||||
inDoubleQuotes = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
param += ch;
|
||||
}
|
||||
}
|
||||
else if( ch == '\'' )
|
||||
{
|
||||
pushParam();
|
||||
inSingleQuotes = true;
|
||||
}
|
||||
else if( ch == '"' )
|
||||
{
|
||||
pushParam();
|
||||
inDoubleQuotes = true;
|
||||
}
|
||||
else if( ch == ' ' )
|
||||
{
|
||||
pushParam();
|
||||
}
|
||||
else
|
||||
{
|
||||
param += ch;
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
pushParam();
|
||||
|
||||
fullEditorName = FindKicadFile( params[0] );
|
||||
params.erase( params.begin() );
|
||||
#else
|
||||
fullEditorName = FindKicadFile( aEditorName );
|
||||
#endif
|
||||
{
|
||||
fullEditorName = FindKicadFile( aEditorName );
|
||||
}
|
||||
|
||||
if( wxFileExists( fullEditorName ) )
|
||||
{
|
||||
int i = 0;
|
||||
const wchar_t* args[4];
|
||||
std::vector<const wchar_t*> args;
|
||||
|
||||
args[i++] = fullEditorName.wc_str();
|
||||
args.emplace_back( fullEditorName.wc_str() );
|
||||
|
||||
if( !param.IsEmpty() )
|
||||
args[i++] = param.wc_str();
|
||||
if( !params.empty() )
|
||||
{
|
||||
for( const wxString& p : params )
|
||||
args.emplace_back( p.wc_str() );
|
||||
}
|
||||
|
||||
if( !aFileName.IsEmpty() )
|
||||
args[i++] = aFileName.wc_str();
|
||||
args.emplace_back( aFileName.wc_str() );
|
||||
|
||||
args[i] = nullptr;
|
||||
args.emplace_back( nullptr );
|
||||
|
||||
return wxExecute( const_cast<wchar_t**>( args ), wxEXEC_ASYNC, aCallback );
|
||||
return wxExecute( const_cast<wchar_t**>( args.data() ), wxEXEC_ASYNC, aCallback );
|
||||
}
|
||||
|
||||
wxString msg;
|
||||
|
||||
+5
-2
@@ -3,7 +3,7 @@
|
||||
*
|
||||
* Copyright (C) 2020 Ian McInerney <ian.s.mcinerney@ieee.org>
|
||||
* Copyright (C) 2007-2014 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
|
||||
* modify it under the terms of the GNU General Public License
|
||||
@@ -324,8 +324,11 @@ bool KIID_PATH::MakeRelativeTo( const KIID_PATH& aPath )
|
||||
|
||||
for( size_t i = 0; i < aPath.size(); ++i )
|
||||
{
|
||||
if( copy.at( i ).AsString() != aPath.at( i ).AsString() )
|
||||
if( copy.at( i ) != aPath.at( i ) )
|
||||
{
|
||||
*this = copy;
|
||||
return false; // this path is not contained within aPath
|
||||
}
|
||||
}
|
||||
|
||||
for( size_t i = aPath.size(); i < copy.size(); ++i )
|
||||
|
||||
+29
-1
@@ -183,6 +183,17 @@ wxString PATHS::GetStockDataPath( bool aRespectRunFromBuildDir )
|
||||
}
|
||||
|
||||
|
||||
#ifdef __WXMSW__
|
||||
/**
|
||||
* Gets the stock (install) data path, which is the base path for things like scripting, etc
|
||||
*/
|
||||
wxString PATHS::GetWindowsBaseSharePath()
|
||||
{
|
||||
return getWindowsKiCadRoot() + wxT( "share\\" );
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
wxString PATHS::GetStockEDALibraryPath()
|
||||
{
|
||||
wxString path;
|
||||
@@ -288,6 +299,24 @@ wxString PATHS::GetStockPlugins3DPath()
|
||||
fn.AppendDir( wxT( "plugins" ) );
|
||||
#elif defined( __WXMAC__ )
|
||||
fn.Assign( wxStandardPaths::Get().GetPluginsDir(), wxEmptyString );
|
||||
|
||||
// This must be mapped to main bundle for everything but kicad.app
|
||||
const wxArrayString dirs = fn.GetDirs();
|
||||
|
||||
// Check if we are the main kicad binary. in this case, the path will be
|
||||
// /path/to/bundlename.app/Contents/PlugIns
|
||||
// If we are an aux binary, the path will be something like
|
||||
// /path/to/bundlename.app/Contents/Applications/<standalone>.app/Contents/PlugIns
|
||||
if( dirs.GetCount() >= 6 &&
|
||||
dirs[dirs.GetCount() - 4] == wxT( "Applications" ) &&
|
||||
dirs[dirs.GetCount() - 6].Lower().EndsWith( wxT( "app" ) ) )
|
||||
{
|
||||
fn.RemoveLastDir();
|
||||
fn.RemoveLastDir();
|
||||
fn.RemoveLastDir();
|
||||
fn.RemoveLastDir();
|
||||
fn.AppendDir( wxT( "PlugIns" ) );
|
||||
}
|
||||
#else
|
||||
if( wxGetEnv( wxT( "KICAD_RUN_FROM_BUILD_DIR" ), nullptr ) )
|
||||
{
|
||||
@@ -370,7 +399,6 @@ void PATHS::EnsureUserPathsExist()
|
||||
{
|
||||
EnsurePathExists( GetUserCachePath() );
|
||||
EnsurePathExists( GetUserPluginsPath() );
|
||||
EnsurePathExists( GetUserPlugins3DPath() );
|
||||
EnsurePathExists( GetUserScriptingPath() );
|
||||
EnsurePathExists( GetUserTemplatesPath() );
|
||||
EnsurePathExists( GetDefaultUserProjectsPath() );
|
||||
|
||||
@@ -161,6 +161,8 @@ void PGM_BASE::Destroy()
|
||||
// unlike a normal destructor, this is designed to be called more than once safely:
|
||||
delete m_locale;
|
||||
m_locale = nullptr;
|
||||
|
||||
m_pgm_checker.reset();
|
||||
}
|
||||
|
||||
|
||||
@@ -443,6 +445,8 @@ bool PGM_BASE::InitPgm( bool aHeadless, bool aSkipPyInit, bool aIsUnitTest )
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
m_pgm_checker = std::make_unique<wxSingleInstanceChecker>();
|
||||
m_pgm_checker->Create( pgm_name, wxStandardPaths::Get().GetTempDir() );
|
||||
|
||||
// Init KiCad environment
|
||||
// the environment variable KICAD (if exists) gives the kicad path:
|
||||
@@ -810,6 +814,10 @@ wxString PGM_BASE::GetLanguageTag()
|
||||
|
||||
void PGM_BASE::SetLanguagePath()
|
||||
{
|
||||
#ifdef _MSC_VER
|
||||
wxLocale::AddCatalogLookupPathPrefix( PATHS::GetWindowsBaseSharePath()
|
||||
+ wxT( "locale" ) );
|
||||
#endif
|
||||
wxLocale::AddCatalogLookupPathPrefix( PATHS::GetLocaleDataPath() );
|
||||
|
||||
if( wxGetEnv( wxT( "KICAD_RUN_FROM_BUILD_DIR" ), nullptr ) )
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
#include <string_utils.h>
|
||||
#include <convert_basic_shapes_to_polygon.h>
|
||||
#include <trigo.h>
|
||||
#include <fmt/core.h>
|
||||
|
||||
/**
|
||||
* Oblique angle for DXF native text
|
||||
@@ -146,6 +147,26 @@ void DXF_PLOTTER::SetUnits( DXF_UNITS aUnit )
|
||||
}
|
||||
|
||||
|
||||
// convert aValue to a string, and remove trailing zeros
|
||||
// In DXF files coordinates need a high precision: at least 9 digits when given
|
||||
// in inches and 7 digits when in mm.
|
||||
// So we use 16 digits and remove trailing 0 (if any)
|
||||
static std::string formatCoord( double aValue )
|
||||
{
|
||||
std::string buf;
|
||||
|
||||
buf = fmt::format( "{:.16f}", aValue );
|
||||
|
||||
// remove trailing zeros
|
||||
while( !buf.empty() && buf[buf.size() - 1] == '0' )
|
||||
{
|
||||
buf.pop_back();
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
||||
void DXF_PLOTTER::SetViewport( const VECTOR2I& aOffset, double aIusPerDecimil,
|
||||
double aScale, bool aMirror )
|
||||
{
|
||||
@@ -417,11 +438,24 @@ void DXF_PLOTTER::SetColor( const COLOR4D& color )
|
||||
void DXF_PLOTTER::Rect( const VECTOR2I& p1, const VECTOR2I& p2, FILL_T fill, int width )
|
||||
{
|
||||
wxASSERT( m_outputFile );
|
||||
MoveTo( p1 );
|
||||
LineTo( VECTOR2I( p1.x, p2.y ) );
|
||||
LineTo( VECTOR2I( p2.x, p2.y ) );
|
||||
LineTo( VECTOR2I( p2.x, p1.y ) );
|
||||
FinishTo( VECTOR2I( p1.x, p1.y ) );
|
||||
|
||||
if( p1 != p2 )
|
||||
{
|
||||
MoveTo( p1 );
|
||||
LineTo( VECTOR2I( p1.x, p2.y ) );
|
||||
LineTo( VECTOR2I( p2.x, p2.y ) );
|
||||
LineTo( VECTOR2I( p2.x, p1.y ) );
|
||||
FinishTo( VECTOR2I( p1.x, p1.y ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
// Draw as a point
|
||||
wxString cname = getDXFColorName( m_currentColor );
|
||||
VECTOR2D point_dev = userToDeviceCoordinates( p1 );
|
||||
|
||||
fprintf( m_outputFile, "0\nPOINT\n8\n%s\n10\n%g\n20\n%g\n", TO_UTF8( cname ), point_dev.x,
|
||||
point_dev.y );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -431,31 +465,43 @@ void DXF_PLOTTER::Circle( const VECTOR2I& centre, int diameter, FILL_T fill, int
|
||||
double radius = userToDeviceSize( diameter / 2 );
|
||||
VECTOR2D centre_dev = userToDeviceCoordinates( centre );
|
||||
|
||||
wxString cname = getDXFColorName( m_currentColor );
|
||||
|
||||
if( radius > 0 )
|
||||
{
|
||||
wxString cname = getDXFColorName( m_currentColor );
|
||||
|
||||
if( fill == FILL_T::NO_FILL )
|
||||
{
|
||||
fprintf( m_outputFile, "0\nCIRCLE\n8\n%s\n10\n%g\n20\n%g\n40\n%g\n",
|
||||
fprintf( m_outputFile, "0\nCIRCLE\n8\n%s\n10\n%s\n20\n%s\n40\n%s\n",
|
||||
TO_UTF8( cname ),
|
||||
centre_dev.x, centre_dev.y, radius );
|
||||
formatCoord( centre_dev.x ).c_str(),
|
||||
formatCoord( centre_dev.y ).c_str(),
|
||||
formatCoord( radius ).c_str() );
|
||||
}
|
||||
else if( fill == FILL_T::FILLED_SHAPE )
|
||||
{
|
||||
double r = radius*0.5;
|
||||
double r = radius * 0.5;
|
||||
fprintf( m_outputFile, "0\nPOLYLINE\n" );
|
||||
fprintf( m_outputFile, "8\n%s\n66\n1\n70\n1\n", TO_UTF8( cname ) );
|
||||
fprintf( m_outputFile, "40\n%g\n41\n%g\n", radius, radius);
|
||||
fprintf( m_outputFile, "40\n%s\n41\n%s\n",
|
||||
formatCoord( radius ).c_str(),
|
||||
formatCoord( radius ).c_str() );
|
||||
fprintf( m_outputFile, "0\nVERTEX\n8\n%s\n", TO_UTF8( cname ) );
|
||||
fprintf( m_outputFile, "10\n%g\n 20\n%g\n42\n1.0\n",
|
||||
centre_dev.x-r, centre_dev.y );
|
||||
fprintf( m_outputFile, "10\n%s\n 20\n%s\n42\n1.0\n",
|
||||
formatCoord( centre_dev.x-r ).c_str(),
|
||||
formatCoord( centre_dev.y ).c_str() );
|
||||
fprintf( m_outputFile, "0\nVERTEX\n8\n%s\n", TO_UTF8( cname ) );
|
||||
fprintf( m_outputFile, "10\n%g\n 20\n%g\n42\n1.0\n",
|
||||
centre_dev.x+r, centre_dev.y );
|
||||
fprintf( m_outputFile, "10\n%s\n 20\n%s\n42\n1.0\n",
|
||||
formatCoord( centre_dev.x+r ).c_str(),
|
||||
formatCoord( centre_dev.y ).c_str() );
|
||||
fprintf( m_outputFile, "0\nSEQEND\n");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Draw as a point
|
||||
fprintf( m_outputFile, "0\nPOINT\n8\n%s\n10\n%g\n20\n%g\n", TO_UTF8( cname ), centre_dev.x,
|
||||
centre_dev.y );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -578,9 +624,12 @@ void DXF_PLOTTER::PenTo( const VECTOR2I& pos, char plume )
|
||||
// DXF LINE
|
||||
wxString cname = getDXFColorName( m_currentColor );
|
||||
const char* lname = getDXFLineType( static_cast<PLOT_DASH_TYPE>( m_currentLineType ) );
|
||||
fprintf( m_outputFile, "0\nLINE\n8\n%s\n6\n%s\n10\n%g\n20\n%g\n11\n%g\n21\n%g\n",
|
||||
fprintf( m_outputFile, "0\nLINE\n8\n%s\n6\n%s\n10\n%s\n20\n%s\n11\n%s\n21\n%s\n",
|
||||
TO_UTF8( cname ), lname,
|
||||
pen_lastpos_dev.x, pen_lastpos_dev.y, pos_dev.x, pos_dev.y );
|
||||
formatCoord( pen_lastpos_dev.x ).c_str(),
|
||||
formatCoord( pen_lastpos_dev.y ).c_str(),
|
||||
formatCoord( pos_dev.x ).c_str(),
|
||||
formatCoord( pos_dev.y ).c_str() );
|
||||
}
|
||||
|
||||
m_penLastpos = pos;
|
||||
@@ -626,8 +675,8 @@ void DXF_PLOTTER::ThickSegment( const VECTOR2I& aStart, const VECTOR2I& aEnd, in
|
||||
}
|
||||
|
||||
|
||||
void DXF_PLOTTER::Arc( const VECTOR2I& aCenter, const EDA_ANGLE& aStartAngle,
|
||||
const EDA_ANGLE& aEndAngle, int aRadius, FILL_T aFill, int aWidth )
|
||||
void DXF_PLOTTER::Arc( const VECTOR2D& aCenter, const EDA_ANGLE& aStartAngle,
|
||||
const EDA_ANGLE& aEndAngle, double aRadius, FILL_T aFill, int aWidth )
|
||||
{
|
||||
wxASSERT( m_outputFile );
|
||||
|
||||
@@ -648,9 +697,11 @@ void DXF_PLOTTER::Arc( const VECTOR2I& aCenter, const EDA_ANGLE& aStartAngle,
|
||||
// Emit a DXF ARC entity
|
||||
wxString cname = getDXFColorName( m_currentColor );
|
||||
fprintf( m_outputFile,
|
||||
"0\nARC\n8\n%s\n10\n%g\n20\n%g\n40\n%g\n50\n%g\n51\n%g\n",
|
||||
"0\nARC\n8\n%s\n10\n%s\n20\n%s\n40\n%s\n50\n%.8f\n51\n%.8f\n",
|
||||
TO_UTF8( cname ),
|
||||
centre_device.x, centre_device.y, radius_device,
|
||||
formatCoord( centre_device.x ).c_str(),
|
||||
formatCoord( centre_device.y ).c_str(),
|
||||
formatCoord( radius_device ).c_str(),
|
||||
startAngle.AsDegrees(), endAngle.AsDegrees() );
|
||||
}
|
||||
|
||||
@@ -936,21 +987,21 @@ void DXF_PLOTTER::plotOneLineOfText( const VECTOR2I& aPos, const COLOR4D& aColor
|
||||
" 8\n"
|
||||
"%s\n" // Layer name
|
||||
" 10\n"
|
||||
"%g\n" // First point X
|
||||
"%s\n" // First point X
|
||||
" 11\n"
|
||||
"%g\n" // Second point X
|
||||
"%s\n" // Second point X
|
||||
" 20\n"
|
||||
"%g\n" // First point Y
|
||||
"%s\n" // First point Y
|
||||
" 21\n"
|
||||
"%g\n" // Second point Y
|
||||
"%s\n" // Second point Y
|
||||
" 40\n"
|
||||
"%g\n" // Text height
|
||||
"%s\n" // Text height
|
||||
" 41\n"
|
||||
"%g\n" // Width factor
|
||||
"%s\n" // Width factor
|
||||
" 50\n"
|
||||
"%g\n" // Rotation
|
||||
"%.8f\n" // Rotation
|
||||
" 51\n"
|
||||
"%g\n" // Oblique angle
|
||||
"%.8f\n" // Oblique angle
|
||||
" 71\n"
|
||||
"%d\n" // Mirror flags
|
||||
" 72\n"
|
||||
@@ -960,9 +1011,9 @@ void DXF_PLOTTER::plotOneLineOfText( const VECTOR2I& aPos, const COLOR4D& aColor
|
||||
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 ),
|
||||
formatCoord( origin_dev.x ).c_str(), formatCoord( origin_dev.x ).c_str(),
|
||||
formatCoord( origin_dev.y ).c_str(), formatCoord( origin_dev.y ).c_str(),
|
||||
formatCoord( size_dev.y ).c_str(), formatCoord( fabs( size_dev.x / size_dev.y ) ).c_str(),
|
||||
aAttributes.m_Angle.AsDegrees(),
|
||||
aAttributes.m_Italic ? DXF_OBLIQUE_ANGLE : 0,
|
||||
aAttributes.m_Mirrored ? 2 : 0, // X mirror flag
|
||||
|
||||
@@ -821,13 +821,14 @@ void GERBER_PLOTTER::Rect( const VECTOR2I& p1, const VECTOR2I& p2, FILL_T fill,
|
||||
|
||||
void GERBER_PLOTTER::Circle( const VECTOR2I& aCenter, int aDiameter, FILL_T aFill, int aWidth )
|
||||
{
|
||||
Arc( aCenter, ANGLE_0, ANGLE_360, aDiameter / 2, aFill, aWidth );
|
||||
Arc( aCenter, ANGLE_0, ANGLE_180, aDiameter / 2, aFill, aWidth );
|
||||
Arc( aCenter, ANGLE_180, ANGLE_360, aDiameter / 2, aFill, aWidth );
|
||||
}
|
||||
|
||||
|
||||
|
||||
void GERBER_PLOTTER::Arc( const VECTOR2I& aCenter, const EDA_ANGLE& aStartAngle,
|
||||
const EDA_ANGLE& aEndAngle, int aRadius, FILL_T aFill, int aWidth )
|
||||
void GERBER_PLOTTER::Arc( const VECTOR2D& aCenter, const EDA_ANGLE& aStartAngle,
|
||||
const EDA_ANGLE& aEndAngle, double aRadius, FILL_T aFill, int aWidth )
|
||||
{
|
||||
SetCurrentLineWidth( aWidth );
|
||||
|
||||
@@ -1149,8 +1150,8 @@ void GERBER_PLOTTER::ThickSegment( const VECTOR2I& start, const VECTOR2I& end, i
|
||||
}
|
||||
}
|
||||
|
||||
void GERBER_PLOTTER::ThickArc( const VECTOR2I& aCentre, const EDA_ANGLE& aStartAngle,
|
||||
const EDA_ANGLE& aEndAngle, int aRadius, int aWidth,
|
||||
void GERBER_PLOTTER::ThickArc( const VECTOR2D& aCentre, const EDA_ANGLE& aStartAngle,
|
||||
const EDA_ANGLE& aEndAngle, double aRadius, int aWidth,
|
||||
OUTLINE_MODE aTraceMode, void* aData )
|
||||
{
|
||||
GBR_METADATA *gbr_metadata = static_cast<GBR_METADATA*>( aData );
|
||||
|
||||
@@ -394,22 +394,16 @@ void HPGL_PLOTTER::Rect( const VECTOR2I& p1, const VECTOR2I& p2, FILL_T aFill, i
|
||||
VECTOR2D p1_device = userToDeviceCoordinates( p1 );
|
||||
VECTOR2D p2_device = userToDeviceCoordinates( p2 );
|
||||
|
||||
MoveTo( p1 );
|
||||
// EA command seems to always fill the rectangle, so plot as a polygon instead
|
||||
std::vector<VECTOR2I> cornerList;
|
||||
|
||||
if( aFill == FILL_T::FILLED_SHAPE )
|
||||
{
|
||||
startOrAppendItem( p1_device, wxString::Format( "RA %.0f,%.0f;",
|
||||
p2_device.x,
|
||||
p2_device.y ) );
|
||||
}
|
||||
cornerList.emplace_back( p1.x, p1.y );
|
||||
cornerList.emplace_back( p2.x, p1.y );
|
||||
cornerList.emplace_back( p2.x, p2.y );
|
||||
cornerList.emplace_back( p1.x, p2.y );
|
||||
cornerList.emplace_back( p1.x, p1.y );
|
||||
|
||||
startOrAppendItem( p1_device, wxString::Format( "EA %.0f,%.0f;",
|
||||
p2_device.x,
|
||||
p2_device.y ) );
|
||||
|
||||
m_current_item->loc_end = m_current_item->loc_start;
|
||||
m_current_item->bbox.Merge( p2_device );
|
||||
PenFinish();
|
||||
PlotPoly( cornerList, aFill, aWidth, nullptr );
|
||||
}
|
||||
|
||||
|
||||
@@ -435,7 +429,6 @@ void HPGL_PLOTTER::Circle( const VECTOR2I& aCenter, int aDiameter, FILL_T aFill,
|
||||
chord_angle.AsDegrees(),
|
||||
hpgl_end_polygon_cmd ) );
|
||||
m_current_item->lift_before = true;
|
||||
m_current_item->pen_returns = true;
|
||||
m_current_item->bbox.Merge( BOX2D( center_dev - radius,
|
||||
VECTOR2D( 2 * radius, 2 * radius ) ) );
|
||||
PenFinish();
|
||||
@@ -448,7 +441,6 @@ void HPGL_PLOTTER::Circle( const VECTOR2I& aCenter, int aDiameter, FILL_T aFill,
|
||||
radius,
|
||||
chord_angle.AsDegrees() ) );
|
||||
m_current_item->lift_before = true;
|
||||
m_current_item->pen_returns = true;
|
||||
m_current_item->bbox.Merge( BOX2D( center_dev - radius,
|
||||
VECTOR2D( 2 * radius, 2 * radius ) ) );
|
||||
PenFinish();
|
||||
@@ -567,8 +559,8 @@ void HPGL_PLOTTER::ThickSegment( const VECTOR2I& start, const VECTOR2I& end,
|
||||
}
|
||||
|
||||
|
||||
void HPGL_PLOTTER::Arc( const VECTOR2I& aCenter, const EDA_ANGLE& aStartAngle,
|
||||
const EDA_ANGLE& aEndAngle, int aRadius, FILL_T aFill, int aWidth )
|
||||
void HPGL_PLOTTER::Arc( const VECTOR2D& aCenter, const EDA_ANGLE& aStartAngle,
|
||||
const EDA_ANGLE& aEndAngle, double aRadius, FILL_T aFill, int aWidth )
|
||||
{
|
||||
if( aRadius <= 0 )
|
||||
return;
|
||||
|
||||
@@ -217,12 +217,43 @@ void PDF_PLOTTER::SetDash( int aLineWidth, PLOT_DASH_TYPE aLineStyle )
|
||||
void PDF_PLOTTER::Rect( const VECTOR2I& p1, const VECTOR2I& p2, FILL_T fill, int width )
|
||||
{
|
||||
wxASSERT( m_workFile );
|
||||
|
||||
SetCurrentLineWidth( width );
|
||||
|
||||
VECTOR2I size = p2 - p1;
|
||||
|
||||
if( size.x == 0 && size.y == 0 )
|
||||
{
|
||||
// Can't draw zero-sized rectangles
|
||||
SetCurrentLineWidth( width );
|
||||
|
||||
MoveTo( VECTOR2I( p1.x, p1.y ) );
|
||||
FinishTo( VECTOR2I( p1.x, p1.y ) );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if( std::min( std::abs( size.x ), std::abs( size.y ) ) < width )
|
||||
{
|
||||
// Too thick stroked rectangles are buggy, draw as polygon
|
||||
std::vector<VECTOR2I> cornerList;
|
||||
|
||||
cornerList.emplace_back( p1.x, p1.y );
|
||||
cornerList.emplace_back( p2.x, p1.y );
|
||||
cornerList.emplace_back( p2.x, p2.y );
|
||||
cornerList.emplace_back( p1.x, p2.y );
|
||||
cornerList.emplace_back( p1.x, p1.y );
|
||||
|
||||
PlotPoly( cornerList, fill, width, nullptr );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
VECTOR2D p1_dev = userToDeviceCoordinates( p1 );
|
||||
VECTOR2D p2_dev = userToDeviceCoordinates( p2 );
|
||||
|
||||
SetCurrentLineWidth( width );
|
||||
fprintf( m_workFile, "%g %g %g %g re %c\n", p1_dev.x, p1_dev.y,
|
||||
p2_dev.x - p1_dev.x, p2_dev.y - p1_dev.y, fill == FILL_T::NO_FILL ? 'S' : 'B' );
|
||||
fprintf( m_workFile, "%g %g %g %g re %c\n", p1_dev.x, p1_dev.y, p2_dev.x - p1_dev.x,
|
||||
p2_dev.y - p1_dev.y, fill == FILL_T::NO_FILL ? 'S' : 'B' );
|
||||
}
|
||||
|
||||
|
||||
@@ -336,8 +367,8 @@ void PDF_PLOTTER::Arc( const VECTOR2I& aCenter, const VECTOR2I& aStart, const VE
|
||||
}
|
||||
|
||||
|
||||
void PDF_PLOTTER::Arc( const VECTOR2I& aCenter, const EDA_ANGLE& aStartAngle,
|
||||
const EDA_ANGLE& aEndAngle, int aRadius, FILL_T aFill, int aWidth )
|
||||
void PDF_PLOTTER::Arc( const VECTOR2D& aCenter, const EDA_ANGLE& aStartAngle,
|
||||
const EDA_ANGLE& aEndAngle, double aRadius, FILL_T aFill, int aWidth )
|
||||
{
|
||||
wxASSERT( m_workFile );
|
||||
|
||||
@@ -1378,10 +1409,11 @@ void PDF_PLOTTER::Text( const VECTOR2I& aPos,
|
||||
double wideningFactor, heightFactor;
|
||||
|
||||
VECTOR2I t_size( std::abs( aSize.x ), std::abs( aSize.y ) );
|
||||
bool textMirrored = aSize.x < 0;
|
||||
|
||||
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 );
|
||||
computeTextParameters( aPos, aText, aOrient, t_size, textMirrored, aH_justify, aV_justify,
|
||||
aWidth, aItalic, aBold, &wideningFactor, &ctm_a, &ctm_b, &ctm_c, &ctm_d,
|
||||
&ctm_e, &ctm_f, &heightFactor );
|
||||
|
||||
SetColor( aColor );
|
||||
SetCurrentLineWidth( aWidth, aData );
|
||||
@@ -1393,6 +1425,10 @@ void PDF_PLOTTER::Text( const VECTOR2I& aPos,
|
||||
aFont = KIFONT::FONT::GetFont();
|
||||
|
||||
VECTOR2I full_box( aFont->StringBoundaryLimits( aText, t_size, aWidth, aBold, aItalic ) );
|
||||
|
||||
if( textMirrored )
|
||||
full_box.x *= -1;
|
||||
|
||||
VECTOR2I box_x( full_box.x, 0 );
|
||||
VECTOR2I box_y( 0, full_box.y );
|
||||
|
||||
@@ -1413,13 +1449,17 @@ void PDF_PLOTTER::Text( const VECTOR2I& aPos,
|
||||
{
|
||||
wxString word = str_tok.GetNextToken();
|
||||
|
||||
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 );
|
||||
computeTextParameters( pos, word, aOrient, t_size, textMirrored, 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, t_size, aWidth, aBold, aItalic ).x, 0 );
|
||||
|
||||
if( textMirrored )
|
||||
bbox.x *= -1;
|
||||
|
||||
RotatePoint( bbox, aOrient );
|
||||
pos += bbox;
|
||||
|
||||
|
||||
@@ -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) 2020-2022 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
* Copyright (C) 2020-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
|
||||
@@ -113,7 +113,7 @@ void PSLIKE_PLOTTER::FlashPadOval( const VECTOR2I& aPadPos, const VECTOR2I& aSiz
|
||||
if( aTraceMode == FILLED )
|
||||
ThickSegment( a + aPadPos, b + aPadPos, size.x, aTraceMode, nullptr );
|
||||
else
|
||||
sketchOval( aPadPos, size, orient, -1 );
|
||||
sketchOval( aPadPos, size, orient, USE_DEFAULT_LINE_WIDTH );
|
||||
}
|
||||
|
||||
|
||||
@@ -423,7 +423,7 @@ void PSLIKE_PLOTTER::computeTextParameters( const VECTOR2I& aPos,
|
||||
// This is an approximation of the text bounds (in IUs)
|
||||
int tw = returnPostscriptTextWidth( aText, aSize.x, aItalic, aWidth );
|
||||
int th = aSize.y;
|
||||
int dx, dy;
|
||||
int dx = 0, dy = 0;
|
||||
|
||||
switch( aH_justify )
|
||||
{
|
||||
@@ -450,7 +450,7 @@ void PSLIKE_PLOTTER::computeTextParameters( const VECTOR2I& aPos,
|
||||
*wideningFactor = sz_dev.x / sz_dev.y;
|
||||
|
||||
// Mirrored texts must be plotted as mirrored!
|
||||
if( m_plotMirror )
|
||||
if( m_plotMirror ^ aMirror )
|
||||
*wideningFactor = -*wideningFactor;
|
||||
|
||||
// The CTM transformation matrix
|
||||
|
||||
@@ -357,7 +357,7 @@ void SVG_PLOTTER::emitSetRGBColor( double r, double g, double b, double a )
|
||||
int blue = (int) ( 255.0 * b );
|
||||
long rgb_color = (red << 16) | (green << 8) | blue;
|
||||
|
||||
if( m_pen_rgb_color != rgb_color )
|
||||
if( m_pen_rgb_color != rgb_color || m_brush_alpha != a )
|
||||
{
|
||||
m_graphics_changed = true;
|
||||
m_pen_rgb_color = rgb_color;
|
||||
@@ -443,8 +443,8 @@ void SVG_PLOTTER::Circle( const VECTOR2I& pos, int diametre, FILL_T fill, int wi
|
||||
}
|
||||
|
||||
|
||||
void SVG_PLOTTER::Arc( const VECTOR2I& aCenter, const EDA_ANGLE& aStartAngle,
|
||||
const EDA_ANGLE& aEndAngle, int aRadius, FILL_T aFill, int aWidth )
|
||||
void SVG_PLOTTER::Arc( const VECTOR2D& aCenter, const EDA_ANGLE& aStartAngle,
|
||||
const EDA_ANGLE& aEndAngle, double aRadius, FILL_T aFill, int aWidth )
|
||||
{
|
||||
/* Draws an arc of a circle, centered on (xc,yc), with starting point (x1, y1) and ending
|
||||
* at (x2, y2). The current pen is used for the outline and the current brush for filling
|
||||
@@ -825,16 +825,16 @@ void SVG_PLOTTER::Text( const VECTOR2I& aPos,
|
||||
|
||||
if( !aOrient.IsZero() )
|
||||
{
|
||||
fprintf( m_outputFile,
|
||||
"<g transform=\"rotate(%f %.*f %.*f)\">\n",
|
||||
- aOrient.AsDegrees(), m_precision, anchor_pos_dev.x, m_precision, anchor_pos_dev.y );
|
||||
fprintf( m_outputFile, "<g transform=\"rotate(%f %.*f %.*f)\">\n",
|
||||
m_plotMirror ? aOrient.AsDegrees() : -aOrient.AsDegrees(), m_precision,
|
||||
anchor_pos_dev.x, m_precision, anchor_pos_dev.y );
|
||||
}
|
||||
|
||||
fprintf( m_outputFile, "<text x=\"%.*f\" y=\"%.*f\"\n",
|
||||
m_precision, text_pos_dev.x, m_precision, text_pos_dev.y );
|
||||
|
||||
/// If the text is mirrored, we should also mirror the hidden text to match
|
||||
if( aSize.x < 0 )
|
||||
if( m_plotMirror != ( aSize.x < 0 ) )
|
||||
fprintf( m_outputFile, "transform=\"scale(-1 1) translate(%f 0)\"\n", -2 * text_pos_dev.x );
|
||||
|
||||
fprintf( m_outputFile,
|
||||
|
||||
@@ -145,13 +145,31 @@ double PLOTTER::GetDashGapLenIU( int aLineWidth ) const
|
||||
return userToDeviceSize( m_renderSettings->GetGapLength( aLineWidth ) );
|
||||
}
|
||||
|
||||
|
||||
#include <wx/log.h>
|
||||
void PLOTTER::Arc( const VECTOR2I& aCenter, const VECTOR2I& aStart, const VECTOR2I& aEnd,
|
||||
FILL_T aFill, int aWidth, int aMaxError )
|
||||
{
|
||||
EDA_ANGLE startAngle( aStart - aCenter );
|
||||
EDA_ANGLE endAngle( aEnd - aCenter );
|
||||
int radius = ( aStart - aCenter ).EuclideanNorm();
|
||||
// Recalculate aCenter using double to be sure we will use a exact value, from aStart and aEnd
|
||||
// it must be on the line passing by the middle of segment {aStart, aEnd}
|
||||
// To simplify calculations, use aStart as origin in intermediate calculations
|
||||
VECTOR2D center = aCenter - aStart;
|
||||
VECTOR2D end = aEnd - aStart;
|
||||
EDA_ANGLE segAngle( end );
|
||||
|
||||
// Rotate end and center, to make segment {aStart, aEnd} horizontal
|
||||
RotatePoint( end, segAngle );
|
||||
RotatePoint( center, segAngle );
|
||||
|
||||
// center.x must be at end.x/2 coordinate
|
||||
center.x = end.x / 2;
|
||||
|
||||
// Now calculate the right center position
|
||||
RotatePoint( center, -segAngle );
|
||||
center += aStart;
|
||||
|
||||
EDA_ANGLE startAngle( VECTOR2D( aStart ) - center );
|
||||
EDA_ANGLE endAngle( VECTOR2D( aEnd ) - center );
|
||||
double radius = ( VECTOR2D( aStart ) - center ).EuclideanNorm();
|
||||
|
||||
if( startAngle > endAngle )
|
||||
{
|
||||
@@ -168,12 +186,12 @@ void PLOTTER::Arc( const VECTOR2I& aCenter, const VECTOR2I& aStart, const VECTOR
|
||||
startAngle = -startAngle;
|
||||
endAngle = -endAngle;
|
||||
|
||||
Arc( aCenter, startAngle, endAngle, radius, aFill, aWidth );
|
||||
Arc( center, startAngle, endAngle, radius, aFill, aWidth );
|
||||
}
|
||||
|
||||
|
||||
void PLOTTER::Arc( const VECTOR2I& aCenter, const EDA_ANGLE& aStartAngle,
|
||||
const EDA_ANGLE& aEndAngle, int aRadius, FILL_T aFill, int aWidth )
|
||||
void PLOTTER::Arc( const VECTOR2D& aCenter, const EDA_ANGLE& aStartAngle,
|
||||
const EDA_ANGLE& aEndAngle, double aRadius, FILL_T aFill, int aWidth )
|
||||
{
|
||||
EDA_ANGLE startAngle( aStartAngle );
|
||||
EDA_ANGLE endAngle( aEndAngle );
|
||||
@@ -570,8 +588,8 @@ void PLOTTER::ThickSegment( const VECTOR2I& start, const VECTOR2I& end, int widt
|
||||
}
|
||||
|
||||
|
||||
void PLOTTER::ThickArc( const VECTOR2I& centre, const EDA_ANGLE& aStartAngle,
|
||||
const EDA_ANGLE& aEndAngle, int aRadius, int aWidth,
|
||||
void PLOTTER::ThickArc( const VECTOR2D& centre, const EDA_ANGLE& aStartAngle,
|
||||
const EDA_ANGLE& aEndAngle, double aRadius, int aWidth,
|
||||
OUTLINE_MODE aTraceMode, void* aData )
|
||||
{
|
||||
if( aTraceMode == FILLED )
|
||||
|
||||
@@ -30,9 +30,10 @@
|
||||
|
||||
LIB_ID AltiumToKiCadLibID( const wxString& aLibName, const wxString& aLibReference )
|
||||
{
|
||||
wxString libName = LIB_ID::FixIllegalChars( aLibName, true );
|
||||
wxString libReference = EscapeString( aLibReference, CTX_LIBID );
|
||||
|
||||
wxString key = !aLibName.empty() ? ( aLibName + ":" + libReference ) : libReference;
|
||||
wxString key = !libName.empty() ? ( libName + ":" + libReference ) : libReference;
|
||||
|
||||
LIB_ID libId;
|
||||
libId.Parse( key, true );
|
||||
|
||||
@@ -177,8 +177,16 @@ bool PROJECT_ARCHIVER::Archive( const wxString& aSrcDir, const wxString& aDestFi
|
||||
|
||||
unsigned long uncompressedBytes = 0;
|
||||
|
||||
// Our filename collector can store duplicate filenames. for instance *.gm2
|
||||
// matches both *.g?? and *.gm??.
|
||||
// So skip duplicate filenames (they are sorted, so it is easy).
|
||||
wxString lastStoredFile;
|
||||
|
||||
for( unsigned ii = 0; ii < files.GetCount(); ii++ )
|
||||
{
|
||||
if( lastStoredFile == files[ii] ) // duplicate name: already stored
|
||||
continue;
|
||||
|
||||
wxFileSystem fsfile;
|
||||
|
||||
wxFileName curr_fn( files[ii] );
|
||||
|
||||
@@ -569,9 +569,42 @@ bool PROJECT_FILE::SaveToFile( const wxString& aDirectory, bool aForce )
|
||||
|
||||
bool PROJECT_FILE::SaveAs( const wxString& aDirectory, const wxString& aFile )
|
||||
{
|
||||
wxFileName oldFilename( GetFilename() );
|
||||
wxString oldProjectName = oldFilename.GetName();
|
||||
wxString oldProjectPath = oldFilename.GetPath();
|
||||
|
||||
Set( "meta.filename", aFile + "." + ProjectFileExtension );
|
||||
SetFilename( aFile );
|
||||
|
||||
auto updatePath =
|
||||
[&]( wxString& aPath )
|
||||
{
|
||||
if( aPath.StartsWith( oldProjectName + wxS( "." ) ) )
|
||||
aPath.Replace( oldProjectName, aFile, false );
|
||||
else if( aPath.StartsWith( oldProjectPath + wxS( "/" ) ) )
|
||||
aPath.Replace( oldProjectPath, aDirectory, false );
|
||||
};
|
||||
|
||||
updatePath( m_BoardDrawingSheetFile );
|
||||
|
||||
for( int ii = LAST_PATH_FIRST; ii < (int) LAST_PATH_SIZE; ++ii )
|
||||
updatePath( m_PcbLastPath[ ii ] );
|
||||
|
||||
auto updatePathByPtr =
|
||||
[&]( const std::string& aPtr )
|
||||
{
|
||||
if( std::optional<wxString> path = Get<wxString>( aPtr ) )
|
||||
{
|
||||
updatePath( path.value() );
|
||||
Set( aPtr, path.value() );
|
||||
}
|
||||
};
|
||||
|
||||
updatePathByPtr( "schematic.page_layout_descr_file" );
|
||||
updatePathByPtr( "schematic.plot_directory" );
|
||||
updatePathByPtr( "schematic.ngspice.workbook_filename" );
|
||||
updatePathByPtr( "pcbnew.page_layout_descr_file" );
|
||||
|
||||
// While performing Save As, we have already checked that we can write to the directory
|
||||
// so don't carry the previous flag
|
||||
SetReadOnly( false );
|
||||
|
||||
+2
-1
@@ -63,7 +63,8 @@ void RC_ITEM::SetItems( const EDA_ITEM* aItem, const EDA_ITEM* bItem,
|
||||
{
|
||||
m_ids.clear();
|
||||
|
||||
m_ids.push_back( aItem->m_Uuid );
|
||||
if( aItem )
|
||||
m_ids.push_back( aItem->m_Uuid );
|
||||
|
||||
if( bItem )
|
||||
m_ids.push_back( bItem->m_Uuid );
|
||||
|
||||
+10
-28
@@ -48,35 +48,17 @@
|
||||
|
||||
static int vprint( std::string* result, const char* format, va_list ap )
|
||||
{
|
||||
char msg[512];
|
||||
// This function can call vsnprintf twice.
|
||||
// But internally, vsnprintf retrieves arguments from the va_list identified by arg as if
|
||||
// va_arg was used on it, and thus the state of the va_list is likely to be altered by the call.
|
||||
// see: www.cplusplus.com/reference/cstdio/vsnprintf
|
||||
// we make a copy of va_list ap for the second call, if happens
|
||||
va_list tmp;
|
||||
va_copy( tmp, ap );
|
||||
size_t len = vsnprintf( nullptr, 0, format, tmp );
|
||||
va_end( tmp );
|
||||
|
||||
size_t len = vsnprintf( msg, sizeof(msg), format, ap );
|
||||
// Resize the output to hold the required data
|
||||
size_t size = result->size();
|
||||
result->resize( size + len );
|
||||
|
||||
if( len < sizeof(msg) ) // the output fit into msg
|
||||
{
|
||||
result->append( msg, msg + len );
|
||||
}
|
||||
else
|
||||
{
|
||||
// output was too big, so now incur the expense of allocating
|
||||
// a buf for holding suffient characters.
|
||||
|
||||
std::vector<char> buf;
|
||||
buf.reserve( len+1 ); // reserve(), not resize() which writes. +1 for trailing nul.
|
||||
|
||||
len = vsnprintf( &buf[0], len+1, format, tmp );
|
||||
|
||||
result->append( &buf[0], &buf[0] + len );
|
||||
}
|
||||
|
||||
va_end( tmp ); // Release the temporary va_list, initialised from ap
|
||||
// Now do the actual printing
|
||||
len = vsnprintf( result->data() + size, len + 1, format, ap );
|
||||
|
||||
return len;
|
||||
}
|
||||
@@ -443,18 +425,18 @@ int OUTPUTFORMATTER::vprint( const char* fmt, va_list ap )
|
||||
// we make a copy of va_list ap for the second call, if happens
|
||||
va_list tmp;
|
||||
va_copy( tmp, ap );
|
||||
int ret = vsnprintf( &m_buffer[0], m_buffer.size(), fmt, ap );
|
||||
int ret = vsnprintf( m_buffer.data(), m_buffer.size(), fmt, ap );
|
||||
|
||||
if( ret >= (int) m_buffer.size() )
|
||||
{
|
||||
m_buffer.resize( ret + 1000 );
|
||||
ret = vsnprintf( &m_buffer[0], m_buffer.size(), fmt, tmp );
|
||||
ret = vsnprintf( m_buffer.data(), m_buffer.size(), fmt, tmp );
|
||||
}
|
||||
|
||||
va_end( tmp ); // Release the temporary va_list, initialised from ap
|
||||
|
||||
if( ret > 0 )
|
||||
write( &m_buffer[0], ret );
|
||||
write( m_buffer.data(), ret );
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -80,6 +80,20 @@ principle should be easily implemented by adapting the current STL containers.
|
||||
%ignore to_json;
|
||||
%ignore from_json;
|
||||
|
||||
%rename(GetEffectiveTextShapeNative) EDA_TEXT::GetEffectiveTextShape;
|
||||
|
||||
%extend EDA_TEXT
|
||||
{
|
||||
%pythoncode
|
||||
%{
|
||||
|
||||
# KiCad 7.0 API Compatibility
|
||||
def GetEffectiveTextShape(self, aTriangulate=True, aUseTextRotation=True):
|
||||
return self.GetEffectiveTextShapeNative(aTriangulate)
|
||||
|
||||
%}
|
||||
}
|
||||
|
||||
// headers/imports that must be included in the _wrapper.cpp at top
|
||||
|
||||
%{
|
||||
|
||||
@@ -59,6 +59,10 @@ ACTION_MENU::ACTION_MENU( bool isContextMenu, TOOL_INTERACTIVE* aTool ) :
|
||||
|
||||
ACTION_MENU::~ACTION_MENU()
|
||||
{
|
||||
Disconnect( wxEVT_COMMAND_MENU_SELECTED, wxMenuEventHandler( ACTION_MENU::OnMenuEvent ),
|
||||
nullptr, this );
|
||||
Disconnect( wxEVT_IDLE, wxIdleEventHandler( ACTION_MENU::OnIdle ), nullptr, this );
|
||||
|
||||
// Set parent to NULL to prevent submenus from unregistering from a nonexistent object
|
||||
for( ACTION_MENU* menu : m_submenus )
|
||||
menu->SetParent( nullptr );
|
||||
|
||||
@@ -569,7 +569,7 @@ TOOL_ACTION ACTIONS::selectionTool( "common.InteractiveSelection.selectionTool",
|
||||
_( "Select item(s)" ), _( "Select item(s)" ),
|
||||
BITMAPS::cursor, AF_ACTIVATE );
|
||||
|
||||
TOOL_ACTION ACTIONS::measureTool( "common.InteractiveEdit.measureTool",
|
||||
TOOL_ACTION ACTIONS::measureTool( "common.Interactive.measureTool",
|
||||
AS_GLOBAL,
|
||||
// Don't be tempted to remove "Modern Toolset only". It's in the legacy property name.
|
||||
MD_CTRL + MD_SHIFT + 'M', LEGACY_HK_NAME( "Measure Distance (Modern Toolset only)" ),
|
||||
|
||||
@@ -41,8 +41,12 @@ bool EDIT_POINT::WithinPoint( const VECTOR2I& aPoint, unsigned int aSize ) const
|
||||
}
|
||||
|
||||
|
||||
EDIT_POINTS::EDIT_POINTS( EDA_ITEM* aParent )
|
||||
: EDA_ITEM( NOT_USED ), m_parent( aParent ), m_allowPoints( true )
|
||||
EDIT_POINTS::EDIT_POINTS( EDA_ITEM* aParent ) :
|
||||
EDA_ITEM( NOT_USED ),
|
||||
m_parent( aParent ),
|
||||
m_swapX( false ),
|
||||
m_swapY( false ),
|
||||
m_allowPoints( true )
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -538,6 +538,23 @@ void TOOL_DISPATCHER::DispatchWxEvent( wxEvent& aEvent )
|
||||
}
|
||||
else if( type == wxEVT_MENU_OPEN || type == wxEVT_MENU_CLOSE || type == wxEVT_MENU_HIGHLIGHT )
|
||||
{
|
||||
wxMenuEvent* tmp = dynamic_cast<wxMenuEvent*>( &aEvent );
|
||||
|
||||
// Something is amiss if the event has these types and isn't a menu event, so bail out on
|
||||
// its processing
|
||||
if( !tmp )
|
||||
{
|
||||
aEvent.Skip();
|
||||
return;
|
||||
}
|
||||
|
||||
wxMenuEvent& menuEvent = *tmp;
|
||||
|
||||
#if wxCHECK_VERSION( 3, 2, 0 )
|
||||
// Forward the event to the menu for processing
|
||||
if( ACTION_MENU* currentMenu = dynamic_cast<ACTION_MENU*>( menuEvent.GetMenu() ) )
|
||||
currentMenu->OnMenuEvent( menuEvent );
|
||||
#else
|
||||
//
|
||||
// wxWidgets has several issues that we have to work around:
|
||||
//
|
||||
@@ -546,16 +563,13 @@ void TOOL_DISPATCHER::DispatchWxEvent( wxEvent& aEvent )
|
||||
// (FWIW, this one is fixed in wxWidgets 3.1.x.)
|
||||
//
|
||||
// 2) wxWidgets doesn't pass the menu pointer for wxEVT_MENU_HIGHLIGHT events. So we
|
||||
// store the menu pointer from the wxEVT_MENU_OPEN call.
|
||||
// store the menu pointer from the wxEVT_MENU_OPEN call (fixed in 3.1.3).
|
||||
//
|
||||
// 3) wxWidgets has no way to tell whether a command is from a menu selection or a
|
||||
// hotkey. So we keep track of menu highlighting so we can differentiate.
|
||||
//
|
||||
|
||||
static ACTION_MENU* currentMenu;
|
||||
|
||||
wxMenuEvent& menuEvent = *dynamic_cast<wxMenuEvent*>( &aEvent );
|
||||
|
||||
if( type == wxEVT_MENU_OPEN )
|
||||
{
|
||||
currentMenu = dynamic_cast<ACTION_MENU*>( menuEvent.GetMenu() );
|
||||
@@ -575,6 +589,7 @@ void TOOL_DISPATCHER::DispatchWxEvent( wxEvent& aEvent )
|
||||
|
||||
currentMenu = nullptr;
|
||||
}
|
||||
#endif
|
||||
|
||||
aEvent.Skip();
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
*
|
||||
* Copyright (C) 2018 jp.charras at wanadoo.fr
|
||||
* Copyright (C) 2011 Wayne Stambaugh <stambaughw@gmail.com>
|
||||
* Copyright (C) 2021-2022 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
* Copyright (C) 2021-2024 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
|
||||
@@ -96,6 +96,22 @@ bool PICKED_ITEMS_LIST::ContainsItem( const EDA_ITEM* aItem ) const
|
||||
}
|
||||
|
||||
|
||||
bool PICKED_ITEMS_LIST::ContainsItemType( KICAD_T aItemType ) const
|
||||
{
|
||||
for( const ITEM_PICKER& picker : m_ItemsList )
|
||||
{
|
||||
const EDA_ITEM* item = picker.GetItem();
|
||||
|
||||
wxCHECK2( item, continue );
|
||||
|
||||
if( item->Type() == aItemType )
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
int PICKED_ITEMS_LIST::FindItem( const EDA_ITEM* aItem ) const
|
||||
{
|
||||
for( size_t i = 0; i < m_ItemsList.size(); i++ )
|
||||
|
||||
@@ -360,7 +360,8 @@ void PAGED_DIALOG::onCharHook( wxKeyEvent& aEvent )
|
||||
{
|
||||
if( dynamic_cast<wxTextEntry*>( aEvent.GetEventObject() )
|
||||
|| dynamic_cast<wxStyledTextCtrl*>( aEvent.GetEventObject() )
|
||||
|| dynamic_cast<wxListView*>( aEvent.GetEventObject() ) )
|
||||
|| dynamic_cast<wxListView*>( aEvent.GetEventObject() )
|
||||
|| dynamic_cast<wxGrid*>( FindFocus() ) )
|
||||
{
|
||||
aEvent.Skip();
|
||||
return;
|
||||
@@ -378,7 +379,7 @@ void PAGED_DIALOG::onCharHook( wxKeyEvent& aEvent )
|
||||
m_treebook->SetSelection( page - 1 );
|
||||
}
|
||||
|
||||
m_treebook->GetTreeCtrl()->SetFocus(); // Don't allow preview canvas to steal focus
|
||||
m_treebook->GetTreeCtrl()->SetFocus(); // Don't allow preview canvas to steal gridFocus
|
||||
}
|
||||
else if( aEvent.GetKeyCode() == WXK_DOWN )
|
||||
{
|
||||
@@ -386,7 +387,7 @@ void PAGED_DIALOG::onCharHook( wxKeyEvent& aEvent )
|
||||
|
||||
m_treebook->SetSelection( std::min<int>( page + 1, m_treebook->GetPageCount() - 1 ) );
|
||||
|
||||
m_treebook->GetTreeCtrl()->SetFocus(); // Don't allow preview canvas to steal focus
|
||||
m_treebook->GetTreeCtrl()->SetFocus(); // Don't allow preview canvas to steal gridFocus
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -184,6 +184,9 @@ bool IFACE::OnKifaceStart( PGM_BASE* aProgram, int aCtlBits )
|
||||
}
|
||||
catch( const IO_ERROR& ioe )
|
||||
{
|
||||
// we didnt get anywhere deregister the settings
|
||||
aProgram->GetSettingsManager().FlushAndRelease( KifaceSettings(), false );
|
||||
|
||||
DisplayErrorMessage( nullptr, _( "An error occurred attempting to load the global "
|
||||
"footprint library table." ),
|
||||
ioe.What() );
|
||||
|
||||
@@ -185,6 +185,28 @@ bool SCH_EDIT_FRAME::SchematicCleanUp( SCH_SCREEN* aScreen )
|
||||
} );
|
||||
|
||||
|
||||
auto minX = []( const SCH_LINE* l )
|
||||
{
|
||||
return std::min( l->GetStartPoint().x, l->GetEndPoint().x );
|
||||
};
|
||||
|
||||
auto maxX = []( const SCH_LINE* l )
|
||||
{
|
||||
return std::max( l->GetStartPoint().x, l->GetEndPoint().x );
|
||||
};
|
||||
|
||||
auto minY = []( const SCH_LINE* l )
|
||||
{
|
||||
return std::min( l->GetStartPoint().y, l->GetEndPoint().y );
|
||||
};
|
||||
|
||||
auto maxY = []( const SCH_LINE* l )
|
||||
{
|
||||
return std::max( l->GetStartPoint().y, l->GetEndPoint().y );
|
||||
};
|
||||
|
||||
// Would be nice to put lines in a canonical form here by swapping
|
||||
// start <-> end as needed but I don't know what swapping breaks.
|
||||
while( changed )
|
||||
{
|
||||
changed = false;
|
||||
@@ -196,6 +218,13 @@ bool SCH_EDIT_FRAME::SchematicCleanUp( SCH_SCREEN* aScreen )
|
||||
lines.push_back( static_cast<SCH_LINE*>( item ) );
|
||||
}
|
||||
|
||||
// Sort by minimum X position
|
||||
std::sort( lines.begin(), lines.end(),
|
||||
[&]( const SCH_LINE* a, const SCH_LINE* b )
|
||||
{
|
||||
return minX( a ) < minX( b );
|
||||
} );
|
||||
|
||||
for( auto it1 = lines.begin(); it1 != lines.end(); ++it1 )
|
||||
{
|
||||
SCH_LINE* firstLine = *it1;
|
||||
@@ -209,11 +238,24 @@ bool SCH_EDIT_FRAME::SchematicCleanUp( SCH_SCREEN* aScreen )
|
||||
continue;
|
||||
}
|
||||
|
||||
int firstRightXEdge = maxX( firstLine );
|
||||
auto it2 = it1;
|
||||
|
||||
for( ++it2; it2 != lines.end(); ++it2 )
|
||||
{
|
||||
SCH_LINE* secondLine = *it2;
|
||||
int secondLeftXEdge = minX( secondLine );
|
||||
|
||||
// impossible to overlap remaining lines
|
||||
if( secondLeftXEdge > firstRightXEdge )
|
||||
break;
|
||||
|
||||
// No Y axis overlap
|
||||
if( !( std::max( minY( firstLine ), minY( secondLine ) )
|
||||
<= std::min( maxY( firstLine ), maxY( secondLine ) ) ) )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if( secondLine->GetFlags() & STRUCT_DELETED )
|
||||
continue;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2018 CERN
|
||||
* Copyright (C) 2021-2022 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
* Copyright (C) 2021-2024 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* @author Jon Evans <jon@craftyjon.com>
|
||||
*
|
||||
@@ -127,16 +127,9 @@ bool CONNECTION_SUBGRAPH::ResolveDrivers( bool aCheckMultipleDrivers )
|
||||
return a_name < b_name;
|
||||
};
|
||||
|
||||
auto strong_cmp = [this]( SCH_ITEM* a, SCH_ITEM* b ) -> bool
|
||||
{
|
||||
const wxString& a_name = GetNameForDriver( a );
|
||||
const wxString& b_name = GetNameForDriver( b );
|
||||
return a_name < b_name;
|
||||
};
|
||||
|
||||
PRIORITY highest_priority = PRIORITY::INVALID;
|
||||
std::set<SCH_ITEM*, decltype( candidate_cmp )> candidates( candidate_cmp );
|
||||
std::set<SCH_ITEM*, decltype( strong_cmp )> strong_drivers( strong_cmp );
|
||||
std::set<SCH_ITEM*> strong_drivers;
|
||||
|
||||
m_driver = nullptr;
|
||||
|
||||
@@ -239,7 +232,11 @@ void CONNECTION_SUBGRAPH::getAllConnectedItems( std::set<std::pair<SCH_SHEET_PAT
|
||||
sg = sg->m_absorbed_by;
|
||||
}
|
||||
|
||||
aSubgraphs.insert( sg );
|
||||
// If we are unable to insert the subgraph into the set, then we have already
|
||||
// visited it and don't need to add it again.
|
||||
if( aSubgraphs.insert( sg ).second == false )
|
||||
return;
|
||||
|
||||
aSubgraphs.insert( sg->m_absorbed_subgraphs.begin(), sg->m_absorbed_subgraphs.end() );
|
||||
|
||||
for( SCH_ITEM* item : sg->m_items )
|
||||
@@ -1345,11 +1342,15 @@ void CONNECTION_GRAPH::generateBusAliasMembers()
|
||||
wxString name = conn->FullLocalName();
|
||||
|
||||
CONNECTION_SUBGRAPH* new_sg = new CONNECTION_SUBGRAPH( this );
|
||||
|
||||
// This connection cannot form a part of the item because the item is not, itself
|
||||
// connected to this subgraph. It exists as part of a virtual item that may be connected
|
||||
// to other items but is not in the schematic.
|
||||
SCH_CONNECTION* new_conn = new SCH_CONNECTION( item, subgraph->m_sheet );
|
||||
new_conn->SetGraph( this );
|
||||
|
||||
new_conn->SetName( name );
|
||||
new_conn->SetType( CONNECTION_TYPE::NET );
|
||||
subgraph->StoreImplicitConnection( new_conn );
|
||||
int code = assignNewNetCode( *new_conn );
|
||||
|
||||
wxLogTrace( ConnTrace, wxS( "SG(%ld), Adding full local name (%s) with sg (%d) on subsheet %s" ), subgraph->m_code,
|
||||
@@ -2996,6 +2997,7 @@ bool CONNECTION_GRAPH::ercCheckBusToNetConflicts( const CONNECTION_SUBGRAPH* aSu
|
||||
if( net_item && bus_item )
|
||||
{
|
||||
std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( ERCE_BUS_TO_NET_CONFLICT );
|
||||
ercItem->SetSheetSpecificPath( sheet );
|
||||
ercItem->SetItems( net_item, bus_item );
|
||||
|
||||
SCH_MARKER* marker = new SCH_MARKER( ercItem, net_item->GetPosition() );
|
||||
@@ -3063,6 +3065,7 @@ bool CONNECTION_GRAPH::ercCheckBusToBusConflicts( const CONNECTION_SUBGRAPH* aSu
|
||||
if( !match )
|
||||
{
|
||||
std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( ERCE_BUS_TO_BUS_CONFLICT );
|
||||
ercItem->SetSheetSpecificPath( sheet );
|
||||
ercItem->SetItems( label, port );
|
||||
|
||||
SCH_MARKER* marker = new SCH_MARKER( ercItem, label->GetPosition() );
|
||||
@@ -3125,7 +3128,7 @@ bool CONNECTION_GRAPH::ercCheckBusToBusEntryConflicts( const CONNECTION_SUBGRAPH
|
||||
bus_name = bus_wire->Connection( &sheet )->Name();
|
||||
|
||||
std::set<wxString> test_names;
|
||||
test_names.insert( bus_entry->Connection( &sheet )->Name() );
|
||||
test_names.insert( bus_entry->Connection( &sheet )->FullLocalName() );
|
||||
|
||||
wxString baseName = sheet.PathHumanReadable();
|
||||
|
||||
@@ -3138,11 +3141,11 @@ bool CONNECTION_GRAPH::ercCheckBusToBusEntryConflicts( const CONNECTION_SUBGRAPH
|
||||
{
|
||||
for( const auto& sub_member : member->Members() )
|
||||
{
|
||||
if( test_names.count( sub_member->Name() ) )
|
||||
if( test_names.count( sub_member->FullLocalName() ) )
|
||||
conflict = false;
|
||||
}
|
||||
}
|
||||
else if( test_names.count( member->Name() ) )
|
||||
else if( test_names.count( member->FullLocalName() ) )
|
||||
{
|
||||
conflict = false;
|
||||
}
|
||||
@@ -3166,6 +3169,7 @@ bool CONNECTION_GRAPH::ercCheckBusToBusEntryConflicts( const CONNECTION_SUBGRAPH
|
||||
UnescapeString( netName ),
|
||||
UnescapeString( bus_name ) );
|
||||
std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( ERCE_BUS_ENTRY_CONFLICT );
|
||||
ercItem->SetSheetSpecificPath( sheet );
|
||||
ercItem->SetItems( bus_entry, bus_wire );
|
||||
ercItem->SetErrorMessage( msg );
|
||||
|
||||
@@ -3179,7 +3183,6 @@ bool CONNECTION_GRAPH::ercCheckBusToBusEntryConflicts( const CONNECTION_SUBGRAPH
|
||||
}
|
||||
|
||||
|
||||
// TODO(JE) Check sheet pins here too?
|
||||
bool CONNECTION_GRAPH::ercCheckNoConnects( const CONNECTION_SUBGRAPH* aSubgraph )
|
||||
{
|
||||
ERC_SETTINGS& settings = m_schematic->ErcSettings();
|
||||
@@ -3250,9 +3253,29 @@ bool CONNECTION_GRAPH::ercCheckNoConnects( const CONNECTION_SUBGRAPH* aSubgraph
|
||||
|
||||
if( aSubgraph->m_no_connect != nullptr )
|
||||
{
|
||||
// Special case: If the subgraph being checked consists of only a hier port/pin and
|
||||
// a no-connect, we don't issue a "no-connect connected" warning just because
|
||||
// connections exist on the sheet on the other side of the link.
|
||||
VECTOR2I noConnectPos = aSubgraph->m_no_connect->GetPosition();
|
||||
|
||||
for( SCH_SHEET_PIN* hierPin : aSubgraph->m_hier_pins )
|
||||
{
|
||||
if( hierPin->GetPosition() == noConnectPos )
|
||||
return true;
|
||||
}
|
||||
|
||||
for( SCH_HIERLABEL* hierLabel : aSubgraph->m_hier_ports )
|
||||
{
|
||||
if( hierLabel->GetPosition() == noConnectPos )
|
||||
return true;
|
||||
}
|
||||
|
||||
if( unique_pins.size() > 1 && settings.IsTestEnabled( ERCE_NOCONNECT_CONNECTED ) )
|
||||
{
|
||||
std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( ERCE_NOCONNECT_CONNECTED );
|
||||
ercItem->SetSheetSpecificPath( sheet );
|
||||
ercItem->SetItemsSheetPaths( sheet );
|
||||
|
||||
VECTOR2I pos;
|
||||
|
||||
if( pin )
|
||||
@@ -3276,6 +3299,8 @@ bool CONNECTION_GRAPH::ercCheckNoConnects( const CONNECTION_SUBGRAPH* aSubgraph
|
||||
{
|
||||
std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( ERCE_NOCONNECT_NOT_CONNECTED );
|
||||
ercItem->SetItems( aSubgraph->m_no_connect );
|
||||
ercItem->SetSheetSpecificPath( sheet );
|
||||
ercItem->SetItemsSheetPaths( sheet );
|
||||
|
||||
SCH_MARKER* marker = new SCH_MARKER( ercItem, aSubgraph->m_no_connect->GetPosition() );
|
||||
screen->Append( marker );
|
||||
@@ -3364,6 +3389,8 @@ bool CONNECTION_GRAPH::ercCheckNoConnects( const CONNECTION_SUBGRAPH* aSubgraph
|
||||
&& settings.IsTestEnabled( ERCE_PIN_NOT_CONNECTED ) )
|
||||
{
|
||||
std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( ERCE_PIN_NOT_CONNECTED );
|
||||
ercItem->SetSheetSpecificPath( sheet );
|
||||
ercItem->SetItemsSheetPaths( sheet );
|
||||
ercItem->SetItems( pin );
|
||||
|
||||
SCH_MARKER* marker = new SCH_MARKER( ercItem, pin->GetTransformedPosition() );
|
||||
@@ -3387,6 +3414,8 @@ bool CONNECTION_GRAPH::ercCheckNoConnects( const CONNECTION_SUBGRAPH* aSubgraph
|
||||
&& settings.IsTestEnabled( ERCE_PIN_NOT_CONNECTED ) )
|
||||
{
|
||||
std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( ERCE_PIN_NOT_CONNECTED );
|
||||
ercItem->SetSheetSpecificPath( sheet );
|
||||
ercItem->SetItemsSheetPaths( sheet );
|
||||
ercItem->SetItems( testPin );
|
||||
|
||||
SCH_MARKER* marker = new SCH_MARKER( ercItem,
|
||||
@@ -3408,6 +3437,7 @@ bool CONNECTION_GRAPH::ercCheckFloatingWires( const CONNECTION_SUBGRAPH* aSubgra
|
||||
if( aSubgraph->m_driver )
|
||||
return true;
|
||||
|
||||
const SCH_SHEET_PATH& sheet = aSubgraph->m_sheet;
|
||||
std::vector<SCH_ITEM*> wires;
|
||||
|
||||
// We've gotten this far, so we know we have no valid driver. All we need to do is check
|
||||
@@ -3426,6 +3456,7 @@ bool CONNECTION_GRAPH::ercCheckFloatingWires( const CONNECTION_SUBGRAPH* aSubgra
|
||||
SCH_SCREEN* screen = aSubgraph->m_sheet.LastScreen();
|
||||
|
||||
std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( ERCE_WIRE_DANGLING );
|
||||
ercItem->SetSheetSpecificPath( sheet );
|
||||
ercItem->SetItems( wires[0],
|
||||
wires.size() > 1 ? wires[1] : nullptr,
|
||||
wires.size() > 2 ? wires[2] : nullptr,
|
||||
@@ -3458,6 +3489,7 @@ bool CONNECTION_GRAPH::ercCheckLabels( const CONNECTION_SUBGRAPH* aSubgraph )
|
||||
if( aSubgraph->m_driver_connection->IsBus() )
|
||||
return true;
|
||||
|
||||
const SCH_SHEET_PATH& sheet = aSubgraph->m_sheet;
|
||||
ERC_SETTINGS& settings = m_schematic->ErcSettings();
|
||||
bool ok = true;
|
||||
int pinCount = 0;
|
||||
@@ -3479,6 +3511,7 @@ bool CONNECTION_GRAPH::ercCheckLabels( const CONNECTION_SUBGRAPH* aSubgraph )
|
||||
if( settings.IsTestEnabled( errCode ) )
|
||||
{
|
||||
std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( errCode );
|
||||
ercItem->SetSheetSpecificPath( sheet );
|
||||
ercItem->SetItems( aText );
|
||||
|
||||
SCH_MARKER* marker = new SCH_MARKER( ercItem, aText->GetPosition() );
|
||||
@@ -3613,6 +3646,8 @@ int CONNECTION_GRAPH::ercCheckHierSheets()
|
||||
{
|
||||
std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( ERCE_PIN_NOT_CONNECTED );
|
||||
ercItem->SetItems( pin );
|
||||
ercItem->SetSheetSpecificPath( sheet );
|
||||
ercItem->SetItemsSheetPaths( sheet );
|
||||
|
||||
SCH_MARKER* marker = new SCH_MARKER( ercItem, pin->GetPosition() );
|
||||
sheet.LastScreen()->Append( marker );
|
||||
|
||||
@@ -89,7 +89,11 @@ public:
|
||||
m_hier_parent( nullptr )
|
||||
{}
|
||||
|
||||
~CONNECTION_SUBGRAPH() = default;
|
||||
~CONNECTION_SUBGRAPH()
|
||||
{
|
||||
for( SCH_CONNECTION* connection : m_bus_element_connections )
|
||||
delete connection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines which potential driver should drive the subgraph.
|
||||
@@ -162,6 +166,13 @@ public:
|
||||
|
||||
void RemoveItem( SCH_ITEM* aItem );
|
||||
|
||||
// Use this to keep a connection pointer that is not owned by any item
|
||||
// This will be destroyed with the subgraph
|
||||
void StoreImplicitConnection( SCH_CONNECTION* aConnection )
|
||||
{
|
||||
m_bus_element_connections.insert( aConnection );
|
||||
}
|
||||
|
||||
private:
|
||||
wxString driverName( SCH_ITEM* aItem ) const;
|
||||
|
||||
@@ -251,6 +262,10 @@ public:
|
||||
/// A cache of escaped netnames from schematic items
|
||||
mutable std::unordered_map<SCH_ITEM*, wxString> m_driver_name_cache;
|
||||
|
||||
/// A cache of connections that are part of this subgraph but that don't have
|
||||
/// an owning element (i.e. bus members)
|
||||
std::set<SCH_CONNECTION*> m_bus_element_connections;
|
||||
|
||||
};
|
||||
|
||||
struct NET_NAME_CODE_CACHE_KEY
|
||||
|
||||
@@ -350,14 +350,35 @@ void DIALOG_CHANGE_SYMBOLS::updateFieldsList()
|
||||
}
|
||||
|
||||
// Update the listbox widget
|
||||
for( unsigned i = m_fieldsBox->GetCount() - 1; i >= MANDATORY_FIELDS; --i )
|
||||
m_fieldsBox->Delete( i );
|
||||
wxArrayInt checkedItems;
|
||||
wxArrayString checkedNames;
|
||||
|
||||
m_fieldsBox->GetCheckedItems( checkedItems );
|
||||
|
||||
for( int ii : checkedItems )
|
||||
checkedNames.push_back( m_fieldsBox->GetString( ii ) );
|
||||
|
||||
bool allChecked = true;
|
||||
|
||||
for( unsigned ii = 0; ii < m_fieldsBox->GetCount(); ++ii )
|
||||
{
|
||||
if( ii == REFERENCE_FIELD || ii == VALUE_FIELD )
|
||||
continue;
|
||||
|
||||
if( !m_fieldsBox->IsChecked( ii ) )
|
||||
allChecked = false;
|
||||
}
|
||||
|
||||
for( unsigned ii = m_fieldsBox->GetCount() - 1; ii >= MANDATORY_FIELDS; --ii )
|
||||
m_fieldsBox->Delete( ii );
|
||||
|
||||
for( const wxString& fieldName : fieldNames )
|
||||
{
|
||||
m_fieldsBox->Append( fieldName );
|
||||
|
||||
for( unsigned i = MANDATORY_FIELDS; i < m_fieldsBox->GetCount(); ++i )
|
||||
m_fieldsBox->Check( i, true );
|
||||
if( allChecked || alg::contains( checkedNames, fieldName ) )
|
||||
m_fieldsBox->Check( m_fieldsBox->GetCount() - 1, true );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -361,6 +361,12 @@ bool DIALOG_LIB_SYMBOL_PROPERTIES::TransferDataFromWindow()
|
||||
wxString newName = EscapeString( m_SymbolNameCtrl->GetValue(), CTX_LIBID );
|
||||
wxString oldName = m_libEntry->GetName();
|
||||
|
||||
if( newName.IsEmpty() )
|
||||
{
|
||||
wxMessageBox( _( "Symbol must have a name." ) );
|
||||
return false;
|
||||
}
|
||||
|
||||
if( oldName != newName )
|
||||
{
|
||||
wxString libName = m_Parent->GetCurLib();
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2009 Wayne Stambaugh <stambaughw@gmail.com>
|
||||
* Copyright (C) 2014-2023 KiCad Developers, see CHANGELOG.txt for contributors.
|
||||
* Copyright (C) 2014-2024 KiCad Developers, see CHANGELOG.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
|
||||
@@ -667,6 +667,9 @@ bool DIALOG_SHEET_PROPERTIES::onSheetFilenameChanged( const wxString& aNewFilena
|
||||
if( m_clearAnnotationNewItems )
|
||||
*m_clearAnnotationNewItems = clearAnnotation;
|
||||
|
||||
// Rebuild the entire connection graph.
|
||||
m_frame->RecalculateConnections( GLOBAL_CLEANUP );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -49,19 +49,20 @@ using CATEGORY = SIM_MODEL::PARAM::CATEGORY;
|
||||
|
||||
template <typename T_symbol, typename T_field>
|
||||
DIALOG_SIM_MODEL<T_symbol, T_field>::DIALOG_SIM_MODEL( wxWindow* aParent, T_symbol& aSymbol,
|
||||
std::vector<T_field>& aFields )
|
||||
: DIALOG_SIM_MODEL_BASE( aParent ),
|
||||
m_symbol( aSymbol ),
|
||||
m_fields( aFields ),
|
||||
m_libraryModelsMgr( &Prj() ),
|
||||
m_builtinModelsMgr( &Prj() ),
|
||||
m_prevModel( nullptr ),
|
||||
m_curModelType( SIM_MODEL::TYPE::NONE ),
|
||||
m_scintillaTricks( nullptr ),
|
||||
m_firstCategory( nullptr ),
|
||||
m_prevParamGridSelection( nullptr ),
|
||||
m_lastParamGridWidth( 0 ),
|
||||
m_inKillFocus( false )
|
||||
std::vector<T_field>& aFields ) :\
|
||||
DIALOG_SIM_MODEL_BASE( aParent ),
|
||||
m_symbol( aSymbol ),
|
||||
m_fields( aFields ),
|
||||
m_libraryModelsMgr( &Prj() ),
|
||||
m_builtinModelsMgr( &Prj() ),
|
||||
m_prevModel( nullptr ),
|
||||
m_curModelType( SIM_MODEL::TYPE::NONE ),
|
||||
m_scintillaTricksCode( nullptr ),
|
||||
m_scintillaTricksSubckt( nullptr ),
|
||||
m_firstCategory( nullptr ),
|
||||
m_prevParamGridSelection( nullptr ),
|
||||
m_lastParamGridWidth( 0 ),
|
||||
m_inKillFocus( false )
|
||||
{
|
||||
m_browseButton->SetBitmap( KiBitmap( BITMAPS::small_folder ) );
|
||||
|
||||
@@ -81,7 +82,8 @@ DIALOG_SIM_MODEL<T_symbol, T_field>::DIALOG_SIM_MODEL( wxWindow* aParent, T_symb
|
||||
|
||||
m_typeChoice->Clear();
|
||||
|
||||
m_scintillaTricks = new SCINTILLA_TRICKS( m_codePreview, wxT( "{}" ), false );
|
||||
m_scintillaTricksCode = new SCINTILLA_TRICKS( m_codePreview, wxT( "{}" ), false );
|
||||
m_scintillaTricksSubckt = new SCINTILLA_TRICKS( m_subckt, wxT( "()" ), false );
|
||||
|
||||
m_paramGridMgr->Bind( wxEVT_PG_SELECTED, &DIALOG_SIM_MODEL::onParamGridSelectionChange, this );
|
||||
|
||||
@@ -131,7 +133,8 @@ DIALOG_SIM_MODEL<T_symbol, T_field>::~DIALOG_SIM_MODEL()
|
||||
// Delete the GRID_TRICKS.
|
||||
m_pinAssignmentsGrid->PopEventHandler( true );
|
||||
|
||||
delete m_scintillaTricks;
|
||||
delete m_scintillaTricksCode;
|
||||
delete m_scintillaTricksSubckt;
|
||||
}
|
||||
|
||||
|
||||
@@ -663,6 +666,7 @@ void DIALOG_SIM_MODEL<T_symbol, T_field>::updatePinAssignments( SIM_MODEL* aMode
|
||||
{
|
||||
SIM_MODEL_SUBCKT* subckt = static_cast<SIM_MODEL_SUBCKT*>( aModel );
|
||||
m_subckt->SetText( subckt->GetSpiceCode() );
|
||||
m_subckt->SetEditable( false );
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -130,7 +130,8 @@ private:
|
||||
std::map<SIM_MODEL::DEVICE_T, SIM_MODEL::TYPE> m_curModelTypeOfDeviceType;
|
||||
SIM_MODEL::TYPE m_curModelType;
|
||||
|
||||
SCINTILLA_TRICKS* m_scintillaTricks;
|
||||
SCINTILLA_TRICKS* m_scintillaTricksCode;
|
||||
SCINTILLA_TRICKS* m_scintillaTricksSubckt;
|
||||
|
||||
wxPGProperty* m_firstCategory; // Used to add principal parameters to root.
|
||||
wxPGProperty* m_prevParamGridSelection;
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2017 Wayne Stambaugh <stambaughw@gmail.com>
|
||||
* 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
|
||||
@@ -54,10 +54,16 @@ DIALOG_SYMBOL_REMAP::DIALOG_SYMBOL_REMAP( SCH_EDIT_FRAME* aParent ) :
|
||||
{
|
||||
m_remapped = false;
|
||||
|
||||
if( !wxFileName::IsDirWritable( Prj().GetProjectPath() ) )
|
||||
wxString projectPath = Prj().GetProjectPath();
|
||||
|
||||
if( !wxFileName::IsDirWritable( projectPath ) )
|
||||
{
|
||||
DisplayInfoMessage( this, _( "Remapping is not possible because you have insufficient "
|
||||
"privileges to the project folder '%s'." ) );
|
||||
wxString msg =
|
||||
wxString::Format( _( "Remapping is not possible because you have insufficient "
|
||||
"privileges to the project folder '%s'." ),
|
||||
projectPath );
|
||||
|
||||
DisplayInfoMessage( this, msg );
|
||||
|
||||
// Disable the remap button.
|
||||
m_remapped = true;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// C++ code generated with wxFormBuilder (version 3.10.1-0-g8feb16b)
|
||||
// C++ code generated with wxFormBuilder (version 3.10.1-0-g8feb16b3)
|
||||
// http://www.wxformbuilder.org/
|
||||
//
|
||||
// PLEASE DO *NOT* EDIT THIS FILE!
|
||||
@@ -296,10 +296,10 @@ DIALOG_TEXT_PROPERTIES_BASE::DIALOG_TEXT_PROPERTIES_BASE( wxWindow* parent, wxWi
|
||||
bSizer11 = new wxBoxSizer( wxHORIZONTAL );
|
||||
|
||||
m_hyperlinkCombo = new WX_COMBOBOX( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0, NULL, 0 );
|
||||
bSizer11->Add( m_hyperlinkCombo, 1, wxALIGN_CENTER_VERTICAL, 5 );
|
||||
bSizer11->Add( m_hyperlinkCombo, 1, wxALIGN_CENTER_VERTICAL|wxFIXED_MINSIZE, 5 );
|
||||
|
||||
|
||||
m_textEntrySizer->Add( bSizer11, wxGBPosition( 9, 1 ), wxGBSpan( 1, 6 ), wxEXPAND|wxBOTTOM|wxALIGN_CENTER_VERTICAL, 5 );
|
||||
m_textEntrySizer->Add( bSizer11, wxGBPosition( 9, 1 ), wxGBSpan( 1, 5 ), wxEXPAND|wxBOTTOM|wxALIGN_CENTER_VERTICAL, 5 );
|
||||
|
||||
|
||||
m_textEntrySizer->AddGrowableCol( 3 );
|
||||
|
||||
@@ -2925,7 +2925,7 @@
|
||||
</object>
|
||||
<object class="gbsizeritem" expanded="1">
|
||||
<property name="border">5</property>
|
||||
<property name="colspan">6</property>
|
||||
<property name="colspan">5</property>
|
||||
<property name="column">1</property>
|
||||
<property name="flag">wxEXPAND|wxBOTTOM|wxALIGN_CENTER_VERTICAL</property>
|
||||
<property name="row">9</property>
|
||||
@@ -2937,7 +2937,7 @@
|
||||
<property name="permission">none</property>
|
||||
<object class="sizeritem" expanded="1">
|
||||
<property name="border">5</property>
|
||||
<property name="flag">wxALIGN_CENTER_VERTICAL</property>
|
||||
<property name="flag">wxALIGN_CENTER_VERTICAL|wxFIXED_MINSIZE</property>
|
||||
<property name="proportion">1</property>
|
||||
<object class="wxBitmapComboBox" expanded="1">
|
||||
<property name="BottomDockable">1</property>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// C++ code generated with wxFormBuilder (version 3.10.1-0-g8feb16b)
|
||||
// C++ code generated with wxFormBuilder (version 3.10.1-0-g8feb16b3)
|
||||
// http://www.wxformbuilder.org/
|
||||
//
|
||||
// PLEASE DO *NOT* EDIT THIS FILE!
|
||||
|
||||
@@ -238,7 +238,7 @@ void PANEL_EESCHEMA_COLOR_SETTINGS::createPreviewItems()
|
||||
{
|
||||
KIGFX::VIEW* view = m_preview->GetView();
|
||||
|
||||
std::vector<DANGLING_END_ITEM> endPoints;
|
||||
std::vector<DANGLING_END_ITEM> endPointsByType;
|
||||
|
||||
m_page = new PAGE_INFO( PAGE_INFO::Custom );
|
||||
m_titleBlock = new TITLE_BLOCK;
|
||||
@@ -396,7 +396,7 @@ void PANEL_EESCHEMA_COLOR_SETTINGS::createPreviewItems()
|
||||
pin->SetNumber( wxT( "1" ) );
|
||||
pin->SetName( wxT( "-" ) );
|
||||
|
||||
endPoints.emplace_back( PIN_END, pin, mapLibItemPosition( pin->GetPosition() ) );
|
||||
endPointsByType.emplace_back( PIN_END, pin, mapLibItemPosition( pin->GetPosition() ) );
|
||||
symbol->AddDrawItem( pin );
|
||||
|
||||
pin = new LIB_PIN( symbol );
|
||||
@@ -408,7 +408,7 @@ void PANEL_EESCHEMA_COLOR_SETTINGS::createPreviewItems()
|
||||
pin->SetNumber( wxT( "2" ) );
|
||||
pin->SetName( wxT( "+" ) );
|
||||
|
||||
endPoints.emplace_back( PIN_END, pin, mapLibItemPosition( pin->GetPosition() ) );
|
||||
endPointsByType.emplace_back( PIN_END, pin, mapLibItemPosition( pin->GetPosition() ) );
|
||||
symbol->AddDrawItem( pin );
|
||||
|
||||
pin = new LIB_PIN( symbol );
|
||||
@@ -420,7 +420,7 @@ void PANEL_EESCHEMA_COLOR_SETTINGS::createPreviewItems()
|
||||
pin->SetNumber( wxT( "3" ) );
|
||||
pin->SetName( wxT( "OUT" ) );
|
||||
|
||||
endPoints.emplace_back( PIN_END, pin, mapLibItemPosition( pin->GetPosition() ) );
|
||||
endPointsByType.emplace_back( PIN_END, pin, mapLibItemPosition( pin->GetPosition() ) );
|
||||
symbol->AddDrawItem( pin );
|
||||
|
||||
addItem( symbol );
|
||||
@@ -445,16 +445,19 @@ void PANEL_EESCHEMA_COLOR_SETTINGS::createPreviewItems()
|
||||
if( sch_item && sch_item->IsConnectable() )
|
||||
{
|
||||
sch_item->AutoplaceFields( nullptr, false );
|
||||
sch_item->GetEndPoints( endPoints );
|
||||
sch_item->GetEndPoints( endPointsByType );
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<DANGLING_END_ITEM> endPointsByPos = endPointsByType;
|
||||
DANGLING_END_ITEM_HELPER::sort_dangling_end_items( endPointsByType, endPointsByPos );
|
||||
|
||||
for( EDA_ITEM* item : m_previewItems )
|
||||
{
|
||||
SCH_ITEM* sch_item = dynamic_cast<SCH_ITEM*>( item );
|
||||
|
||||
if( sch_item && sch_item->IsConnectable() )
|
||||
sch_item->UpdateDanglingState( endPoints, nullptr );
|
||||
sch_item->UpdateDanglingState( endPointsByType, endPointsByPos, nullptr );
|
||||
}
|
||||
|
||||
zoomFitPreview();
|
||||
|
||||
@@ -334,7 +334,8 @@ bool IFACE::OnKifaceStart( PGM_BASE* aProgram, int aCtlBits )
|
||||
InitSettings( new EESCHEMA_SETTINGS );
|
||||
// Register the symbol editor settings as well because they share a KiFACE and need to be
|
||||
// loaded prior to use to avoid threading deadlocks
|
||||
aProgram->GetSettingsManager().RegisterSettings( new SYMBOL_EDITOR_SETTINGS );
|
||||
SYMBOL_EDITOR_SETTINGS* symSettings = new SYMBOL_EDITOR_SETTINGS();
|
||||
aProgram->GetSettingsManager().RegisterSettings( symSettings ); // manager takes ownership
|
||||
|
||||
// We intentionally register KifaceSettings after SYMBOL_EDITOR_SETTINGS
|
||||
// In legacy configs, many settings were in a single editor config nd the migration routine
|
||||
@@ -345,7 +346,12 @@ bool IFACE::OnKifaceStart( PGM_BASE* aProgram, int aCtlBits )
|
||||
start_common( aCtlBits );
|
||||
|
||||
if( !loadGlobalLibTable() )
|
||||
{
|
||||
// we didnt get anywhere deregister the settings
|
||||
aProgram->GetSettingsManager().FlushAndRelease( symSettings, false );
|
||||
aProgram->GetSettingsManager().FlushAndRelease( KifaceSettings(), false );
|
||||
return false;
|
||||
}
|
||||
|
||||
m_jobHandler = std::make_unique<EESCHEMA_JOBS_HANDLER>();
|
||||
|
||||
|
||||
@@ -91,7 +91,7 @@ void EESCHEMA_JOBS_HANDLER::InitRenderSettings( KIGFX::SCH_RENDER_SETTINGS* aRen
|
||||
aSch->Prj().GetProjectPath() );
|
||||
|
||||
if( !DS_DATA_MODEL::GetTheInstance().LoadDrawingSheet( filename ) )
|
||||
wxFprintf( stderr, _( "Error loading drawing sheet." ) );
|
||||
wxFprintf( stderr, _( "Error loading drawing sheet." ) + wxS( "\n" ) );
|
||||
}
|
||||
|
||||
|
||||
@@ -379,7 +379,7 @@ int EESCHEMA_JOBS_HANDLER::doSymExportSvg( JOB_SYM_EXPORT_SVG* aSvgJob,
|
||||
|
||||
if( !plotter->OpenFile( fn.GetFullPath() ) )
|
||||
{
|
||||
wxFprintf( stderr, _( "Unable to open destination '%s'" ), fn.GetFullPath() );
|
||||
wxFprintf( stderr, _( "Unable to open destination '%s'" ) + wxS( "\n" ), fn.GetFullPath() );
|
||||
|
||||
delete plotter;
|
||||
return CLI::EXIT_CODES::ERR_INVALID_INPUT_FILE;
|
||||
@@ -442,7 +442,7 @@ int EESCHEMA_JOBS_HANDLER::JobSymExportSvg( JOB* aJob )
|
||||
|
||||
if( !symbol )
|
||||
{
|
||||
wxFprintf( stderr, _( "There is no symbol selected to save." ) );
|
||||
wxFprintf( stderr, _( "There is no symbol selected to save." ) + wxS( "\n" ) );
|
||||
return CLI::EXIT_CODES::ERR_ARGS;
|
||||
}
|
||||
}
|
||||
|
||||
+12
-19
@@ -3,7 +3,7 @@
|
||||
*
|
||||
* Copyright (C) 2015 Jean-Pierre Charras, jp.charras at wanadoo.fr
|
||||
* Copyright (C) 2011 Wayne Stambaugh <stambaughw@gmail.com>
|
||||
* Copyright (C) 1992-2023 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
* Copyright (C) 1992-2024 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
|
||||
@@ -215,6 +215,7 @@ void ERC_TESTER::TestTextVars( DS_PROXY_VIEW_ITEM* aDrawingSheet )
|
||||
std::shared_ptr<ERC_ITEM> ercItem =
|
||||
ERC_ITEM::Create( ERCE_UNRESOLVED_VARIABLE );
|
||||
ercItem->SetItems( &field );
|
||||
ercItem->SetSheetSpecificPath( sheet );
|
||||
|
||||
SCH_MARKER* marker = new SCH_MARKER( ercItem, pos );
|
||||
screen->Append( marker );
|
||||
@@ -232,6 +233,7 @@ void ERC_TESTER::TestTextVars( DS_PROXY_VIEW_ITEM* aDrawingSheet )
|
||||
std::shared_ptr<ERC_ITEM> ercItem =
|
||||
ERC_ITEM::Create( ERCE_UNRESOLVED_VARIABLE );
|
||||
ercItem->SetItems( &field );
|
||||
ercItem->SetSheetSpecificPath( sheet );
|
||||
|
||||
SCH_MARKER* marker = new SCH_MARKER( ercItem, field.GetPosition() );
|
||||
screen->Append( marker );
|
||||
@@ -245,6 +247,7 @@ void ERC_TESTER::TestTextVars( DS_PROXY_VIEW_ITEM* aDrawingSheet )
|
||||
std::shared_ptr<ERC_ITEM> ercItem =
|
||||
ERC_ITEM::Create( ERCE_UNRESOLVED_VARIABLE );
|
||||
ercItem->SetItems( pin );
|
||||
ercItem->SetSheetSpecificPath( sheet );
|
||||
|
||||
SCH_MARKER* marker = new SCH_MARKER( ercItem, pin->GetPosition() );
|
||||
screen->Append( marker );
|
||||
@@ -258,6 +261,7 @@ void ERC_TESTER::TestTextVars( DS_PROXY_VIEW_ITEM* aDrawingSheet )
|
||||
std::shared_ptr<ERC_ITEM> ercItem =
|
||||
ERC_ITEM::Create( ERCE_UNRESOLVED_VARIABLE );
|
||||
ercItem->SetItems( text );
|
||||
ercItem->SetSheetSpecificPath( sheet );
|
||||
|
||||
SCH_MARKER* marker = new SCH_MARKER( ercItem, text->GetPosition() );
|
||||
screen->Append( marker );
|
||||
@@ -270,6 +274,7 @@ void ERC_TESTER::TestTextVars( DS_PROXY_VIEW_ITEM* aDrawingSheet )
|
||||
std::shared_ptr<ERC_ITEM> ercItem =
|
||||
ERC_ITEM::Create( ERCE_UNRESOLVED_VARIABLE );
|
||||
ercItem->SetItems( textBox );
|
||||
ercItem->SetSheetSpecificPath( sheet );
|
||||
|
||||
SCH_MARKER* marker = new SCH_MARKER( ercItem, textBox->GetPosition() );
|
||||
screen->Append( marker );
|
||||
@@ -285,6 +290,7 @@ void ERC_TESTER::TestTextVars( DS_PROXY_VIEW_ITEM* aDrawingSheet )
|
||||
{
|
||||
std::shared_ptr<ERC_ITEM> erc = ERC_ITEM::Create( ERCE_UNRESOLVED_VARIABLE );
|
||||
erc->SetErrorMessage( _( "Unresolved text variable in drawing sheet" ) );
|
||||
erc->SetSheetSpecificPath( sheet );
|
||||
|
||||
SCH_MARKER* marker = new SCH_MARKER( erc, text->GetPosition() );
|
||||
screen->Append( marker );
|
||||
@@ -580,6 +586,7 @@ int ERC_TESTER::TestNoConnectPins()
|
||||
pair.second.size() > 2 ? pair.second[2] : nullptr,
|
||||
pair.second.size() > 3 ? pair.second[3] : nullptr );
|
||||
ercItem->SetErrorMessage( _( "Pins with 'no connection' type are connected" ) );
|
||||
ercItem->SetSheetSpecificPath( sheet );
|
||||
|
||||
SCH_MARKER* marker = new SCH_MARKER( ercItem, pair.first );
|
||||
sheet.LastScreen()->Append( marker );
|
||||
@@ -619,8 +626,6 @@ int ERC_TESTER::TestPinToPin()
|
||||
}
|
||||
}
|
||||
|
||||
std::set<std::pair<ERC_SCH_PIN_CONTEXT, ERC_SCH_PIN_CONTEXT>> tested;
|
||||
|
||||
ERC_SCH_PIN_CONTEXT needsDriver;
|
||||
bool hasDriver = false;
|
||||
|
||||
@@ -638,8 +643,9 @@ int ERC_TESTER::TestPinToPin()
|
||||
}
|
||||
}
|
||||
|
||||
for( ERC_SCH_PIN_CONTEXT& refPin : pins )
|
||||
for( auto refIt = pins.begin(); refIt != pins.end(); ++refIt )
|
||||
{
|
||||
ERC_SCH_PIN_CONTEXT& refPin = *refIt;
|
||||
ELECTRICAL_PINTYPE refType = refPin.Pin()->GetType();
|
||||
|
||||
if( DrivenPinTypes.count( refType ) )
|
||||
@@ -663,22 +669,9 @@ int ERC_TESTER::TestPinToPin()
|
||||
else
|
||||
hasDriver |= ( DrivingPinTypes.count( refType ) != 0 );
|
||||
|
||||
for( ERC_SCH_PIN_CONTEXT& testPin : pins )
|
||||
for( auto testIt = refIt + 1; testIt != pins.end(); ++testIt )
|
||||
{
|
||||
if( testPin == refPin )
|
||||
continue;
|
||||
|
||||
ERC_SCH_PIN_CONTEXT first_pin = refPin;
|
||||
ERC_SCH_PIN_CONTEXT second_pin = testPin;
|
||||
|
||||
if( second_pin < first_pin )
|
||||
std::swap( first_pin, second_pin );
|
||||
|
||||
std::pair<ERC_SCH_PIN_CONTEXT, ERC_SCH_PIN_CONTEXT> pair =
|
||||
std::make_pair( first_pin, second_pin );
|
||||
|
||||
if( auto [ins_pin, inserted ] = tested.insert( pair ); !inserted )
|
||||
continue;
|
||||
ERC_SCH_PIN_CONTEXT& testPin = *testIt;
|
||||
|
||||
// Multiple pins in the same symbol that share a type,
|
||||
// name and position are considered
|
||||
|
||||
@@ -580,7 +580,7 @@ wxString FIELDS_GRID_TABLE<T>::GetValue( int aRow, int aCol )
|
||||
return StringFromBool( field.IsNameShown() );
|
||||
|
||||
case FDC_H_ALIGN:
|
||||
switch ( field.GetHorizJustify() )
|
||||
switch ( field.GetEffectiveHorizJustify() )
|
||||
{
|
||||
case GR_TEXT_H_ALIGN_LEFT: return _( "Left" );
|
||||
case GR_TEXT_H_ALIGN_CENTER: return _( "Center" );
|
||||
@@ -590,7 +590,7 @@ wxString FIELDS_GRID_TABLE<T>::GetValue( int aRow, int aCol )
|
||||
break;
|
||||
|
||||
case FDC_V_ALIGN:
|
||||
switch ( field.GetVertJustify() )
|
||||
switch ( field.GetEffectiveVertJustify() )
|
||||
{
|
||||
case GR_TEXT_V_ALIGN_TOP: return _( "Top" );
|
||||
case GR_TEXT_V_ALIGN_CENTER: return _( "Center" );
|
||||
@@ -727,28 +727,52 @@ void FIELDS_GRID_TABLE<T>::SetValue( int aRow, int aCol, const wxString &aValue
|
||||
break;
|
||||
|
||||
case FDC_H_ALIGN:
|
||||
{
|
||||
GR_TEXT_H_ALIGN_T horizontalJustification;
|
||||
|
||||
if( value == _( "Left" ) )
|
||||
field.SetHorizJustify( GR_TEXT_H_ALIGN_LEFT );
|
||||
horizontalJustification = GR_TEXT_H_ALIGN_LEFT;
|
||||
else if( value == _( "Center" ) )
|
||||
field.SetHorizJustify( GR_TEXT_H_ALIGN_CENTER );
|
||||
horizontalJustification = GR_TEXT_H_ALIGN_CENTER;
|
||||
else if( value == _( "Right" ) )
|
||||
field.SetHorizJustify( GR_TEXT_H_ALIGN_RIGHT );
|
||||
horizontalJustification = GR_TEXT_H_ALIGN_RIGHT;
|
||||
else
|
||||
wxFAIL_MSG( wxT( "unknown horizontal alignment: " ) + value );
|
||||
|
||||
// Note that we must set justifications before we can ask if they're flipped. If the old
|
||||
// justification is center then it won't know (whereas if the new justification is center
|
||||
// the we don't care).
|
||||
field.SetHorizJustify( horizontalJustification );
|
||||
|
||||
if( field.IsHorizJustifyFlipped() )
|
||||
field.SetHorizJustify( EDA_TEXT::MapHorizJustify( - horizontalJustification ) );
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case FDC_V_ALIGN:
|
||||
{
|
||||
GR_TEXT_V_ALIGN_T verticalJustification;
|
||||
|
||||
if( value == _( "Top" ) )
|
||||
field.SetVertJustify( GR_TEXT_V_ALIGN_TOP );
|
||||
verticalJustification = GR_TEXT_V_ALIGN_TOP;
|
||||
else if( value == _( "Center" ) )
|
||||
field.SetVertJustify( GR_TEXT_V_ALIGN_CENTER );
|
||||
verticalJustification = GR_TEXT_V_ALIGN_CENTER;
|
||||
else if( value == _( "Bottom" ) )
|
||||
field.SetVertJustify( GR_TEXT_V_ALIGN_BOTTOM );
|
||||
verticalJustification = GR_TEXT_V_ALIGN_BOTTOM;
|
||||
else
|
||||
wxFAIL_MSG( wxT( "unknown vertical alignment: " ) + value);
|
||||
|
||||
// Note that we must set justifications before we can ask if they're flipped. If the old
|
||||
// justification is center then it won't know (whereas if the new justification is center
|
||||
// the we don't care).
|
||||
field.SetVertJustify( verticalJustification );
|
||||
|
||||
if( field.IsVertJustifyFlipped() )
|
||||
field.SetVertJustify( EDA_TEXT::MapVertJustify( -verticalJustification ) );
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case FDC_ITALIC:
|
||||
field.SetItalic( BoolFromString( value ) );
|
||||
|
||||
+14
-2
@@ -103,7 +103,7 @@ bool SCH_EDIT_FRAME::OpenProjectFiles( const std::vector<wxString>& aFileSet, in
|
||||
{
|
||||
msg.Printf( _( "Schematic '%s' is already open." ), wx_filename.GetFullName() );
|
||||
|
||||
if( !OverrideLock( this, msg ) )
|
||||
if( !AskOverrideLock( this, msg ) )
|
||||
return false;
|
||||
|
||||
m_file_checker->OverrideLock( false );
|
||||
@@ -465,6 +465,9 @@ bool SCH_EDIT_FRAME::OpenProjectFiles( const std::vector<wxString>& aFileSet, in
|
||||
screen->MigrateSimModels();
|
||||
}
|
||||
|
||||
schematic.PruneOrphanedSymbolInstances( Prj().GetProjectName(), Schematic().GetSheets() );
|
||||
schematic.PruneOrphanedSheetInstances( Prj().GetProjectName(), Schematic().GetSheets() );
|
||||
|
||||
Schematic().ConnectionGraph()->Reset();
|
||||
|
||||
SetScreen( GetCurrentSheet().LastScreen() );
|
||||
@@ -590,6 +593,15 @@ void SCH_EDIT_FRAME::OnImportProject( wxCommandEvent& aEvent )
|
||||
if( !AskToSaveChanges() )
|
||||
return;
|
||||
|
||||
if( Schematic().RootScreen() && !Schematic().RootScreen()->Items().empty() )
|
||||
{
|
||||
wxString msg = _( "This operation replaces the contents of the current project.\n\n"
|
||||
"Do you want to proceed?" );
|
||||
|
||||
if( !IsOK( this, msg ) )
|
||||
return;
|
||||
}
|
||||
|
||||
// Set the project location if none is set or if we are running in standalone mode
|
||||
bool setProject = Prj().GetProjectFullName().IsEmpty() || Kiface().IsSingle();
|
||||
wxString path = wxPathOnly( Prj().GetProjectFullName() );
|
||||
@@ -1234,7 +1246,7 @@ bool SCH_EDIT_FRAME::importFile( const wxString& aFileName, int aFileType )
|
||||
msg.Printf( _( "Schematic '%s' is already open by '%s' at '%s'." ), aFileName,
|
||||
m_file_checker->GetUsername(), m_file_checker->GetHostname() );
|
||||
|
||||
if( !OverrideLock( this, msg ) )
|
||||
if( !AskOverrideLock( this, msg ) )
|
||||
return false;
|
||||
|
||||
m_file_checker->OverrideLock();
|
||||
|
||||
@@ -118,6 +118,12 @@ public:
|
||||
|
||||
KIFONT::FONT* getDrawFont() const override;
|
||||
|
||||
bool IsHorizJustifyFlipped() const { return false; }
|
||||
bool IsVertJustifyFlipped() const { return false; }
|
||||
|
||||
GR_TEXT_H_ALIGN_T GetEffectiveHorizJustify() const { return GetHorizJustify(); }
|
||||
GR_TEXT_V_ALIGN_T GetEffectiveVertJustify() const { return GetVertJustify(); }
|
||||
|
||||
/**
|
||||
* Copy parameters of this field to another field. Pointers are not copied.
|
||||
*
|
||||
|
||||
+29
-15
@@ -1369,49 +1369,63 @@ BITMAPS LIB_PIN::GetMenuImage() const
|
||||
}
|
||||
|
||||
|
||||
wxString LIB_PIN::GetItemDescription( UNITS_PROVIDER* aUnitsProvider, ALT* aAlt ) const
|
||||
{
|
||||
return getItemDescription( aAlt );
|
||||
}
|
||||
|
||||
|
||||
wxString LIB_PIN::GetItemDescription( UNITS_PROVIDER* aUnitsProvider ) const
|
||||
{
|
||||
// This code previously checked "m_name.IsEmpty()" to choose the correct
|
||||
return getItemDescription( nullptr );
|
||||
}
|
||||
|
||||
|
||||
wxString LIB_PIN::getItemDescription( ALT* aAlt ) const
|
||||
{
|
||||
// This code previously checked "m_name.IsEmpty()" to choose the correct
|
||||
// formatting path, but that check fails if the pin is called "~" which is
|
||||
// the default for an empty pin name. Instead we get the final display string
|
||||
// the default for an empty pin name. Instead we get the final display string
|
||||
// that will be shown and check if it's empty.
|
||||
|
||||
wxString shownName = UnescapeString( GetShownName() );
|
||||
wxString name = UnescapeString( aAlt ? aAlt->m_Name : GetShownName() );
|
||||
wxString electricalTypeName = ElectricalPinTypeGetText( aAlt ? aAlt->m_Type : m_type );
|
||||
wxString pinShapeName = PinShapeGetText( aAlt ? aAlt->m_Shape : m_shape );
|
||||
|
||||
if( IsVisible() )
|
||||
{
|
||||
if ( !shownName.IsEmpty() )
|
||||
if ( !name.IsEmpty() )
|
||||
{
|
||||
return wxString::Format( _( "Pin %s [%s, %s, %s]" ),
|
||||
GetShownNumber(),
|
||||
shownName,
|
||||
GetElectricalTypeName(),
|
||||
PinShapeGetText( m_shape ) );
|
||||
name,
|
||||
electricalTypeName,
|
||||
pinShapeName );
|
||||
}
|
||||
else
|
||||
{
|
||||
return wxString::Format( _( "Pin %s [%s, %s]" ),
|
||||
GetShownNumber(),
|
||||
GetElectricalTypeName(),
|
||||
PinShapeGetText( m_shape ) );
|
||||
electricalTypeName,
|
||||
pinShapeName );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if( !shownName.IsEmpty() )
|
||||
if( !name.IsEmpty() )
|
||||
{
|
||||
return wxString::Format( _( "Hidden pin %s [%s, %s, %s]" ),
|
||||
GetShownNumber(),
|
||||
shownName,
|
||||
GetElectricalTypeName(),
|
||||
PinShapeGetText( m_shape ) );
|
||||
name,
|
||||
electricalTypeName,
|
||||
pinShapeName );
|
||||
}
|
||||
else
|
||||
{
|
||||
return wxString::Format( _( "Hidden pin %s [%s, %s]" ),
|
||||
GetShownNumber(),
|
||||
GetElectricalTypeName(),
|
||||
PinShapeGetText( m_shape ) );
|
||||
electricalTypeName,
|
||||
pinShapeName );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -244,6 +244,7 @@ public:
|
||||
BITMAPS GetMenuImage() const override;
|
||||
|
||||
wxString GetItemDescription( UNITS_PROVIDER* aUnitsProvider ) const override;
|
||||
wxString GetItemDescription( UNITS_PROVIDER* aUnitsProvider, ALT* aAlt ) const;
|
||||
|
||||
EDA_ITEM* Clone() const override;
|
||||
|
||||
@@ -260,6 +261,8 @@ public:
|
||||
static const wxString GetCanonicalElectricalTypeName( ELECTRICAL_PINTYPE aType );
|
||||
|
||||
protected:
|
||||
wxString getItemDescription( ALT* aAlt ) const;
|
||||
|
||||
struct EXTENTS_CACHE
|
||||
{
|
||||
KIFONT::FONT* m_Font = nullptr;
|
||||
|
||||
@@ -414,7 +414,7 @@ void LIB_TEXTBOX::Plot( PLOTTER* aPlotter, bool aBackground, const VECTOR2I& aOf
|
||||
color = renderSettings->GetLayerColor( LAYER_DEVICE );
|
||||
|
||||
if( lineStyle == PLOT_DASH_TYPE::DEFAULT )
|
||||
lineStyle = PLOT_DASH_TYPE::DASH;
|
||||
lineStyle = PLOT_DASH_TYPE::SOLID;
|
||||
|
||||
if( aDimmed )
|
||||
{
|
||||
@@ -465,7 +465,7 @@ void LIB_TEXTBOX::Plot( PLOTTER* aPlotter, bool aBackground, const VECTOR2I& aOf
|
||||
|
||||
text.GetLinePositions( positions, (int) strings_list.Count() );
|
||||
|
||||
TEXT_ATTRIBUTES attrs = GetAttributes();
|
||||
TEXT_ATTRIBUTES attrs = text.GetAttributes();
|
||||
attrs.m_StrokeWidth = penWidth;
|
||||
attrs.m_Multiline = false;
|
||||
|
||||
|
||||
@@ -106,10 +106,14 @@ void SCH_EDIT_FRAME::doReCreateMenuBar()
|
||||
ACTION_MENU* submenuImport = new ACTION_MENU( false, selTool );
|
||||
submenuImport->SetTitle( _( "Import" ) );
|
||||
submenuImport->SetIcon( BITMAPS::import );
|
||||
submenuImport->Add( _( "Non-KiCad Schematic..." ),
|
||||
|
||||
if( Kiface().IsSingle() )
|
||||
{
|
||||
submenuImport->Add( _( "Non-KiCad Schematic..." ),
|
||||
_( "Replace current schematic sheet with one imported from another application" ),
|
||||
ID_IMPORT_NON_KICAD_SCH,
|
||||
BITMAPS::import_document );
|
||||
}
|
||||
|
||||
submenuImport->Add( EE_ACTIONS::importFPAssignments, ACTION_MENU::NORMAL, _( "Footprint Assignments..." ) );
|
||||
fileMenu->Add( submenuImport );
|
||||
|
||||
+13
-10
@@ -304,8 +304,9 @@ void SCH_BUS_ENTRY_BASE::Rotate( const VECTOR2I& aCenter )
|
||||
}
|
||||
|
||||
|
||||
bool SCH_BUS_WIRE_ENTRY::UpdateDanglingState( std::vector<DANGLING_END_ITEM>& aItemList,
|
||||
const SCH_SHEET_PATH* aPath )
|
||||
bool SCH_BUS_WIRE_ENTRY::UpdateDanglingState( std::vector<DANGLING_END_ITEM>& aItemListByType,
|
||||
std::vector<DANGLING_END_ITEM>& aItemListByPos,
|
||||
const SCH_SHEET_PATH* aPath )
|
||||
{
|
||||
bool previousStateStart = m_isDanglingStart;
|
||||
bool previousStateEnd = m_isDanglingEnd;
|
||||
@@ -316,9 +317,9 @@ bool SCH_BUS_WIRE_ENTRY::UpdateDanglingState( std::vector<DANGLING_END_ITEM>& aI
|
||||
bool has_wire[2] = { false };
|
||||
bool has_bus[2] = { false };
|
||||
|
||||
for( unsigned ii = 0; ii < aItemList.size(); ii++ )
|
||||
for( unsigned ii = 0; ii < aItemListByType.size(); ii++ )
|
||||
{
|
||||
DANGLING_END_ITEM& item = aItemList[ii];
|
||||
DANGLING_END_ITEM& item = aItemListByType[ii];
|
||||
|
||||
if( item.GetItem() == this )
|
||||
continue;
|
||||
@@ -336,7 +337,7 @@ bool SCH_BUS_WIRE_ENTRY::UpdateDanglingState( std::vector<DANGLING_END_ITEM>& aI
|
||||
case BUS_END:
|
||||
{
|
||||
// The bus has created 2 DANGLING_END_ITEMs, one per end.
|
||||
DANGLING_END_ITEM& nextItem = aItemList[++ii];
|
||||
DANGLING_END_ITEM& nextItem = aItemListByType[++ii];
|
||||
|
||||
if( IsPointOnSegment( item.GetPosition(), nextItem.GetPosition(), m_pos ) )
|
||||
has_bus[0] = true;
|
||||
@@ -363,17 +364,19 @@ bool SCH_BUS_WIRE_ENTRY::UpdateDanglingState( std::vector<DANGLING_END_ITEM>& aI
|
||||
}
|
||||
|
||||
|
||||
bool SCH_BUS_BUS_ENTRY::UpdateDanglingState( std::vector<DANGLING_END_ITEM>& aItemList,
|
||||
const SCH_SHEET_PATH* aPath )
|
||||
bool SCH_BUS_BUS_ENTRY::UpdateDanglingState( std::vector<DANGLING_END_ITEM>& aItemListByType,
|
||||
std::vector<DANGLING_END_ITEM>& aItemListByPos,
|
||||
const SCH_SHEET_PATH* aPath )
|
||||
{
|
||||
bool previousStateStart = m_isDanglingStart;
|
||||
bool previousStateEnd = m_isDanglingEnd;
|
||||
|
||||
m_isDanglingStart = m_isDanglingEnd = true;
|
||||
|
||||
for( unsigned ii = 0; ii < aItemList.size(); ii++ )
|
||||
// TODO: filter using get_lower as we only use one item type
|
||||
for( unsigned ii = 0; ii < aItemListByType.size(); ii++ )
|
||||
{
|
||||
DANGLING_END_ITEM& item = aItemList[ii];
|
||||
DANGLING_END_ITEM& item = aItemListByType[ii];
|
||||
|
||||
if( item.GetItem() == this )
|
||||
continue;
|
||||
@@ -383,7 +386,7 @@ bool SCH_BUS_BUS_ENTRY::UpdateDanglingState( std::vector<DANGLING_END_ITEM>& aIt
|
||||
case BUS_END:
|
||||
{
|
||||
// The bus has created 2 DANGLING_END_ITEMs, one per end.
|
||||
DANGLING_END_ITEM& nextItem = aItemList[++ii];
|
||||
DANGLING_END_ITEM& nextItem = aItemListByType[++ii];
|
||||
|
||||
if( IsPointOnSegment( item.GetPosition(), nextItem.GetPosition(), m_pos ) )
|
||||
m_isDanglingStart = false;
|
||||
|
||||
@@ -188,8 +188,9 @@ public:
|
||||
|
||||
BITMAPS GetMenuImage() const override;
|
||||
|
||||
bool UpdateDanglingState( std::vector<DANGLING_END_ITEM>& aItemList,
|
||||
const SCH_SHEET_PATH* aPath = nullptr ) override;
|
||||
bool UpdateDanglingState( std::vector<DANGLING_END_ITEM>& aItemListByType,
|
||||
std::vector<DANGLING_END_ITEM>& aItemListByPos,
|
||||
const SCH_SHEET_PATH* aPath = nullptr ) override;
|
||||
|
||||
/**
|
||||
* Pointer to the bus item (usually a bus wire) connected to this bus-wire
|
||||
@@ -233,8 +234,9 @@ public:
|
||||
|
||||
BITMAPS GetMenuImage() const override;
|
||||
|
||||
bool UpdateDanglingState( std::vector<DANGLING_END_ITEM>& aItemList,
|
||||
const SCH_SHEET_PATH* aPath = nullptr ) override;
|
||||
bool UpdateDanglingState( std::vector<DANGLING_END_ITEM>& aItemListByType,
|
||||
std::vector<DANGLING_END_ITEM>& aItemListByPos,
|
||||
const SCH_SHEET_PATH* aPath = nullptr ) override;
|
||||
|
||||
/**
|
||||
* Pointer to the bus items (usually bus wires) connected to this bus-bus
|
||||
|
||||
@@ -180,7 +180,7 @@ void SCH_CONNECTION::ConfigureFromLabel( const wxString& aLabel )
|
||||
auto member = std::make_shared< SCH_CONNECTION >( m_parent, m_sheet );
|
||||
member->SetPrefix( prefix );
|
||||
member->SetGraph( m_graph );
|
||||
member->ConfigureFromLabel( alias_member );
|
||||
member->ConfigureFromLabel( EscapeString( alias_member, CTX_NETNAME ) );
|
||||
m_members.push_back( member );
|
||||
}
|
||||
}
|
||||
|
||||
+39
-19
@@ -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) 1992-2023 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
* Copyright (C) 1992-2024 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
|
||||
@@ -51,6 +51,7 @@
|
||||
#include <sch_painter.h>
|
||||
#include <sch_sheet.h>
|
||||
#include <sch_marker.h>
|
||||
#include <sch_sheet_pin.h>
|
||||
#include <schematic.h>
|
||||
#include <settings/settings_manager.h>
|
||||
#include <advanced_config.h>
|
||||
@@ -133,7 +134,11 @@ SCH_EDIT_FRAME::SCH_EDIT_FRAME( KIWAY* aKiway, wxWindow* aParent ) :
|
||||
wxIcon icon;
|
||||
wxIconBundle icon_bundle;
|
||||
|
||||
icon.CopyFromBitmap( KiBitmap( BITMAPS::icon_eeschema ) );
|
||||
icon.CopyFromBitmap( KiBitmap( BITMAPS::icon_eeschema, 48 ) );
|
||||
icon_bundle.AddIcon( icon );
|
||||
icon.CopyFromBitmap( KiBitmap( BITMAPS::icon_eeschema, 128 ) );
|
||||
icon_bundle.AddIcon( icon );
|
||||
icon.CopyFromBitmap( KiBitmap( BITMAPS::icon_eeschema, 256 ) );
|
||||
icon_bundle.AddIcon( icon );
|
||||
icon.CopyFromBitmap( KiBitmap( BITMAPS::icon_eeschema_32 ) );
|
||||
icon_bundle.AddIcon( icon );
|
||||
@@ -950,7 +955,6 @@ void SCH_EDIT_FRAME::OnModify()
|
||||
RecalculateConnections( NO_CLEANUP );
|
||||
|
||||
GetCanvas()->Refresh();
|
||||
UpdateHierarchyNavigator();
|
||||
|
||||
if( !GetTitle().StartsWith( wxS( "*" ) ) )
|
||||
updateTitle();
|
||||
@@ -1113,6 +1117,10 @@ void SCH_EDIT_FRAME::OnClearFileHistory( wxCommandEvent& aEvent )
|
||||
|
||||
void SCH_EDIT_FRAME::NewProject()
|
||||
{
|
||||
// Only standalone mode can directly load a new document
|
||||
if( !Kiface().IsSingle() )
|
||||
return;
|
||||
|
||||
wxString pro_dir = m_mruPath;
|
||||
|
||||
wxFileDialog dlg( this, _( "New Schematic" ), pro_dir, wxEmptyString,
|
||||
@@ -1143,6 +1151,10 @@ void SCH_EDIT_FRAME::NewProject()
|
||||
|
||||
void SCH_EDIT_FRAME::LoadProject()
|
||||
{
|
||||
// Only standalone mode can directly load a new document
|
||||
if( !Kiface().IsSingle() )
|
||||
return;
|
||||
|
||||
wxString pro_dir = m_mruPath;
|
||||
wxString wildcards = AllSchematicFilesWildcard()
|
||||
+ wxS( "|" ) + KiCadSchematicFileWildcard()
|
||||
@@ -1503,37 +1515,46 @@ void SCH_EDIT_FRAME::RecalculateConnections( SCH_CLEANUP_FLAGS aCleanupFlags )
|
||||
|
||||
for( unsigned ii = 0; ii < changed_list->GetCount(); ++ii )
|
||||
{
|
||||
EDA_ITEM* item = changed_list->GetPickedItem( ii );
|
||||
SCH_ITEM* item = dynamic_cast<SCH_ITEM*>( changed_list->GetPickedItem( ii ) );
|
||||
|
||||
if( !item || !IsEeschemaType( item->Type() ) )
|
||||
// Ignore non SCH_ITEM objects and objects that are not connectable.
|
||||
if( !item || !item->IsConnectable() )
|
||||
continue;
|
||||
|
||||
SCH_SCREEN* screen = static_cast<SCH_SCREEN*>( changed_list->GetScreenForItem( ii ) );
|
||||
SCH_ITEM* sch_item = static_cast<SCH_ITEM*>( item );
|
||||
SCH_SHEET_PATHS& paths = screen->GetClientSheetPaths();
|
||||
|
||||
std::vector<VECTOR2I> tmp_pts = sch_item->GetConnectionPoints();
|
||||
std::vector<VECTOR2I> tmp_pts = item->GetConnectionPoints();
|
||||
pts.insert( pts.end(), tmp_pts.begin(), tmp_pts.end() );
|
||||
changed_items.insert( sch_item );
|
||||
changed_items.insert( item );
|
||||
|
||||
for( SCH_SHEET_PATH& path : paths )
|
||||
item_paths.insert( std::make_pair( path, sch_item ) );
|
||||
item_paths.insert( std::make_pair( path, item ) );
|
||||
}
|
||||
|
||||
for( VECTOR2I& pt: pts )
|
||||
{
|
||||
for( SCH_ITEM* item : GetScreen()->Items().Overlapping(pt ) )
|
||||
{
|
||||
if( !item->IsConnectable() )
|
||||
continue;
|
||||
|
||||
if( SCH_LINE* line = dyn_cast<SCH_LINE*>( item ) )
|
||||
if( item->Type() == SCH_LINE_T )
|
||||
{
|
||||
if( line->HitTest( pt ) )
|
||||
{
|
||||
if( item->HitTest( pt ) )
|
||||
changed_items.insert( item );
|
||||
}
|
||||
else if( item->Type() == SCH_SHEET_T )
|
||||
{
|
||||
SCH_SHEET* sheet = static_cast<SCH_SHEET*>( item );
|
||||
|
||||
wxCHECK2( sheet, continue );
|
||||
|
||||
std::vector<SCH_SHEET_PIN*> sheetPins = sheet->GetPins();
|
||||
changed_items.insert( sheetPins.begin(), sheetPins.end() );
|
||||
}
|
||||
else
|
||||
{
|
||||
// Non-connectable objects have already been pruned.
|
||||
if( item->IsConnected( pt ) )
|
||||
changed_items.insert( item );
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if( SCH_SYMBOL* sym = dyn_cast<SCH_SYMBOL*>( item ) )
|
||||
@@ -1549,8 +1570,7 @@ void SCH_EDIT_FRAME::RecalculateConnections( SCH_CLEANUP_FLAGS aCleanupFlags )
|
||||
}
|
||||
|
||||
std::set<std::pair<SCH_SHEET_PATH, SCH_ITEM*>> all_items =
|
||||
Schematic().ConnectionGraph()->ExtractAffectedItems(
|
||||
changed_items );
|
||||
Schematic().ConnectionGraph()->ExtractAffectedItems( changed_items );
|
||||
|
||||
all_items.insert( item_paths.begin(), item_paths.end() );
|
||||
|
||||
|
||||
@@ -316,3 +316,50 @@ void SCH_ITEM::Plot( PLOTTER* aPlotter, bool aBackground ) const
|
||||
{
|
||||
wxFAIL_MSG( wxT( "Plot() method not implemented for class " ) + GetClass() );
|
||||
}
|
||||
|
||||
|
||||
static bool lessYX( const DANGLING_END_ITEM& a, const DANGLING_END_ITEM& b )
|
||||
{
|
||||
const auto aPos = a.GetPosition();
|
||||
const auto bPos = b.GetPosition();
|
||||
return aPos.y < bPos.y ? true : ( aPos.y > bPos.y ? false : aPos.x < bPos.x );
|
||||
};
|
||||
|
||||
|
||||
static bool lessType( const DANGLING_END_ITEM& a, const DANGLING_END_ITEM& b )
|
||||
{
|
||||
return a.GetType() < b.GetType();
|
||||
};
|
||||
|
||||
|
||||
std::vector<DANGLING_END_ITEM>::iterator
|
||||
DANGLING_END_ITEM_HELPER::get_lower_pos( std::vector<DANGLING_END_ITEM>& aItemListByPos,
|
||||
const VECTOR2I& aPos )
|
||||
{
|
||||
DANGLING_END_ITEM needle = DANGLING_END_ITEM( PIN_END, nullptr, aPos );
|
||||
auto start = aItemListByPos.begin();
|
||||
auto end = aItemListByPos.end();
|
||||
return std::lower_bound( start, end, needle, lessYX );
|
||||
}
|
||||
|
||||
|
||||
std::vector<DANGLING_END_ITEM>::iterator
|
||||
DANGLING_END_ITEM_HELPER::get_lower_type( std::vector<DANGLING_END_ITEM>& aItemListByType,
|
||||
const DANGLING_END_T& aType )
|
||||
{
|
||||
DANGLING_END_ITEM needle = DANGLING_END_ITEM( aType, nullptr, VECTOR2I{} );
|
||||
auto start = aItemListByType.begin();
|
||||
auto end = aItemListByType.end();
|
||||
return std::lower_bound( start, end, needle, lessType );
|
||||
}
|
||||
|
||||
|
||||
void DANGLING_END_ITEM_HELPER::sort_dangling_end_items(
|
||||
std::vector<DANGLING_END_ITEM>& aItemListByType,
|
||||
std::vector<DANGLING_END_ITEM>& aItemListByPos )
|
||||
{
|
||||
// WIRE_END pairs must be kept together. Hence stable sort.
|
||||
std::stable_sort( aItemListByType.begin(), aItemListByType.end(), lessType );
|
||||
// Sort by y first, pins are more likely to share x than y.
|
||||
std::sort( aItemListByPos.begin(), aItemListByPos.end(), lessYX );
|
||||
}
|
||||
|
||||
+20
-3
@@ -133,6 +133,20 @@ private:
|
||||
};
|
||||
|
||||
|
||||
class DANGLING_END_ITEM_HELPER
|
||||
{
|
||||
public:
|
||||
static std::vector<DANGLING_END_ITEM>::iterator
|
||||
get_lower_pos( std::vector<DANGLING_END_ITEM>& aItemListByPos, const VECTOR2I& aPos );
|
||||
|
||||
static std::vector<DANGLING_END_ITEM>::iterator
|
||||
get_lower_type( std::vector<DANGLING_END_ITEM>& aItemListByType, const DANGLING_END_T& aType );
|
||||
|
||||
/** Both contain the same information */
|
||||
static void sort_dangling_end_items( std::vector<DANGLING_END_ITEM>& aItemListByType,
|
||||
std::vector<DANGLING_END_ITEM>& aItemListByPos );
|
||||
};
|
||||
|
||||
typedef std::vector<SCH_ITEM*> SCH_ITEM_SET;
|
||||
|
||||
|
||||
@@ -329,12 +343,15 @@ public:
|
||||
* If aSheet is passed a non-null pointer to a SCH_SHEET_PATH, the overridden method can
|
||||
* optionally use it to update sheet-local connectivity information
|
||||
*
|
||||
* @param aItemList is the list of items to test item against.
|
||||
* @param aItemListByType is the list of items to test item against. It's sorted
|
||||
* by item type, keeping WIRE_END pairs together.
|
||||
* @param aItemListByPos is the same list but sorted first by Y then by X.
|
||||
* @param aSheet is the sheet path to update connections for.
|
||||
* @return True if the dangling state has changed from it's current setting.
|
||||
*/
|
||||
virtual bool UpdateDanglingState( std::vector<DANGLING_END_ITEM>& aItemList,
|
||||
const SCH_SHEET_PATH* aPath = nullptr )
|
||||
virtual bool UpdateDanglingState( std::vector<DANGLING_END_ITEM>& aItemListByType,
|
||||
std::vector<DANGLING_END_ITEM>& aItemListByPos,
|
||||
const SCH_SHEET_PATH* aPath = nullptr )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
+98
-31
@@ -868,16 +868,19 @@ bool SCH_LABEL_BASE::HitTest( const BOX2I& aRect, bool aContained, int aAccuracy
|
||||
}
|
||||
|
||||
|
||||
bool SCH_LABEL_BASE::UpdateDanglingState( std::vector<DANGLING_END_ITEM>& aItemList,
|
||||
const SCH_SHEET_PATH* aPath )
|
||||
bool SCH_LABEL_BASE::UpdateDanglingState( std::vector<DANGLING_END_ITEM>& aItemListByType,
|
||||
std::vector<DANGLING_END_ITEM>& aItemListByPos,
|
||||
const SCH_SHEET_PATH* aPath )
|
||||
{
|
||||
bool previousState = m_isDangling;
|
||||
m_isDangling = true;
|
||||
bool previousState = m_isDangling;
|
||||
VECTOR2I text_pos = GetTextPos();
|
||||
m_isDangling = true;
|
||||
m_connectionType = CONNECTION_TYPE::NONE;
|
||||
|
||||
for( unsigned ii = 0; ii < aItemList.size(); ii++ )
|
||||
for( auto it = DANGLING_END_ITEM_HELPER::get_lower_pos( aItemListByPos, text_pos );
|
||||
it < aItemListByPos.end() && it->GetPosition() == text_pos; it++ )
|
||||
{
|
||||
DANGLING_END_ITEM& item = aItemList[ii];
|
||||
DANGLING_END_ITEM& item = *it;
|
||||
|
||||
if( item.GetItem() == this )
|
||||
continue;
|
||||
@@ -888,33 +891,68 @@ bool SCH_LABEL_BASE::UpdateDanglingState( std::vector<DANGLING_END_ITEM>& aItemL
|
||||
case LABEL_END:
|
||||
case SHEET_LABEL_END:
|
||||
case NO_CONNECT_END:
|
||||
if( GetTextPos() == item.GetPosition() )
|
||||
if( text_pos == item.GetPosition() )
|
||||
{
|
||||
m_isDangling = false;
|
||||
|
||||
if( aPath && item.GetType() != PIN_END )
|
||||
AddConnectionTo( *aPath, static_cast<SCH_ITEM*>( item.GetItem() ) );
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case BUS_END:
|
||||
m_connectionType = CONNECTION_TYPE::BUS;
|
||||
KI_FALLTHROUGH;
|
||||
default: break;
|
||||
}
|
||||
|
||||
case WIRE_END:
|
||||
if( !m_isDangling )
|
||||
break;
|
||||
}
|
||||
|
||||
if( m_isDangling )
|
||||
{
|
||||
for( auto it = DANGLING_END_ITEM_HELPER::get_lower_type( aItemListByType, BUS_END );
|
||||
it < aItemListByType.end() && it->GetType() == BUS_END; it++ )
|
||||
{
|
||||
DANGLING_END_ITEM& nextItem = aItemList[++ii];
|
||||
DANGLING_END_ITEM& item = *it;
|
||||
DANGLING_END_ITEM& nextItem = *( ++it );
|
||||
|
||||
int accuracy = 1; // We have rounding issues with an accuracy of 0
|
||||
int accuracy = 1; // We have rounding issues with an accuracy of 0
|
||||
|
||||
m_isDangling = !TestSegmentHit( GetTextPos(), item.GetPosition(),
|
||||
nextItem.GetPosition(), accuracy );
|
||||
m_isDangling = !TestSegmentHit( text_pos, item.GetPosition(), nextItem.GetPosition(),
|
||||
accuracy );
|
||||
|
||||
if( !m_isDangling )
|
||||
if( m_isDangling )
|
||||
continue;
|
||||
|
||||
m_connectionType = CONNECTION_TYPE::BUS;
|
||||
|
||||
// Add the line to the connected items, since it won't be picked
|
||||
// up by a search of intersecting connection points
|
||||
if( aPath )
|
||||
{
|
||||
if( m_connectionType != CONNECTION_TYPE::BUS )
|
||||
m_connectionType = CONNECTION_TYPE::NET;
|
||||
auto sch_item = static_cast<SCH_ITEM*>( item.GetItem() );
|
||||
AddConnectionTo( *aPath, sch_item );
|
||||
sch_item->AddConnectionTo( *aPath, this );
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if( m_isDangling )
|
||||
{
|
||||
for( auto it = DANGLING_END_ITEM_HELPER::get_lower_type( aItemListByType, WIRE_END );
|
||||
it < aItemListByType.end() && it->GetType() == WIRE_END; it++ )
|
||||
{
|
||||
DANGLING_END_ITEM& item = *it;
|
||||
DANGLING_END_ITEM& nextItem = *( ++it );
|
||||
|
||||
int accuracy = 1; // We have rounding issues with an accuracy of 0
|
||||
|
||||
m_isDangling = !TestSegmentHit( text_pos, item.GetPosition(),
|
||||
nextItem.GetPosition(), accuracy );
|
||||
|
||||
if( m_isDangling )
|
||||
continue;
|
||||
|
||||
m_connectionType = CONNECTION_TYPE::NET;
|
||||
|
||||
// Add the line to the connected items, since it won't be picked
|
||||
// up by a search of intersecting connection points
|
||||
@@ -924,16 +962,9 @@ bool SCH_LABEL_BASE::UpdateDanglingState( std::vector<DANGLING_END_ITEM>& aItemL
|
||||
AddConnectionTo( *aPath, sch_item );
|
||||
sch_item->AddConnectionTo( *aPath, this );
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if( !m_isDangling )
|
||||
break;
|
||||
}
|
||||
|
||||
if( m_isDangling )
|
||||
@@ -1037,8 +1068,27 @@ void SCH_LABEL_BASE::Plot( PLOTTER* aPlotter, bool aBackground ) const
|
||||
{
|
||||
aPlotter->PlotText( textpos, color, GetShownText( true ), attrs, font );
|
||||
|
||||
if( s_poly.size() )
|
||||
aPlotter->PlotPoly( s_poly, FILL_T::NO_FILL, penWidth );
|
||||
if( GetShape() == LABEL_FLAG_SHAPE::F_DOT )
|
||||
{
|
||||
aPlotter->MoveTo( s_poly[0] );
|
||||
aPlotter->LineTo( s_poly[1] );
|
||||
|
||||
int diameter = ( s_poly[2] - s_poly[1] ).EuclideanNorm() * 2;
|
||||
aPlotter->FilledCircle( s_poly[2], diameter , FILLED, nullptr );
|
||||
}
|
||||
else if( GetShape() == LABEL_FLAG_SHAPE::F_ROUND )
|
||||
{
|
||||
aPlotter->MoveTo( s_poly[0] );
|
||||
aPlotter->LineTo( s_poly[1] );
|
||||
|
||||
int diameter = ( s_poly[2] - s_poly[1] ).EuclideanNorm() * 2;
|
||||
aPlotter->ThickCircle( s_poly[2], diameter, penWidth, FILLED, nullptr );
|
||||
}
|
||||
else
|
||||
{
|
||||
if( !s_poly.empty() )
|
||||
aPlotter->PlotPoly( s_poly, FILL_T::NO_FILL, penWidth );
|
||||
}
|
||||
|
||||
// Plot attributes to a hypertext menu
|
||||
std::vector<wxString> properties;
|
||||
@@ -1092,8 +1142,25 @@ void SCH_LABEL_BASE::Print( const RENDER_SETTINGS* aSettings, const VECTOR2I& aO
|
||||
|
||||
CreateGraphicShape( aSettings, s_poly, GetTextPos() + aOffset );
|
||||
|
||||
if( !s_poly.empty() )
|
||||
GRPoly( DC, s_poly.size(), &s_poly[0], false, penWidth, color, color );
|
||||
if( GetShape() == LABEL_FLAG_SHAPE::F_DOT )
|
||||
{
|
||||
GRLine( DC, s_poly[0], s_poly[1], penWidth, color );
|
||||
|
||||
int radius = ( s_poly[2] - s_poly[1] ).EuclideanNorm();
|
||||
GRFilledCircle( DC, s_poly[2], radius, penWidth, color, color );
|
||||
}
|
||||
else if( GetShape() == LABEL_FLAG_SHAPE::F_ROUND )
|
||||
{
|
||||
GRLine( DC, s_poly[0], s_poly[1], penWidth, color );
|
||||
|
||||
int radius = ( s_poly[2] - s_poly[1] ).EuclideanNorm();
|
||||
GRCircle( DC, s_poly[2], radius, penWidth, color );
|
||||
}
|
||||
else
|
||||
{
|
||||
if( !s_poly.empty() )
|
||||
GRPoly( DC, s_poly.size(), &s_poly[0], false, penWidth, color, color );
|
||||
}
|
||||
|
||||
for( SCH_FIELD& field : m_fields )
|
||||
field.Print( aSettings, aOffset );
|
||||
|
||||
@@ -187,8 +187,9 @@ public:
|
||||
|
||||
void GetEndPoints( std::vector< DANGLING_END_ITEM >& aItemList ) override;
|
||||
|
||||
bool UpdateDanglingState( std::vector<DANGLING_END_ITEM>& aItemList,
|
||||
const SCH_SHEET_PATH* aPath = nullptr ) override;
|
||||
bool UpdateDanglingState( std::vector<DANGLING_END_ITEM>& aItemListByType,
|
||||
std::vector<DANGLING_END_ITEM>& aItemListByPos,
|
||||
const SCH_SHEET_PATH* aPath = nullptr ) override;
|
||||
|
||||
bool IsDangling() const override { return m_isDangling; }
|
||||
void SetIsDangling( bool aIsDangling ) { m_isDangling = aIsDangling; }
|
||||
|
||||
+42
-30
@@ -580,44 +580,56 @@ void SCH_LINE::GetEndPoints( std::vector <DANGLING_END_ITEM>& aItemList )
|
||||
}
|
||||
|
||||
|
||||
bool SCH_LINE::UpdateDanglingState( std::vector<DANGLING_END_ITEM>& aItemList,
|
||||
const SCH_SHEET_PATH* aPath )
|
||||
bool SCH_LINE::UpdateDanglingState( std::vector<DANGLING_END_ITEM>& aItemListByType,
|
||||
std::vector<DANGLING_END_ITEM>& aItemListByPos,
|
||||
const SCH_SHEET_PATH* aPath )
|
||||
{
|
||||
if( IsConnectable() )
|
||||
if( !IsConnectable() )
|
||||
return false;
|
||||
|
||||
bool previousStartState = m_startIsDangling;
|
||||
bool previousEndState = m_endIsDangling;
|
||||
|
||||
m_startIsDangling = m_endIsDangling = true;
|
||||
|
||||
for( auto it = DANGLING_END_ITEM_HELPER::get_lower_pos( aItemListByPos, m_start );
|
||||
it < aItemListByPos.end() && it->GetPosition() == m_start; it++ )
|
||||
{
|
||||
bool previousStartState = m_startIsDangling;
|
||||
bool previousEndState = m_endIsDangling;
|
||||
DANGLING_END_ITEM& item = *it;
|
||||
|
||||
m_startIsDangling = m_endIsDangling = true;
|
||||
if( item.GetItem() == this )
|
||||
continue;
|
||||
|
||||
for( DANGLING_END_ITEM item : aItemList )
|
||||
if( ( IsWire() && item.GetType() != BUS_END && item.GetType() != BUS_ENTRY_END )
|
||||
|| ( IsBus() && item.GetType() != WIRE_END && item.GetType() != PIN_END ) )
|
||||
{
|
||||
if( item.GetItem() == this )
|
||||
continue;
|
||||
|
||||
if( ( IsWire() && item.GetType() != BUS_END && item.GetType() != BUS_ENTRY_END )
|
||||
|| ( IsBus() && item.GetType() != WIRE_END && item.GetType() != PIN_END ) )
|
||||
{
|
||||
if( m_start == item.GetPosition() )
|
||||
m_startIsDangling = false;
|
||||
|
||||
if( m_end == item.GetPosition() )
|
||||
m_endIsDangling = false;
|
||||
|
||||
if( !m_startIsDangling && !m_endIsDangling )
|
||||
break;
|
||||
}
|
||||
m_startIsDangling = false;
|
||||
break;
|
||||
}
|
||||
|
||||
// We only use the bus dangling state for automatic line starting, so we don't care if it
|
||||
// has changed or not (and returning true will result in extra work)
|
||||
if( IsBus() )
|
||||
return false;
|
||||
|
||||
return previousStartState != m_startIsDangling || previousEndState != m_endIsDangling;
|
||||
}
|
||||
|
||||
return false;
|
||||
for( auto it = DANGLING_END_ITEM_HELPER::get_lower_pos( aItemListByPos, m_end );
|
||||
it < aItemListByPos.end() && it->GetPosition() == m_end; it++ )
|
||||
{
|
||||
DANGLING_END_ITEM& item = *it;
|
||||
|
||||
if( item.GetItem() == this )
|
||||
continue;
|
||||
|
||||
if( ( IsWire() && item.GetType() != BUS_END && item.GetType() != BUS_ENTRY_END )
|
||||
|| ( IsBus() && item.GetType() != WIRE_END && item.GetType() != PIN_END ) )
|
||||
{
|
||||
m_endIsDangling = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// We only use the bus dangling state for automatic line starting, so we don't care if it
|
||||
// has changed or not (and returning true will result in extra work)
|
||||
if( IsBus() )
|
||||
return false;
|
||||
|
||||
return previousStartState != m_startIsDangling || previousEndState != m_endIsDangling;
|
||||
}
|
||||
|
||||
|
||||
|
||||
+3
-2
@@ -251,8 +251,9 @@ public:
|
||||
|
||||
void GetEndPoints( std::vector<DANGLING_END_ITEM>& aItemList ) override;
|
||||
|
||||
bool UpdateDanglingState( std::vector<DANGLING_END_ITEM>& aItemList,
|
||||
const SCH_SHEET_PATH* aPath = nullptr ) override;
|
||||
bool UpdateDanglingState( std::vector<DANGLING_END_ITEM>& aItemListByType,
|
||||
std::vector<DANGLING_END_ITEM>& aItemListByPos,
|
||||
const SCH_SHEET_PATH* aPath = nullptr ) override;
|
||||
|
||||
bool IsStartDangling() const { return m_startIsDangling; }
|
||||
bool IsEndDangling() const { return m_endIsDangling; }
|
||||
|
||||
@@ -843,12 +843,9 @@ void SCH_PAINTER::draw( const LIB_SHAPE *aShape, int aLayer, bool aDimmed )
|
||||
|
||||
case SHAPE_T::BEZIER:
|
||||
{
|
||||
std::deque<VECTOR2D> mappedPts;
|
||||
|
||||
for( const VECTOR2I& p : shape->GetBezierPoints() )
|
||||
mappedPts.push_back( mapCoords( p ) );
|
||||
|
||||
m_gal->DrawPolygon( mappedPts );
|
||||
m_gal->DrawCurve(
|
||||
mapCoords( shape->GetStart() ), mapCoords( shape->GetBezierC1() ),
|
||||
mapCoords( shape->GetBezierC2() ), mapCoords( shape->GetEnd() ) );
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -1851,12 +1848,8 @@ void SCH_PAINTER::draw( const SCH_SHAPE* aShape, int aLayer )
|
||||
|
||||
case SHAPE_T::BEZIER:
|
||||
{
|
||||
std::deque<VECTOR2D> pts;
|
||||
|
||||
for( const VECTOR2I &p : shape->GetPolyShape().Outline( 0 ).CPoints() )
|
||||
pts.push_back( p );
|
||||
|
||||
m_gal->DrawPolygon( pts );
|
||||
m_gal->DrawCurve( shape->GetStart(), shape->GetBezierC1(), shape->GetBezierC2(),
|
||||
shape->GetEnd() );
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
+10
-1
@@ -193,9 +193,18 @@ SCH_SYMBOL* SCH_PIN::GetParentSymbol() const
|
||||
|
||||
wxString SCH_PIN::GetItemDescription( UNITS_PROVIDER* aUnitsProvider ) const
|
||||
{
|
||||
LIB_PIN::ALT localStorage;
|
||||
LIB_PIN::ALT* alt = nullptr;
|
||||
|
||||
if( !m_alt.IsEmpty() )
|
||||
{
|
||||
localStorage = m_libPin->GetAlt( m_alt );
|
||||
alt = &localStorage;
|
||||
}
|
||||
|
||||
return wxString::Format( "Symbol %s %s",
|
||||
UnescapeString( GetParentSymbol()->GetField( REFERENCE_FIELD )->GetText() ),
|
||||
m_libPin->GetItemDescription( aUnitsProvider ) );
|
||||
m_libPin->GetItemDescription( aUnitsProvider, alt ) );
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -110,6 +110,8 @@ public:
|
||||
|
||||
void SetIsDangling( bool isDangling ) { m_isDangling = isDangling; }
|
||||
|
||||
void SetLibPin( LIB_PIN* aLibPin ) { m_libPin = aLibPin; }
|
||||
|
||||
/**
|
||||
* @param aPin Comparison Pin
|
||||
* @return True if aPin is stacked with this pin
|
||||
|
||||
@@ -773,7 +773,6 @@ bool SCH_PLOTTER::plotOneSheetHpgl( const wxString& aFileName,
|
||||
plotter->SetPageSettings( aPageInfo );
|
||||
plotter->SetRenderSettings( aRenderSettings );
|
||||
plotter->RenderSettings()->LoadColors( m_colorSettings );
|
||||
plotter->SetColorMode( !aPlotSettings.m_blackAndWhite );
|
||||
plotter->SetViewport( aPlot0ffset, schIUScale.IU_PER_MILS/10, aScale, false );
|
||||
|
||||
// TODO this could be configurable
|
||||
|
||||
@@ -60,6 +60,7 @@
|
||||
#include <wx/log.h>
|
||||
#include <wx/zstream.h>
|
||||
#include <wx/wfstream.h>
|
||||
#include <wx/dir.h>
|
||||
#include <trigo.h>
|
||||
|
||||
// Harness port object itself does not contain color information about itself
|
||||
@@ -367,6 +368,24 @@ void SCH_ALTIUM_PLUGIN::ParseAltiumSch( const wxString& aFileName )
|
||||
// path as the parent sheet path.
|
||||
wxFileName loadAltiumFileName( parentFileName.GetPath(), sheet->GetFileName() );
|
||||
|
||||
if( !loadAltiumFileName.IsFileReadable() )
|
||||
{
|
||||
// Try case-insensitive search
|
||||
wxArrayString files;
|
||||
wxDir::GetAllFiles( parentFileName.GetPath(), &files, wxEmptyString, wxDIR_FILES | wxDIR_HIDDEN );
|
||||
|
||||
for( const wxString& candidate : files )
|
||||
{
|
||||
wxFileName candidateFname( candidate );
|
||||
|
||||
if( candidateFname.GetFullName().IsSameAs( sheet->GetFileName(), false ) )
|
||||
{
|
||||
loadAltiumFileName = candidateFname;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( loadAltiumFileName.GetFullName().IsEmpty() || !loadAltiumFileName.IsFileReadable() )
|
||||
{
|
||||
wxString msg;
|
||||
@@ -1411,21 +1430,28 @@ void SCH_ALTIUM_PLUGIN::ParsePolyline( const std::map<wxString, wxString>& aProp
|
||||
{
|
||||
ASCH_POLYLINE elem( aProperties );
|
||||
|
||||
if( elem.Points.size() < 2 )
|
||||
return;
|
||||
|
||||
SCH_SCREEN* screen = getCurrentScreen();
|
||||
wxCHECK( screen, /* void */ );
|
||||
|
||||
if( elem.OwnerPartID == ALTIUM_COMPONENT_NONE )
|
||||
{
|
||||
SCH_SHAPE* poly = new SCH_SHAPE( SHAPE_T::POLY );
|
||||
for( size_t i = 1; i < elem.Points.size(); i++ )
|
||||
{
|
||||
SCH_LINE* line = new SCH_LINE;
|
||||
|
||||
for( VECTOR2I& point : elem.Points )
|
||||
poly->AddPoint( point + m_sheetOffset );
|
||||
line->SetStartPoint( elem.Points[i - 1] + m_sheetOffset );
|
||||
line->SetEndPoint( elem.Points[i] + m_sheetOffset );
|
||||
|
||||
poly->SetStroke( STROKE_PARAMS( elem.LineWidth, GetPlotDashType( elem.LineStyle ),
|
||||
GetColorFromInt( elem.Color ) ) );
|
||||
poly->SetFlags( IS_NEW );
|
||||
line->SetStroke( STROKE_PARAMS( elem.LineWidth, GetPlotDashType( elem.LineStyle ),
|
||||
GetColorFromInt( elem.Color ) ) );
|
||||
|
||||
screen->Append( poly );
|
||||
line->SetFlags( IS_NEW );
|
||||
|
||||
screen->Append( line );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -2151,10 +2177,10 @@ VECTOR2I HelperGeneratePowerPortGraphics( LIB_SYMBOL* aKsymbol, ASCH_POWER_PORT_
|
||||
LIB_SHAPE* bezier = new LIB_SHAPE( aKsymbol, SHAPE_T::BEZIER );
|
||||
aKsymbol->AddDrawItem( bezier );
|
||||
bezier->SetStroke( STROKE_PARAMS( schIUScale.MilsToIU( 5 ), PLOT_DASH_TYPE::SOLID ) );
|
||||
bezier->AddPoint( { schIUScale.MilsToIU( 30 ), schIUScale.MilsToIU( -50 ) } );
|
||||
bezier->AddPoint( { schIUScale.MilsToIU( 30 ), schIUScale.MilsToIU( -87 ) } );
|
||||
bezier->AddPoint( { schIUScale.MilsToIU( -30 ), schIUScale.MilsToIU( -63 ) } );
|
||||
bezier->AddPoint( { schIUScale.MilsToIU( -30 ), schIUScale.MilsToIU( -100 ) } );
|
||||
bezier->SetStart( { schIUScale.MilsToIU( 30 ), schIUScale.MilsToIU( -50 ) } );
|
||||
bezier->SetBezierC1( { schIUScale.MilsToIU( 30 ), schIUScale.MilsToIU( -87 ) } );
|
||||
bezier->SetBezierC2( { schIUScale.MilsToIU( -30 ), schIUScale.MilsToIU( -63 ) } );
|
||||
bezier->SetEnd( { schIUScale.MilsToIU( -30 ), schIUScale.MilsToIU( -100 ) } );
|
||||
|
||||
return { 0, schIUScale.MilsToIU( 150 ) };
|
||||
}
|
||||
@@ -2317,10 +2343,17 @@ VECTOR2I HelperGeneratePowerPortGraphics( LIB_SYMBOL* aKsymbol, ASCH_POWER_PORT_
|
||||
void SCH_ALTIUM_PLUGIN::ParsePowerPort( const std::map<wxString, wxString>& aProperties )
|
||||
{
|
||||
ASCH_POWER_PORT elem( aProperties );
|
||||
LIB_ID libId = AltiumToKiCadLibID( getLibName(), elem.text );
|
||||
LIB_SYMBOL* libSymbol = nullptr;
|
||||
|
||||
const auto& powerSymbolIt = m_powerSymbols.find( elem.text );
|
||||
wxString symName( elem.text );
|
||||
wxString styleName = wxString( "Style" ) << static_cast<int>( elem.style );
|
||||
|
||||
if( !styleName.empty() )
|
||||
symName << '_' << styleName;
|
||||
|
||||
LIB_ID libId = AltiumToKiCadLibID( getLibName(), symName );
|
||||
LIB_SYMBOL* libSymbol = nullptr;
|
||||
|
||||
const auto& powerSymbolIt = m_powerSymbols.find( symName );
|
||||
|
||||
if( powerSymbolIt != m_powerSymbols.end() )
|
||||
{
|
||||
@@ -2358,7 +2391,7 @@ void SCH_ALTIUM_PLUGIN::ParsePowerPort( const std::map<wxString, wxString>& aPro
|
||||
|
||||
// this has to be done after parsing the LIB_SYMBOL!
|
||||
m_pi->SaveSymbol( getLibFileName().GetFullPath(), libSymbol, m_properties.get() );
|
||||
m_powerSymbols.insert( { elem.text, libSymbol } );
|
||||
m_powerSymbols.insert( { symName, libSymbol } );
|
||||
}
|
||||
|
||||
SCH_SCREEN* screen = getCurrentScreen();
|
||||
|
||||
@@ -499,8 +499,17 @@ LIB_SYMBOL* SCH_DATABASE_PLUGIN::loadSymbolFromRow( const wxString& aSymbolName,
|
||||
continue;
|
||||
}
|
||||
|
||||
wxString value( std::any_cast<std::string>( aRow.at( mapping.column ) ).c_str(),
|
||||
wxConvUTF8 );
|
||||
std:: string strValue;
|
||||
|
||||
try
|
||||
{
|
||||
strValue = std::any_cast<std::string>( aRow.at( mapping.column ) );
|
||||
}
|
||||
catch( std::bad_any_cast& e )
|
||||
{
|
||||
}
|
||||
|
||||
wxString value( strValue.c_str(), wxConvUTF8 );
|
||||
|
||||
if( mapping.name == wxT( "Value" ) )
|
||||
{
|
||||
|
||||
@@ -192,6 +192,11 @@ LIB_SYMBOL* SCH_SEXPR_PARSER::ParseSymbol( LIB_SYMBOL_MAP& aSymbolLibMap, int aF
|
||||
|
||||
name = FromUTF8();
|
||||
|
||||
// Some symbol LIB_IDs have the '/' character escaped which can break derived symbol links.
|
||||
// The '/' character is no longer an illegal LIB_ID character so it doesn't need to be
|
||||
// escaped.
|
||||
name.Replace( wxS( "{slash}" ), wxT( "/" ) );
|
||||
|
||||
LIB_ID id;
|
||||
int bad_pos = id.Parse( name );
|
||||
|
||||
@@ -268,6 +273,12 @@ LIB_SYMBOL* SCH_SEXPR_PARSER::ParseSymbol( LIB_SYMBOL_MAP& aSymbolLibMap, int aF
|
||||
}
|
||||
|
||||
name = FromUTF8();
|
||||
|
||||
// Some symbol LIB_IDs have the '/' character escaped which can break derived
|
||||
// symbol links. The '/' character is no longer an illegal LIB_ID character so
|
||||
// it doesn't need to be escaped.
|
||||
name.Replace( wxS( "{slash}" ), wxT( "/" ) );
|
||||
|
||||
auto it = aSymbolLibMap.find( name );
|
||||
|
||||
if( it == aSymbolLibMap.end() )
|
||||
@@ -293,6 +304,11 @@ LIB_SYMBOL* SCH_SEXPR_PARSER::ParseSymbol( LIB_SYMBOL_MAP& aSymbolLibMap, int aF
|
||||
|
||||
name = FromUTF8();
|
||||
|
||||
// Some symbol LIB_IDs have the '/' character escaped which can break derived
|
||||
// symbol links. The '/' character is no longer an illegal LIB_ID character so
|
||||
// it doesn't need to be escaped.
|
||||
name.Replace( wxS( "{slash}" ), wxT( "/" ) );
|
||||
|
||||
if( !name.StartsWith( m_symbolName ) )
|
||||
{
|
||||
error.Printf( _( "Invalid symbol unit name prefix %s" ), name.c_str() );
|
||||
@@ -1678,6 +1694,8 @@ LIB_TEXTBOX* SCH_SEXPR_PARSER::parseTextBox()
|
||||
FILL_PARAMS fill;
|
||||
std::unique_ptr<LIB_TEXTBOX> textBox = std::make_unique<LIB_TEXTBOX>( nullptr );
|
||||
|
||||
textBox->SetUnit( m_unit );
|
||||
textBox->SetConvert( m_convert );
|
||||
token = NextTok();
|
||||
|
||||
if( token == T_private )
|
||||
@@ -2593,6 +2611,11 @@ SCH_SYMBOL* SCH_SEXPR_PARSER::parseSchematicSymbol()
|
||||
}
|
||||
|
||||
libName = FromUTF8();
|
||||
// Some symbol LIB_IDs or lib_name have the '/' character escaped which can break
|
||||
// symbol links. The '/' character is no longer an illegal LIB_ID character so
|
||||
// it doesn't need to be escaped.
|
||||
libName.Replace( "{slash}", "/" );
|
||||
|
||||
NeedRIGHT();
|
||||
break;
|
||||
}
|
||||
@@ -2606,6 +2629,11 @@ SCH_SYMBOL* SCH_SEXPR_PARSER::parseSchematicSymbol()
|
||||
|
||||
LIB_ID libId;
|
||||
wxString name = FromUTF8();
|
||||
// Some symbol LIB_IDs have the '/' character escaped which can break
|
||||
// symbol links. The '/' character is no longer an illegal LIB_ID character so
|
||||
// it doesn't need to be escaped.
|
||||
name.Replace( "{slash}", "/" );
|
||||
|
||||
int bad_pos = libId.Parse( name );
|
||||
|
||||
if( bad_pos >= 0 )
|
||||
@@ -3363,6 +3391,11 @@ SCH_SHAPE* SCH_SEXPR_PARSER::parseSchPolyLine()
|
||||
|
||||
case T_stroke:
|
||||
parseStroke( stroke );
|
||||
|
||||
// In 6.0, the default schematic line style was Dashed.
|
||||
if( m_requiredVersion <= 20211123 && stroke.GetPlotStyle() == PLOT_DASH_TYPE::DEFAULT )
|
||||
stroke.SetPlotStyle( PLOT_DASH_TYPE::DASH );
|
||||
|
||||
polyline->SetStroke( stroke );
|
||||
break;
|
||||
|
||||
|
||||
@@ -550,10 +550,6 @@ void SCH_SEXPR_PLUGIN::Format( EE_SELECTION* aSelection, SCH_SHEET_PATH* aSelect
|
||||
m_out->Print( 0, ")\n\n" );
|
||||
}
|
||||
|
||||
// Store the selected sheets instance information
|
||||
SCH_SHEET_LIST selectedSheets;
|
||||
SCH_REFERENCE_LIST selectedSymbols;
|
||||
|
||||
for( i = 0; i < aSelection->GetSize(); ++i )
|
||||
{
|
||||
item = (SCH_ITEM*) aSelection->GetItem( i );
|
||||
@@ -561,10 +557,8 @@ void SCH_SEXPR_PLUGIN::Format( EE_SELECTION* aSelection, SCH_SHEET_PATH* aSelect
|
||||
switch( item->Type() )
|
||||
{
|
||||
case SCH_SYMBOL_T:
|
||||
saveSymbol( static_cast<SCH_SYMBOL*>( item ), aSchematic, 0, aForClipboard );
|
||||
|
||||
aSelectionPath->AppendSymbol( selectedSymbols, static_cast<SCH_SYMBOL*>( item ),
|
||||
true, true );
|
||||
saveSymbol( static_cast<SCH_SYMBOL*>( item ), aSchematic, 0, aForClipboard,
|
||||
aSelectionPath );
|
||||
break;
|
||||
|
||||
case SCH_BITMAP_T:
|
||||
@@ -573,15 +567,6 @@ void SCH_SEXPR_PLUGIN::Format( EE_SELECTION* aSelection, SCH_SHEET_PATH* aSelect
|
||||
|
||||
case SCH_SHEET_T:
|
||||
saveSheet( static_cast< SCH_SHEET* >( item ), 0 );
|
||||
|
||||
{
|
||||
SCH_SHEET_PATH subSheetPath = *aSelectionPath;
|
||||
subSheetPath.push_back( static_cast<SCH_SHEET*>( item ) );
|
||||
|
||||
fullHierarchy.GetSheetsWithinPath( selectedSheets, subSheetPath );
|
||||
fullHierarchy.GetSymbolsWithinPath( selectedSymbols, subSheetPath, true, true );
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case SCH_JUNCTION_T:
|
||||
@@ -621,33 +606,12 @@ void SCH_SEXPR_PLUGIN::Format( EE_SELECTION* aSelection, SCH_SHEET_PATH* aSelect
|
||||
wxASSERT( "Unexpected schematic object type in SCH_SEXPR_PLUGIN::Format()" );
|
||||
}
|
||||
}
|
||||
|
||||
// Make all instance information relative to the selection path
|
||||
KIID_PATH selectionPath = aSelectionPath->Path();
|
||||
|
||||
selectedSheets.SortByPageNumbers();
|
||||
std::vector<SCH_SHEET_INSTANCE> sheetinstances = selectedSheets.GetSheetInstances();
|
||||
|
||||
for( SCH_SHEET_INSTANCE& sheetInstance : sheetinstances )
|
||||
{
|
||||
wxASSERT_MSG( sheetInstance.m_Path.MakeRelativeTo( selectionPath ),
|
||||
"Sheet is not inside the selection path?" );
|
||||
}
|
||||
|
||||
selectionPath = aSelectionPath->Path();
|
||||
selectedSymbols.SortByReferenceOnly();
|
||||
std::vector<SCH_SYMBOL_INSTANCE> symbolInstances = selectedSymbols.GetSymbolInstances();
|
||||
|
||||
for( SCH_SYMBOL_INSTANCE& symbolInstance : symbolInstances )
|
||||
{
|
||||
wxASSERT_MSG( symbolInstance.m_Path.MakeRelativeTo( selectionPath ),
|
||||
"Symbol is not inside the selection path?" );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void SCH_SEXPR_PLUGIN::saveSymbol( SCH_SYMBOL* aSymbol, const SCHEMATIC& aSchematic,
|
||||
int aNestLevel, bool aForClipboard )
|
||||
int aNestLevel, bool aForClipboard,
|
||||
const SCH_SHEET_PATH* aRelativePath )
|
||||
{
|
||||
wxCHECK_RET( aSymbol != nullptr && m_out != nullptr, "" );
|
||||
|
||||
@@ -717,6 +681,14 @@ void SCH_SEXPR_PLUGIN::saveSymbol( SCH_SYMBOL* aSymbol, const SCHEMATIC& aSchema
|
||||
aSymbol->GetUnit() :
|
||||
aSymbol->GetInstanceReferences()[0].m_Unit;
|
||||
|
||||
if( aForClipboard && aRelativePath )
|
||||
{
|
||||
SCH_SYMBOL_INSTANCE unitInstance;
|
||||
|
||||
if( aSymbol->GetInstance( unitInstance, aRelativePath->Path() ) )
|
||||
unit = unitInstance.m_Unit;
|
||||
}
|
||||
|
||||
m_out->Print( 0, " (unit %d)", unit );
|
||||
|
||||
if( aSymbol->GetConvert() == LIB_ITEM::LIB_CONVERT::DEMORGAN )
|
||||
@@ -759,6 +731,14 @@ void SCH_SEXPR_PLUGIN::saveSymbol( SCH_SYMBOL* aSymbol, const SCHEMATIC& aSchema
|
||||
field.SetText( aSymbol->GetField( FOOTPRINT_FIELD )->GetText() );
|
||||
}
|
||||
}
|
||||
else if( aForClipboard && aSymbol->GetInstanceReferences().size() && aRelativePath
|
||||
&& ( id == REFERENCE_FIELD ) )
|
||||
{
|
||||
SCH_SYMBOL_INSTANCE instance;
|
||||
|
||||
if( aSymbol->GetInstance( instance, aRelativePath->Path() ) )
|
||||
field.SetText( instance.m_Reference );
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
@@ -805,6 +785,9 @@ void SCH_SEXPR_PLUGIN::saveSymbol( SCH_SYMBOL* aSymbol, const SCHEMATIC& aSchema
|
||||
|
||||
for( size_t i = 0; i < aSymbol->GetInstanceReferences().size(); i++ )
|
||||
{
|
||||
// Zero length KIID_PATH objects are not valid and will cause a crash below.
|
||||
wxCHECK2( aSymbol->GetInstanceReferences()[i].m_Path.size(), continue );
|
||||
|
||||
// If the instance data is part of this design but no longer has an associated sheet
|
||||
// path, don't save it. This prevents large amounts of orphaned instance data for the
|
||||
// current project from accumulating in the schematic files.
|
||||
@@ -839,7 +822,13 @@ void SCH_SEXPR_PLUGIN::saveSymbol( SCH_SYMBOL* aSymbol, const SCHEMATIC& aSchema
|
||||
project_open = true;
|
||||
}
|
||||
|
||||
wxString path = aSymbol->GetInstanceReferences()[i].m_Path.AsString();
|
||||
wxString path;
|
||||
KIID_PATH tmp = aSymbol->GetInstanceReferences()[i].m_Path;
|
||||
|
||||
if( aForClipboard && aRelativePath )
|
||||
tmp.MakeRelativeTo( aRelativePath->Path() );
|
||||
|
||||
path = tmp.AsString();
|
||||
|
||||
m_out->Print( aNestLevel + 3, "(path %s\n",
|
||||
m_out->Quotew( path ).c_str() );
|
||||
|
||||
@@ -146,7 +146,7 @@ private:
|
||||
void loadFile( const wxString& aFileName, SCH_SHEET* aSheet );
|
||||
|
||||
void saveSymbol( SCH_SYMBOL* aSymbol, const SCHEMATIC& aSchematic, int aNestLevel,
|
||||
bool aForClipboard );
|
||||
bool aForClipboard, const SCH_SHEET_PATH* aRelativePath = nullptr );
|
||||
void saveField( SCH_FIELD* aField, int aNestLevel );
|
||||
void saveBitmap( SCH_BITMAP* aBitmap, int aNestLevel );
|
||||
void saveSheet( SCH_SHEET* aSheet, int aNestLevel );
|
||||
|
||||
@@ -95,12 +95,23 @@ void SCH_LEGACY_PLUGIN_CACHE::Load()
|
||||
|
||||
m_versionMajor = parseInt( reader, line, &line );
|
||||
|
||||
if( *line != '.' )
|
||||
SCH_PARSE_ERROR( "invalid file version formatting in header", reader, line );
|
||||
if( *line == '/' )
|
||||
{
|
||||
// Some old libraries use a version syntax like
|
||||
// EESchema-LIBRARY Version 2/10/2006-18:49:15
|
||||
// use 2.3 version numer to read the file
|
||||
m_versionMajor = 2;
|
||||
m_versionMinor = 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
if( *line != '.' )
|
||||
SCH_PARSE_ERROR( "invalid file version formatting in header", reader, line );
|
||||
|
||||
line++;
|
||||
line++;
|
||||
|
||||
m_versionMinor = parseInt( reader, line, &line );
|
||||
m_versionMinor = parseInt( reader, line, &line );
|
||||
}
|
||||
|
||||
if( m_versionMajor < 1 || m_versionMinor < 0 || m_versionMinor > 99 )
|
||||
SCH_PARSE_ERROR( "invalid file version in header", reader, line );
|
||||
@@ -658,7 +669,20 @@ void SCH_LEGACY_PLUGIN_CACHE::loadField( std::unique_ptr<LIB_SYMBOL>& aSymbol,
|
||||
}
|
||||
else
|
||||
{
|
||||
parseQuotedString( field->m_name, aReader, line, &line, true ); // Optional.
|
||||
wxString fieldName = wxEmptyString;
|
||||
parseQuotedString( fieldName, aReader, line, &line, true ); // Optional.
|
||||
|
||||
if( fieldName.IsEmpty() )
|
||||
return;
|
||||
|
||||
wxString candidateFieldName = fieldName;
|
||||
int suffix = 0;
|
||||
|
||||
//Deduplicate field name
|
||||
while( aSymbol->FindField( candidateFieldName ) != nullptr )
|
||||
candidateFieldName = wxString::Format( "%s_%d", fieldName, ++suffix );
|
||||
|
||||
field->m_name = candidateFieldName;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -746,6 +770,68 @@ FILL_T SCH_LEGACY_PLUGIN_CACHE::parseFillMode( LINE_READER& aReader, const char*
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This function based on version 6.0 is required for reading legacy arcs.
|
||||
* Changing it in any way will likely break arcs.
|
||||
*/
|
||||
static bool MapAnglesV6( int* aAngle1, int* aAngle2 )
|
||||
{
|
||||
auto DECIDEG2RAD = []( double deg ) -> double
|
||||
{
|
||||
return deg * M_PI / 1800.0;
|
||||
};
|
||||
|
||||
int angle, delta;
|
||||
double x, y;
|
||||
bool swap = false;
|
||||
|
||||
delta = *aAngle2 - *aAngle1;
|
||||
|
||||
if( delta >= 1800 )
|
||||
{
|
||||
*aAngle1 -= 1;
|
||||
*aAngle2 += 1;
|
||||
}
|
||||
|
||||
x = cos( DECIDEG2RAD( *aAngle1 ) );
|
||||
y = -sin( DECIDEG2RAD( *aAngle1 ) );
|
||||
*aAngle1 = KiROUND( RAD2DECIDEG( atan2( y, x ) ) );
|
||||
|
||||
x = cos( DECIDEG2RAD( *aAngle2 ) );
|
||||
y = -sin( DECIDEG2RAD( *aAngle2 ) );
|
||||
*aAngle2 = KiROUND( RAD2DECIDEG( atan2( y, x ) ) );
|
||||
|
||||
NORMALIZE_ANGLE_POS( *aAngle1 );
|
||||
NORMALIZE_ANGLE_POS( *aAngle2 );
|
||||
|
||||
if( *aAngle2 < *aAngle1 )
|
||||
*aAngle2 += 3600;
|
||||
|
||||
if( *aAngle2 - *aAngle1 > 1800 ) // Need to swap the two angles
|
||||
{
|
||||
angle = ( *aAngle1 );
|
||||
*aAngle1 = ( *aAngle2 );
|
||||
*aAngle2 = angle;
|
||||
|
||||
NORMALIZE_ANGLE_POS( *aAngle1 );
|
||||
NORMALIZE_ANGLE_POS( *aAngle2 );
|
||||
|
||||
if( *aAngle2 < *aAngle1 )
|
||||
*aAngle2 += 3600;
|
||||
|
||||
swap = true;
|
||||
}
|
||||
|
||||
if( delta >= 1800 )
|
||||
{
|
||||
*aAngle1 += 1;
|
||||
*aAngle2 -= 1;
|
||||
}
|
||||
|
||||
return swap;
|
||||
}
|
||||
|
||||
|
||||
LIB_SHAPE* SCH_LEGACY_PLUGIN_CACHE::loadArc( std::unique_ptr<LIB_SYMBOL>& aSymbol,
|
||||
LINE_READER& aReader )
|
||||
{
|
||||
@@ -762,10 +848,12 @@ LIB_SHAPE* SCH_LEGACY_PLUGIN_CACHE::loadArc( std::unique_ptr<LIB_SYMBOL>& aSymbo
|
||||
|
||||
arc->SetPosition( center );
|
||||
|
||||
(void) schIUScale.MilsToIU( parseInt( aReader, line, &line ) );
|
||||
int radius = schIUScale.MilsToIU( parseInt( aReader, line, &line ) );
|
||||
int angle1 = parseInt( aReader, line, &line );
|
||||
int angle2 = parseInt( aReader, line, &line );
|
||||
|
||||
EDA_ANGLE angle1( parseInt( aReader, line, &line ), TENTHS_OF_A_DEGREE_T );
|
||||
EDA_ANGLE angle2( parseInt( aReader, line, &line ), TENTHS_OF_A_DEGREE_T );
|
||||
NORMALIZE_ANGLE_POS( angle1 );
|
||||
NORMALIZE_ANGLE_POS( angle2 );
|
||||
|
||||
arc->SetUnit( parseInt( aReader, line, &line ) );
|
||||
arc->SetConvert( parseInt( aReader, line, &line ) );
|
||||
@@ -792,38 +880,33 @@ LIB_SHAPE* SCH_LEGACY_PLUGIN_CACHE::loadArc( std::unique_ptr<LIB_SYMBOL>& aSymbo
|
||||
arc->SetStart( arcStart );
|
||||
arc->SetEnd( arcEnd );
|
||||
}
|
||||
// Actual Coordinates of arc ends are not read from file (old library), calculate them
|
||||
else
|
||||
{
|
||||
arc->SetArcAngleAndEnd( angle2 - angle1, true );
|
||||
// Actual Coordinates of arc ends are not read from file
|
||||
// (old library), calculate them
|
||||
VECTOR2I arcStart( radius, 0 );
|
||||
VECTOR2I arcEnd( radius, 0 );
|
||||
|
||||
RotatePoint( arcStart, EDA_ANGLE( -angle1, EDA_ANGLE_T::TENTHS_OF_A_DEGREE_T ) );
|
||||
arcStart += arc->GetCenter();
|
||||
arc->SetStart( arcStart );
|
||||
RotatePoint( arcEnd, EDA_ANGLE( -angle2, EDA_ANGLE_T::TENTHS_OF_A_DEGREE_T ) );
|
||||
arcEnd += arc->GetCenter();
|
||||
arc->SetEnd( arcEnd );
|
||||
}
|
||||
|
||||
/*
|
||||
* Current file format stores start-mid-end and so doesn't care about winding. We
|
||||
* store start-end with an implied winding internally though.
|
||||
* This issue is only for 180 deg arcs, because 180 deg are a limit to handle arcs in
|
||||
* legacy libs.
|
||||
*
|
||||
* So a workaround is to slightly change the arc angle to
|
||||
* avoid 180 deg arc after correction
|
||||
/**
|
||||
* This accounts for an oddity in the old library format, where the symbol is overdefined.
|
||||
* The previous draw (based on wxwidgets) used start point and end point and always drew
|
||||
* counter-clockwise. The new GAL draw takes center, radius and start/end angles. All of
|
||||
* these points were stored in the file, so we need to mimic the swapping of start/end
|
||||
* points rather than using the stored angles in order to properly map edge cases.
|
||||
*/
|
||||
EDA_ANGLE arc_angle = arc->GetArcAngle();
|
||||
|
||||
if( arc_angle == ANGLE_180 )
|
||||
if( !MapAnglesV6( &angle1, &angle2 ) )
|
||||
{
|
||||
VECTOR2I new_center = CalcArcCenter( arc->GetStart(), arc->GetEnd(),
|
||||
EDA_ANGLE( 179.5, DEGREES_T ) );
|
||||
arc->SetCenter( new_center );
|
||||
}
|
||||
|
||||
// In legacy libraries, an arc angle is always <= 180.0 degrees
|
||||
// So if the created arc is > 180 degrees, swap arc ends to have a < 180 deg arc.
|
||||
if( arc->GetArcAngle() > ANGLE_180 )
|
||||
{
|
||||
VECTOR2I new_end = arc->GetStart();
|
||||
VECTOR2I new_start = arc->GetEnd();
|
||||
arc->SetStart( new_start );
|
||||
arc->SetEnd( new_end );
|
||||
VECTOR2I temp = arc->GetStart();
|
||||
arc->SetStart( arc->GetEnd() );
|
||||
arc->SetEnd( temp );
|
||||
}
|
||||
|
||||
return arc;
|
||||
|
||||
@@ -353,6 +353,8 @@ void SCH_LEGACY_PLUGIN::LoadContent( LINE_READER& aReader, SCH_SCREEN* aScreen,
|
||||
aScreen->Append( loadText( aReader ) );
|
||||
else if( strCompare( "BusAlias", line ) )
|
||||
aScreen->AddBusAlias( loadBusAlias( aReader, aScreen ) );
|
||||
else if( strCompare( "Kmarq", line ) )
|
||||
continue; // Ignore legacy (until 2009) ERC marker entry
|
||||
else if( strCompare( "$EndSCHEMATC", line ) )
|
||||
return;
|
||||
else
|
||||
@@ -800,6 +802,10 @@ SCH_LINE* SCH_LEGACY_PLUGIN::loadWire( LINE_READER& aReader )
|
||||
if( !strCompare( "Line", line, &line ) )
|
||||
SCH_PARSE_ERROR( "invalid wire definition", aReader, line );
|
||||
|
||||
// The default graphical line style was Dashed.
|
||||
if( wire->GetLayer() == LAYER_NOTES )
|
||||
wire->SetLineStyle( PLOT_DASH_TYPE::DASH );
|
||||
|
||||
// Since Sept 15, 2017, a line style is alloved (width, style, color)
|
||||
// Only non default values are stored
|
||||
while( !is_eol( *line ) )
|
||||
|
||||
+143
-10
@@ -4,7 +4,7 @@
|
||||
* Copyright (C) 2013 Jean-Pierre Charras, jp.charras at wanadoo.fr
|
||||
* Copyright (C) 2012 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
|
||||
* Copyright (C) 2008 Wayne Stambaugh <stambaughw@gmail.com>
|
||||
* Copyright (C) 1992-2023 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
* Copyright (C) 1992-2024 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
|
||||
@@ -34,6 +34,7 @@
|
||||
#include <project.h>
|
||||
#include <reporter.h>
|
||||
#include <sch_draw_panel.h>
|
||||
#include <trace_helpers.h>
|
||||
#include <sch_edit_frame.h>
|
||||
#include <sch_item.h>
|
||||
|
||||
@@ -1029,7 +1030,8 @@ void SCH_SCREEN::UpdateSymbolLinks( REPORTER* aReporter )
|
||||
}
|
||||
}
|
||||
|
||||
symbol->SetLibSymbol( libSymbol.release() );
|
||||
if( libSymbol.get() ) // Only change the old link if the new link exists
|
||||
symbol->SetLibSymbol( libSymbol.release() );
|
||||
}
|
||||
|
||||
// Changing the symbol may adjust the bbox of the symbol. This re-inserts the
|
||||
@@ -1174,12 +1176,14 @@ void SCH_SCREEN::Plot( PLOTTER* aPlotter ) const
|
||||
item->Plot( aPlotter, background );
|
||||
}
|
||||
|
||||
// Plot the background items
|
||||
for( const SCH_ITEM* item : other )
|
||||
{
|
||||
aPlotter->SetCurrentLineWidth( std::max( item->GetPenWidth(), defaultPenWidth ) );
|
||||
item->Plot( aPlotter, background );
|
||||
}
|
||||
|
||||
// Plot the foreground items
|
||||
for( const SCH_ITEM* item : other )
|
||||
{
|
||||
aPlotter->SetCurrentLineWidth( std::max( item->GetPenWidth(), defaultPenWidth ) );
|
||||
@@ -1193,7 +1197,10 @@ void SCH_SCREEN::Plot( PLOTTER* aPlotter ) const
|
||||
aPlotter->SetCurrentLineWidth( std::max( sym->GetPenWidth(), defaultPenWidth ) );
|
||||
|
||||
for( SCH_FIELD field : sym->GetFields() )
|
||||
{
|
||||
field.ClearRenderCache();
|
||||
field.Plot( aPlotter, false );
|
||||
}
|
||||
|
||||
sym->PlotPins( aPlotter );
|
||||
|
||||
@@ -1363,36 +1370,46 @@ void SCH_SCREEN::TestDanglingEnds( const SCH_SHEET_PATH* aPath,
|
||||
{
|
||||
PROF_TIMER timer( __FUNCTION__ );
|
||||
|
||||
std::vector<DANGLING_END_ITEM> endPoints;
|
||||
std::vector<DANGLING_END_ITEM> endPointsByPos;
|
||||
std::vector<DANGLING_END_ITEM> endPointsByType;
|
||||
|
||||
auto getends =
|
||||
auto get_ends =
|
||||
[&]( SCH_ITEM* item )
|
||||
{
|
||||
if( item->IsConnectable() )
|
||||
item->GetEndPoints( endPoints );
|
||||
item->GetEndPoints( endPointsByType );
|
||||
};
|
||||
|
||||
auto update_state =
|
||||
[&]( SCH_ITEM* item )
|
||||
{
|
||||
if( item->UpdateDanglingState( endPoints, aPath ) )
|
||||
if( item->UpdateDanglingState( endPointsByType, endPointsByPos, aPath ) )
|
||||
{
|
||||
if( aChangedHandler )
|
||||
(*aChangedHandler)( item );
|
||||
( *aChangedHandler )( item );
|
||||
}
|
||||
};
|
||||
|
||||
for( SCH_ITEM* item : Items() )
|
||||
{
|
||||
|
||||
getends( item );
|
||||
item->RunOnChildren( getends );
|
||||
get_ends( item );
|
||||
item->RunOnChildren( get_ends );
|
||||
}
|
||||
|
||||
PROF_TIMER sortTimer( "SCH_SCREEN::TestDanglingEnds pre-sort" );
|
||||
endPointsByPos = endPointsByType;
|
||||
DANGLING_END_ITEM_HELPER::sort_dangling_end_items( endPointsByType, endPointsByPos );
|
||||
sortTimer.Stop();
|
||||
|
||||
if( wxLog::IsAllowedTraceMask( DanglingProfileMask ) )
|
||||
sortTimer.Show();
|
||||
|
||||
for( SCH_ITEM* item : Items() )
|
||||
{
|
||||
update_state( item );
|
||||
item->RunOnChildren( update_state );
|
||||
}
|
||||
|
||||
if( wxLog::IsAllowedTraceMask( DanglingProfileMask ) )
|
||||
timer.Show();
|
||||
}
|
||||
@@ -1621,6 +1638,100 @@ size_t SCH_SCREEN::getLibSymbolNameMatches( const SCH_SYMBOL& aSymbol,
|
||||
}
|
||||
|
||||
|
||||
void SCH_SCREEN::PruneOrphanedSymbolInstances( const wxString& aProjectName,
|
||||
const SCH_SHEET_LIST& aValidSheetPaths )
|
||||
{
|
||||
// The project name cannot be empty. Projects older than 7.0 did not save project names
|
||||
// when saving instance data. Running this algorithm with an empty project name would
|
||||
// clobber all instance data for projects other than the current one when a schematic
|
||||
// file is shared across multiple projects. Because running the schematic editor in
|
||||
// stand alone mode can result in an empty project name, do not assert here.
|
||||
if( aProjectName.IsEmpty() )
|
||||
return;
|
||||
|
||||
for( SCH_ITEM* item : Items().OfType( SCH_SYMBOL_T ) )
|
||||
{
|
||||
SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
|
||||
|
||||
wxCHECK2( symbol, continue );
|
||||
|
||||
std::set<KIID_PATH> pathsToPrune;
|
||||
const std::vector<SCH_SYMBOL_INSTANCE> instances = symbol->GetInstanceReferences();
|
||||
|
||||
for( const SCH_SYMBOL_INSTANCE& instance : instances )
|
||||
{
|
||||
// Ignore instance paths from other projects.
|
||||
if( aProjectName != instance.m_ProjectName )
|
||||
continue;
|
||||
|
||||
std::optional<SCH_SHEET_PATH> pathFound =
|
||||
aValidSheetPaths.GetSheetPathByKIIDPath( instance.m_Path );
|
||||
|
||||
// Check for paths that do not exist in the current project and paths that do
|
||||
// not contain the current symbol.
|
||||
if( !pathFound )
|
||||
pathsToPrune.emplace( instance.m_Path );
|
||||
else if( pathFound.value().LastScreen() != this )
|
||||
pathsToPrune.emplace( pathFound.value().Path() );
|
||||
}
|
||||
|
||||
for( const KIID_PATH& sheetPath : pathsToPrune )
|
||||
{
|
||||
wxLogTrace( traceSchSheetPaths, wxS( "Pruning project '%s' symbol instance %s." ),
|
||||
aProjectName, sheetPath.AsString() );
|
||||
symbol->RemoveInstance( sheetPath );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void SCH_SCREEN::PruneOrphanedSheetInstances( const wxString& aProjectName,
|
||||
const SCH_SHEET_LIST& aValidSheetPaths )
|
||||
{
|
||||
// The project name cannot be empty. Projects older than 7.0 did not save project names
|
||||
// when saving instance data. Running this algorithm with an empty project name would
|
||||
// clobber all instance data for projects other than the current one when a schematic
|
||||
// file is shared across multiple projects. Because running the schematic editor in
|
||||
// stand alone mode can result in an empty project name, do not assert here.
|
||||
if( aProjectName.IsEmpty() )
|
||||
return;
|
||||
|
||||
for( SCH_ITEM* item : Items().OfType( SCH_SHEET_T ) )
|
||||
{
|
||||
SCH_SHEET* sheet = static_cast<SCH_SHEET*>( item );
|
||||
|
||||
wxCHECK2( sheet, continue );
|
||||
|
||||
std::set<KIID_PATH> pathsToPrune;
|
||||
const std::vector<SCH_SHEET_INSTANCE> instances = sheet->GetInstances();
|
||||
|
||||
for( const SCH_SHEET_INSTANCE& instance : instances )
|
||||
{
|
||||
// Ignore instance paths from other projects.
|
||||
if( aProjectName != instance.m_ProjectName )
|
||||
continue;
|
||||
|
||||
std::optional<SCH_SHEET_PATH> pathFound =
|
||||
aValidSheetPaths.GetSheetPathByKIIDPath( instance.m_Path );
|
||||
|
||||
// Check for paths that do not exist in the current project and paths that do
|
||||
// not contain the current symbol.
|
||||
if( !pathFound )
|
||||
pathsToPrune.emplace( instance.m_Path );
|
||||
else if( pathFound.value().LastScreen() != this )
|
||||
pathsToPrune.emplace( pathFound.value().Path() );
|
||||
}
|
||||
|
||||
for( const KIID_PATH& sheetPath : pathsToPrune )
|
||||
{
|
||||
wxLogTrace( traceSchSheetPaths, wxS( "Pruning project '%s' sheet instance %s." ),
|
||||
aProjectName, sheetPath.AsString() );
|
||||
sheet->RemoveInstance( sheetPath );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#if defined(DEBUG)
|
||||
void SCH_SCREEN::Show( int nestLevel, std::ostream& os ) const
|
||||
{
|
||||
@@ -2037,3 +2148,25 @@ void SCH_SCREEN::MigrateSimModels()
|
||||
SIM_MODEL::MigrateSimModel<SCH_SYMBOL, SCH_FIELD>( *symbol, &Schematic()->Prj() );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void SCH_SCREENS::PruneOrphanedSymbolInstances( const wxString& aProjectName,
|
||||
const SCH_SHEET_LIST& aValidSheetPaths )
|
||||
{
|
||||
if( aProjectName.IsEmpty() )
|
||||
return;
|
||||
|
||||
for( SCH_SCREEN* screen = GetFirst(); screen; screen = GetNext() )
|
||||
screen->PruneOrphanedSymbolInstances( aProjectName, aValidSheetPaths );
|
||||
}
|
||||
|
||||
|
||||
void SCH_SCREENS::PruneOrphanedSheetInstances( const wxString& aProjectName,
|
||||
const SCH_SHEET_LIST& aValidSheetPaths )
|
||||
{
|
||||
if( aProjectName.IsEmpty() )
|
||||
return;
|
||||
|
||||
for( SCH_SCREEN* screen = GetFirst(); screen; screen = GetNext() )
|
||||
screen->PruneOrphanedSheetInstances( aProjectName, aValidSheetPaths );
|
||||
}
|
||||
|
||||
+41
-4
@@ -545,6 +545,36 @@ public:
|
||||
*/
|
||||
void MigrateSimModels();
|
||||
|
||||
/**
|
||||
* Remove all invalid symbol instance data in this screen object for the project defined
|
||||
* by \a aProjectName and the list of \a aValidSheetPaths.
|
||||
*
|
||||
* @warning This method will assert and exit on debug builds when \a aProjectName is empty.
|
||||
*
|
||||
* @note This method does not affect instance data for any other projects.
|
||||
*
|
||||
* @param aProjectName is the name of the current project.
|
||||
* @param aValidSheetPaths is the list of valid #SCH_SHEET_PATH objects for the current
|
||||
* project.
|
||||
*/
|
||||
void PruneOrphanedSymbolInstances( const wxString& aProjectName,
|
||||
const SCH_SHEET_LIST& aValidSheetPaths );
|
||||
|
||||
/**
|
||||
* Remove all invalid sheet instance data in this screen object for the project defined
|
||||
* by \a aProjectName and the list of \a aValidSheetPaths.
|
||||
*
|
||||
* @warning This method will assert and exit on debug builds when \a aProjectName is empty.
|
||||
*
|
||||
* @note This method does not affect instance data for any other projects.
|
||||
*
|
||||
* @param aProjectName is the name of the current project.
|
||||
* @param aValidSheetPaths is the list of valid #SCH_SHEET_PATH objects for the current
|
||||
* project.
|
||||
*/
|
||||
void PruneOrphanedSheetInstances( const wxString& aProjectName,
|
||||
const SCH_SHEET_LIST& aValidSheetPaths );
|
||||
|
||||
private:
|
||||
friend SCH_EDIT_FRAME; // Only to populate m_symbolInstances.
|
||||
friend SCH_SEXPR_PARSER; // Only to load instance information from schematic file.
|
||||
@@ -572,12 +602,13 @@ private:
|
||||
size_t getLibSymbolNameMatches( const SCH_SYMBOL& aSymbol, std::vector<wxString>& aMatches );
|
||||
|
||||
|
||||
/**
|
||||
* Compare two #BUS_ALIAS objects by name. For sorting in the set.
|
||||
*/
|
||||
/**
|
||||
* Compare two #BUS_ALIAS objects by name. For sorting in the set.
|
||||
*/
|
||||
struct BusAliasCmp
|
||||
{
|
||||
bool operator()( const std::shared_ptr<BUS_ALIAS>& a, const std::shared_ptr<BUS_ALIAS>& b ) const
|
||||
bool operator()( const std::shared_ptr<BUS_ALIAS>& a,
|
||||
const std::shared_ptr<BUS_ALIAS>& b ) const
|
||||
{
|
||||
return a->GetName() < b->GetName();
|
||||
}
|
||||
@@ -793,6 +824,12 @@ public:
|
||||
*/
|
||||
void SetLegacySymbolInstanceData();
|
||||
|
||||
void PruneOrphanedSymbolInstances( const wxString& aProjectName,
|
||||
const SCH_SHEET_LIST& aValidSheetPaths );
|
||||
|
||||
void PruneOrphanedSheetInstances( const wxString& aProjectName,
|
||||
const SCH_SHEET_LIST& aValidSheetPaths );
|
||||
|
||||
private:
|
||||
void addScreenToList( SCH_SCREEN* aScreen, SCH_SHEET* aSheet );
|
||||
void buildScreenList( SCH_SHEET* aSheet);
|
||||
|
||||
@@ -128,7 +128,7 @@ void SCH_SHAPE::Plot( PLOTTER* aPlotter, bool aBackground ) const
|
||||
if( !aPlotter->GetColorMode() )
|
||||
return;
|
||||
|
||||
if( m_fill == FILL_T::FILLED_WITH_COLOR && GetFillColor() != COLOR4D::UNSPECIFIED )
|
||||
if( IsFilled() )
|
||||
{
|
||||
if( GetFillColor() != COLOR4D::UNSPECIFIED )
|
||||
aPlotter->SetColor( GetFillColor() );
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user