Compare commits

...

127 Commits

Author SHA1 Message Date
Wayne Stambaugh b29f91cc15 Tag release version 6.0.9. 2022-10-28 16:51:23 -04:00
Jon Evans f81313068e ERC: Include power connections in multiple driver test
Fixes https://gitlab.com/kicad/code/kicad/-/issues/12138


(cherry picked from commit 141c1f020e)
2022-10-28 02:55:42 +00:00
Jeff Young 882756b676 Fix typo.
Fixes https://gitlab.com/kicad/code/kicad/issues/12753


(cherry picked from commit c026c3af7b)
2022-10-25 17:40:33 +00:00
Jeff Young 8c3cd200d1 Clean up layer handling and normalize to remove magic numbers.
Fixes https://gitlab.com/kicad/code/kicad/issues/12747

(cherry picked from commit 5fe5534822)
2022-10-25 14:21:03 +01:00
Jeff Young a5fd03df88 Don't delete pin out from under selection & move tools.
Fixes https://gitlab.com/kicad/code/kicad/issues/12610

(cherry picked from commit 3cb6a80954)
2022-10-25 14:21:03 +01:00
Jon Evans 2d2912c23d Improve logic of Position Relative tool
Fixes https://gitlab.com/kicad/code/kicad/-/issues/12672
2022-10-24 18:46:15 -04:00
Jeff Young 3106f6c9f4 We must check clearance on all layers of multi-layer items.
(One layer may have a custom rule.)

Fixes https://gitlab.com/kicad/code/kicad/issues/12733

(cherry picked from commit 2dec37f806)
2022-10-24 10:57:07 +01:00
Jeff Young fde2b429b9 Make sure pair caches are layer-specific where they need to be.
(cherry picked from commit 909358e643)
2022-10-24 10:57:07 +01:00
Wayne Stambaugh 0593663462 Fix 3D viewer canvas timer event clash.
Manual cherry-pick of commit f6297d328c.
2022-10-23 07:53:51 -04:00
Marek Roszko bce8c95647 Avoid netlist export dialog crash from trying to delete a non-custom format
Fixes https://gitlab.com/kicad/code/kicad/-/issues/12229
2022-10-22 16:41:32 -04:00
Marek Roszko 4d729110d5 Fix build error due to C++17 use 2022-10-22 16:38:17 -04:00
Mark Roszko 6c2b9eb433 Bring 6.0 msvc ci in line with master 2022-10-22 17:12:29 +00:00
jean-pierre charras df223cced4 pl_editor: fix a crash when trying to delete an item during its creation.
Fixes #12717
https://gitlab.com/kicad/code/kicad/issues/12717
2022-10-22 18:32:46 +02:00
jean-pierre charras 8e331628b6 Do not add a title/comment in mandatory field strings when writting netlists.
This is mainly for "Sheetfile" property because current it is the only one
that has a title when plotting/drawing it.
2022-10-22 15:38:26 +02:00
Mikolaj Wielgus ceaf3fc72d Ngspice: Preload a basically empty circuit to avoid error messages
Fixes https://gitlab.com/kicad/code/kicad/issues/12481

(cherry picked from commit 6e874f4c1e)
2022-10-21 09:22:53 -07:00
Seth Hillbrand b004d7a1cb Fix ERC global label unit tests
Need to test all units in the subgraph as there are chances that the
subgraph might have more than one label, which needs to be consistently
handled

(cherry picked from commit 60374daa49)
2022-10-21 09:17:11 -07:00
Seth Hillbrand f3ff9ddd31 Show ERC errors when any label only has 1 pin
To be connected, the label must have at least two pins on a subgraph
(or, in the case of a hierarchical label, two pins somewhere in its
connection)

Fixes https://gitlab.com/kicad/code/kicad/issues/7203

(cherry picked from commit 05cdf915d0)
2022-10-21 09:11:24 -07:00
jean-pierre charras e5fa18c9b1 fix an issue in a bom script (extra empty lines created)
Fixes #10473
https://gitlab.com/kicad/code/kicad/issues/10473

(cherry picked from commit 380cb452b2)
2022-10-21 09:10:30 -07:00
Seth Hillbrand d52f246b2a Allow up to three discarded characters when detecting gerbers
Some layout programs add a blank block at the beginning but include the
terminating '*' on a line before starting the actual data.  This is
ignored by GerbView so we all this type of behavior in the mimetype file
detection as well

Suggested by Mark Jeronimus

Fixes https://gitlab.com/kicad/code/kicad/issues/12097

(cherry picked from commit 64335d94d7)
2022-10-21 09:10:01 -07:00
Seth Hillbrand 3dfbe582db Add "Letter-like character" Omega for Unicode x2126
Fixes https://gitlab.com/kicad/code/kicad/issues/12531

(cherry picked from commit 1b38acd9c6)
2022-10-21 09:08:58 -07:00
Seth Hillbrand 431aa88612 Allow printing backgrounds prior to foreground
Eeschema shows background fills on a different z-level than the rest of
the symbols/elements.  Print the backgrounds prior to the foregrounds in
order to preserve this view for print output

Fixes https://gitlab.com/kicad/code/kicad/issues/12559

(cherry picked from commit e055302a3c)
2022-10-21 09:00:13 -07:00
Seth Hillbrand 03a1a8e6d3 Fix missing token initializer
Fixes https://gitlab.com/kicad/code/kicad/issues/12555

(cherry picked from commit fdf9fcc24d)
2022-10-21 08:58:59 -07:00
Seth Hillbrand 5f6de83981 Ensure that token size is large enough
Input tokens can be arbitrary, so output needs to keep pace

Fixes https://gitlab.com/kicad/code/kicad/issues/12555

(cherry picked from commit 19378675f1)
2022-10-21 08:40:30 -07:00
jean-pierre charras 02d38db577 Fix about fix_swig_imports.py, useless or not working with swig 4, but needed by swig 3
fix_swig_imports.py cleans pcbnew.py, but the section to clean does not exist
in swig 4, only in swig 3.
2022-10-21 16:33:01 +02:00
Alex bd1698f80e Allow GAL_DRAWING_CONTEXT dtor to throw exceptions.
These destructors are implicitly noexcept, which woudnt't allow
OpenGL errors to be caught in DoRePaint.

Fixes https://gitlab.com/kicad/code/kicad/issues/12117

(cherry picked from commit 39089ad805)
2022-10-21 17:24:11 +03:00
Alex 6de30b19a0 Don't sync the world twice in inline router tools.
Activate() already clears and syncs the world via PNS::TOOL_BASE::Reset,
so there's no need to sync in InlineDrag and InlineBreakTrack.

(cherry picked from commit cc4e34ef49)
2022-10-21 17:21:24 +03:00
Alex 00ff5baf59 kiplatform: Add quotes to restart registration command line.
(cherry picked from commit 6e0d940b98)
2022-10-21 17:20:29 +03:00
Alex 152252c685 Fix selecting pads of footprints in groups.
(cherry picked from commit 67985510a8)
2022-10-21 17:19:05 +03:00
Alex 3b0466f3e8 Fix selection and entering in nested groups.
Fixes https://gitlab.com/kicad/code/kicad/issues/12586

(cherry picked from commit 0fea6f5ac3)
2022-10-21 17:18:07 +03:00
Seth Hillbrand 2ca7a76693 Don't connect disparate nets
Only some elements get their nets assigned based on connectivity.  Other
elements should be keps in different clusters for connection

Fixes https://gitlab.com/kicad/code/kicad/issues/12622

(cherry picked from commit c9f11827a7)
2022-10-21 11:35:31 +01:00
Seth Hillbrand af159c9841 Be sure to update UUID when placing new elements
Fixes https://gitlab.com/kicad/code/kicad/issues/12588

(cherry picked from commit a5da46459c)
2022-10-21 11:19:46 +01:00
Jeff Young de9ae28bdb Fix typo.
Fixes https://gitlab.com/kicad/code/kicad/issues/12467

(cherry picked from commit bb1eb94aa0)
2022-10-21 11:16:19 +01:00
Jeff Young 9f151025b3 Fix typo found by dsa-t.
(cherry picked from commit 7e97dc6974)
2022-10-21 11:14:05 +01:00
Jeff Young 549dca1a05 Copy connected-only and keep-top-bottom properties.
Fixes https://gitlab.com/kicad/code/kicad/issues/12691

(cherry picked from commit 585fac19c6)
2022-10-21 11:12:02 +01:00
Jeff Young da520f83ee Use comma to separate diff pair nets/netclassse rather than /.
("/" is problematic because it's more likely to appear in netnames.)

Fixes https://gitlab.com/kicad/code/kicad/issues/12592

(cherry picked from commit 6fd195c389)
2022-10-21 11:11:02 +01:00
Jeff Young 47547713de Broaden reset-sizes-after-layer-switch algorithm.
Fixes https://gitlab.com/kicad/code/kicad/issues/12576

(cherry picked from commit 40ad5b6de3)
2022-10-21 11:09:47 +01:00
jean-pierre charras 705570923e Fix some outdated things (mainly about fix_swig_imports.py, useless with swig version 4)
From Master, commit 397a9302.
Fixes #12414
2022-10-20 17:12:57 +02:00
jean-pierre charras 2827835720 board_stackup_manager: fix incorrect behavior when adding a new dielectric layer.
From Master branch
Fixes #12680
https://gitlab.com/kicad/code/kicad/issues/12680
2022-10-20 11:47:04 +02:00
Jeff Young bf95906f90 Re-entrancy guard for router tool.
Fixes https://gitlab.com/kicad/code/kicad/issues/12604

(cherry picked from commit 413fd82813)
2022-10-19 18:24:33 +01:00
Jeff Young e8d2c222b6 We need both a tool-oriented delete and one that doesn't push/pop, etc.
Fixes https://gitlab.com/kicad/code/kicad/issues/12600

(cherry picked from commit 46752499df)
2022-10-19 18:22:32 +01:00
Jeff Young f891c4641b We were saving the old board pointer, but not updating the current one.
This also makes a few other adjustments to order and to where we look
for the enabled layers which should make it more robust.

Fixes https://gitlab.com/kicad/code/kicad/issues/10925

(cherry picked from commit 631980b0ab)
2022-10-19 18:17:40 +01:00
Jeff Young a65fc7f82a Pin 0-sized pads at 1um rather than throwing them out.
(See bug report for more commentary.)

Fixes https://gitlab.com/kicad/code/kicad/issues/12617

(cherry picked from commit 46a41e2e34)
2022-10-19 18:15:49 +01:00
Jeff Young 5bcd0a5828 Update router sizes when switching layers.
We may have layer-specific rules involved.  Note that at some point
we also need to do something similar on every "fix route" step to
handle area-specific rules.

Fixes https://gitlab.com/kicad/code/kicad/issues/12576

(cherry picked from commit d8a3ba7917)
2022-10-19 14:47:08 +01:00
Jeff Young 74d8040e8c Force flashing when generating SOLIDs.
We only have a single SOLID per pad, so the solid's shape must always
be the flashed shape and then we can do layer-specific flashing tests
internally.

Fixes https://gitlab.com/kicad/code/kicad/issues/12458

(cherry picked from commit 08260661b8)
2022-10-19 14:43:13 +01:00
Jeff Young c5514d43c7 Don't reset editPad if it still exists after model reset.
Fixes https://gitlab.com/kicad/code/kicad/issues/12630

(cherry picked from commit 8b9cbd5805)
2022-10-19 14:42:16 +01:00
Jeff Young 0704e37eb5 Make sure a collector has a guide before handing it to a client filter.
Fixes https://gitlab.com/kicad/code/kicad/issues/12460

(cherry picked from commit 1566bd8b14)
2022-10-19 14:41:30 +01:00
Jeff Young c94de31a8c Try to reconcile SELECTION and BRIGHTENED use of overlay.
For some reason the overlay doesn't get redrawn during the PCBNew
selection disambiguation menu, so we need to not hide BRIGHTENED
items.

Fixes https://gitlab.com/kicad/code/kicad/issues/12547

(cherry picked from commit 436d75e7f9)
2022-10-19 14:40:07 +01:00
Jeff Young 2793e67bab Bring adding-to-group and hiding in sync.
(cherry picked from commit 6a6ef9b1f4)
2022-10-19 14:39:45 +01:00
Jeff Young 3213ea582d Avoid trying to draw empty pads.
Fixes https://gitlab.com/kicad/code/kicad/issues/12605

(cherry picked from commit e866dfe137)
2022-10-19 14:38:40 +01:00
Jeff Young 6003097411 Areas might have layers defined in area as well as rule.
Fixes https://gitlab.com/kicad/code/kicad/issues/12584

(cherry picked from commit 51c20da93e)
2022-10-19 14:34:22 +01:00
Jeff Young 6390633a7b Use GetCurrentNets(), not m_startItem for message panel updates.
Fixes https://gitlab.com/kicad/code/kicad/issues/12592

(cherry picked from commit cbb997a3b5)
2022-10-19 14:28:06 +01:00
Jeff Young dde5f2bed1 Respect DRCEpsilon in diff-pair coupling test.
Fixes https://gitlab.com/kicad/code/kicad/issues/12587

(cherry picked from commit 9119b5072a)
2022-10-19 14:26:19 +01:00
Jeff Young 7c4b8d50dd Fix qa test. 2022-10-19 14:26:19 +01:00
Jeff Young 56f58cf53f Manual cherry-pick of 6ed3618ce5. 2022-10-19 13:49:53 +01:00
Jeff Young 914e396e2e Implement annular ring checking for pads.
Fixes https://gitlab.com/kicad/code/kicad/issues/12109

(cherry picked from commit 9a4136de00)
2022-10-19 13:49:40 +01:00
Jeff Young f6bdd40c30 Manual cherry-pick of ba630971af. 2022-10-19 13:31:16 +01:00
Jeff Young 1bf1620157 Improve default new-library destination logic to be more project aware.
Fixes https://gitlab.com/kicad/code/kicad/issues/12570

(cherry picked from commit 2be9586c38)
2022-10-19 12:59:24 +01:00
Jeff Young da85a5f6bf Work around more instances of the wxWidgets color string locale bug.
Fixes https://gitlab.com/kicad/code/kicad/issues/12552

(cherry picked from commit c0a666507c)
2022-10-19 12:56:17 +01:00
Jeff Young e2219a0c4d Attempt to work-around wxWidgets bug with Serbian & Russian locales.
Fixes https://gitlab.com/kicad/code/kicad/issues/12002

Fixes https://gitlab.com/kicad/code/kicad/issues/11963

(cherry picked from commit 7386e64923)
2022-10-19 12:52:03 +01:00
Mark Roszko de46097ce0 Woops, wrong hash 2022-10-18 04:41:29 +00:00
Mark Roszko ae53986487 Update vcpkg wxpython again 2022-10-18 04:37:50 +00:00
Mark Roszko 3cf3a3ebe0 Bump vcpkg for patched wxpython 2022-10-17 23:50:14 +00:00
Seth Hillbrand a62e6b1f7f Update Translations 2022-10-17 10:28:21 -07:00
Seth Hillbrand d99ce976b9 Don't translate new strings in 6
Debian bookworm updated the ITS files to translate keywords as well.
This puts new strings into the 6 translation archive.  We explicitly set
keywords to non-translate in KiCad version 6
2022-10-17 10:26:49 -07:00
Ulices 161d15dcea Translated using Weblate (Spanish (Mexico))
Currently translated at 100.0% (7156 of 7156 strings)

Translation: KiCad EDA/v6
Translate-URL: https://hosted.weblate.org/projects/kicad/v6/es_MX/
2022-10-17 19:04:59 +02:00
taotieren 81319a5fcf Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (7156 of 7156 strings)

Translation: KiCad EDA/v6
Translate-URL: https://hosted.weblate.org/projects/kicad/v6/zh_Hans/
2022-10-17 19:04:59 +02:00
Huanyin Liu 628b4ca8b8 Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (7156 of 7156 strings)

Translation: KiCad EDA/v6
Translate-URL: https://hosted.weblate.org/projects/kicad/v6/zh_Hans/
2022-10-17 19:04:59 +02:00
Henrik Kauhanen d8ed1fea61 Translated using Weblate (Swedish)
Currently translated at 99.9% (7149 of 7156 strings)

Translation: KiCad EDA/v6
Translate-URL: https://hosted.weblate.org/projects/kicad/v6/sv/
2022-10-17 19:04:59 +02:00
___davidpr 6f474a389f Translated using Weblate (Serbian)
Currently translated at 14.0% (1008 of 7156 strings)

Translation: KiCad EDA/v6
Translate-URL: https://hosted.weblate.org/projects/kicad/v6/sr/
2022-10-17 19:04:59 +02:00
Mads Dyrmann 5a1a147585 Translated using Weblate (Danish)
Currently translated at 75.1% (5375 of 7156 strings)

Translation: KiCad EDA/v6
Translate-URL: https://hosted.weblate.org/projects/kicad/v6/da/
2022-10-17 19:04:59 +02:00
Jan Straka de9ef4ce70 Translated using Weblate (Czech)
Currently translated at 92.9% (6648 of 7156 strings)

Translation: KiCad EDA/v6
Translate-URL: https://hosted.weblate.org/projects/kicad/v6/cs/
2022-10-17 19:04:59 +02:00
Jan Straka 835f358816 Translated using Weblate (Czech)
Currently translated at 92.8% (6643 of 7156 strings)

Translation: KiCad EDA/v6
Translate-URL: https://hosted.weblate.org/projects/kicad/v6/cs/
2022-10-17 19:04:59 +02:00
Seth Hillbrand 61cfe53be1 Correctly sort positions for default align
When not aligning under mouse cursor, choose the X-most element where X
is top/bottom/left/right.  Previous sorting was not correct for two
directions

Fixes https://gitlab.com/kicad/code/kicad/issues/12627

(cherry picked from commit 697056fa7e)
2022-10-14 16:15:51 -07:00
Seth Hillbrand 535982f245 Avoid scaling unity models
There is no benefit to applying the identity transformation to models
when exporting the board to STEP

Fixes https://gitlab.com/kicad/code/kicad/issues/12036

(cherry picked from commit 98431eed79)

Fixes https://gitlab.com/kicad/code/kicad/issues/10232
2022-10-14 13:08:13 -07:00
jean-pierre charras 8ee73903c6 GERBVIEW_SELECTION_TOOL, disambiguationMenu: do not hide an item before highlight it.
This is not useful, and creates an issue when closing the menu by ESC key.
Fixes #12636
https://gitlab.com/kicad/code/kicad/issues/12636
2022-10-14 09:34:02 +02:00
Seth Hillbrand 292492bd01 Prevent crashes when canceling duplication
Duplicating multiple footprints, moving and then pressing Esc could
crash when we attempt to re-select the original items.  This allows
bypassing the issue when running from the duplication tool
2022-10-13 16:32:56 -07:00
Jeff Young f1029b7280 We don't always have a line when dragging.
Fixes https://gitlab.com/kicad/code/kicad/issues/12612

(cherry picked from commit b2f05c758b)
2022-10-13 09:15:24 -07:00
jean-pierre charras 578c0ef0f0 3D viewer: add missing initialization of FL_SOLDERPASTE in BOARD_ADAPTER.
Fixes #12631
https://gitlab.com/kicad/code/kicad/issues/12631
2022-10-13 10:08:24 +02:00
Alex 238c8df8b5 Fix crash on Specctra import.
Fixes https://gitlab.com/kicad/code/kicad/issues/12583


(cherry picked from commit 2741d0eb4b)
2022-10-10 18:37:59 +00:00
jean-pierre charras 95acc1bf33 Eeschema printing: fix some issues.
The offset setting was incorrect when using wxAffineMatrix2D.
It was visible when printing more than one sheet.
Note also when not using wxAffineMatrix2D, all pages must have the same orientation
(PORTRAIT/LANDSCAPE is not managed)
From master branch, commit 79c30180
2022-10-09 19:57:32 +02:00
jean-pierre charras 8dbfe79536 Symbol Editor: Fix reverting changes on a root symbol: derived symbols are displayed wrong
Reverting changes broke links between derived symbols and the root symbol.
Now fixed by do not delete and recreate reverted symbol.
From master, commit f5fd12c0
Fixes #10792
2022-10-08 16:15:16 +02:00
Seth Hillbrand 8f9830eb92 Update Translations 2022-10-07 11:37:40 -07:00
Seth Hillbrand bf0b80d676 Remove errant new string 2022-10-07 11:37:28 -07:00
Henrik Kauhanen bc8e3c22d8 Translated using Weblate (Swedish)
Currently translated at 99.8% (7149 of 7157 strings)

Translation: KiCad EDA/v6
Translate-URL: https://hosted.weblate.org/projects/kicad/v6/sv/
2022-10-06 11:15:53 +02:00
Jan Straka 28ddfbadbf Translated using Weblate (Czech)
Currently translated at 92.7% (6641 of 7157 strings)

Translation: KiCad EDA/v6
Translate-URL: https://hosted.weblate.org/projects/kicad/v6/cs/
2022-10-05 00:26:50 +02:00
Seth Hillbrand e834374ad2 Drill size is absolute
Use hole plating size for visibility only, not zone filling, routing or
DRC

(cherry picked from commit b4f3390626)
2022-10-04 10:00:36 -07:00
Seth Hillbrand 981aafd5d9 Allow non-named tool in Remove()
The tool command string was optional and not set when calling Remove()
through the Cut action.  Referencing the value causes unhandled
assertions.  We don't actually need the value because we don't pop
anything without a match.  The empty string will not match

Fixes https://gitlab.com/kicad/code/kicad/issues/12562
2022-10-02 13:43:33 -07:00
jean-pierre charras 09960caa66 Apply commit e73dd40f from master to this branch.
(APPEARANCE_CONTROLS: fix incorrect behavior of Preset layers widget in non English languages)
fixes #12227
2022-10-02 17:57:02 +02:00
Jeff Young cf6fd64758 Remove wxFloatingPointValidator which causes issues in some locales.
Fixes https://gitlab.com/kicad/code/kicad/issues/12176
2022-10-02 13:00:20 +01:00
Seth Hillbrand b08dccb7b3 Update Translations 2022-09-29 19:10:56 -07:00
boonchai k d6e5c74573 Translated using Weblate (Thai)
Currently translated at 99.5% (7128 of 7157 strings)

Translation: KiCad EDA/v6
Translate-URL: https://hosted.weblate.org/projects/kicad/v6/th/
2022-09-29 19:10:18 -07:00
obit ea93502ab3 Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (7157 of 7157 strings)

Translation: KiCad EDA/v6
Translate-URL: https://hosted.weblate.org/projects/kicad/v6/zh_Hans/
2022-09-29 19:10:18 -07:00
Henrik Kauhanen e1f402aa3d Translated using Weblate (Swedish)
Currently translated at 99.8% (7149 of 7157 strings)

Translation: KiCad EDA/v6
Translate-URL: https://hosted.weblate.org/projects/kicad/v6/sv/
2022-09-29 19:10:18 -07:00
obit 08f1b666d1 Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (7157 of 7157 strings)

Translation: KiCad EDA/v6
Translate-URL: https://hosted.weblate.org/projects/kicad/v6/zh_Hans/
2022-09-29 19:10:18 -07:00
boonchai k 8d62725598 Translated using Weblate (Thai)
Currently translated at 99.5% (7127 of 7157 strings)

Translation: KiCad EDA/v6
Translate-URL: https://hosted.weblate.org/projects/kicad/v6/th/
2022-09-29 19:10:18 -07:00
ZbeeGin cbd8b3c59e Translated using Weblate (Polish)
Currently translated at 100.0% (7157 of 7157 strings)

Translation: KiCad EDA/v6
Translate-URL: https://hosted.weblate.org/projects/kicad/v6/pl/
2022-09-29 19:10:17 -07:00
Jan Straka e9cc66cc8d Translated using Weblate (Czech)
Currently translated at 92.7% (6638 of 7157 strings)

Translation: KiCad EDA/v6
Translate-URL: https://hosted.weblate.org/projects/kicad/v6/cs/
2022-09-29 19:10:17 -07:00
Henrik Kauhanen 258b702dad Translated using Weblate (Swedish)
Currently translated at 99.8% (7149 of 7157 strings)

Translation: KiCad EDA/v6
Translate-URL: https://hosted.weblate.org/projects/kicad/v6/sv/
2022-09-29 19:10:17 -07:00
ZbeeGin 6c3e891123 Translated using Weblate (Polish)
Currently translated at 100.0% (7157 of 7157 strings)

Translation: KiCad EDA/v6
Translate-URL: https://hosted.weblate.org/projects/kicad/v6/pl/
2022-09-29 19:10:17 -07:00
taotieren 80937ae2c0 Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (7157 of 7157 strings)

Translation: KiCad EDA/v6
Translate-URL: https://hosted.weblate.org/projects/kicad/v6/zh_Hans/
2022-09-29 19:10:17 -07:00
Henrik Kauhanen 2d37b86530 Translated using Weblate (Swedish)
Currently translated at 99.8% (7148 of 7157 strings)

Translation: KiCad EDA/v6
Translate-URL: https://hosted.weblate.org/projects/kicad/v6/sv/
2022-09-29 19:10:17 -07:00
Henrik Kauhanen 8bdcd299d7 Translated using Weblate (Finnish)
Currently translated at 99.9% (7154 of 7157 strings)

Translation: KiCad EDA/v6
Translate-URL: https://hosted.weblate.org/projects/kicad/v6/fi/
2022-09-29 19:10:17 -07:00
Jeff Young 22e9985f5d Use more basic strings which have already been translated. 2022-09-29 23:58:35 +01:00
Mark Roszko 594beef22e Bump vcpkg wxwidgets to 3.2.1 2022-09-29 13:38:53 +00:00
Marek Roszko 03ed7a4a27 Ensure the socket server is killed during destruction of the kiway player
(cherry picked from commit 8ae48bb093)
2022-09-29 02:22:54 +00:00
Jeff Young 8cbfd8af9f Files missing from earlier commit. 2022-09-28 15:10:28 +01:00
Jeff Young c16e86be9a Use router's connectivity algorithm, not CONNECTIVITY_DATA's.
Fixes https://gitlab.com/kicad/code/kicad/issues/10745

(cherry picked from commit 107f409106)
2022-09-28 15:01:29 +01:00
Jeff Young b0e2aeb972 Apply the same accuracy band to connectivity as we use for hittesting.
Fixes https://gitlab.com/kicad/code/kicad/issues/10745

(cherry picked from commit 9cf3c529d3)
2022-09-28 14:58:43 +01:00
Jeff Young fc06192643 More improvements to drag tool selection disambiguation.
Fixes https://gitlab.com/kicad/code/kicad/issues/10745

(cherry picked from commit 2743fd583f)
2022-09-28 14:57:22 +01:00
Jeff Young 2faaa0a042 Improve drop-a-knee-selection-to-a-single-segment algorithm.
In particular, don't rely on there being only two items in the
collector at the start.

Fixes https://gitlab.com/kicad/code/kicad/issues/10745

(cherry picked from commit a619ef9d53)
2022-09-28 14:56:11 +01:00
Jeff Young 2d4bcc6557 Move cvpcb filter to a timer.
Fixes https://gitlab.com/kicad/code/kicad/issues/12445

(cherry picked from commit 1fcd7d6285)
2022-09-28 14:53:10 +01:00
Jeff Young ba72676edb Fix uninitialized variable.
(cherry picked from commit 1e1aedbe30)
2022-09-28 14:51:57 +01:00
Jeff Young 1a2e2bd29a Try and reduce opportunity for lost keystrokes.
Fixes https://gitlab.com/kicad/code/kicad/issues/12445

(cherry picked from commit d2712bac37)
2022-09-28 14:50:49 +01:00
Jeff Young 8b690c9a3c Restore fix for #10029.
Fixes https://gitlab.com/kicad/code/kicad/issues/12445

(cherry picked from commit 1be8adebf5)
2022-09-28 14:50:31 +01:00
Jeff Young 6d25e57cd7 Allow free pad usage in router.
Fixes https://gitlab.com/kicad/code/kicad/issues/11730

(cherry picked from commit 7c83c78afe)
2022-09-28 14:49:44 +01:00
Jeff Young 7dfa715a45 Bug fixes for layer expression processing.
1) Push a VAR onto the stack, not a resolved value
2) Don't collapse a PCB_LAYER_VALUE to a VALUE during processing
3) Make sure we run overloaded operators from the correct side

Fixes https://gitlab.com/kicad/code/kicad/issues/12437

(cherry picked from commit cf1565a16a)
2022-09-28 14:00:25 +01:00
Jeff Young e8a10939b5 Fix old copy/paste error (from 2017, believe it or not).
Fixes https://gitlab.com/kicad/code/kicad/issues/11487

(cherry picked from commit d9f75556bd)
2022-09-28 13:55:44 +01:00
Jeff Young 44ec38ad2d Fix logic around Select All inside an entered group.
Fixes https://gitlab.com/kicad/code/kicad/issues/12411

(cherry picked from commit 2d3b8d6393)
2022-09-28 13:31:16 +01:00
Jeff Young 9cb6df9c38 Don't crash on empty SHAPE_LINE_CHAINs.
Fixes https://gitlab.com/kicad/code/kicad/issues/12407

(cherry picked from commit fc74de81fb)
2022-09-28 13:30:04 +01:00
Jeff Young 4a5fdd4214 Display crosshairs in picker tools.
Fixes https://gitlab.com/kicad/code/kicad/issues/10183

(cherry picked from commit 0a5ca5b485)
2022-09-28 13:29:32 +01:00
Jeff Young fe7ed364b6 Allow vias to connect <no net> tracks even when DRC checking is on.
Fixes https://gitlab.com/kicad/code/kicad/issues/12403

(cherry picked from commit eaccd40c75)
2022-09-28 13:26:12 +01:00
Jeff Young 43f9863182 Copy field properly.
Offset for new parent, and set parent property.

Fixes https://gitlab.com/kicad/code/kicad/issues/12376

(cherry picked from commit 45fb0107a0)
2022-09-28 12:50:02 +01:00
Jeff Young 4987809fe3 Make Scintilla paste a separate undo operation.
Fixes https://gitlab.com/kicad/code/kicad/issues/11756

(cherry picked from commit c3a5947fe6)
2022-09-28 12:49:12 +01:00
Jeff Young 894f424d14 Don't give Scintilla a colour with alpha; it doesn't know what to do.
Fixes https://gitlab.com/kicad/code/kicad/issues/10829

(cherry picked from commit 1b104f20b6)
2022-09-28 12:48:24 +01:00
Jeff Young e21995c401 Prune pasted data of non-enabled layers.
Fixes https://gitlab.com/kicad/code/kicad/issues/11997

(cherry picked from commit 5b3bd9be83)
2022-09-28 12:47:14 +01:00
Jeff Young bb7362ceba Don't allow a SaveAs to overwrite the root sheet.
Also prevents EESchema from loading sheets which recurse.

Fixes https://gitlab.com/kicad/code/kicad/issues/10872

(cherry picked from commit d030f03844)
2022-09-28 12:45:20 +01:00
Wayne Stambaugh 334268f5e7 Begin version 6.0.9 development. 2022-09-26 21:11:47 -04:00
148 changed files with 9836 additions and 8559 deletions
+1 -1
View File
@@ -40,6 +40,6 @@ include:
- local: '/.gitlab/templates.yml'
- local: '/.gitlab/Fedora-Linux-CI.yml'
- local: '/.gitlab/Ubuntu-20.04-CI.yml'
# - local: '/.gitlab/Windows-CI.yml'
- local: '/.gitlab/Windows-CI.yml'
- local: '/.gitlab/coverity.yml'
- local: '/.gitlab/linux-metadata-validate.yml'
+13 -2
View File
@@ -7,16 +7,27 @@ win64_build:
- kicad-windows-1809
extends: .only_code
interruptible: false
image: registry.gitlab.com/kicad/kicad-ci/source_containers/win64:msvc1809
image: registry.gitlab.com/kicad/kicad-ci/windows-build-image/win1809-msvc:latest
variables:
VCPKG_BINARY_SOURCES: 'nuget,kicad,readwrite'
cache:
key: win64-vcpkg-"$CI_COMMIT_REF_SLUG"
paths:
- build\windows\vcpkg_installed
- .vcpkgCache
only:
- branches@kicad/code/kicad
- tags@kicad/code/kicad
script:
- C:\builder\build.ps1 -Env -Arch x64
- $vcpkgCache=Join-Path -Path (Get-Location) -ChildPath ".vcpkgCache";$env:VCPKG_DEFAULT_BINARY_CACHE=$vcpkgCache;New-Item -ItemType Directory -Force -Path $vcpkgCache
- nuget.exe sources add -Name kicad -Source "https://nuget.kicad.org:443/v3/index.json"
- nuget.exe setapikey $env:KICAD_NUGET_KEY -Source "https://nuget.kicad.org:443/v3/index.json"
- mkdir -p build/windows -Force
- cd build/windows
- cmake `
-G "Ninja" `
-DCMAKE_TOOLCHAIN_FILE=C:\build\vcpkg\scripts\buildsystems\vcpkg.cmake `
-DCMAKE_TOOLCHAIN_FILE=C:\builder\vcpkg\scripts\buildsystems\vcpkg.cmake `
-DCMAKE_BUILD_TYPE=Debug `
-DKICAD_SCRIPTING_WXPYTHON=OFF `
-DKICAD_USE_OCC=ON `
+1
View File
@@ -119,6 +119,7 @@ BOARD_ADAPTER::BOARD_ADAPTER() :
SetFlag( FL_ZONE, true );
SetFlag( FL_SILKSCREEN, true );
SetFlag( FL_SOLDERMASK, true );
SetFlag( FL_SOLDERPASTE, true );
SetFlag( FL_SUBTRACT_MASK_FROM_SILK, false );
SetFlag( FL_RENDER_OPENGL_COPPER_THICKNESS, true );
+40 -26
View File
@@ -2,7 +2,7 @@
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015-2016 Mario Luzeiro <mrluzeiro@ua.pt>
* Copyright (C) 1992-2021 KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 1992-2022 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
@@ -89,30 +89,32 @@ END_EVENT_TABLE()
EDA_3D_CANVAS::EDA_3D_CANVAS( wxWindow* aParent, const int* aAttribList,
BOARD_ADAPTER& aBoardAdapter, CAMERA& aCamera,
S3D_CACHE* a3DCachePointer )
: HIDPI_GL_CANVAS( aParent, wxID_ANY, aAttribList, wxDefaultPosition, wxDefaultSize,
S3D_CACHE* a3DCachePointer ) :
HIDPI_GL_CANVAS( aParent, wxID_ANY, aAttribList, wxDefaultPosition, wxDefaultSize,
wxFULL_REPAINT_ON_RESIZE ),
m_eventDispatcher( nullptr ),
m_parentStatusBar( nullptr ),
m_parentInfoBar( nullptr ),
m_glRC( nullptr ),
m_is_opengl_initialized( false ),
m_is_opengl_version_supported( true ),
m_mouse_is_moving( false ),
m_mouse_was_moved( false ),
m_camera_is_moving( false ),
m_render_pivot( false ),
m_camera_moving_speed( 1.0f ),
m_strtime_camera_movement( 0 ),
m_animation_enabled( true ),
m_moving_speed_multiplier( 3 ),
m_boardAdapter( aBoardAdapter ),
m_camera( aCamera ),
m_3d_render( nullptr ),
m_opengl_supports_raytracing( true ),
m_render_raytracing_was_requested( false ),
m_accelerator3DShapes( nullptr ),
m_currentRollOverItem( nullptr )
m_eventDispatcher( nullptr ),
m_parentStatusBar( nullptr ),
m_parentInfoBar( nullptr ),
m_glRC( nullptr ),
m_is_opengl_initialized( false ),
m_is_opengl_version_supported( true ),
m_editing_timeout_timer( this, wxID_HIGHEST + 1 ),
m_redraw_trigger_timer( this, wxID_HIGHEST + 2 ),
m_mouse_is_moving( false ),
m_mouse_was_moved( false ),
m_camera_is_moving( false ),
m_render_pivot( false ),
m_camera_moving_speed( 1.0f ),
m_strtime_camera_movement( 0 ),
m_animation_enabled( true ),
m_moving_speed_multiplier( 3 ),
m_boardAdapter( aBoardAdapter ),
m_camera( aCamera ),
m_3d_render( nullptr ),
m_opengl_supports_raytracing( true ),
m_render_raytracing_was_requested( false ),
m_accelerator3DShapes( nullptr ),
m_currentRollOverItem( nullptr )
{
wxLogTrace( m_logTrace, wxT( "EDA_3D_CANVAS::EDA_3D_CANVAS" ) );
@@ -845,8 +847,14 @@ void EDA_3D_CANVAS::OnMiddleUp( wxMouseEvent& event )
}
void EDA_3D_CANVAS::OnTimerTimeout_Editing( wxTimerEvent& /* event */ )
void EDA_3D_CANVAS::OnTimerTimeout_Editing( wxTimerEvent& aEvent )
{
if( aEvent.GetId() != m_editing_timeout_timer.GetId() )
{
aEvent.Skip();
return;
}
m_mouse_is_moving = false;
m_mouse_was_moved = false;
@@ -867,8 +875,14 @@ void EDA_3D_CANVAS::restart_editingTimeOut_Timer()
}
void EDA_3D_CANVAS::OnTimerTimeout_Redraw( wxTimerEvent& event )
void EDA_3D_CANVAS::OnTimerTimeout_Redraw( wxTimerEvent& aEvent )
{
if( aEvent.GetId() != m_redraw_trigger_timer.GetId() )
{
aEvent.Skip();
return;
}
Request_refresh( true );
}
+1 -1
View File
@@ -37,7 +37,7 @@
# KiCad.
#
# Note: This version string should follow the semantic versioning system
set( KICAD_SEMANTIC_VERSION "6.0.8" )
set( KICAD_SEMANTIC_VERSION "6.0.9" )
# Default the version to the semantic version.
# This is overridden by the git repository tag though (if using git)
+4 -2
View File
@@ -40,10 +40,11 @@ static int DEFAULT_COL_WIDTHS[] = { 200, 600 };
EDA_LIST_DIALOG::EDA_LIST_DIALOG( wxWindow* aParent, const wxString& aTitle,
const wxArrayString& aItemHeaders,
const std::vector<wxArrayString>& aItemList,
const wxString& aPreselectText ) :
const wxString& aPreselectText, bool aSortList ) :
EDA_LIST_DIALOG_BASE( aParent, wxID_ANY, aTitle )
{
m_itemsList = &aItemList;
m_sortList = aSortList;
m_filterBox->SetHint( _( "Filter" ) );
@@ -234,5 +235,6 @@ static int wxCALLBACK myCompareFunction( wxIntPtr aItem1, wxIntPtr aItem2,
void EDA_LIST_DIALOG::sortList()
{
m_listBox->SortItems( myCompareFunction, 0 );
if( m_sortList )
m_listBox->SortItems( myCompareFunction, 0 );
}
+1 -1
View File
@@ -250,7 +250,7 @@ static void netclassToGridRow( EDA_UNITS aUnits, wxGrid* aGrid, int aRow, const
SET_MILS_CELL( GRID_WIREWIDTH, nc->GetWireWidth() );
SET_MILS_CELL( GRID_BUSWIDTH, nc->GetBusWidth() );
wxString colorAsString = nc->GetSchematicColor().ToWxString( wxC2S_CSS_SYNTAX );
wxString colorAsString = nc->GetSchematicColor().ToCSSString();
aGrid->SetCellValue( aRow, GRID_SCHEMATIC_COLOR, colorAsString );
int lineStyleIdx = std::max( 0, nc->GetLineStyle() );
+17 -17
View File
@@ -969,22 +969,27 @@ bool EDA_DRAW_FRAME::LibraryFileBrowser( bool doOpen, wxFileName& aFilename,
wxString prompt = doOpen ? _( "Select Library" ) : _( "New Library" );
aFilename.SetExt( ext );
wxString dir;
wxString projectDir = Prj().IsNullProject() ? aFilename.GetPath() : Prj().GetProjectPath();
wxString defaultDir;
if( GetMruPath().IsEmpty() )
dir = aGlobalPath;
if( aIsGlobal )
{
if( !GetMruPath().IsEmpty() && !GetMruPath().StartsWith( projectDir ) )
defaultDir = GetMruPath();
else
defaultDir = aGlobalPath;
}
else
dir = GetMruPath();
{
if( !GetMruPath().IsEmpty() && GetMruPath().StartsWith( projectDir ) )
defaultDir = GetMruPath();
else
defaultDir = projectDir;
}
if( isDirectory && doOpen )
{
if( !aIsGlobal && GetMruPath().IsEmpty() )
{
dir = Prj().GetProjectPath();
}
wxDirDialog dlg( this, prompt, dir, wxDD_DEFAULT_STYLE | wxDD_DIR_MUST_EXIST );
wxDirDialog dlg( this, prompt, defaultDir, wxDD_DEFAULT_STYLE | wxDD_DIR_MUST_EXIST );
if( dlg.ShowModal() == wxID_CANCEL )
return false;
@@ -998,12 +1003,7 @@ bool EDA_DRAW_FRAME::LibraryFileBrowser( bool doOpen, wxFileName& aFilename,
if( aFilename.GetName().empty() )
aFilename.SetName( wxT( "Library" ) );
if( !aIsGlobal && GetMruPath().IsEmpty() )
{
dir = Prj().IsNullProject() ? aFilename.GetFullPath() : Prj().GetProjectPath();
}
wxFileDialog dlg( this, prompt, dir, aFilename.GetFullName(),
wxFileDialog dlg( this, prompt, defaultDir, aFilename.GetFullName(),
wildcard, doOpen ? wxFD_OPEN | wxFD_FILE_MUST_EXIST
: wxFD_SAVE | wxFD_CHANGE_DIR | wxFD_OVERWRITE_PROMPT );
+27 -4
View File
@@ -144,10 +144,33 @@ bool COLOR4D::SetFromWxString( const wxString& aColorString )
}
wxString COLOR4D::ToWxString( long flags ) const
wxString COLOR4D::ToCSSString() const
{
wxColour c = ToColour();
return c.GetAsString( flags );
wxString str;
const int red = c.Red();
const int green = c.Green();
const int blue = c.Blue();
const int alpha = c.Alpha();
if ( alpha == wxALPHA_OPAQUE )
{
str.Printf( wxT( "rgb(%d, %d, %d)" ), red, green, blue );
}
else // use rgba() form
{
wxString alpha_str = wxString::FromCDouble( alpha / 255.0, 3 );
// The wxC2S_CSS_SYNTAX is particularly sensitive to ','s (as it uses them for value
// delimiters), and wxWidgets is known to be buggy in this respect when dealing with
// Serbian and Russian locales (at least), so we enforce an extra level of safety.
alpha_str.Replace( wxT( "," ), wxT( "." ) );
str.Printf( wxT( "rgba(%d, %d, %d, %s)" ), red, green, blue, alpha_str );
}
return str;
}
@@ -271,13 +294,13 @@ const bool operator<( const COLOR4D& lhs, const COLOR4D& rhs )
std::ostream &operator<<( std::ostream &aStream, COLOR4D const &aColor )
{
return aStream << aColor.ToWxString( wxC2S_CSS_SYNTAX );
return aStream << aColor.ToCSSString();
}
void to_json( nlohmann::json& aJson, const COLOR4D& aColor )
{
aJson = nlohmann::json( aColor.ToWxString( wxC2S_CSS_SYNTAX ).ToStdString() );
aJson = nlohmann::json( aColor.ToCSSString().ToStdString() );
}
+14 -1
View File
@@ -31,6 +31,7 @@
#include <typeinfo>
#include <wx/utils.h>
#include <wx/evtloop.h>
#include <wx/socket.h>
BEGIN_EVENT_TABLE( KIWAY_PLAYER, EDA_BASE_FRAME )
@@ -65,7 +66,19 @@ KIWAY_PLAYER::KIWAY_PLAYER( wxWindow* aParent, wxWindowID aId, const wxString& a
}
KIWAY_PLAYER::~KIWAY_PLAYER() throw() {}
KIWAY_PLAYER::~KIWAY_PLAYER() throw() {
// socket server must be destructed before we complete
// destructing the frame or else we could crash
// as the socket server holds a reference to this frame
if( m_socketServer )
{
// ensure any event handling stops
m_socketServer->Notify( false );
delete m_socketServer;
}
}
void KIWAY_PLAYER::KiwayMailIn( KIWAY_EXPRESS& aEvent )
+6 -6
View File
@@ -77,7 +77,7 @@ NUMERIC_EVALUATOR::~NUMERIC_EVALUATOR()
void NUMERIC_EVALUATOR::Clear()
{
free( m_token.token );
delete[] m_token.token;
m_token.token = nullptr;
m_token.input = nullptr;
m_parseError = true;
@@ -103,7 +103,7 @@ void NUMERIC_EVALUATOR::parseSetResult( double val )
{
// Naively printing this with %g produces "nan" on some platforms
// and "-nan(ind)" on others (e.g. MSVC). So force a "standard" string.
snprintf( m_token.token, m_token.OutLen, "%s", "NaN" );
snprintf( m_token.token, m_token.outputLen, "%s", "NaN" );
}
else
{
@@ -111,7 +111,7 @@ void NUMERIC_EVALUATOR::parseSetResult( double val )
// Warning: DO NOT use a format like %f or %g, because they can create issues.
// especially %g can generate an exponent, incompatible with UNIT_BINDER
// Use the optimized Double2Str
snprintf( m_token.token, m_token.OutLen, "%s", Double2Str( val ).c_str() );
snprintf( m_token.token, m_token.outputLen, "%s", Double2Str( val ).c_str() );
}
}
@@ -159,12 +159,12 @@ void NUMERIC_EVALUATOR::newString( const wxString& aString )
Clear();
m_originalText = aString;
m_token.token = reinterpret_cast<decltype( m_token.token )>( malloc( TokenStat::OutLen + 1 ) );
strcpy( m_token.token, "0" );
m_token.inputLen = aString.length();
m_token.outputLen = std::max<std::size_t>( 64, m_token.inputLen + 1 );
m_token.pos = 0;
m_token.input = aString.mb_str();
m_token.token = new char[m_token.outputLen]();
m_token.token[0] = '0';
m_parseFinished = false;
}
+17 -5
View File
@@ -1038,7 +1038,7 @@ bool COMPILER::generateUCode( UCODE* aCode, CONTEXT* aPreflightContext )
reportError( CST_CODEGEN, msg, node->srcPos - (int) node->value.str->length() );
}
node->SetUop( TR_UOP_PUSH_VALUE, std::move( vref ) );
node->SetUop( TR_UOP_PUSH_VAR, std::move( vref ) );
node->isTerminal = true;
break;
}
@@ -1090,10 +1090,12 @@ void UOP::Exec( CONTEXT* ctx )
{
case TR_UOP_PUSH_VAR:
{
VALUE* value = ctx->AllocValue();
VALUE* value = nullptr;
if( m_ref )
value->Set( m_ref->GetValue( ctx ) );
value = ctx->StoreValue( m_ref->GetValue( ctx ) );
else
value = ctx->AllocValue();
ctx->Push( value );
}
@@ -1162,10 +1164,20 @@ void UOP::Exec( CONTEXT* ctx )
result = arg1Value > arg2Value ? 1 : 0;
break;
case TR_OP_EQUAL:
result = arg1 && arg2 && arg1->EqualTo( ctx, arg2 ) ? 1 : 0;
if( !arg1 || !arg2 )
result = arg1 == arg2 ? 1 : 0;
else if( arg2->GetType() == VT_UNDEFINED )
result = arg2->EqualTo( ctx, arg1 ) ? 1 : 0;
else
result = arg1->EqualTo( ctx, arg2 ) ? 1 : 0;
break;
case TR_OP_NOT_EQUAL:
result = arg1 && arg2 && arg1->NotEqualTo( ctx, arg2 ) ? 1 : 0;
if( !arg1 || !arg2 )
result = arg1 != arg2 ? 1 : 0;
else if( arg2->GetType() == VT_UNDEFINED )
result = arg2->NotEqualTo( ctx, arg1 ) ? 1 : 0;
else
result = arg1->NotEqualTo( ctx, arg2 ) ? 1 : 0;
break;
case TR_OP_BOOL_AND:
result = arg1Value != 0.0 && arg2Value != 0.0 ? 1 : 0;
+3 -2
View File
@@ -8635,7 +8635,7 @@ const char* const newstroke_font[] =
"F^K[KFYFY[K[",
"F^K[KFYFY[K[",
"F^K[KFYFY[K[",
/* // Letterlike Symbols (2100-214F) */
/* // Letterlike Symbols (2100-2125) */
"F^K[KFYFY[K[", /* U+2100 */
"F^K[KFYFY[K[",
"F^K[KFYFY[K[",
@@ -8674,7 +8674,8 @@ const char* const newstroke_font[] =
"F^K[KFYFY[K[",
"F^K[KFYFY[K[",
"F^K[KFYFY[K[",
"F^K[KFYFY[K[",
"F^J[O[OWMVKTJQJLKIMGPFTFWGYIZLZQYTWVUWU[Z[",
/* // Letterlike Symbols (2127-214F) */
"F^K[KFYFY[K[",
"F^K[KFYFY[K[",
"F^K[KFYFY[K[",
+21 -15
View File
@@ -79,18 +79,23 @@ void SCINTILLA_TRICKS::onThemeChanged( wxSysColourChangedEvent &aEvent )
void SCINTILLA_TRICKS::setupStyles()
{
wxTextCtrl dummy( m_te->GetParent(), wxID_ANY );
wxColour foreground = dummy.GetForegroundColour();
wxColour background = dummy.GetBackgroundColour();
wxColour highlight = wxSystemSettings::GetColour( wxSYS_COLOUR_HIGHLIGHT );
wxColour highlightText = wxSystemSettings::GetColour( wxSYS_COLOUR_HIGHLIGHTTEXT );
wxTextCtrl dummy( m_te->GetParent(), wxID_ANY );
wxColour foreground = dummy.GetForegroundColour();
wxColour background = dummy.GetBackgroundColour();
KIGFX::COLOR4D highlight = wxSystemSettings::GetColour( wxSYS_COLOUR_HIGHLIGHT );
KIGFX::COLOR4D highlightText = wxSystemSettings::GetColour( wxSYS_COLOUR_HIGHLIGHTTEXT );
m_te->StyleSetForeground( wxSTC_STYLE_DEFAULT, foreground );
m_te->StyleSetBackground( wxSTC_STYLE_DEFAULT, background );
m_te->StyleClearAll();
m_te->SetSelForeground( true, highlightText );
m_te->SetSelBackground( true, highlight );
// Scintilla doesn't handle alpha channel, which at least OSX uses in some highlight colours,
// such as "graphite".
highlight = highlight.Mix( background, highlight.a ).WithAlpha( 1.0 );
highlightText = highlightText.Mix( background, highlightText.a ).WithAlpha( 1.0 );
m_te->SetSelForeground( true, highlightText.ToColour() );
m_te->SetSelBackground( true, highlight.ToColour() );
m_te->SetCaretForeground( foreground );
if( !m_singleLine )
@@ -105,14 +110,13 @@ void SCINTILLA_TRICKS::setupStyles()
m_te->SetTabWidth( 4 );
}
// Set up the brace highlighting
unsigned char r = highlight.Red();
unsigned char g = highlight.Green();
unsigned char b = highlight.Blue();
wxColour::MakeGrey( &r, &g, &b );
highlight.Set( r, g, b );
m_te->StyleSetForeground( wxSTC_STYLE_BRACELIGHT, highlightText );
m_te->StyleSetBackground( wxSTC_STYLE_BRACELIGHT, highlight );
// Set up the brace highlighting. Scintilla doesn't handle alpha, so we construct our own
// 20% wash by blending with the background.
KIGFX::COLOR4D braceText = foreground;
KIGFX::COLOR4D braceHighlight = braceText.Mix( background, 0.2 );
m_te->StyleSetForeground( wxSTC_STYLE_BRACELIGHT, highlightText.ToColour() );
m_te->StyleSetBackground( wxSTC_STYLE_BRACELIGHT, braceHighlight.ToColour() );
m_te->StyleSetForeground( wxSTC_STYLE_BRACEBAD, *wxRED );
}
@@ -228,7 +232,9 @@ void SCINTILLA_TRICKS::onCharHook( wxKeyEvent& aEvent )
str = data.GetText();
ConvertSmartQuotesAndDashes( &str );
m_te->BeginUndoAction();
m_te->AddText( str );
m_te->EndUndoAction();
}
wxTheClipboard->Close();
+1 -1
View File
@@ -230,7 +230,7 @@ COLOR_SETTINGS::COLOR_SETTINGS( const wxString& aFilename, bool aAbsolutePath )
// Fix LAYER_VIA_HOLES color - before version 2, this setting had no effect
nlohmann::json::json_pointer ptr( "/board/via_hole");
( *m_internals )[ptr] = COLOR4D( 0.5, 0.4, 0, 0.8 ).ToWxString( wxC2S_CSS_SYNTAX );
( *m_internals )[ptr] = COLOR4D( 0.5, 0.4, 0, 0.8 ).ToCSSString();
return true;
} );
+1 -1
View File
@@ -146,7 +146,7 @@ void GRID_CELL_COLOR_SELECTOR::Create( wxWindow* aParent, wxWindowID aId,
wxString GRID_CELL_COLOR_SELECTOR::GetValue() const
{
return m_value.ToWxString( wxC2S_CSS_SYNTAX );
return m_value.ToCSSString();
}
+25
View File
@@ -210,12 +210,17 @@ CVPCB_MAINFRAME::CVPCB_MAINFRAME( KIWAY* aKiway, wxWindow* aParent ) :
// Start the main processing loop
m_toolManager->InvokeTool( "cvpcb.Control" );
m_filterTimer->StartOnce( 100 );
KIPLATFORM::APP::SetShutdownBlockReason( this, _( "Symbol to footprint changes are unsaved" ) );
}
CVPCB_MAINFRAME::~CVPCB_MAINFRAME()
{
// Stop the timer during destruction early to avoid potential race conditions (that do happen)
m_filterTimer->Stop();
// Shutdown all running tools
if( m_toolManager )
m_toolManager->ShutdownAllTools();
@@ -371,6 +376,9 @@ void CVPCB_MAINFRAME::setupEventHandlers()
// Attach the events to the tool dispatcher
Bind( wxEVT_CHAR, &TOOL_DISPATCHER::DispatchWxEvent, m_toolDispatcher );
Bind( wxEVT_CHAR_HOOK, &TOOL_DISPATCHER::DispatchWxEvent, m_toolDispatcher );
m_filterTimer = new wxTimer( this );
Bind( wxEVT_TIMER, &CVPCB_MAINFRAME::onTextFilterChangedTimer, this, m_filterTimer->GetId() );
}
@@ -421,6 +429,17 @@ void CVPCB_MAINFRAME::OnEnterFilteringText( wxCommandEvent& aEvent )
// If the option FOOTPRINTS_LISTBOX::FILTERING_BY_TEXT_PATTERN is set, update the list
// of available footprints which match the filter
m_filterTimer->StartOnce( 200 );
}
void CVPCB_MAINFRAME::onTextFilterChangedTimer( wxTimerEvent& aEvent )
{
// GTK loses the search-control's focus on a Refresh event, so we record the focus and
// insertion point here and then restore them at the end.
bool searchCtrlHasFocus = m_tcFilterString->HasFocus();
long pos = m_tcFilterString->GetInsertionPoint();
COMPONENT* symbol = GetSelectedComponent();
wxString libraryName = m_librariesListBox->GetSelectedLibrary();
@@ -435,6 +454,12 @@ void CVPCB_MAINFRAME::OnEnterFilteringText( wxCommandEvent& aEvent )
RefreshFootprintViewer();
DisplayStatus();
if( searchCtrlHasFocus )
{
m_tcFilterString->SetFocus();
m_tcFilterString->SetInsertionPoint( pos );
}
}
+3
View File
@@ -357,6 +357,8 @@ private:
void updateFootprintViewerOnIdle( wxIdleEvent& aEvent );
void onTextFilterChangedTimer( wxTimerEvent& aEvent );
/**
* Read the .equ files and populate the list of equivalents.
*
@@ -407,6 +409,7 @@ private:
CVPCB_UNDO_REDO_LIST m_undoList;
CVPCB_UNDO_REDO_LIST m_redoList;
wxTimer* m_filterTimer;
bool m_viewerPendingUpdate;
};
+124 -75
View File
@@ -2372,7 +2372,9 @@ bool CONNECTION_GRAPH::ercCheckMultipleDrivers( const CONNECTION_SUBGRAPH* aSubg
if( driver->Type() == SCH_GLOBAL_LABEL_T
|| driver->Type() == SCH_HIER_LABEL_T
|| driver->Type() == SCH_LABEL_T )
|| driver->Type() == SCH_LABEL_T
|| ( driver->Type() == SCH_PIN_T
&& static_cast<SCH_PIN*>( driver )->IsPowerConnection() ) )
{
wxString primaryName = aSubgraph->GetNameForDriver( aSubgraph->m_driver );
wxString secondaryName = aSubgraph->GetNameForDriver( driver );
@@ -2852,13 +2854,11 @@ bool CONNECTION_GRAPH::ercCheckFloatingWires( const CONNECTION_SUBGRAPH* aSubgra
bool CONNECTION_GRAPH::ercCheckLabels( const CONNECTION_SUBGRAPH* aSubgraph )
{
// Label connection rules:
// Any label without a no-connect needs to have at least 2 pins, otherwise it is invalid
// Local labels are flagged if they don't connect to any pins and don't have a no-connect
// Global labels are flagged if they appear only once, don't connect to any local labels,
// and don't have a no-connect marker
// So, if there is a no-connect, we will never generate a warning here
if( aSubgraph->m_no_connect )
return true;
if( !aSubgraph->m_driver_connection )
return true;
@@ -2870,28 +2870,46 @@ bool CONNECTION_GRAPH::ercCheckLabels( const CONNECTION_SUBGRAPH* aSubgraph )
ERC_SETTINGS& settings = m_schematic->ErcSettings();
bool ok = true;
SCH_TEXT* text = nullptr;
bool hasOtherConnections = false;
int pinCount = 0;
std::map<KICAD_T, std::vector<SCH_TEXT*>> label_map;
auto hasPins =
[]( const CONNECTION_SUBGRAPH* aLocSubgraph )
[]( const CONNECTION_SUBGRAPH* aLocSubgraph ) -> int
{
int retval = 0;
for( const SCH_ITEM* item : aLocSubgraph->m_items )
{
switch( item->Type() )
{
case SCH_PIN_T:
case SCH_SHEET_PIN_T:
return true;
++retval;
break;
default: break;
}
}
return false;
return retval;
};
auto reportError = [&]( SCH_TEXT* aText, int errCode )
{
if( settings.IsTestEnabled( errCode ) )
{
std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( errCode );
ercItem->SetItems( aText );
SCH_MARKER* marker = new SCH_MARKER( ercItem, aText->GetPosition() );
aSubgraph->m_sheet.LastScreen()->Append( marker );
}
};
pinCount = hasPins( aSubgraph );
for( SCH_ITEM* item : aSubgraph->m_items )
{
switch( item->Type() )
@@ -2900,105 +2918,136 @@ bool CONNECTION_GRAPH::ercCheckLabels( const CONNECTION_SUBGRAPH* aSubgraph )
case SCH_GLOBAL_LABEL_T:
case SCH_HIER_LABEL_T:
{
text = static_cast<SCH_TEXT*>( item );
SCH_TEXT* text = static_cast<SCH_TEXT*>( item );
label_map[item->Type()].push_back( text );
// Below, we'll create an ERC if the whole subgraph is unconnected. But, additionally,
// we want to error if an individual label in the subgraph is floating, even if it's
// connected to other valid things by way of another label on the same sheet.
if( text->IsDangling() && settings.IsTestEnabled( ERCE_LABEL_NOT_CONNECTED ) )
if( text->IsDangling() )
{
std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( ERCE_LABEL_NOT_CONNECTED );
ercItem->SetItems( text );
SCH_MARKER* marker = new SCH_MARKER( ercItem, text->GetPosition() );
aSubgraph->m_sheet.LastScreen()->Append( marker );
ok = false;
reportError( text, ERCE_LABEL_NOT_CONNECTED );
return false;
}
break;
}
case SCH_PIN_T:
case SCH_SHEET_PIN_T:
hasOtherConnections = true;
pinCount++;
break;
// If this subgraph has a no-connect, do not continue processing as we do not
// submit no-connect errors for nets explicitly designated as no-connect
case SCH_NO_CONNECT_T:
return true;
default:
break;
}
}
if( !text )
if( label_map.empty() )
return true;
bool isGlobal = text->Type() == SCH_GLOBAL_LABEL_T;
int errCode = isGlobal ? ERCE_GLOBLABEL : ERCE_LABEL_NOT_CONNECTED;
wxCHECK_MSG( m_schematic, true, wxT( "Null m_schematic in CONNECTION_GRAPH::ercCheckLabels" ) );
wxString name = EscapeString( text->GetShownText(), CTX_NETNAME );
// Labels that have multiple pins connected are not dangling (may be used for naming segments)
// so leave them without errors here
if( pinCount > 1 )
return true;
if( isGlobal )
for( const auto& label_pair : label_map )
{
// This will be set to true if the global is connected to a pin above, but we want to
// reset this to false so that globals get flagged if they only have a single instance
// connected to a single pin
hasOtherConnections = ( pinCount > 1 );
auto it = m_net_name_to_subgraphs_map.find( name );
if( it != m_net_name_to_subgraphs_map.end() )
const KICAD_T type = label_pair.first;
std::vector<SCH_TEXT*> label_vec = label_pair.second;
switch( type )
{
if( it->second.size() > 1 || aSubgraph->m_multiple_drivers )
hasOtherConnections = true;
}
}
else if( text->Type() == SCH_HIER_LABEL_T )
{
// For a hier label, check if the parent pin is connected
if( aSubgraph->m_hier_parent
&& ( aSubgraph->m_hier_parent->m_strong_driver
|| aSubgraph->m_hier_parent->m_drivers.size() > 1) )
{
// For now, a simple check: if there is more than one driver, the parent is probably
// connected elsewhere (because at least one driver will be the hier pin itself)
hasOtherConnections = true;
}
}
else
{
auto pair = std::make_pair( aSubgraph->m_sheet, name );
auto it = m_local_label_cache.find( pair );
case SCH_GLOBAL_LABEL_T:
if( !settings.IsTestEnabled( ERCE_GLOBLABEL ) )
break;
if( it != m_local_label_cache.end() && it->second.size() > 1 )
{
for( const CONNECTION_SUBGRAPH* neighbor : it->second )
for( SCH_TEXT* text : label_vec )
{
if( neighbor == aSubgraph )
wxString name = EscapeString( text->GetShownText(), CTX_NETNAME );
int allPins = pinCount;
// If the global label is connected to a subgraph but is not the driver
// then there is a driver conflict somewhere that is handled by a different
// ERC check. Here, we are just looking for unconnected elements
if( name != aSubgraph->m_driver_connection->Name() )
continue;
if( hasPins( neighbor ) )
// Global labels are connected if there is another instance of
// their name in the circuit
auto it = m_net_name_to_subgraphs_map.find( name );
for( const CONNECTION_SUBGRAPH* neighbor : it->second )
{
hasOtherConnections = true;
break;
if( neighbor == aSubgraph )
continue;
allPins += hasPins( neighbor );
}
if( allPins < 2 )
{
reportError( text, ERCE_GLOBLABEL );
ok = false;
}
}
break;
case SCH_HIER_LABEL_T:
if( !settings.IsTestEnabled( ERCE_LABEL_NOT_CONNECTED ) )
break;
for( SCH_TEXT* text : label_vec )
{
if( !aSubgraph->m_hier_parent
|| ( !aSubgraph->m_hier_parent->m_strong_driver
&& aSubgraph->m_hier_parent->m_drivers.size() <= 1 ) )
{
reportError( text, ERCE_LABEL_NOT_CONNECTED );
ok = false;
}
}
break;
case SCH_LABEL_T:
if( !settings.IsTestEnabled( ERCE_LABEL_NOT_CONNECTED ) )
break;
for( SCH_TEXT* text : label_vec )
{
int allPins = pinCount;
wxString name = EscapeString( text->GetShownText(), CTX_NETNAME );
auto pair = std::make_pair( aSubgraph->m_sheet, name );
auto it = m_local_label_cache.find( pair );
if( it == m_local_label_cache.end() )
continue;
for( const CONNECTION_SUBGRAPH* neighbor : it->second )
{
if( neighbor == aSubgraph )
continue;
allPins += hasPins( neighbor );
}
if( allPins < 2 )
{
reportError( text, ERCE_LABEL_NOT_CONNECTED );
ok = false;
}
}
break;
default:
break;
}
}
if( !hasOtherConnections && settings.IsTestEnabled( errCode ) )
{
std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( errCode );
ercItem->SetItems( text );
SCH_MARKER* marker = new SCH_MARKER( ercItem, text->GetPosition() );
aSubgraph->m_sheet.LastScreen()->Append( marker );
return false;
}
return ok;
}
+40 -22
View File
@@ -83,8 +83,8 @@ public:
* @param title is the title of the notebook page.
* @param id_NetType is the netlist ID type.
*/
NETLIST_PAGE_DIALOG( wxNotebook* parent, const wxString& title,
NETLIST_TYPE_ID id_NetType );
NETLIST_PAGE_DIALOG( wxNotebook* aParent, const wxString& aTitle,
NETLIST_TYPE_ID aIdNetType, bool aCustom );
~NETLIST_PAGE_DIALOG() { };
/**
@@ -102,8 +102,12 @@ public:
wxBoxSizer* m_RightOptionsBoxSizer;
wxBoxSizer* m_LowBoxSizer;
bool IsCustom() const { return m_custom; }
private:
wxString m_pageNetFmtName;
bool m_custom;
};
@@ -125,6 +129,8 @@ private:
bool TransferDataFromWindow() override;
void NetlistUpdateOpt();
void updateGeneratorButtons();
// Called when changing the notebook page (and therefore the current netlist format)
void OnNetlistTypeSelection( wxNotebookEvent& event ) override;
@@ -206,17 +212,18 @@ BEGIN_EVENT_TABLE( NETLIST_DIALOG, NETLIST_DIALOG_BASE )
END_EVENT_TABLE()
NETLIST_PAGE_DIALOG::NETLIST_PAGE_DIALOG( wxNotebook* parent, const wxString& title,
NETLIST_TYPE_ID id_NetType ) :
wxPanel( parent, -1, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL )
NETLIST_PAGE_DIALOG::NETLIST_PAGE_DIALOG( wxNotebook* aParent, const wxString& aTitle,
NETLIST_TYPE_ID aIdNetType, bool aCustom ) :
wxPanel( aParent, -1, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL )
{
m_IdNetType = id_NetType;
m_pageNetFmtName = title;
m_IdNetType = aIdNetType;
m_pageNetFmtName = aTitle;
m_CommandStringCtrl = nullptr;
m_TitleStringCtrl = nullptr;
m_AdjustPassiveValues = nullptr;
m_custom = aCustom;
parent->AddPage( this, title, false );
aParent->AddPage( this, aTitle, false );
wxBoxSizer* MainBoxSizer = new wxBoxSizer( wxVERTICAL );
SetSizer( MainBoxSizer );
@@ -245,14 +252,14 @@ NETLIST_DIALOG::NETLIST_DIALOG( SCH_EDIT_FRAME* parent ) :
page = nullptr;
// Add notebook pages:
m_PanelNetType[PANELPCBNEW] = new NETLIST_PAGE_DIALOG( m_NoteBook, wxT( "KiCad" ),
NET_TYPE_PCBNEW );
m_PanelNetType[PANELPCBNEW] =
new NETLIST_PAGE_DIALOG( m_NoteBook, wxT( "KiCad" ), NET_TYPE_PCBNEW, false );
m_PanelNetType[PANELORCADPCB2] = new NETLIST_PAGE_DIALOG( m_NoteBook, wxT( "OrcadPCB2" ),
NET_TYPE_ORCADPCB2 );
m_PanelNetType[PANELORCADPCB2] =
new NETLIST_PAGE_DIALOG( m_NoteBook, wxT( "OrcadPCB2" ), NET_TYPE_ORCADPCB2, false );
m_PanelNetType[PANELCADSTAR] = new NETLIST_PAGE_DIALOG( m_NoteBook, wxT( "CadStar" ),
NET_TYPE_CADSTAR );
m_PanelNetType[PANELCADSTAR] =
new NETLIST_PAGE_DIALOG( m_NoteBook, wxT( "CadStar" ), NET_TYPE_CADSTAR, false );
InstallPageSpice();
InstallCustomPages();
@@ -275,6 +282,8 @@ NETLIST_DIALOG::NETLIST_DIALOG( SCH_EDIT_FRAME* parent ) :
// Now all widgets have the size fixed, call FinishDialogSettings
finishDialogSettings();
updateGeneratorButtons();
}
@@ -320,7 +329,7 @@ void NETLIST_DIALOG::OnRunSpiceButtUI( wxUpdateUIEvent& aEvent )
void NETLIST_DIALOG::InstallPageSpice()
{
NETLIST_PAGE_DIALOG* page = m_PanelNetType[PANELSPICE] =
new NETLIST_PAGE_DIALOG( m_NoteBook, wxT( "Spice" ), NET_TYPE_SPICE );
new NETLIST_PAGE_DIALOG( m_NoteBook, wxT( "Spice" ), NET_TYPE_SPICE, false );
SCHEMATIC_SETTINGS& settings = m_Parent->Schematic().Settings();
@@ -385,7 +394,7 @@ NETLIST_PAGE_DIALOG* NETLIST_DIALOG::AddOneCustomPage( const wxString& aTitle,
const wxString& aCommandString,
NETLIST_TYPE_ID aNetTypeId )
{
NETLIST_PAGE_DIALOG* currPage = new NETLIST_PAGE_DIALOG( m_NoteBook, aTitle, aNetTypeId );
NETLIST_PAGE_DIALOG* currPage = new NETLIST_PAGE_DIALOG( m_NoteBook, aTitle, aNetTypeId, true );
currPage->m_LowBoxSizer->Add( new wxStaticText( currPage, -1, _( "Title:" ) ), 0,
wxGROW | wxLEFT | wxRIGHT | wxTOP, 5 );
@@ -413,12 +422,7 @@ NETLIST_PAGE_DIALOG* NETLIST_DIALOG::AddOneCustomPage( const wxString& aTitle,
void NETLIST_DIALOG::OnNetlistTypeSelection( wxNotebookEvent& event )
{
NETLIST_PAGE_DIALOG* currPage = (NETLIST_PAGE_DIALOG*) m_NoteBook->GetCurrentPage();
if( currPage == nullptr )
return;
m_buttonDelGenerator->Enable( currPage->m_IdNetType >= NET_TYPE_CUSTOM1 );
updateGeneratorButtons();
}
@@ -588,6 +592,9 @@ void NETLIST_DIALOG::OnDelGenerator( wxCommandEvent& event )
{
NETLIST_PAGE_DIALOG* currPage = (NETLIST_PAGE_DIALOG*) m_NoteBook->GetCurrentPage();
if( !currPage->IsCustom() )
return;
currPage->m_CommandStringCtrl->SetValue( wxEmptyString );
currPage->m_TitleStringCtrl->SetValue( wxEmptyString );
@@ -712,6 +719,17 @@ void NETLIST_DIALOG_ADD_GENERATOR::OnBrowseGenerators( wxCommandEvent& event )
}
void NETLIST_DIALOG::updateGeneratorButtons()
{
NETLIST_PAGE_DIALOG* currPage = (NETLIST_PAGE_DIALOG*) m_NoteBook->GetCurrentPage();
if( currPage == nullptr )
return;
m_buttonDelGenerator->Enable( currPage->IsCustom() );
}
int InvokeDialogNetList( SCH_EDIT_FRAME* aCaller )
{
NETLIST_DIALOG dlg( aCaller );
@@ -409,6 +409,11 @@ bool SCH_PRINTOUT::OnBeginDocument( int startPage, int endPage )
*/
void SCH_PRINTOUT::PrintPage( SCH_SCREEN* aScreen )
{
// Warning:
// When printing many pages, changes in the current wxDC will affect all next printings
// because all prints are using the same wxPrinterDC after creation
// So be careful and reinit parameters, especially when using offsets.
wxPoint tmp_startvisu;
wxSize pageSizeIU; // Page size in internal units
wxPoint old_org;
@@ -439,16 +444,31 @@ void SCH_PRINTOUT::PrintPage( SCH_SCREEN* aScreen )
int xoffset = ( fitRect.width - pageSizeIU.x ) / 2;
int yoffset = ( fitRect.height - pageSizeIU.y ) / 2;
// Using a wxAffineMatrix2D has a big advantage: it handles different pages orientations
//(PORTRAIT/LANDSCAPE), but the affine matrix is not always supported
if( dc->CanUseTransformMatrix() )
{
wxAffineMatrix2D matrix = dc->GetTransformMatrix();
wxAffineMatrix2D matrix; // starts from a unity matrix (the current wxDC default)
// Check for portrait/landscape mismatch:
if( ( fitRect.width > fitRect.height ) != ( pageSizeIU.x > pageSizeIU.y ) )
{
// Rotate the coordinates, and keep the draw coordinates inside the page
matrix.Rotate( M_PI_2 );
xoffset = ( fitRect.height - pageSizeIU.x ) / 2;
yoffset = ( fitRect.width - pageSizeIU.y ) / 2;
matrix.Translate( 0, -pageSizeIU.y );
// Recalculate the offsets and page sizes according to the page rotation
std::swap( pageSizeIU.x, pageSizeIU.y );
FitThisSizeToPaper( pageSizeIU );
fitRect = GetLogicalPaperRect();
xoffset = ( fitRect.width - pageSizeIU.x ) / 2;
yoffset = ( fitRect.height - pageSizeIU.y ) / 2;
// All the coordinates will be rotated 90 deg when printing,
// so the X,Y offset vector must be rotated -90 deg before printing
std::swap( xoffset, yoffset );
yoffset = -yoffset;
}
matrix.Translate( xoffset, yoffset );
@@ -456,12 +476,8 @@ void SCH_PRINTOUT::PrintPage( SCH_SCREEN* aScreen )
}
else
{
// wxWidgets appears to have a bug when OffsetLogicalOrigin()'s yoffset changes from
// page to page.
// NB: this is a workaround, not a fix. The Y centering will be off, but this is less
// annoying than a blank page. See https://bugs.launchpad.net/kicad/+bug/1464773.
yoffset = 0;
SetLogicalOrigin( 0, 0 ); // Reset all offset settings made previously.
// When printing previous pages (all prints are using the same wxDC)
OffsetLogicalOrigin( xoffset, yoffset );
}
@@ -758,8 +758,14 @@ bool DIALOG_SYMBOL_PROPERTIES::TransferDataFromWindow()
}
else
{
SCH_FIELD* newField = otherUnit->AddField( m_fields->at( ii ) );
const_cast<KIID&>( newField->m_Uuid ) = KIID();
SCH_FIELD newField( m_fields->at( ii ) );
const_cast<KIID&>( newField.m_Uuid ) = KIID();
newField.Offset( -m_symbol->GetPosition() );
newField.Offset( otherUnit->GetPosition() );
newField.SetParent( otherUnit );
otherUnit->AddField( newField );
}
}
+13
View File
@@ -321,7 +321,20 @@ void IFACE::SaveFileAs( const wxString& aProjectBasePath, const wxString& aProje
ext == KiCadSchematicFileExtension + BackupFileSuffix )
{
if( destFile.GetName() == aProjectName )
{
destFile.SetName( aNewProjectName );
}
else if( destFile.GetName() == aNewProjectName )
{
wxString msg;
if( !aErrors.empty() )
aErrors += "\n";
msg.Printf( _( "Cannot copy file '%s'." ), destFile.GetFullPath() );
aErrors += msg;
return;
}
// Sheet paths when auto-generated are relative to the root, so those will stay
// pointing to whatever they were pointing at.
+7 -1
View File
@@ -526,7 +526,7 @@ wxString LIB_SYMBOL::SubReference( int aUnit, bool aAddSeparator )
}
void LIB_SYMBOL::Print( const RENDER_SETTINGS* aSettings, const wxPoint& aOffset,
void LIB_SYMBOL::PrintBackground( const RENDER_SETTINGS* aSettings, const wxPoint& aOffset,
int aUnit, int aConvert, const LIB_SYMBOL_OPTIONS& aOpts )
{
/* draw background for filled items using background option
@@ -553,6 +553,12 @@ void LIB_SYMBOL::Print( const RENDER_SETTINGS* aSettings, const wxPoint& aOffset
}
}
}
}
void LIB_SYMBOL::Print( const RENDER_SETTINGS* aSettings, const wxPoint& aOffset, int aUnit,
int aConvert, const LIB_SYMBOL_OPTIONS& aOpts )
{
for( LIB_ITEM& item : m_drawings )
{
+11
View File
@@ -314,6 +314,17 @@ public:
void Print( const RENDER_SETTINGS* aSettings, const wxPoint& aOffset,
int aMulti, int aConvert, const LIB_SYMBOL_OPTIONS& aOpts );
/**
* Print just the background fills of a symbol
*
* @param aOffset - Position of symbol.
* @param aMulti - unit if multiple units per symbol.
* @param aConvert - Symbol conversion (DeMorgan) if available.
* @param aOpts - Drawing options
*/
void PrintBackground( const RENDER_SETTINGS *aSettings, const wxPoint &aOffset, int aMulti,
int aConvert, const LIB_SYMBOL_OPTIONS &aOpts );
/**
* Plot lib symbol to plotter.
* Lib Fields not are plotted here, because this plot function
@@ -332,7 +332,9 @@ XNODE* NETLIST_EXPORTER_XML::makeSymbols( unsigned aCtl )
xproperty->AddAttribute( wxT( "name" ), sheetField.GetCanonicalName() );
if( m_resolveTextVars )
xproperty->AddAttribute( wxT( "value" ), sheetField.GetShownText() );
// do not allow GetShownText() to add any prefix useful only when displaying
// the field on screen
xproperty->AddAttribute( wxT( "value" ), sheetField.GetShownText( 0, false ) );
else
xproperty->AddAttribute( wxT( "value" ), sheetField.GetText() );
}
@@ -40,7 +40,7 @@ except IOError:
f = sys.stdout
# Create a new csv writer object to use as the output formatter
out = csv.writer(f, delimiter=',', quotechar='\"', quoting=csv.QUOTE_ALL)
out = csv.writer(f, lineterminator='\n', delimiter=',', quotechar='\"', quoting=csv.QUOTE_ALL)
# Output a set of rows for a header providing general information
out.writerow(['Source:', net.getSource()])
+2 -2
View File
@@ -102,7 +102,7 @@ void SCH_FIELD::SetId( int aId )
}
wxString SCH_FIELD::GetShownText( int aDepth ) const
wxString SCH_FIELD::GetShownText( int aDepth, bool aAllowExtraText ) const
{
std::function<bool( wxString* )> symbolResolver =
[&]( wxString* token ) -> bool
@@ -185,7 +185,7 @@ wxString SCH_FIELD::GetShownText( int aDepth ) const
}
else if( m_parent && m_parent->Type() == SCH_SHEET_T )
{
if( m_id == SHEETFILENAME )
if( m_id == SHEETFILENAME && aAllowExtraText )
text = _( "File:" ) + wxS( " " )+ text;
}
+1 -1
View File
@@ -114,7 +114,7 @@ public:
void SetId( int aId );
wxString GetShownText( int aDepth = 0 ) const override;
wxString GetShownText( int aDepth = 0, bool aAllowExtraText = true ) const override;
/**
* Adjusters to allow EDA_TEXT to draw/print/etc. text in absolute coords.
+9
View File
@@ -285,6 +285,15 @@ public:
*/
virtual void Print( const RENDER_SETTINGS* aSettings, const wxPoint& aOffset ) = 0;
/**
* Print the (optional) backaground elements if they exist
* @param aSettings Print settings
* @param aOffset is the drawing offset (usually {0,0} but can be different when moving an
* object).
*/
virtual void PrintBackground( const RENDER_SETTINGS* aSettings, const wxPoint& aOffset ) {};
/**
* Move the item by \a aMoveVector to a new position.
*/
@@ -572,7 +572,7 @@ SCH_SHEET* SCH_SEXPR_PLUGIN::Load( const wxString& aFileName, SCHEMATIC* aSchema
newSheet->SetFileName( relPath.GetFullPath() );
m_rootSheet = newSheet.get();
loadHierarchy( newSheet.get() );
loadHierarchy( SCH_SHEET_PATH(), newSheet.get() );
// If we got here, the schematic loaded successfully.
sheet = newSheet.release();
@@ -583,7 +583,7 @@ SCH_SHEET* SCH_SEXPR_PLUGIN::Load( const wxString& aFileName, SCHEMATIC* aSchema
wxCHECK_MSG( aSchematic->IsValid(), nullptr, "Can't append to a schematic with no root!" );
m_rootSheet = &aSchematic->Root();
sheet = aAppendToMe;
loadHierarchy( sheet );
loadHierarchy( SCH_SHEET_PATH(), sheet );
}
wxASSERT( m_currentPath.size() == 1 ); // only the project path should remain
@@ -596,7 +596,7 @@ SCH_SHEET* SCH_SEXPR_PLUGIN::Load( const wxString& aFileName, SCHEMATIC* aSchema
// Everything below this comment is recursive. Modify with care.
void SCH_SEXPR_PLUGIN::loadHierarchy( SCH_SHEET* aSheet )
void SCH_SEXPR_PLUGIN::loadHierarchy( const SCH_SHEET_PATH& aParentSheetPath, SCH_SHEET* aSheet )
{
SCH_SCREEN* screen = nullptr;
@@ -618,7 +618,34 @@ void SCH_SEXPR_PLUGIN::loadHierarchy( SCH_SHEET* aSheet )
wxLogTrace( traceSchLegacyPlugin, "Current path '%s'", m_currentPath.top() );
wxLogTrace( traceSchLegacyPlugin, "Loading '%s'", fileName.GetFullPath() );
m_rootSheet->SearchHierarchy( fileName.GetFullPath(), &screen );
SCH_SHEET_PATH ancestorSheetPath = aParentSheetPath;
while( !ancestorSheetPath.empty() )
{
if( ancestorSheetPath.LastScreen()->GetFileName() == fileName.GetFullPath() )
{
if( m_error.IsEmpty() )
{
m_error = _( "The entire schematic could not be loaded. Errors occurred "
"attempting to load hierarchical sheets." );
}
if( !m_error.IsEmpty() )
m_error += "\n";
m_error += wxString::Format( _( "Error loading schematic '%s'." ),
fileName.GetFullPath() );
fileName = wxEmptyString;
break;
}
ancestorSheetPath.pop_back();
}
if( ancestorSheetPath.empty() )
m_rootSheet->SearchHierarchy( fileName.GetFullPath(), &screen );
if( screen )
{
@@ -659,7 +686,10 @@ void SCH_SEXPR_PLUGIN::loadHierarchy( SCH_SHEET* aSheet )
aSheet->GetScreen()->SetFileExists( false );
}
// This was moved out of the try{} block so that any sheets definitionsthat
SCH_SHEET_PATH currentSheetPath = aParentSheetPath;
currentSheetPath.push_back( aSheet );
// This was moved out of the try{} block so that any sheet definitions that
// the plugin fully parsed before the exception was raised will be loaded.
for( SCH_ITEM* aItem : aSheet->GetScreen()->Items().OfType( SCH_SHEET_T ) )
{
@@ -667,7 +697,7 @@ void SCH_SEXPR_PLUGIN::loadHierarchy( SCH_SHEET* aSheet )
SCH_SHEET* sheet = static_cast<SCH_SHEET*>( aItem );
// Recursion starts here.
loadHierarchy( sheet );
loadHierarchy( currentSheetPath, sheet );
}
}
@@ -137,7 +137,7 @@ public:
static void FormatLibSymbol( LIB_SYMBOL* aPart, OUTPUTFORMATTER& aFormatter );
private:
void loadHierarchy( SCH_SHEET* aSheet );
void loadHierarchy( const SCH_SHEET_PATH& aParentSheetPath, SCH_SHEET* aSheet );
void loadFile( const wxString& aFileName, SCH_SHEET* aSheet );
void saveSymbol( SCH_SYMBOL* aSymbol, SCH_SHEET_PATH* aSheetPath, int aNestLevel );
@@ -2352,7 +2352,7 @@ void SCH_LEGACY_PLUGIN::saveLine( SCH_LINE* aLine )
if( aLine->GetLineColor() != COLOR4D::UNSPECIFIED )
m_out->Print( 0, " %s",
TO_UTF8( aLine->GetLineColor().ToColour().GetAsString( wxC2S_CSS_SYNTAX ) ) );
TO_UTF8( aLine->GetLineColor().ToCSSString() ) );
}
m_out->Print( 0, "\n" );
+7 -2
View File
@@ -45,7 +45,9 @@
#include <symbol_library.h>
#include <connection_graph.h>
#include <lib_item.h>
#include <lib_pin.h>
#include <lib_shape.h>
#include <sch_symbol.h>
#include <sch_junction.h>
#include <sch_line.h>
@@ -815,18 +817,21 @@ void SCH_SCREEN::Print( const RENDER_SETTINGS* aSettings )
}
/// Sort to ensure plot-order consistency with screen drawing
std::sort( other.begin(), other.end(),
std::stable_sort( other.begin(), other.end(),
[]( const SCH_ITEM* a, const SCH_ITEM* b )
{
if( a->Type() == b->Type() )
return a->GetLayer() > b->GetLayer();
return a->Type() > b->Type();
return a->Type() < b->Type();
} );
for( SCH_ITEM* item : bitmaps )
item->Print( aSettings, wxPoint( 0, 0 ) );
for( SCH_ITEM* item : other )
item->PrintBackground( aSettings, wxPoint( 0, 0 ) );
for( SCH_ITEM* item : other )
item->Print( aSettings, wxPoint( 0, 0 ) );
+13
View File
@@ -409,6 +409,19 @@ int SCH_SYMBOL::GetUnitCount() const
}
void SCH_SYMBOL::PrintBackground( const RENDER_SETTINGS* aSettings, const wxPoint& aOffset )
{
LIB_SYMBOL_OPTIONS opts;
opts.transform = m_transform;
opts.draw_visible_fields = false;
opts.draw_hidden_fields = false;
if( m_part )
m_part->PrintBackground( aSettings, m_pos + aOffset, m_unit, m_convert, opts );
}
void SCH_SYMBOL::Print( const RENDER_SETTINGS* aSettings, const wxPoint& aOffset )
{
LIB_SYMBOL_OPTIONS opts;
+11 -2
View File
@@ -488,12 +488,21 @@ public:
/**
* Print a symbol.
*
* @param aDC is the device context (can be null).
* @param aOffset is the drawing offset (usually wxPoint(0,0), but can be different when
* @param aSettings Render settings controlling output
* @param aOffset is the drawing offset (usually VECTOR2I(0,0), but can be different when
* moving an object)
*/
void Print( const RENDER_SETTINGS* aSettings, const wxPoint& aOffset ) override;
/**
* Print only the background parts of a symbol (if any)
*
* @param aSettings Render settings controlling output
* @param aOffset is the drawing offset (usually VECTOR2I(0,0), but can be different when
* moving an object)
*/
void PrintBackground( const RENDER_SETTINGS* aSettings, const wxPoint& aOffset ) override;
void SwapData( SCH_ITEM* aItem ) override;
/**
+1 -1
View File
@@ -597,7 +597,7 @@ void SCH_TEXT::GetContextualTextVars( wxArrayString* aVars ) const
}
wxString SCH_TEXT::GetShownText( int aDepth ) const
wxString SCH_TEXT::GetShownText( int aDepth, bool aAllowExtraText ) const
{
std::function<bool( wxString* )> textResolver =
[&]( wxString* token ) -> bool
+1 -1
View File
@@ -139,7 +139,7 @@ public:
*/
void GetContextualTextVars( wxArrayString* aVars ) const;
wxString GetShownText( int aDepth = 0 ) const override;
wxString GetShownText( int aDepth = 0, bool aAllowExtraText = true ) const override;
/**
* Increment the label text, if it ends with a number.
+13
View File
@@ -559,6 +559,19 @@ void NGSPICE::init_dll()
Command( "set noaskquit" );
Command( "set nomoremode" );
// reset and remcirc give an error if no circuit is loaded, so load an empty circuit at the
// start.
vector<char*> lines;
lines.push_back( strdup( "*" ) );
lines.push_back( strdup( ".end" ) );
lines.push_back( nullptr ); // Sentinel.
m_ngSpice_Circ( lines.data() );
for( auto line : lines )
free( line );
m_initialized = true;
}
@@ -93,5 +93,7 @@ void SYMBOL_EDIT_FRAME::PrintPage( const RENDER_SETTINGS* aSettings )
plot_offset.x = pagesize.x / 2;
plot_offset.y = pagesize.y / 2;
m_symbol->PrintBackground( aSettings, plot_offset, m_unit, m_convert, LIB_SYMBOL_OPTIONS() );
m_symbol->Print( aSettings, plot_offset, m_unit, m_convert, LIB_SYMBOL_OPTIONS() );
}
@@ -531,7 +531,8 @@ LIB_ID SYMBOL_LIBRARY_MANAGER::RevertSymbol( const wxString& aAlias, const wxStr
}
else
{
symbolBuf->SetSymbol( new LIB_SYMBOL( original ) );
// copy the initial data to the current symbol to restore
*symbolBuf->GetSymbol() = original;
m_frame.SyncLibraries( false );
}
+1
View File
@@ -750,6 +750,7 @@ int SCH_DRAWING_TOOLS::SingleClickPlace( const TOOL_EVENT& aEvent )
}
SCH_ITEM* newItem = static_cast<SCH_ITEM*>( previewItem->Clone() );
const_cast<KIID&>( newItem->m_Uuid ) = KIID();
newItem->SetPosition( cursorPos );
newItem->SetFlags( IS_NEW );
+1 -1
View File
@@ -244,7 +244,7 @@ bool SYMBOL_EDITOR_PIN_TOOL::PlacePin( LIB_PIN* aPin )
if( !status )
{
if( aPin->IsNew() )
if( aPin->IsNew() && !aPin->HasFlag( IS_PASTED ) )
delete aPin;
return false;
+1 -4
View File
@@ -442,7 +442,6 @@ EDA_ITEM* GERBVIEW_SELECTION_TOOL::disambiguationMenu( GERBER_COLLECTOR* aCollec
if( current )
{
current->ClearBrightened();
getView()->Hide( current, false );
highlightGroup.Remove( current );
getView()->MarkTargetDirty( KIGFX::TARGET_OVERLAY );
}
@@ -454,7 +453,6 @@ EDA_ITEM* GERBVIEW_SELECTION_TOOL::disambiguationMenu( GERBER_COLLECTOR* aCollec
{
current = ( *aCollector )[id - 1];
current->SetBrightened();
getView()->Hide( current, true );
highlightGroup.Add( current );
getView()->MarkTargetDirty( KIGFX::TARGET_OVERLAY );
}
@@ -477,10 +475,9 @@ EDA_ITEM* GERBVIEW_SELECTION_TOOL::disambiguationMenu( GERBER_COLLECTOR* aCollec
}
}
if( current && current->IsBrightened() )
if( current )
{
current->ClearBrightened();
getView()->Hide( current, false );
getView()->MarkTargetDirty( KIGFX::TARGET_OVERLAY );
}
@@ -2128,8 +2128,13 @@ skipcodes 26 0
// Combining Diacritical Marks For Symbols (20D0-20FF)
skipcodes 48 0
// Letterlike Symbols (2100-214F)
skipcodes 80 0
// Letterlike Symbols (2100-2125)
skipcodes 38 0
+ OMEGA_CAP
// Letterlike Symbols (2127-214F)
skipcodes 41 0
// Number Forms (2150-218F)
skipcodes 64 0
+6
View File
@@ -148,6 +148,12 @@ public:
virtual LSET GetLayerSet() const { return LSET( m_layer ); }
virtual void SetLayerSet( LSET aLayers )
{
if( aLayers.count() == 1 )
{
SetLayer( aLayers.Seq()[0] );
return;
}
wxFAIL_MSG( wxT( "Attempted to SetLayerSet() on a single-layer object." ) );
// Derived classes which support multiple layers must implement this
+3 -1
View File
@@ -52,7 +52,8 @@ public:
*/
EDA_LIST_DIALOG( wxWindow* aParent, const wxString& aTitle, const wxArrayString& aItemHeaders,
const std::vector<wxArrayString>& aItemList,
const wxString& aPreselectText = wxEmptyString );
const wxString& aPreselectText = wxEmptyString,
bool aSortList = true );
void SetListLabel( const wxString& aLabel );
void SetOKLabel( const wxString& aLabel );
@@ -80,6 +81,7 @@ private:
private:
const std::vector<wxArrayString>* m_itemsList;
bool m_sortList;
};
+4 -1
View File
@@ -158,8 +158,11 @@ public:
*
* @param aDepth is used to prevent infinite recursions and loops when expanding
* text variables.
* @param aAllowExtraText true to allow adding more text than the initial expanded text,
* for intance a title, a prefix for texts in display functions.
* False to disable any added text (for instance when writing the shown text in netlists).
*/
virtual wxString GetShownText( int aDepth = 0 ) const { return m_shown_text; }
virtual wxString GetShownText( int aDepth = 0, bool aAllowExtraText = true ) const { return m_shown_text; }
/**
* Returns a shortened version (max 15 characters) of the shown text
+1 -1
View File
@@ -166,7 +166,7 @@ public:
*/
bool SetFromWxString( const wxString& aColorString );
wxString ToWxString( long flags ) const;
wxString ToCSSString() const;
bool SetFromHexString( const wxString& aColorString );
wxString ToHexString() const;
+1 -1
View File
@@ -1275,7 +1275,7 @@ public:
m_gal->BeginDrawing();
}
~GAL_DRAWING_CONTEXT()
~GAL_DRAWING_CONTEXT() noexcept( false )
{
m_gal->EndDrawing();
}
+5 -2
View File
@@ -159,11 +159,14 @@ private:
/* Token state for input string. */
struct TokenStat
{
enum { OutLen = 32 };
TokenStat() : input( nullptr ), token( nullptr ), inputLen( 0 ), pos( 0 ) { /* empty */ }
TokenStat() :
input( nullptr ), token( nullptr ), inputLen( 0 ), outputLen( 0 ), pos( 0 )
{ /* empty */ }
const char* input; // current input string ("var=4")
char* token; // output token ("var", type:VAR; "4", type:VALUE)
size_t inputLen; // strlen(input)
size_t outputLen; // At least 64, up to input length
size_t pos; // current index
}
m_token;
+8 -2
View File
@@ -277,7 +277,7 @@ public:
virtual ~VAR_REF() {};
virtual VAR_TYPE_T GetType() const = 0;
virtual VALUE GetValue( CONTEXT* aCtx ) = 0;
virtual VALUE* GetValue( CONTEXT* aCtx ) = 0;
};
@@ -293,7 +293,7 @@ public:
virtual ~CONTEXT()
{
for( auto &v : m_ownedValues )
for( VALUE* v : m_ownedValues )
{
delete v;
}
@@ -305,6 +305,12 @@ public:
return m_ownedValues.back();
}
VALUE* StoreValue( VALUE* aValue )
{
m_ownedValues.emplace_back( aValue );
return m_ownedValues.back();
}
void Push( VALUE* v )
{
m_stack[ m_stackPtr++ ] = v;
+2 -2
View File
@@ -92,11 +92,11 @@ public:
void RemoveAll();
/*
* Search for highest level group containing item.
* Search for highest level group inside of aScope, containing item.
*
* @param aScope restricts the search to groups within the group scope.
* @param isFootprintEditor true if we should stop promoting at the footprint level
* @return group containing item, if it exists, otherwise, NULL
* @return group inside of aScope, containing item, if exists, otherwise, nullptr
*/
static PCB_GROUP* TopLevelGroup( BOARD_ITEM* aItem, PCB_GROUP* aScope, bool isFootprintEditor );
+5 -28
View File
@@ -276,34 +276,9 @@ public:
return ( d1 <= 1 && d2 <= 1 );
}
bool ApproxCollinear( const SEG& aSeg ) const
{
ecoord p, q, r;
CanonicalCoefs( p, q, r );
ecoord dist1 = ( p * aSeg.A.x + q * aSeg.A.y + r ) / sqrt( p * p + q * q );
ecoord dist2 = ( p * aSeg.B.x + q * aSeg.B.y + r ) / sqrt( p * p + q * q );
return std::abs( dist1 ) <= 1 && std::abs( dist2 ) <= 1;
}
bool ApproxParallel( const SEG& aSeg, int aDistanceThreshold = 1 ) const
{
ecoord p, q, r;
CanonicalCoefs( p, q, r );
ecoord dist1 = ( p * aSeg.A.x + q * aSeg.A.y + r ) / sqrt( p * p + q * q );
ecoord dist2 = ( p * aSeg.B.x + q * aSeg.B.y + r ) / sqrt( p * p + q * q );
return std::abs( dist1 - dist2 ) <= aDistanceThreshold;
}
bool ApproxPerpendicular( const SEG& aSeg ) const
{
SEG perp = PerpendicularSeg( A );
return aSeg.ApproxParallel( perp );
}
bool ApproxCollinear( const SEG& aSeg, int aDistanceThreshold = 1 ) const;
bool ApproxParallel( const SEG& aSeg, int aDistanceThreshold = 1 ) const;
bool ApproxPerpendicular( const SEG& aSeg ) const;
bool Overlaps( const SEG& aSeg ) const
{
@@ -394,6 +369,8 @@ private:
bool intersects( const SEG& aSeg, bool aIgnoreEndpoints = false, bool aLines = false,
VECTOR2I* aPt = nullptr ) const;
bool mutualDistance( const SEG& aSeg, ecoord& aD1, ecoord& aD2 ) const;
private:
///< index within the parent shape (used when m_is_local == false)
int m_index;
+1 -1
View File
@@ -229,7 +229,7 @@ public:
// calculate the right common area coordinate:
int right = std::min( me.m_Pos.x + me.m_Size.x, rect.m_Pos.x + rect.m_Size.x );
// calculate the upper common area coordinate:
int top = std::max( me.m_Pos.y, aRect.m_Pos.y );
int top = std::max( me.m_Pos.y, rect.m_Pos.y );
// calculate the lower common area coordinate:
int bottom = std::min( me.m_Pos.y + me.m_Size.y, rect.m_Pos.y + rect.m_Size.y );
@@ -273,7 +273,7 @@ void CornerListToPolygon( SHAPE_POLY_SET& outline, std::vector<ROUNDED_CORNER>&
endAngle = RAD2DECIDEG( angle );
}
if( aInflate )
if( aInflate && tanAngle2 )
{
radius += aInflate;
cornerPosition += incoming.Resize( aInflate / tanAngle2 )
+60
View File
@@ -349,3 +349,63 @@ int SEG::LineDistance( const VECTOR2I& aP, bool aDetermineSide ) const
return aDetermineSide ? dist : std::abs( dist );
}
bool SEG::mutualDistance( const SEG& aSeg, ecoord& aD1, ecoord& aD2 ) const
{
SEG a( *this );
SEG b( aSeg );
if( a.SquaredLength() < b.SquaredLength() )
{
std::swap(a, b);
}
ecoord p = ecoord{ a.A.y } - a.B.y;
ecoord q = ecoord{ a.B.x } - a.A.x;
ecoord r = -p * a.A.x - q * a.A.y;
ecoord l = p * p + q * q;
if( l == 0 )
return false;
ecoord det1 = p * b.A.x + q * b.A.y + r;
ecoord det2 = p * b.B.x + q * b.B.y + r;
ecoord dsq1 = rescale( det1, det1, l );
ecoord dsq2 = rescale( det2, det2, l );
aD1 = sgn( det1 ) * isqrt( dsq1 );
aD2 = sgn( det2 ) * isqrt( dsq2 );
return true;
}
bool SEG::ApproxCollinear( const SEG& aSeg, int aDistanceThreshold ) const
{
ecoord d1, d2;
if( ! mutualDistance( aSeg, d1, d2 ) )
return false;
return std::abs( d1 ) <= aDistanceThreshold && std::abs( d2 ) <= aDistanceThreshold;
}
bool SEG::ApproxParallel( const SEG& aSeg, int aDistanceThreshold ) const
{
ecoord d1, d2;
if( ! mutualDistance( aSeg, d1, d2 ) )
return false;
return std::abs( d1 - d2 ) <= (ecoord) aDistanceThreshold;
}
bool SEG::ApproxPerpendicular( const SEG& aSeg ) const
{
SEG perp = PerpendicularSeg( A );
return aSeg.ApproxParallel( perp );
}
@@ -1791,6 +1791,12 @@ SHAPE_LINE_CHAIN& SHAPE_LINE_CHAIN::Simplify( bool aRemoveColinear )
const VECTOR2I SHAPE_LINE_CHAIN::NearestPoint( const VECTOR2I& aP,
bool aAllowInternalShapePoints ) const
{
if( PointCount() == 0 )
{
// The only right answer here is "don't crash".
return { 0, 0 };
}
int min_d = INT_MAX;
int nearest = 0;
@@ -1842,6 +1848,12 @@ const VECTOR2I SHAPE_LINE_CHAIN::NearestPoint( const VECTOR2I& aP,
const VECTOR2I SHAPE_LINE_CHAIN::NearestPoint( const SEG& aSeg, int& dist ) const
{
if( PointCount() == 0 )
{
// The only right answer here is "don't crash".
return { 0, 0 };
}
int nearest = 0;
dist = INT_MAX;
+5 -2
View File
@@ -83,15 +83,18 @@ bool KIPLATFORM::APP::IsOperatingSystemUnsupported()
bool KIPLATFORM::APP::RegisterApplicationRestart( const wxString& aCommandLine )
{
// Command line arguments with spaces require quotes.
wxString restartCmd = wxS( "\"" ) + aCommandLine + wxS( "\"" );
// Ensure we don't exceed the maximum allowable size
if( aCommandLine.length() > RESTART_MAX_CMD_LINE - 1 )
if( restartCmd.length() > RESTART_MAX_CMD_LINE - 1 )
{
return false;
}
HRESULT hr = S_OK;
hr = ::RegisterApplicationRestart( aCommandLine.wc_str(), RESTART_NO_PATCH );
hr = ::RegisterApplicationRestart( restartCmd.wc_str(), RESTART_NO_PATCH );
return SUCCEEDED( hr );
}
+9 -1
View File
@@ -2,7 +2,7 @@
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2019 CERN
* Copyright (C) 2019-2021 KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 2019-2022 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
@@ -357,6 +357,14 @@ int PL_EDIT_TOOL::DoDelete( const TOOL_EVENT& aEvent )
if( selection.Size() == 0 )
return 0;
// Do not delete an item if it is currently a new item being created to avoid a crash
// In this case the selection contains only one item.
DS_DRAW_ITEM_BASE* currItem = static_cast<DS_DRAW_ITEM_BASE*>( selection.Front() );
if( currItem->GetFlags() & ( IS_NEW ) )
return 0;
m_frame->SaveCopyInUndoList();
while( selection.Front() )
+9 -3
View File
@@ -437,6 +437,13 @@ if( EXISTS ${CMAKE_CURRENT_BINARY_DIR}/doxygen-xml )
set( SWIG_OPTS ${SWIG_OPTS} -I${CMAKE_CURRENT_BINARY_DIR}/docstrings )
endif()
# This command is needed only with SWIG version < 4 to disable a python section "def swig_import_helper()"
# found at the beginning of pcbnew.py, but not longer existing in SWIG version >= 4
if( ${SWIG_VERSION} VERSION_LESS 4.0.0 )
set( OPT_CMD COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_SOURCE_DIR}/scripting/build_tools/fix_swig_imports.py ${CMAKE_CURRENT_BINARY_DIR}/pcbnew.py )
endif()
add_custom_command( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/pcbnew_wrap.cxx
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/pcbnew.py
@@ -487,9 +494,8 @@ add_custom_command( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/pcbnew_wrap.cxx
COMMAND ${SWIG_EXECUTABLE}
${SWIG_OPTS} -o ${CMAKE_CURRENT_BINARY_DIR}/pcbnew_wrap.cxx ${CMAKE_SOURCE_DIR}/pcbnew/python/swig/pcbnew.i
COMMAND ${PYTHON_EXECUTABLE}
${CMAKE_SOURCE_DIR}/scripting/build_tools/fix_swig_imports.py
${CMAKE_CURRENT_BINARY_DIR}/pcbnew.py
# Optional command for SWIG version < 4 to disable a python section "def swig_import_helper()"
${OPT_CMD}
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
)
@@ -2,7 +2,7 @@
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2019 Jean-Pierre Charras, jp.charras at wanadoo.fr
* Copyright (C) 2019-2021 KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 2019-2022 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
@@ -307,7 +307,8 @@ void PANEL_SETUP_BOARD_STACKUP::onAddDielectricLayer( wxCommandEvent& event )
}
}
EDA_LIST_DIALOG dlg( m_parentDialog, _( "Add Dielectric Layer" ), headers, d_list );
EDA_LIST_DIALOG dlg( m_parentDialog, _( "Add Dielectric Layer" ), headers, d_list,
wxEmptyString, false /* do not sort the list: it is **expected** in stack order */);
dlg.SetListLabel( _( "Select layer to add:" ) );
dlg.HideFilter();
@@ -363,7 +364,8 @@ void PANEL_SETUP_BOARD_STACKUP::onRemoveDielectricLayer( wxCommandEvent& event )
}
}
EDA_LIST_DIALOG dlg( m_parentDialog, _( "Remove Dielectric Layer" ), headers, d_list );
EDA_LIST_DIALOG dlg( m_parentDialog, _( "Remove Dielectric Layer" ), headers, d_list,
wxEmptyString, false /* do not sort the list: it is **expected** in stack order */);
dlg.SetListLabel( _( "Select layer to remove:" ) );
dlg.HideFilter();
@@ -606,7 +608,6 @@ void PANEL_SETUP_BOARD_STACKUP::synchronizeWithBoard( bool aFullSync )
void PANEL_SETUP_BOARD_STACKUP::showOnlyActiveLayers()
{
// Now enable/disable stackup items, according to the m_enabledLayers config
// Calculate copper layer count from m_enabledLayers, and *do not use* brd_stackup
// for that, because it is not necessary up to date
@@ -1214,13 +1215,15 @@ bool PANEL_SETUP_BOARD_STACKUP::TransferDataFromWindow()
void PANEL_SETUP_BOARD_STACKUP::ImportSettingsFrom( BOARD* aBoard )
{
BOARD* savedBrd = m_board;
m_board = aBoard;
BOARD_DESIGN_SETTINGS* savedSettings = m_brdSettings;
m_brdSettings = &aBoard->GetDesignSettings();
m_enabledLayers = m_panelLayers->GetUILayerMask() & BOARD_STACKUP::StackupAllowedBrdLayers();
synchronizeWithBoard( true );
m_enabledLayers = m_board->GetEnabledLayers() & BOARD_STACKUP::StackupAllowedBrdLayers();
rebuildLayerStackPanel();
synchronizeWithBoard( true );
computeBoardThickness();
m_brdSettings = savedSettings;
+6 -6
View File
@@ -669,10 +669,9 @@ void CN_CONNECTIVITY_ALGO::MarkNetAsDirty( int aNet )
void CN_VISITOR::checkZoneItemConnection( CN_ZONE_LAYER* aZoneLayer, CN_ITEM* aItem )
{
if( aZoneLayer->Net() != aItem->Net() && !aItem->CanChangeNet() )
return;
PCB_LAYER_ID layer = aZoneLayer->GetLayer();
if( !aZoneLayer->BBox().Intersects( aItem->BBox() ) )
if( !aItem->Parent()->IsOnLayer( layer ) )
return;
int accuracy = 0;
@@ -703,9 +702,6 @@ void CN_VISITOR::checkZoneZoneConnection( CN_ZONE_LAYER* aZoneLayerA, CN_ZONE_LA
if( aZoneLayerA->Layer() != aZoneLayerB->Layer() )
return;
if( aZoneLayerB->Net() != aZoneLayerA->Net() )
return; // we only test zones belonging to the same net
const BOX2I& boxA = aZoneLayerA->BBox();
const BOX2I& boxB = aZoneLayerB->BBox();
@@ -765,6 +761,10 @@ bool CN_VISITOR::operator()( CN_ITEM* aCandidate )
if( parentA == parentB )
return true;
// Don't connect items in different nets that can't be changed
if( !aCandidate->CanChangeNet() && !m_item->CanChangeNet() && aCandidate->Net() != m_item->Net() )
return true;
LSET commonLayers = parentA->GetLayerSet() & parentB->GetLayerSet();
if( !commonLayers.any() )
+1 -1
View File
@@ -249,8 +249,8 @@ void DIALOG_BOARD_SETUP::OnAuxiliaryAction( wxCommandEvent& event )
// separately, and stackup can be imported only after layers options
if( importDlg.m_LayersOpt->GetValue() )
{
m_layers->ImportSettingsFrom( otherBoard );
m_physicalStackup->ImportSettingsFrom( otherBoard );
m_layers->ImportSettingsFrom( otherBoard );
}
if( importDlg.m_TextAndGraphicsOpt->GetValue() )
@@ -58,9 +58,6 @@ private:
bool m_flipStartEnd;
wxFloatingPointValidator<double> m_AngleValidator;
double m_AngleValue;
public:
DIALOG_GRAPHIC_ITEM_PROPERTIES( PCB_BASE_EDIT_FRAME* aParent, BOARD_ITEM* aItem );
~DIALOG_GRAPHIC_ITEM_PROPERTIES() {};
@@ -94,9 +91,7 @@ DIALOG_GRAPHIC_ITEM_PROPERTIES::DIALOG_GRAPHIC_ITEM_PROPERTIES( PCB_BASE_EDIT_FR
m_bezierCtrl1Y( aParent, m_BezierPointC1YLabel, m_BezierC1Y_Ctrl, m_BezierPointC1YUnit ),
m_bezierCtrl2X( aParent, m_BezierPointC2XLabel, m_BezierC2X_Ctrl, m_BezierPointC2XUnit ),
m_bezierCtrl2Y( aParent, m_BezierPointC2YLabel, m_BezierC2Y_Ctrl, m_BezierPointC2YUnit ),
m_flipStartEnd( false ),
m_AngleValidator( 1, &m_AngleValue ),
m_AngleValue( 0.0 )
m_flipStartEnd( false )
{
m_parent = aParent;
m_item = dynamic_cast<PCB_SHAPE*>( aItem );
@@ -113,9 +108,6 @@ DIALOG_GRAPHIC_ITEM_PROPERTIES::DIALOG_GRAPHIC_ITEM_PROPERTIES( PCB_BASE_EDIT_FR
m_bezierCtrl2Y.SetCoordType( ORIGIN_TRANSFORMS::ABS_Y_COORD );
m_angle.SetUnits( EDA_UNITS::DEGREES );
m_AngleValidator.SetRange( -359.9, 359.9 );
m_angleCtrl->SetValidator( m_AngleValidator );
m_AngleValidator.SetWindow( m_angleCtrl );
// Do not allow locking items in the footprint editor
m_locked->Show( dynamic_cast<PCB_EDIT_FRAME*>( aParent ) != nullptr );
@@ -189,7 +181,7 @@ bool DIALOG_GRAPHIC_ITEM_PROPERTIES::TransferDataToWindow()
case SHAPE_T::ARC:
SetTitle( _( "Arc Properties" ) );
m_AngleValue = m_item->GetArcAngle() / 10.0;
m_angle.SetDoubleValue( m_item->GetArcAngle() );
m_filledCtrl->Show( false );
break;
@@ -310,7 +302,8 @@ bool DIALOG_GRAPHIC_ITEM_PROPERTIES::TransferDataFromWindow()
if( m_item->GetShape() == SHAPE_T::ARC )
{
VECTOR2D center = CalcArcCenter( m_item->GetStart(), m_item->GetEnd(), m_AngleValue );
VECTOR2D center = CalcArcCenter( m_item->GetStart(), m_item->GetEnd(),
m_angle.GetDoubleValue() / 10.0 );
m_item->SetCenter( wxPoint( KiROUND( center.x ), KiROUND( center.y ) ) );
}
+2 -4
View File
@@ -1242,13 +1242,11 @@ bool DIALOG_PAD_PROPERTIES::padValuesOK()
// Test hole size against pad size
if( m_dummyPad->IsOnCopperLayer() )
{
LSET lset = m_dummyPad->GetLayerSet() & LSET::AllCuMask();
PCB_LAYER_ID layer = lset.Seq().at( 0 );
int maxError = m_board->GetDesignSettings().m_MaxError;
SHAPE_POLY_SET padOutline;
m_dummyPad->TransformShapeWithClearanceToPolygon( padOutline, layer, 0, maxError,
ERROR_LOC::ERROR_INSIDE );
m_dummyPad->TransformShapeWithClearanceToPolygon( padOutline, UNDEFINED_LAYER, 0,
maxError, ERROR_INSIDE );
const SHAPE_SEGMENT* drillShape = m_dummyPad->GetEffectiveHoleShape();
const SEG drillSeg = drillShape->GetSeg();
-5
View File
@@ -1345,12 +1345,7 @@ std::shared_ptr<SHAPE> DRC_ENGINE::GetShape( BOARD_ITEM* aItem, PCB_LAYER_ID aLa
if( aPad->GetAttribute() == PAD_ATTRIB::PTH )
{
BOARD_DESIGN_SETTINGS& bds = aPad->GetBoard()->GetDesignSettings();
// Note: drill size represents finish size, which means the actual holes size is the
// plating thickness larger.
auto hole = static_cast<SHAPE_SEGMENT*>( aPad->GetEffectiveHoleShape()->Clone() );
hole->SetWidth( hole->GetWidth() + bds.GetHolePlatingThickness() );
return std::make_shared<SHAPE_SEGMENT>( *hole );
}
+159 -10
View File
@@ -23,10 +23,15 @@
#include <common.h>
#include <pcb_track.h>
#include <pad.h>
#include <footprint.h>
#include <drc/drc_engine.h>
#include <drc/drc_item.h>
#include <drc/drc_rule.h>
#include <drc/drc_test_provider.h>
#include <macros.h>
#include <convert_basic_shapes_to_polygon.h>
#include <board_design_settings.h>
/*
Via/pad annular ring width test. Checks if there's sufficient copper ring around
@@ -87,24 +92,138 @@ bool DRC_TEST_PROVIDER_ANNULAR_WIDTH::Run()
if( !reportPhase( _( "Checking via annular rings..." ) ) )
return false; // DRC cancelled
int maxError = m_drcEngine->GetBoard()->GetDesignSettings().m_MaxError;
auto calcEffort =
[]( BOARD_ITEM* item )
{
switch( item->Type() )
{
case PCB_VIA_T:
return 1;
case PCB_PAD_T:
{
PAD* pad = static_cast<PAD*>( item );
if( !pad->HasHole() || pad->GetAttribute() != PAD_ATTRIB::PTH )
return 0;
if( pad->GetOffset() == wxPoint( 0, 0 ) )
{
switch( pad->GetShape() )
{
case PAD_SHAPE::CHAMFERED_RECT:
if( pad->GetChamferRectRatio() > 0.30 )
break;
KI_FALLTHROUGH;
case PAD_SHAPE::CIRCLE:
case PAD_SHAPE::OVAL:
case PAD_SHAPE::RECT:
case PAD_SHAPE::ROUNDRECT:
return 1;
default:
break;
}
}
return 100;
}
default:
return 0;
}
};
auto checkAnnularWidth =
[&]( BOARD_ITEM* item ) -> bool
{
if( m_drcEngine->IsErrorLimitExceeded( DRCE_ANNULAR_WIDTH ) )
return false;
int v_min = 0;
int v_max = 0;
PCB_VIA* via = dyn_cast<PCB_VIA*>( item );
int annularWidth = 0;
// fixme: check minimum IAR/OAR ring for THT pads too
if( !via )
switch( item->Type() )
{
case PCB_VIA_T:
{
PCB_VIA* via = static_cast<PCB_VIA*>( item );
annularWidth = ( via->GetWidth() - via->GetDrillValue() ) / 2;
break;
}
case PCB_PAD_T:
{
PAD* pad = static_cast<PAD*>( item );
bool handled = false;
if( !pad->HasHole() || pad->GetAttribute() != PAD_ATTRIB::PTH )
return true;
if( pad->GetOffset() == wxPoint( 0, 0 ) )
{
switch( pad->GetShape() )
{
case PAD_SHAPE::CHAMFERED_RECT:
if( pad->GetChamferRectRatio() > 0.30 )
break;
KI_FALLTHROUGH;
case PAD_SHAPE::CIRCLE:
case PAD_SHAPE::OVAL:
case PAD_SHAPE::RECT:
case PAD_SHAPE::ROUNDRECT:
annularWidth = std::min( pad->GetSizeX() - pad->GetDrillSizeX(),
pad->GetSizeY() - pad->GetDrillSizeY() ) / 2;
handled = true;
break;
default:
break;
}
}
if( !handled )
{
// Slow (but general purpose) method.
SHAPE_POLY_SET padOutline;
pad->TransformShapeWithClearanceToPolygon( padOutline, UNDEFINED_LAYER, 0,
maxError, ERROR_INSIDE );
if( !padOutline.Collide( pad->GetPosition() ) )
{
// Hole outside pad
annularWidth = 0;
}
else
{
const SHAPE_SEGMENT* slot = pad->GetEffectiveHoleShape();
// Disable is-inside test in SquaredDistance
padOutline.Outline( 0 ).SetClosed( false );
SEG::ecoord dist_sq = padOutline.SquaredDistance( slot->GetSeg() );
annularWidth = sqrt( dist_sq ) - slot->GetWidth() / 2;
}
}
break;
}
default:
return true;
}
// PADSTACKS TODO: once we have padstacks we'll need to run this per-layer....
auto constraint = m_drcEngine->EvalRules( ANNULAR_WIDTH_CONSTRAINT, via, nullptr,
auto constraint = m_drcEngine->EvalRules( ANNULAR_WIDTH_CONSTRAINT, item, nullptr,
UNDEFINED_LAYER );
int annularWidth = ( via->GetWidth() - via->GetDrillValue() ) / 2;
int v_min = 0;
int v_max = 0;
bool fail_min = false;
bool fail_max = false;
@@ -126,39 +245,69 @@ bool DRC_TEST_PROVIDER_ANNULAR_WIDTH::Run()
wxString msg;
if( fail_min )
{
msg.Printf( _( "(%s min annular width %s; actual %s)" ),
constraint.GetName(),
MessageTextFromValue( userUnits(), v_min ),
MessageTextFromValue( userUnits(), annularWidth ) );
}
if( fail_max )
{
msg.Printf( _( "(%s max annular width %s; actual %s)" ),
constraint.GetName(),
MessageTextFromValue( userUnits(), v_max ),
MessageTextFromValue( userUnits(), annularWidth ) );
}
drcItem->SetErrorMessage( drcItem->GetErrorText() + wxS( " " ) + msg );
drcItem->SetItems( item );
drcItem->SetViolatingRule( constraint.GetParentRule() );
reportViolation( drcItem, via->GetPosition() );
reportViolation( drcItem, item->GetPosition() );
}
return true;
};
BOARD* board = m_drcEngine->GetBoard();
int ii = 0;
size_t ii = 0;
size_t total = 0;
for( PCB_TRACK* item : board->Tracks() )
total += calcEffort( item );
for( FOOTPRINT* footprint : board->Footprints() )
{
for( PAD* pad : footprint->Pads() )
total += calcEffort( pad );
}
for( PCB_TRACK* item : board->Tracks() )
{
if( !reportProgress( ii++, board->Tracks().size(), delta ) )
ii += calcEffort( item );
if( !reportProgress( ii, total, delta ) )
return false; // DRC cancelled
if( !checkAnnularWidth( item ) )
break;
}
for( FOOTPRINT* footprint : board->Footprints() )
{
for( PAD* pad : footprint->Pads() )
{
ii += calcEffort( pad );
if( !reportProgress( ii, total, delta ) )
return false; // DRC cancelled
if( !checkAnnularWidth( pad ) )
break;
}
}
reportRuleStatistics();
return true;
@@ -449,11 +449,6 @@ void DRC_TEST_PROVIDER_COPPER_CLEARANCE::testItemAgainstZones( BOARD_ITEM* aItem
const SHAPE_SEGMENT* hole = pad->GetEffectiveHoleShape();
int size = hole->GetWidth();
// Note: drill size represents finish size, which means the actual hole
// size is 2x the plating thickness larger.
if( pad->GetAttribute() == PAD_ATTRIB::PTH )
size += 2 * m_board->GetDesignSettings().GetHolePlatingThickness();
itemShape = std::make_shared<SHAPE_SEGMENT>( hole->GetSeg(), size );
}
}
@@ -537,7 +532,7 @@ void DRC_TEST_PROVIDER_COPPER_CLEARANCE::testTrackClearances()
reportAux( wxT( "Testing %d tracks & vias..." ), m_board->Tracks().size() );
std::map< std::pair<BOARD_ITEM*, BOARD_ITEM*>, int> checkedPairs;
std::map< std::pair<BOARD_ITEM*, BOARD_ITEM*>, LSET> checkedPairs;
for( PCB_TRACK* track : m_board->Tracks() )
{
@@ -570,13 +565,15 @@ void DRC_TEST_PROVIDER_COPPER_CLEARANCE::testTrackClearances()
if( static_cast<void*>( a ) > static_cast<void*>( b ) )
std::swap( a, b );
if( checkedPairs.count( { a, b } ) )
auto it = checkedPairs.find( { a, b } );
if( it != checkedPairs.end() && it->second.test( layer ) )
{
return false;
}
else
{
checkedPairs[ { a, b } ] = 1;
checkedPairs[ { a, b } ].set( layer );
return true;
}
},
@@ -18,15 +18,14 @@
*/
#include <common.h>
#include <board.h>
#include <board_design_settings.h>
#include <pcb_track.h>
#include <drc/drc_engine.h>
#include <drc/drc_item.h>
#include <drc/drc_rule.h>
#include <drc/drc_test_provider.h>
#include <drc/drc_length_report.h>
#include <drc/drc_rtree.h>
#include <geometry/shape_segment.h>
@@ -277,7 +276,7 @@ bool test::DRC_TEST_PROVIDER_DIFF_PAIR_COUPLING::Run()
{
m_board = m_drcEngine->GetBoard();
int epsilon = m_board->GetDesignSettings().GetDRCEpsilon();
std::map<DIFF_PAIR_KEY, DIFF_PAIR_ITEMS> dpRuleMatches;
@@ -423,10 +422,10 @@ bool test::DRC_TEST_PROVIDER_DIFF_PAIR_COUPLING::Run()
auto val = gapConstraint->GetValue();
bool insideRange = true;
if( val.HasMin() && gap < val.Min() )
if( val.HasMin() && gap < val.Min() - epsilon )
insideRange = false;
if( val.HasMax() && gap > val.Max() )
if( val.HasMax() && gap > val.Max() + epsilon )
insideRange = false;
// if(val.HasMin() && val.HasMax() )
+1 -1
View File
@@ -408,7 +408,7 @@ double FP_TEXT::ViewGetLOD( int aLayer, KIGFX::VIEW* aView ) const
}
wxString FP_TEXT::GetShownText( int aDepth ) const
wxString FP_TEXT::GetShownText( int aDepth, bool aAllowExtraText ) const
{
const FOOTPRINT* parentFootprint = static_cast<FOOTPRINT*>( GetParent() );
wxASSERT( parentFootprint );
+1 -1
View File
@@ -221,7 +221,7 @@ public:
EDA_ITEM* Clone() const override;
virtual wxString GetShownText( int aDepth = 0 ) const override;
virtual wxString GetShownText( int aDepth = 0, bool aAllowExtraText = true ) const override;
virtual const BOX2I ViewBBox() const override;
+17
View File
@@ -156,6 +156,20 @@ bool PAD::IsLocked() const
};
bool PAD::IsNoConnectPad() const
{
return GetShortNetname().StartsWith( wxT( "unconnected-(" ) )
&& ( m_pinType == wxT( "no_connect" ) || m_pinType.EndsWith( wxT( "+no_connect" ) ) );
}
bool PAD::IsFreePad() const
{
return GetShortNetname().StartsWith( wxT( "unconnected-(" ) )
&& m_pinType == wxT( "free" );
}
LSET PAD::PTHMask()
{
static LSET saved = LSET::AllCuMask() | LSET( 2, F_Mask, B_Mask );
@@ -1506,6 +1520,9 @@ void PAD::ImportSettingsFrom( const PAD& aMasterPad )
SetOrientation( pad_rot );
SetRemoveUnconnected( aMasterPad.GetRemoveUnconnected() );
SetKeepTopBottom( aMasterPad.GetKeepTopBottom() );
SetSize( aMasterPad.GetSize() );
SetDelta( wxSize( 0, 0 ) );
SetOffset( aMasterPad.GetOffset() );
+17
View File
@@ -102,6 +102,11 @@ public:
return false;
}
bool HasHole() const
{
return GetDrillSizeX() > 0 && GetDrillSizeY() > 0;
}
FOOTPRINT* GetParent() const;
wxString GetParentAsString() const { return m_parent->m_Uuid.AsString(); }
@@ -155,6 +160,18 @@ public:
return GetParent() == other->GetParent() && m_number == other->m_number;
}
/**
* @return true if the pad is associated with an "unconnected" pin (or a no-connect symbol)
* and has no net.
*/
bool IsNoConnectPad() const;
/**
* @return true if the pad is associated with a "free" pin (not-internally-connected) and has
* not yet been assigned another net (ie: by being routed to).
*/
bool IsFreePad() const;
/**
* Set the new shape of this pad.
*/
+35 -26
View File
@@ -576,6 +576,9 @@ bool isInsideArea( BOARD_ITEM* aItem, const EDA_RECT& aItemBBox, PCB_EXPR_CONTEX
if( !aArea || aArea == aItem || aArea->GetParent() == aItem )
return false;
if( !( aArea->GetLayerSet() & aItem->GetLayerSet() ).any() )
return false;
BOARD* board = aArea->GetBoard();
std::unique_lock<std::mutex> cacheLock( board->m_CachesMutex );
PCB_LAYER_ID layer = aCtx->GetLayer();
@@ -897,7 +900,8 @@ class PCB_LAYER_VALUE : public LIBEVAL::VALUE
{
public:
PCB_LAYER_VALUE( PCB_LAYER_ID aLayer ) :
LIBEVAL::VALUE( double( aLayer ) )
LIBEVAL::VALUE( LayerName( aLayer ) ),
m_layer( aLayer )
{};
virtual bool EqualTo( LIBEVAL::CONTEXT* aCtx, const VALUE* b ) const override
@@ -930,25 +934,25 @@ public:
mask = i->second;
}
PCB_LAYER_ID layerId = ToLAYER_ID( (int) AsDouble() );
return mask.Contains( layerId );
return mask.Contains( m_layer );
}
protected:
PCB_LAYER_ID m_layer;
};
LIBEVAL::VALUE PCB_EXPR_VAR_REF::GetValue( LIBEVAL::CONTEXT* aCtx )
LIBEVAL::VALUE* PCB_EXPR_VAR_REF::GetValue( LIBEVAL::CONTEXT* aCtx )
{
PCB_EXPR_CONTEXT* context = static_cast<PCB_EXPR_CONTEXT*>( aCtx );
if( m_itemIndex == 2 )
{
PCB_EXPR_CONTEXT* context = static_cast<PCB_EXPR_CONTEXT*>( aCtx );
return PCB_LAYER_VALUE( context->GetLayer() );
}
return new PCB_LAYER_VALUE( context->GetLayer() );
BOARD_ITEM* item = GetObject( aCtx );
if( !item )
return LIBEVAL::VALUE();
return new LIBEVAL::VALUE();
auto it = m_matchingTypes.find( TYPE_HASH( *item ) );
@@ -958,12 +962,12 @@ LIBEVAL::VALUE PCB_EXPR_VAR_REF::GetValue( LIBEVAL::CONTEXT* aCtx )
// simpler "A.Via_Type == 'buried'" is perfectly clear. Instead, return an undefined
// value when the property doesn't appear on a particular object.
return LIBEVAL::VALUE();
return new LIBEVAL::VALUE();
}
else
{
if( m_type == LIBEVAL::VT_NUMERIC )
return LIBEVAL::VALUE( (double) item->Get<int>( it->second ) );
return new LIBEVAL::VALUE( (double) item->Get<int>( it->second ) );
else
{
wxString str;
@@ -971,7 +975,7 @@ LIBEVAL::VALUE PCB_EXPR_VAR_REF::GetValue( LIBEVAL::CONTEXT* aCtx )
if( !m_isEnum )
{
str = item->Get<wxString>( it->second );
return LIBEVAL::VALUE( str );
return new LIBEVAL::VALUE( str );
}
else
{
@@ -979,51 +983,56 @@ LIBEVAL::VALUE PCB_EXPR_VAR_REF::GetValue( LIBEVAL::CONTEXT* aCtx )
bool valid = any.GetAs<wxString>( &str );
if( valid )
return LIBEVAL::VALUE( str );
{
if( it->second->Name() == wxT( "Layer" ) )
return new PCB_LAYER_VALUE( context->GetBoard()->GetLayerID( str ) );
else
return new LIBEVAL::VALUE( str );
}
}
return LIBEVAL::VALUE();
return new LIBEVAL::VALUE();
}
}
}
LIBEVAL::VALUE PCB_EXPR_NETCLASS_REF::GetValue( LIBEVAL::CONTEXT* aCtx )
LIBEVAL::VALUE* PCB_EXPR_NETCLASS_REF::GetValue( LIBEVAL::CONTEXT* aCtx )
{
BOARD_ITEM* item = GetObject( aCtx );
if( !item )
return LIBEVAL::VALUE();
return new LIBEVAL::VALUE();
if( item->IsConnected() )
return LIBEVAL::VALUE( static_cast<BOARD_CONNECTED_ITEM*>( item )->GetNetClassName() );
return new LIBEVAL::VALUE( static_cast<BOARD_CONNECTED_ITEM*>( item )->GetNetClassName() );
else
return LIBEVAL::VALUE();
return new LIBEVAL::VALUE();
}
LIBEVAL::VALUE PCB_EXPR_NETNAME_REF::GetValue( LIBEVAL::CONTEXT* aCtx )
LIBEVAL::VALUE* PCB_EXPR_NETNAME_REF::GetValue( LIBEVAL::CONTEXT* aCtx )
{
BOARD_ITEM* item = GetObject( aCtx );
if( !item )
return LIBEVAL::VALUE();
return new LIBEVAL::VALUE();
if( item->IsConnected() )
return LIBEVAL::VALUE( static_cast<BOARD_CONNECTED_ITEM*>( item )->GetNetname() );
return new LIBEVAL::VALUE( static_cast<BOARD_CONNECTED_ITEM*>( item )->GetNetname() );
else
return LIBEVAL::VALUE();
return new LIBEVAL::VALUE();
}
LIBEVAL::VALUE PCB_EXPR_TYPE_REF::GetValue( LIBEVAL::CONTEXT* aCtx )
LIBEVAL::VALUE* PCB_EXPR_TYPE_REF::GetValue( LIBEVAL::CONTEXT* aCtx )
{
BOARD_ITEM* item = GetObject( aCtx );
if( !item )
return LIBEVAL::VALUE();
return new LIBEVAL::VALUE();
return LIBEVAL::VALUE( ENUM_MAP<KICAD_T>::Instance().ToString( item->Type() ) );
return new LIBEVAL::VALUE( ENUM_MAP<KICAD_T>::Instance().ToString( item->Type() ) );
}
+4 -4
View File
@@ -103,7 +103,7 @@ public:
m_matchingTypes[type_hash] = prop;
}
virtual LIBEVAL::VALUE GetValue( LIBEVAL::CONTEXT* aCtx ) override;
LIBEVAL::VALUE* GetValue( LIBEVAL::CONTEXT* aCtx ) override;
BOARD_ITEM* GetObject( const LIBEVAL::CONTEXT* aCtx ) const;
@@ -126,7 +126,7 @@ public:
//printf("*** CreateVarRef %p %d\n", this, aItemIndex );
}
LIBEVAL::VALUE GetValue( LIBEVAL::CONTEXT* aCtx ) override;
LIBEVAL::VALUE* GetValue( LIBEVAL::CONTEXT* aCtx ) override;
};
@@ -141,7 +141,7 @@ public:
//printf("*** CreateVarRef %p %d\n", this, aItemIndex );
}
LIBEVAL::VALUE GetValue( LIBEVAL::CONTEXT* aCtx ) override;
LIBEVAL::VALUE* GetValue( LIBEVAL::CONTEXT* aCtx ) override;
};
@@ -155,7 +155,7 @@ public:
//printf("*** CreateVarRef %p %d\n", this, aItemIndex );
}
LIBEVAL::VALUE GetValue( LIBEVAL::CONTEXT* aCtx ) override;
LIBEVAL::VALUE* GetValue( LIBEVAL::CONTEXT* aCtx ) override;
};
+27 -18
View File
@@ -70,21 +70,26 @@ void PCB_GROUP::RemoveAll()
}
PCB_GROUP* getTopLevelGroup( BOARD_ITEM* aItem, PCB_GROUP* aScope, bool isFootprintEditor )
/*
* @return if not in the footprint editor and aItem is in a footprint, returns the
* footprint's parent group. Otherwise, returns the aItem's parent group.
*/
PCB_GROUP* getClosestGroup( BOARD_ITEM* aItem, bool isFootprintEditor )
{
PCB_GROUP* group = nullptr;
if( isFootprintEditor )
{
group = aItem->GetParentGroup();
}
if( !isFootprintEditor && aItem->GetParent() && aItem->GetParent()->Type() == PCB_FOOTPRINT_T )
return aItem->GetParent()->GetParentGroup();
else
{
if( aItem->GetParent() && aItem->GetParent()->Type() == PCB_FOOTPRINT_T )
group = aItem->GetParent()->GetParentGroup();
else
group = aItem->GetParentGroup();
}
return aItem->GetParentGroup();
}
/// Returns the top level group inside the aScope group, or nullptr
PCB_GROUP* getNestedGroup( BOARD_ITEM* aItem, PCB_GROUP* aScope, bool isFootprintEditor )
{
PCB_GROUP* group = getClosestGroup( aItem, isFootprintEditor );
if( group == aScope )
return nullptr;
while( group && group->GetParentGroup() && group->GetParentGroup() != aScope )
{
@@ -97,19 +102,23 @@ PCB_GROUP* getTopLevelGroup( BOARD_ITEM* aItem, PCB_GROUP* aScope, bool isFootpr
return group;
}
PCB_GROUP* PCB_GROUP::TopLevelGroup( BOARD_ITEM* aItem, PCB_GROUP* aScope, bool isFootprintEditor )
{
PCB_GROUP* candidate = getTopLevelGroup( aItem, aScope, isFootprintEditor );
return candidate == aScope ? nullptr : candidate;
return getNestedGroup( aItem, aScope, isFootprintEditor );
}
bool PCB_GROUP::WithinScope( BOARD_ITEM* aItem, PCB_GROUP* aScope, bool isFootprintEditor )
{
PCB_GROUP* candidate = getTopLevelGroup( aItem, aScope, isFootprintEditor );
PCB_GROUP* group = getClosestGroup( aItem, isFootprintEditor );
return candidate == aScope;
if( group && group == aScope )
return true;
PCB_GROUP* nested = getNestedGroup( aItem, aScope, isFootprintEditor );
return nested && nested->GetParentGroup() && nested->GetParentGroup() == aScope;
}
+6 -1
View File
@@ -1247,6 +1247,9 @@ void PCB_PAINTER::draw( const PAD* aPad, int aLayer )
{
const SHAPE_SIMPLE* poly = static_cast<const SHAPE_SIMPLE*>( shape );
if( poly->PointCount() < 2 ) // Careful of empty pads
break;
if( margin.x < 0 ) // The poly shape must be deflated
{
int numSegs = GetArcToSegmentCount( -margin.x, m_maxError, 360.0 );
@@ -1347,7 +1350,9 @@ void PCB_PAINTER::draw( const PAD* aPad, int aLayer )
// Use ERROR_INSIDE because it avoids Clipper and is therefore much faster.
aPad->TransformShapeWithClearanceToPolygon( polySet, ToLAYER_ID( aLayer ),
clearance, m_maxError, ERROR_INSIDE );
m_gal->DrawPolygon( polySet );
if( polySet.Outline( 0 ).PointCount() > 2 ) // Careful of empty pads
m_gal->DrawPolygon( polySet );
}
}
else if( aPad->GetEffectiveHoleShape() && clearance > 0 )
+1 -1
View File
@@ -53,7 +53,7 @@ PCB_TEXT::~PCB_TEXT()
}
wxString PCB_TEXT::GetShownText( int aDepth ) const
wxString PCB_TEXT::GetShownText( int aDepth, bool aAllowExtraText ) const
{
BOARD* board = dynamic_cast<BOARD*>( GetParent() );
+1 -1
View File
@@ -62,7 +62,7 @@ public:
return false;
}
wxString GetShownText( int aDepth = 0 ) const override;
wxString GetShownText( int aDepth = 0, bool aAllowExtraText = true ) const override;
/// PCB_TEXTs are always visible:
void SetVisible( bool aVisible ) override { /* do nothing */}
+1 -6
View File
@@ -1013,12 +1013,7 @@ std::shared_ptr<SHAPE> PCB_VIA::GetEffectiveShape( PCB_LAYER_ID aLayer, FLASHING
}
else
{
int radius = GetDrillValue() / 2;
if( GetBoard() )
radius += GetBoard()->GetDesignSettings().GetHolePlatingThickness();
return std::make_shared<SHAPE_CIRCLE>( m_Start, radius );
return std::make_shared<SHAPE_CIRCLE>( m_Start, GetDrillValue() / 2 );
}
}
+7 -3
View File
@@ -4500,10 +4500,14 @@ PAD* PCB_PARSER::parsePAD( FOOTPRINT* aParent )
if( !pad->GetRemoveUnconnected() )
pad->SetKeepTopBottom( true );
// Zero-sized pads are not really selectable and likely cause crashes.
// They are not supported by KiCad and are removed on loading
// Zero-sized pads are likely algorithmically unsafe.
if( pad->GetSizeX() <= 0 || pad->GetSizeY() <= 0 )
return nullptr;
{
pad->SetSize( wxSize( IU_PER_MM * 0.001, IU_PER_MM * 0.001 ) );
wxLogWarning( wxT( "Invalid zero-sized pad pinned to 1µm in\nfile: %s\nline: %d\noffset: %d" ),
CurSource(), CurLineNumber(), CurOffset() );
}
return pad.release();
}
+9
View File
@@ -266,6 +266,15 @@ void DRAGGER::SetMode( int aMode )
}
const std::vector<int> DRAGGER::CurrentNets() const
{
if( m_mode == PNS::DM_VIA )
return std::vector<int>( 1, m_draggedVia.net );
else
return std::vector<int>( 1, m_draggedLine.Net() );
}
bool DRAGGER::dragMarkObstacles( const VECTOR2I& aP )
{
// fixme: rewrite using shared_ptr...
+1 -4
View File
@@ -88,10 +88,7 @@ public:
*
* Returns the net code(s) of currently routed track(s).
*/
const std::vector<int> CurrentNets() const override
{
return std::vector<int>( 1, m_draggedLine.Net() );
}
const std::vector<int> CurrentNets() const override;
/**
* Function CurrentLayer()
+4
View File
@@ -51,6 +51,10 @@ bool ITEM::collideSimple( const ITEM* aOther, const NODE* aNode, bool aDifferent
if( aDifferentNetsOnly && m_net == aOther->m_net && m_net >= 0 && aOther->m_net >= 0 )
return false;
// a pad associated with a "free" pin (NIC) doesn't have a net until it has been used
if( aDifferentNetsOnly && ( IsFreePad() || aOther->IsFreePad() ) )
return false;
// check if we are not on completely different layers first
if( !m_layers.Overlaps( aOther->m_layers ) )
return false;
+6
View File
@@ -81,6 +81,7 @@ public:
m_rank = -1;
m_routable = true;
m_isVirtual = false;
m_isFreePad = false;
m_isCompoundShapePrimitive = false;
}
@@ -96,6 +97,7 @@ public:
m_rank = aOther.m_rank;
m_routable = aOther.m_routable;
m_isVirtual = aOther.m_isVirtual;
m_isFreePad = aOther.m_isFreePad;
m_isCompoundShapePrimitive = aOther.m_isCompoundShapePrimitive;
}
@@ -232,6 +234,9 @@ public:
void SetRoutable( bool aRoutable ) { m_routable = aRoutable; }
bool IsRoutable() const { return m_routable; }
void SetIsFreePad( bool aIsFreePad = true ) { m_isFreePad = aIsFreePad; }
bool IsFreePad() const { return m_isFreePad; }
bool IsVirtual() const
{
return m_isVirtual;
@@ -256,6 +261,7 @@ protected:
int m_rank;
bool m_routable;
bool m_isVirtual;
bool m_isFreePad;
bool m_isCompoundShapePrimitive;
};
+43 -24
View File
@@ -251,7 +251,7 @@ bool PNS_PCBNEW_RULE_RESOLVER::QueryConstraint( PNS::CONSTRAINT_TYPE aType,
if( parentA )
{
parentA->SetLayer( (PCB_LAYER_ID) aLayer );
parentA->SetLayer( ToLAYER_ID( aLayer ) );
static_cast<BOARD_CONNECTED_ITEM*>( parentA )->SetNetCode( aItemA->Net(), true );
}
}
@@ -269,13 +269,13 @@ bool PNS_PCBNEW_RULE_RESOLVER::QueryConstraint( PNS::CONSTRAINT_TYPE aType,
if( parentB )
{
parentB->SetLayer( (PCB_LAYER_ID) aLayer );
parentB->SetLayer( ToLAYER_ID( aLayer ) );
static_cast<BOARD_CONNECTED_ITEM*>( parentB )->SetNetCode( aItemB->Net(), true );
}
}
if( parentA )
hostConstraint = drcEngine->EvalRules( hostType, parentA, parentB, (PCB_LAYER_ID) aLayer );
hostConstraint = drcEngine->EvalRules( hostType, parentA, parentB, ToLAYER_ID( aLayer ) );
if( hostConstraint.IsNull() )
return false;
@@ -318,26 +318,39 @@ int PNS_PCBNEW_RULE_RESOLVER::Clearance( const PNS::ITEM* aA, const PNS::ITEM* a
return it->second;
PNS::CONSTRAINT constraint;
int rv = 0;
int layer;
int rv = 0;
LAYER_RANGE layers;
if( !aA->Layers().IsMultilayer() || !aB || aB->Layers().IsMultilayer() )
layer = aA->Layer();
if( !aB )
layers = aA->Layers();
else if( isEdge( aA ) )
layers = aB->Layers();
else if( isEdge( aB ) )
layers = aA->Layers();
else
layer = aB->Layer();
layers = aA->Layers().Intersection( aB->Layers() );
if( isCopper( aA ) && ( !aB || isCopper( aB ) ) )
{
if( QueryConstraint( PNS::CONSTRAINT_TYPE::CT_CLEARANCE, aA, aB, layer, &constraint ) )
rv = constraint.m_Value.Min();
}
// Normalize layer range (no -1 magic numbers)
layers = layers.Intersection( LAYER_RANGE( PCBNEW_LAYER_ID_START, PCB_LAYER_ID_COUNT - 1 ) );
if( isEdge( aA ) || ( aB && isEdge( aB ) ) )
for( int layer = layers.Start(); layer <= layers.End(); ++layer )
{
if( QueryConstraint( PNS::CONSTRAINT_TYPE::CT_EDGE_CLEARANCE, aA, aB, layer, &constraint ) )
if( isCopper( aA ) && ( !aB || isCopper( aB ) ) )
{
if( constraint.m_Value.Min() > rv )
rv = constraint.m_Value.Min();
if( QueryConstraint( PNS::CONSTRAINT_TYPE::CT_CLEARANCE, aA, aB, layer, &constraint ) )
{
if( constraint.m_Value.Min() > rv )
rv = constraint.m_Value.Min();
}
}
if( isEdge( aA ) || ( aB && isEdge( aB ) ) )
{
if( QueryConstraint( PNS::CONSTRAINT_TYPE::CT_EDGE_CLEARANCE, aA, aB, layer, &constraint ) )
{
if( constraint.m_Value.Min() > rv )
rv = constraint.m_Value.Min();
}
}
}
@@ -533,8 +546,8 @@ bool PNS_KICAD_IFACE_BASE::ImportSizes( PNS::SIZES_SETTINGS& aSizes, PNS::ITEM*
viaDiameter = std::max( viaDiameter, constraint.m_Value.Opt() );
}
if( m_ruleResolver->QueryConstraint( PNS::CONSTRAINT_TYPE::CT_VIA_HOLE, aStartItem, nullptr,
m_startLayer, &constraint ) )
if( m_ruleResolver->QueryConstraint( PNS::CONSTRAINT_TYPE::CT_VIA_HOLE, aStartItem,
nullptr, m_startLayer, &constraint ) )
{
viaDrill = std::max( viaDrill, constraint.m_Value.Opt() );
}
@@ -947,6 +960,9 @@ std::unique_ptr<PNS::SOLID> PNS_KICAD_IFACE_BASE::syncPad( PAD* aPad )
solid->SetPadToDie( aPad->GetPadToDieLength() );
solid->SetOrientation( aPad->GetOrientation() );
if( aPad->IsFreePad() )
solid->SetIsFreePad();
wxPoint wx_c = aPad->ShapePos();
wxPoint offset = aPad->GetOffset();
@@ -964,13 +980,16 @@ std::unique_ptr<PNS::SOLID> PNS_KICAD_IFACE_BASE::syncPad( PAD* aPad )
if( aPad->GetAttribute() != PAD_ATTRIB::NPTH )
{
BOARD_DESIGN_SETTINGS& bds = m_board->GetDesignSettings();
slot->SetWidth( slot->GetWidth() + bds.GetHolePlatingThickness() * 2 );
slot->SetWidth( slot->GetWidth() );
}
solid->SetHole( slot );
}
std::shared_ptr<SHAPE> shape = aPad->GetEffectiveShape();
// We generate a single SOLID for a pad, so we have to treat it as ALWAYS_FLASHED and then
// perform layer-specific flashing tests internally.
std::shared_ptr<SHAPE> shape = aPad->GetEffectiveShape( UNDEFINED_LAYER,
FLASHING::ALWAYS_FLASHED );
if( shape->HasIndexableSubshapes() && shape->GetIndexableSubshapeCount() == 1 )
{
@@ -1041,7 +1060,7 @@ std::unique_ptr<PNS::VIA> PNS_KICAD_IFACE_BASE::syncVia( PCB_VIA* aVia )
BOARD_DESIGN_SETTINGS& bds = m_board->GetDesignSettings();
via->SetHole( SHAPE_CIRCLE( aVia->GetPosition(),
aVia->GetDrillValue() / 2 + bds.GetHolePlatingThickness() ) );
aVia->GetDrillValue() / 2 ) );
return via;
}
@@ -1254,14 +1273,14 @@ bool PNS_KICAD_IFACE::IsFlashedOnLayer( const PNS::ITEM* aItem, int aLayer ) con
{
const PCB_VIA* via = static_cast<const PCB_VIA*>( aItem->Parent() );
return via->FlashLayer( static_cast<PCB_LAYER_ID>( aLayer ) );
return via->FlashLayer( ToLAYER_ID( aLayer ) );
}
case PCB_PAD_T:
{
const PAD* pad = static_cast<const PAD*>( aItem->Parent() );
return pad->FlashLayer( static_cast<PCB_LAYER_ID>( aLayer ) );
return pad->FlashLayer( ToLAYER_ID( aLayer ) );
}
default:
+16
View File
@@ -105,6 +105,22 @@ public:
m_end = aOther.m_end;
}
LAYER_RANGE Intersection( const LAYER_RANGE& aOther ) const
{
LAYER_RANGE overlap;
overlap.m_start = std::max( m_start, aOther.m_start );
if( m_end < 0 )
overlap.m_end = aOther.m_end;
else if( aOther.m_end < 0 )
overlap.m_end = m_end;
else
overlap.m_end = std::min( m_end, aOther.m_end );
return overlap;
}
///< Shortcut for comparisons/overlap tests
static LAYER_RANGE All()
{
+14 -7
View File
@@ -134,13 +134,14 @@ ITEM* TOOL_BASE::pickSingleItem( const VECTOR2I& aWhere, int aNet, int aLayer, b
//if( item->Parent() && !item->Parent()->ViewIsVisible() )
// continue;
if( aNet <= 0 || item->Net() == aNet )
if( item->OfKind( ITEM::SOLID_T ) && aIgnorePads )
{
continue;
}
else if( aNet <= 0 || item->Net() == aNet )
{
if( item->OfKind( ITEM::VIA_T | ITEM::SOLID_T ) )
{
if( item->OfKind( ITEM::SOLID_T ) && aIgnorePads )
continue;
SEG::ecoord d = ( item->Shape()->Centre() - aWhere ).SquaredEuclideanNorm();
if( d < dist[2] )
@@ -174,12 +175,18 @@ ITEM* TOOL_BASE::pickSingleItem( const VECTOR2I& aWhere, int aNet, int aLayer, b
}
}
}
else if( item->OfKind( ITEM::SOLID_T ) && item->IsFreePad() )
{
// Allow free pads only when already inside pad
if( item->Shape()->Collide( aWhere ) )
{
prioritized[0] = item;
dist[0] = 0;
}
}
else if ( item->Net() == 0 && m_router->Settings().Mode() == RM_MarkObstacles )
{
// Allow unconnected items as last resort in RM_MarkObstacles mode
if( item->OfKind( ITEM::SOLID_T ) && aIgnorePads )
continue;
if( item->Layers().Overlaps( tl ) )
prioritized[4] = item;
}
+100 -12
View File
@@ -49,6 +49,7 @@ using namespace std::placeholders;
#include <tools/pcb_actions.h>
#include <tools/pcb_selection_tool.h>
#include <tools/pcb_grid_helper.h>
#include <string_utils.h>
#include "router_tool.h"
#include "pns_segment.h"
@@ -170,7 +171,8 @@ static const TOOL_ACTION ACT_SwitchCornerMode( "pcbnew.InteractiveRouter.SwitchR
ROUTER_TOOL::ROUTER_TOOL() :
TOOL_BASE( "pcbnew.InteractiveRouter" ),
m_lastTargetLayer( UNDEFINED_LAYER )
m_lastTargetLayer( UNDEFINED_LAYER ),
m_inRouterTool( false )
{
}
@@ -615,6 +617,54 @@ void ROUTER_TOOL::switchLayerOnViaPlacement()
m_router->SwitchLayer( *newLayer );
m_lastTargetLayer = *newLayer;
updateSizesAfterLayerSwitch( ToLAYER_ID( *newLayer ) );
}
void ROUTER_TOOL::updateSizesAfterLayerSwitch( PCB_LAYER_ID targetLayer )
{
std::vector<int> nets = m_router->GetCurrentNets();
PNS::SIZES_SETTINGS sizes = m_router->Sizes();
BOARD_DESIGN_SETTINGS& bds = board()->GetDesignSettings();
std::shared_ptr<DRC_ENGINE>& drcEngine = bds.m_DRCEngine;
DRC_CONSTRAINT constraint;
PCB_TRACK dummyTrack( board() );
dummyTrack.SetLayer( targetLayer );
dummyTrack.SetNetCode( nets.empty() ? 0 : nets[0] );
if( bds.UseNetClassTrack() || !sizes.TrackWidthIsExplicit() )
{
constraint = drcEngine->EvalRules( TRACK_WIDTH_CONSTRAINT, &dummyTrack, nullptr,
targetLayer );
if( !constraint.IsNull() )
sizes.SetTrackWidth( std::max( bds.m_TrackMinWidth, constraint.m_Value.Opt() ) );
}
if( nets.size() >= 2 && ( bds.UseNetClassDiffPair() || !sizes.TrackWidthIsExplicit() ) )
{
PCB_TRACK dummyTrackB( board() );
dummyTrackB.SetLayer( targetLayer );
dummyTrackB.SetNetCode( nets[1] );
constraint = drcEngine->EvalRules( TRACK_WIDTH_CONSTRAINT, &dummyTrack, &dummyTrackB,
targetLayer );
if( !constraint.IsNull() )
sizes.SetDiffPairWidth( std::max( bds.m_TrackMinWidth, constraint.m_Value.Opt() ) );
constraint = drcEngine->EvalRules( DIFF_PAIR_GAP_CONSTRAINT, &dummyTrack, &dummyTrackB,
targetLayer );
if( !constraint.IsNull() )
sizes.SetDiffPairGap( std::max( bds.m_MinClearance, constraint.m_Value.Opt() ) );
}
m_router->UpdateSizes( sizes );
frame()->UpdateMsgPanel();
}
@@ -782,6 +832,7 @@ int ROUTER_TOOL::handleLayerSwitch( const TOOL_EVENT& aEvent, bool aForceVia )
if( !aForceVia && m_router && m_router->SwitchLayer( targetLayer ) )
{
updateSizesAfterLayerSwitch( targetLayer );
updateEndItem( aEvent );
m_router->Move( m_endSnapPoint, m_endItem ); // refresh
return 0;
@@ -1348,6 +1399,11 @@ void ROUTER_TOOL::breakTrack()
int ROUTER_TOOL::MainLoop( const TOOL_EVENT& aEvent )
{
if( m_inRouterTool )
return 0;
REENTRANCY_GUARD guard( &m_inRouterTool );
PNS::ROUTER_MODE mode = aEvent.Parameter<PNS::ROUTER_MODE>();
PCB_EDIT_FRAME* frame = getEditFrame<PCB_EDIT_FRAME>();
VIEW_CONTROLS* controls = getViewControls();
@@ -1459,6 +1515,7 @@ int ROUTER_TOOL::MainLoop( const TOOL_EVENT& aEvent )
else if( evt->IsAction( &PCB_ACTIONS::layerChanged ) )
{
m_router->SwitchLayer( frame->GetActiveLayer() );
updateSizesAfterLayerSwitch( frame->GetActiveLayer() );
updateStartItem( *evt );
}
else if( evt->IsKeyPressed() )
@@ -1705,10 +1762,10 @@ int ROUTER_TOOL::InlineDrag( const TOOL_EVENT& aEvent )
item->SetLocked( false );
}
m_toolMgr->RunAction( PCB_ACTIONS::selectionClear, true );
Activate();
m_toolMgr->RunAction( PCB_ACTIONS::selectionClear, true );
m_router->SyncWorld();
m_startItem = nullptr;
PNS::ITEM* startItem = nullptr;
@@ -1985,10 +2042,10 @@ int ROUTER_TOOL::InlineBreakTrack( const TOOL_EVENT& aEvent )
if( item->Type() != PCB_TRACE_T )
return 0;
m_toolMgr->RunAction( PCB_ACTIONS::selectionClear, true );
Activate();
m_toolMgr->RunAction( PCB_ACTIONS::selectionClear, true );
m_router->SyncWorld();
m_startItem = m_router->GetWorld()->FindItemByParent( item );
TOOL_MANAGER* toolManager = frame()->GetToolManager();
@@ -2085,22 +2142,53 @@ void ROUTER_TOOL::UpdateMessagePanel()
PNS::SIZES_SETTINGS sizes( m_router->Sizes() );
PNS::RULE_RESOLVER* resolver = m_iface->GetRuleResolver();
bool isDiffPair = m_router->Mode() == PNS::ROUTER_MODE::PNS_MODE_ROUTE_DIFF_PAIR;
std::vector<int> nets = m_router->GetCurrentNets();
wxString description;
wxString secondary;
if( m_startItem && m_startItem->Net() > 0 )
if( isDiffPair )
{
wxString description = isDiffPair ? _( "Routing Diff Pair: %s" ) : _( "Routing Track: %s" );
wxASSERT( nets.size() >= 2 );
NETINFO_ITEM* netInfo = board()->FindNet( m_startItem->Net() );
wxASSERT( netInfo );
NETINFO_ITEM* netA = board()->FindNet( nets[0] );
NETINFO_ITEM* netB = board()->FindNet( nets[1] );
wxASSERT( netA );
wxASSERT( netB );
items.emplace_back( wxString::Format( description, netInfo->GetNetname() ),
wxString::Format( _( "Net Class: %s" ), netInfo->GetNetClassName() ) );
description = wxString::Format( _( "Routing Diff Pair: %s" ),
netA->GetNetname() + wxT( ", " ) + netB->GetNetname() );
wxString netclass;
NETCLASS* netclassA = netA->GetNetClass();
NETCLASS* netclassB = netB->GetNetClass();
if( netclassA == netclassB )
netclass = netclassA->GetName();
else
netclass = netclassA->GetName() + wxT( ", " ) + netclassB->GetName();
secondary = wxString::Format( _( "Net Class: %s" ),
UnescapeString( netclass ) );
}
else if( !nets.empty() )
{
NETINFO_ITEM* net = board()->FindNet( nets[0] );
wxASSERT( net );
description = wxString::Format( _( "Routing Track: %s" ),
net->GetNetname() );
secondary = wxString::Format( _( "Net Class: %s" ),
UnescapeString( net->GetNetClass()->GetName() ) );
}
else
{
items.emplace_back( _( "Routing Track" ), _( "(no net)" ) );
description = _( "Routing Track" );
secondary = _( "(no net)" );
}
items.emplace_back( description, secondary );
wxString cornerMode;
if( m_router->Settings().GetFreeAngleMode() )
+3
View File
@@ -75,6 +75,7 @@ private:
int getStartLayer( const PNS::ITEM* aItem );
void switchLayerOnViaPlacement();
void updateSizesAfterLayerSwitch( PCB_LAYER_ID targetLayer );
int onLayerCommand( const TOOL_EVENT& aEvent );
int onViaCommand( const TOOL_EVENT& aEvent );
@@ -89,6 +90,8 @@ private:
std::shared_ptr<ACTION_MENU> m_trackViaMenu;
int m_lastTargetLayer;
bool m_inRouterTool; // Re-entrancy guard
};
#endif
@@ -83,11 +83,11 @@ bool PCB_EDIT_FRAME::ImportSpecctraSession( const wxString& fullFileName )
return false;
}
OnModify();
GetBoard()->GetConnectivity()->Clear();
GetBoard()->GetConnectivity()->Build( GetBoard() );
OnModify();
if( GetCanvas() ) // Update view:
{
// Update footprint positions
+15 -14
View File
@@ -2376,7 +2376,7 @@ int DRAWING_TOOL::DrawVia( const TOOL_EVENT& aEvent )
{
BOARD_ITEM* item = static_cast<BOARD_ITEM*>( it.first );
if( !(item->GetLayerSet() & lset ).any() )
if( !( item->GetLayerSet() & lset ).any() )
continue;
if( PCB_TRACK* track = dyn_cast<PCB_TRACK*>( item ) )
@@ -2412,25 +2412,26 @@ int DRAWING_TOOL::DrawVia( const TOOL_EVENT& aEvent )
if( DRC_ENGINE::IsNetTie( aOther ) )
return false;
DRC_CONSTRAINT constraint;
DRC_CONSTRAINT constraint;
int clearance;
BOARD_CONNECTED_ITEM* connectedItem = dynamic_cast<BOARD_CONNECTED_ITEM*>( aOther );
ZONE* zone = dynamic_cast<ZONE*>( aOther );
if( ( aOther->Type() == PCB_ZONE_T || aOther->Type() == PCB_FP_ZONE_T )
&& static_cast<ZONE*>( aOther )->GetIsRuleArea() )
if( zone && zone->GetIsRuleArea() )
{
ZONE* ruleArea = static_cast<ZONE*>( aOther );
if( ruleArea->GetDoNotAllowVias() )
return ruleArea->Outline()->Collide( aVia->GetPosition(), aVia->GetWidth() / 2 );
if( zone->GetDoNotAllowVias() )
return zone->Outline()->Collide( aVia->GetPosition(), aVia->GetWidth() / 2 );
return false;
}
BOARD_CONNECTED_ITEM* cItem = dynamic_cast<BOARD_CONNECTED_ITEM*>( aOther );
if( connectedItem )
{
int connectedItemNet = connectedItem->GetNetCode();
if( cItem && cItem->GetNetCode() == aVia->GetNetCode() )
return false;
int clearance;
if( connectedItemNet == 0 || connectedItemNet == aVia->GetNetCode() )
return false;
}
for( PCB_LAYER_ID layer : aOther->GetLayerSet().Seq() )
{
@@ -2576,7 +2577,7 @@ int DRAWING_TOOL::DrawVia( const TOOL_EVENT& aEvent )
{
for( ZONE* z : m_board->Zones() )
{
if( z->IsOnLayer( m_frame->GetActiveLayer() ) )
if( z->IsOnLayer( layer ) )
{
if( z->HitTestFilledArea( layer, position ) )
return z->GetNetCode();
+137 -93
View File
@@ -290,20 +290,49 @@ int EDIT_TOOL::Drag( const TOOL_EVENT& aEvent )
sTool->FilterCollectorForFreePads( aCollector );
sTool->FilterCollectorForHierarchy( aCollector, true );
// drop a knee between two segments to a single segment
if( aCollector.GetCount() == 2 && dynamic_cast<PCB_TRACK*>( aCollector[0] ) )
if( aCollector.GetCount() > 1 )
sTool->GuessSelectionCandidates( aCollector, aPt );
/*
* If we have a knee between two segments, or a via attached to two segments,
* then drop the selection to a single item.
*/
std::vector<PCB_TRACK*> tracks;
std::vector<PCB_TRACK*> vias;
for( EDA_ITEM* item : aCollector )
{
static KICAD_T types[] = { PCB_VIA_T, PCB_TRACE_T, PCB_ARC_T, EOT };
if( PCB_TRACK* track = dynamic_cast<PCB_TRACK*>( item ) )
{
if( track->Type() == PCB_VIA_T )
vias.push_back( track );
else
tracks.push_back( track );
}
}
PCB_TRACK* a = static_cast<PCB_TRACK*>( aCollector[0] );
PCB_TRACK* b = static_cast<PCB_TRACK*>( aCollector[1] );
const auto& c = aCollector[0]->GetBoard()->GetConnectivity();
auto connected = []( PCB_TRACK* track, const wxPoint& pt )
{
return track->GetStart() == pt || track->GetEnd() == pt;
};
int dist = a->GetWidth() / 2;
auto connectedItems = c->GetConnectedItemsAtAnchor( a, aPt, types, dist );
if( alg::contains( connectedItems, b ) )
aCollector.Remove( b );
if( tracks.size() == 2 && vias.size() == 0 )
{
if( connected( tracks[0], tracks[1]->GetStart() )
|| connected( tracks[0], tracks[1]->GetEnd() ) )
{
aCollector.Remove( tracks[1] );
}
}
else if( tracks.size() == 2 && vias.size() == 1 )
{
if( connected( tracks[0], vias[0]->GetPosition() )
&& connected( tracks[1], vias[0]->GetPosition() ) )
{
aCollector.Remove( tracks[0] );
aCollector.Remove( tracks[1] );
}
}
},
true /* prompt user regarding locked items */ );
@@ -703,7 +732,7 @@ int EDIT_TOOL::MoveWithReference( const TOOL_EVENT& aEvent )
// Note: aEvent MUST NOT be const&; the source will get de-allocated if we go into the picker's
// event loop.
int EDIT_TOOL::doMoveSelection( TOOL_EVENT aEvent, bool aPickReference )
int EDIT_TOOL::doMoveSelection( TOOL_EVENT aEvent, bool aPickReference, bool aReselect )
{
PCB_BASE_EDIT_FRAME* editFrame = getEditFrame<PCB_BASE_EDIT_FRAME>();
KIGFX::VIEW_CONTROLS* controls = getViewControls();
@@ -1082,6 +1111,15 @@ int EDIT_TOOL::doMoveSelection( TOOL_EVENT aEvent, bool aPickReference )
// Discard reference point when selection is "dropped" onto the board
selection.ClearReferencePoint();
// Unselect all items to clear selection flags and then re-select the originally selected
// items.
m_toolMgr->RunAction( PCB_ACTIONS::selectionClear, true );
// In the case where the original items are temporary, we don't want to reselect
// as the items may be invalidated by the Revert above
if( !restore_state || aReselect )
m_toolMgr->RunAction( PCB_ACTIONS::selectItems, true, &orig_items );
// TODO: there's an encapsulation leak here: this commit often has more than just the move
// in it; for instance it might have a paste, append board, etc. as well.
if( restore_state )
@@ -1092,11 +1130,6 @@ int EDIT_TOOL::doMoveSelection( TOOL_EVENT aEvent, bool aPickReference )
// Remove the dynamic ratsnest from the screen
m_toolMgr->RunAction( PCB_ACTIONS::hideDynamicRatsnest, true );
// Unselect all items to clear selection flags and then re-select the originally selected
// items.
m_toolMgr->RunAction( PCB_ACTIONS::selectionClear, true );
m_toolMgr->RunAction( PCB_ACTIONS::selectItems, true, &orig_items );
editFrame->PopTool( tool );
editFrame->GetCanvas()->SetCurrentCursor( KICURSOR::ARROW );
@@ -1760,82 +1793,12 @@ int EDIT_TOOL::Flip( const TOOL_EVENT& aEvent )
}
int EDIT_TOOL::Remove( const TOOL_EVENT& aEvent )
void EDIT_TOOL::DeleteItems( const PCB_SELECTION& aItems, bool aIsCut )
{
PCB_BASE_EDIT_FRAME* editFrame = getEditFrame<PCB_BASE_EDIT_FRAME>();
if( isRouterActive() )
{
m_toolMgr->RunAction( PCB_ACTIONS::routerUndoLastSegment, true );
return 0;
}
std::string tool = aEvent.GetCommandStr().value();
editFrame->PushTool( tool );
std::vector<BOARD_ITEM*> lockedItems;
Activate();
// get a copy instead of reference (as we're going to clear the selection before removing items)
PCB_SELECTION selectionCopy;
bool isCut = aEvent.Parameter<PCB_ACTIONS::REMOVE_FLAGS>() == PCB_ACTIONS::REMOVE_FLAGS::CUT;
bool isAlt = aEvent.Parameter<PCB_ACTIONS::REMOVE_FLAGS>() == PCB_ACTIONS::REMOVE_FLAGS::ALT;
// If we are in a "Cut" operation, then the copied selection exists already and we want to
// delete exactly that; no more, no fewer. Any filtering for locked items must be done in
// the copyToClipboard() routine.
if( isCut )
{
selectionCopy = m_selectionTool->GetSelection();
}
else
{
// When not in free-pad mode we normally auto-promote selected pads to their parent
// footprints. But this is probably a little too dangerous for a destructive operation,
// so we just do the promotion but not the deletion (allowing for a second delete to do
// it if that's what the user wanted).
selectionCopy = m_selectionTool->RequestSelection(
[]( const VECTOR2I& aPt, GENERAL_COLLECTOR& aCollector, PCB_SELECTION_TOOL* sTool )
{
} );
size_t beforeFPCount = selectionCopy.CountType( PCB_FOOTPRINT_T );
m_selectionTool->RequestSelection(
[]( const VECTOR2I& aPt, GENERAL_COLLECTOR& aCollector, PCB_SELECTION_TOOL* sTool )
{
sTool->FilterCollectorForFreePads( aCollector );
} );
if( !selectionCopy.IsHover()
&& m_selectionTool->GetSelection().CountType( PCB_FOOTPRINT_T ) > beforeFPCount )
{
wxBell();
canvas()->Refresh();
editFrame->PopTool( tool );
return 0;
}
// In "alternative" mode, we expand selected track items to their full connection.
if( isAlt && ( selectionCopy.HasType( PCB_TRACE_T ) || selectionCopy.HasType( PCB_VIA_T ) ) )
{
m_toolMgr->RunAction( PCB_ACTIONS::selectConnection, true );
}
// Finally run RequestSelection() one more time to find out what user wants to do about
// locked objects.
selectionCopy = m_selectionTool->RequestSelection(
[]( const VECTOR2I& aPt, GENERAL_COLLECTOR& aCollector, PCB_SELECTION_TOOL* sTool )
{
sTool->FilterCollectorForFreePads( aCollector );
},
true /* prompt user regarding locked items */ );
}
// As we are about to remove items, they have to be removed from the selection first
m_toolMgr->RunAction( PCB_ACTIONS::selectionClear, true );
for( EDA_ITEM* item : selectionCopy )
for( EDA_ITEM* item : aItems )
{
PCB_GROUP* parentGroup = static_cast<BOARD_ITEM*>( item )->GetParentGroup();
@@ -1891,7 +1854,7 @@ int EDIT_TOOL::Remove( const TOOL_EVENT& aEvent )
// is called from inside a cutout when the zone is selected.
{
// Only interact with cutouts when deleting and a single item is selected
if( !isCut && selectionCopy.GetSize() == 1 )
if( !aIsCut && aItems.GetSize() == 1 )
{
VECTOR2I curPos = getViewControls()->GetCursorPosition();
ZONE* zone = static_cast<ZONE*>( item );
@@ -1978,10 +1941,91 @@ int EDIT_TOOL::Remove( const TOOL_EVENT& aEvent )
if( enteredGroup && enteredGroup->GetItems().empty() )
m_selectionTool->ExitGroup();
if( isCut )
if( aIsCut )
m_commit->Push( _( "Cut" ) );
else
m_commit->Push( _( "Delete" ) );
}
int EDIT_TOOL::Remove( const TOOL_EVENT& aEvent )
{
PCB_BASE_EDIT_FRAME* editFrame = getEditFrame<PCB_BASE_EDIT_FRAME>();
if( isRouterActive() )
{
m_toolMgr->RunAction( PCB_ACTIONS::routerUndoLastSegment, true );
return 0;
}
std::string tool{};
if( aEvent.GetCommandStr() )
{
tool = aEvent.GetCommandStr().value();
editFrame->PushTool( tool );
}
std::vector<BOARD_ITEM*> lockedItems;
Activate();
// get a copy instead of reference (as we're going to clear the selection before removing items)
PCB_SELECTION selectionCopy;
bool isCut = aEvent.Parameter<PCB_ACTIONS::REMOVE_FLAGS>() == PCB_ACTIONS::REMOVE_FLAGS::CUT;
bool isAlt = aEvent.Parameter<PCB_ACTIONS::REMOVE_FLAGS>() == PCB_ACTIONS::REMOVE_FLAGS::ALT;
// If we are in a "Cut" operation, then the copied selection exists already and we want to
// delete exactly that; no more, no fewer. Any filtering for locked items must be done in
// the copyToClipboard() routine.
if( isCut )
{
selectionCopy = m_selectionTool->GetSelection();
}
else
{
// When not in free-pad mode we normally auto-promote selected pads to their parent
// footprints. But this is probably a little too dangerous for a destructive operation,
// so we just do the promotion but not the deletion (allowing for a second delete to do
// it if that's what the user wanted).
selectionCopy = m_selectionTool->RequestSelection(
[]( const VECTOR2I& aPt, GENERAL_COLLECTOR& aCollector, PCB_SELECTION_TOOL* sTool )
{
} );
size_t beforeFPCount = selectionCopy.CountType( PCB_FOOTPRINT_T );
m_selectionTool->RequestSelection(
[]( const VECTOR2I& aPt, GENERAL_COLLECTOR& aCollector, PCB_SELECTION_TOOL* sTool )
{
sTool->FilterCollectorForFreePads( aCollector );
} );
if( !selectionCopy.IsHover()
&& m_selectionTool->GetSelection().CountType( PCB_FOOTPRINT_T ) > beforeFPCount )
{
wxBell();
canvas()->Refresh();
editFrame->PopTool( tool );
return 0;
}
// In "alternative" mode, we expand selected track items to their full connection.
if( isAlt && ( selectionCopy.HasType( PCB_TRACE_T ) || selectionCopy.HasType( PCB_VIA_T ) ) )
{
m_toolMgr->RunAction( PCB_ACTIONS::selectConnection, true );
}
// Finally run RequestSelection() one more time to find out what user wants to do about
// locked objects.
selectionCopy = m_selectionTool->RequestSelection(
[]( const VECTOR2I& aPt, GENERAL_COLLECTOR& aCollector, PCB_SELECTION_TOOL* sTool )
{
sTool->FilterCollectorForFreePads( aCollector );
},
true /* prompt user regarding locked items */ );
}
DeleteItems( selectionCopy, isCut );
editFrame->PopTool( tool );
return 0;
@@ -2220,7 +2264,7 @@ int EDIT_TOOL::Duplicate( const TOOL_EVENT& aEvent )
// If items were duplicated, pick them up
// this works well for "dropping" copies around and pushes the commit
TOOL_EVENT evt = PCB_ACTIONS::move.MakeEvent();
Move( evt );
doMoveSelection( evt, false, false );
// Deslect the duplicated item if we originally started as a hover selection
if( is_hover )
@@ -2465,7 +2509,7 @@ int EDIT_TOOL::cutToClipboard( const TOOL_EVENT& aEvent )
// N.B. Setting the CUT flag prevents lock filtering as we only want to delete the items
// that were copied to the clipboard, no more, no fewer. Filtering for locked item, if
// any will be done in the copyToClipboard() routine
TOOL_EVENT evt( aEvent.Category(), aEvent.Action(), TOOL_ACTION_SCOPE::AS_GLOBAL );
TOOL_EVENT evt( aEvent.Category(), aEvent.Action(), "Cut", TOOL_ACTION_SCOPE::AS_GLOBAL );
evt.SetParameter( PCB_ACTIONS::REMOVE_FLAGS::CUT );
Remove( evt );
}
+3 -1
View File
@@ -123,6 +123,8 @@ public:
*/
int Remove( const TOOL_EVENT& aEvent );
void DeleteItems( const PCB_SELECTION& aItems, bool aIsCut );
/**
* Duplicate the current selection and starts a move action.
*/
@@ -180,7 +182,7 @@ private:
bool invokeInlineRouter( int aDragMode );
bool isRouterActive() const;
int doMoveSelection( TOOL_EVENT aEvent, bool aPickReference = false );
int doMoveSelection( TOOL_EVENT aEvent, bool aPickReference = false, bool aReselect = true );
bool pickReferencePoint( const wxString& aTooltip, const wxString& aSuccessMessage,
const wxString& aCanceledMessage, VECTOR2I& aReferencePoint );
+3 -3
View File
@@ -59,7 +59,7 @@ void PAD_TOOL::Reset( RESET_REASON aReason )
if( aReason == MODEL_RELOAD )
m_lastPadNumber = wxT( "1" );
if( m_editPad != niluuid )
if( board() && board()->GetItem( m_editPad ) == DELETED_BOARD_ITEM::GetInstance() )
{
PCB_DISPLAY_OPTIONS opts = frame()->GetDisplayOptions();
bool highContrast = ( opts.m_ContrastModeDisplay != HIGH_CONTRAST_MODE::NORMAL );
@@ -68,9 +68,9 @@ void PAD_TOOL::Reset( RESET_REASON aReason )
m_toolMgr->RunAction( ACTIONS::highContrastMode, true );
frame()->GetInfoBar()->Dismiss();
}
m_editPad = niluuid;
m_editPad = niluuid;
}
}
+86 -2
View File
@@ -591,8 +591,13 @@ int PCB_CONTROL::DeleteItemCursor( const TOOL_EVENT& aEvent )
PCB_SELECTION_TOOL* selectionTool = m_toolMgr->GetTool<PCB_SELECTION_TOOL>();
selectionTool->UnbrightenItem( m_pickerItem );
selectionTool->AddItemToSel( m_pickerItem, true /*quiet mode*/ );
m_toolMgr->RunAction( ACTIONS::doDelete, true );
PCB_SELECTION items;
items.Add( m_pickerItem );
EDIT_TOOL* editTool = m_toolMgr->GetTool<EDIT_TOOL>();
editTool->DeleteItems( items, false );
m_pickerItem = nullptr;
}
@@ -724,6 +729,79 @@ static void pasteFootprintItemsToFootprintEditor( FOOTPRINT* aClipFootprint, BOA
}
void PCB_CONTROL::pruneItemLayers( std::vector<BOARD_ITEM*>& aItems )
{
LSET enabledLayers = board()->GetEnabledLayers();
std::vector<BOARD_ITEM*> returnItems;
bool fpItemDeleted = false;
auto processFPItem =
[&]( FOOTPRINT* aFootprint, BOARD_ITEM* aItem )
{
LSET allowed = aItem->GetLayerSet() & enabledLayers;
if( allowed.any() )
{
aItem->SetLayerSet( allowed );
}
else
{
aFootprint->Remove( aItem );
fpItemDeleted = true;
}
};
for( BOARD_ITEM* item : aItems )
{
if( item->Type() == PCB_FOOTPRINT_T )
{
FOOTPRINT* fp = static_cast<FOOTPRINT*>( item );
if( !enabledLayers.test( fp->Reference().GetLayer() ) )
fp->Reference().SetLayer( fp->IsFlipped() ? B_SilkS : F_SilkS );
if( !enabledLayers.test( fp->Value().GetLayer() ) )
fp->Value().SetLayer( fp->IsFlipped() ? B_Fab : F_Fab );
// NOTE: all traversals from the back as processFPItem() might delete the item
for( int ii = static_cast<int>( fp->Pads().size() ) - 1; ii >= 0; ii-- )
processFPItem( fp, fp->Pads()[ii] );
for( int ii = static_cast<int>( fp->Zones().size() ) - 1; ii >= 0; ii-- )
processFPItem( fp, fp->Zones()[ii] );
for( int ii = static_cast<int>( fp->GraphicalItems().size() ) - 1; ii >= 0; ii-- )
processFPItem( fp, fp->GraphicalItems()[ii] );
if( fp->GraphicalItems().size() || fp->Pads().size() || fp->Zones().size() )
returnItems.push_back( fp );
}
else
{
LSET allowed = item->GetLayerSet() & enabledLayers;
if( allowed.any() )
{
item->SetLayerSet( allowed );
returnItems.push_back( item );
}
}
}
if( ( returnItems.size() < aItems.size() ) || fpItemDeleted )
{
// We have no existing strings in 6.0 that are even remotely appropriate here, so the
// best we can do is show the user English and let them use Google Translate.
DisplayError( m_frame, wxT( "Warning: some pasted items were on layers which are not "
"present in the current board.\n"
"These items could not be pasted.\n" ) );
}
aItems = returnItems;
}
int PCB_CONTROL::Paste( const TOOL_EVENT& aEvent )
{
CLIPBOARD_IO pi;
@@ -813,6 +891,8 @@ int PCB_CONTROL::Paste( const TOOL_EVENT& aEvent )
delete clipBoard;
pruneItemLayers( pastedItems );
placeBoardItems( pastedItems, true, true,
pasteMode == PASTE_MODE::UNIQUE_ANNOTATIONS );
}
@@ -859,6 +939,8 @@ int PCB_CONTROL::Paste( const TOOL_EVENT& aEvent )
pastedItems.push_back( clipFootprint );
}
pruneItemLayers( pastedItems );
placeBoardItems( pastedItems, true, true, pasteMode == PASTE_MODE::UNIQUE_ANNOTATIONS );
break;
}
@@ -974,6 +1056,8 @@ int PCB_CONTROL::placeBoardItems( BOARD* aBoard, bool aAnchorAtOrigin, bool aRea
// selection created aBoard that has the group and all descendants in it.
moveUnflaggedItems( aBoard->Groups(), items, isNew );
pruneItemLayers( items );
return placeBoardItems( items, isNew, aAnchorAtOrigin, aReannotateDuplicates );
}
+6
View File
@@ -109,6 +109,12 @@ private:
*/
void unfilledZoneCheck();
/**
* Helper for pasting. Remove non-enabled layers from the items in \a aItems. If an item
* exists only on non-enabled layers, it will be removed entirely.
*/
void pruneItemLayers( std::vector<BOARD_ITEM*>& aItems );
/**
* Add and select or just select for move/place command a list of board items.
*
+2 -2
View File
@@ -27,8 +27,6 @@
#include "pcb_actions.h"
#include "pcb_grid_helper.h"
#include <view/view_controls.h>
#include <tool/tool_manager.h>
#include "pcb_selection_tool.h"
PCB_PICKER_TOOL::PCB_PICKER_TOOL() :
@@ -57,6 +55,7 @@ int PCB_PICKER_TOOL::Main( const TOOL_EVENT& aEvent )
[&]()
{
frame->GetCanvas()->SetCurrentCursor( m_cursor );
controls->ShowCursor( true );
};
// Set initial cursor
@@ -168,6 +167,7 @@ int PCB_PICKER_TOOL::Main( const TOOL_EVENT& aEvent )
reset();
controls->ForceCursorPosition( false );
controls->ShowCursor( false );
if( !tool.empty() )
frame->PopTool( tool );
+16 -15
View File
@@ -522,8 +522,11 @@ PCB_SELECTION& PCB_SELECTION_TOOL::RequestSelection( CLIENT_SELECTION_FILTER aCl
enum DISPOSITION { BEFORE = 1, AFTER, BOTH };
std::map<EDA_ITEM*, DISPOSITION> itemDispositions;
GENERAL_COLLECTORS_GUIDE guide = getCollectorsGuide();
GENERAL_COLLECTOR collector;
collector.SetGuide( &guide );
for( EDA_ITEM* item : m_selection )
{
collector.Append( item );
@@ -2312,7 +2315,7 @@ void PCB_SELECTION_TOOL::highlightInternal( BOARD_ITEM* aItem, int aMode, bool a
else if( aMode == BRIGHTENED )
aItem->SetBrightened();
if( aUsingOverlay )
if( aUsingOverlay && aMode != BRIGHTENED )
view()->Hide( aItem, true ); // Hide the original item, so it is shown only on overlay
if( aItem->Type() == PCB_FOOTPRINT_T )
@@ -2355,7 +2358,7 @@ void PCB_SELECTION_TOOL::unhighlightInternal( BOARD_ITEM* aItem, int aMode, bool
else if( aMode == BRIGHTENED )
aItem->ClearBrightened();
if( aUsingOverlay )
if( aUsingOverlay && aMode != BRIGHTENED )
view()->Hide( aItem, false ); // // Restore original item visibility
if( aItem->Type() == PCB_FOOTPRINT_T )
@@ -2700,28 +2703,26 @@ void PCB_SELECTION_TOOL::FilterCollectorForHierarchy( GENERAL_COLLECTOR& aCollec
if( !m_isFootprintEditor && parent && parent->Type() == PCB_FOOTPRINT_T )
start = parent;
// If a group is entered, disallow selections of objects outside the group.
if( m_enteredGroup && !PCB_GROUP::WithinScope( item, m_enteredGroup, m_isFootprintEditor ) )
{
aCollector.Remove( item );
continue;
}
// If any element is a member of a group, replace those elements with the top containing
// group.
PCB_GROUP* aTop = PCB_GROUP::TopLevelGroup( start, m_enteredGroup, m_isFootprintEditor );
if( aTop )
if( PCB_GROUP* top = PCB_GROUP::TopLevelGroup( start, m_enteredGroup, m_isFootprintEditor ) )
{
if( aTop != item )
if( top != item )
{
toAdd.insert( aTop );
aTop->SetFlags( TEMP_SELECTED );
toAdd.insert( top );
top->SetFlags(CANDIDATE );
aCollector.Remove( item );
continue;
}
}
else if( m_enteredGroup
&& !PCB_GROUP::WithinScope( item, m_enteredGroup, m_isFootprintEditor ) )
{
// If a group is entered, disallow selections of objects outside the group.
aCollector.Remove( item );
continue;
}
// Footprints are a bit easier as they can't be nested.
if( parent && ( parent->GetFlags() & TEMP_SELECTED ) )

Some files were not shown because too many files have changed in this diff Show More