Compare commits

..

411 Commits

Author SHA1 Message Date
Wayne Stambaugh 8a3464bdf1 Tag stable version 9.0.6. 2025-10-30 08:41:59 -04:00
Alex Shvartzkop 51646e6605 Update translations 2025-10-30 04:51:46 +03:00
Vic e962686afb Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 97.9% (9891 of 10096 strings)

Translation: KiCad EDA/v9
Translate-URL: https://hosted.weblate.org/projects/kicad/v9/zh_Hant/
2025-10-30 02:50:56 +01:00
2tama3 9211d60d7b Translated using Weblate (Japanese)
Currently translated at 100.0% (10096 of 10096 strings)

Translation: KiCad EDA/v9
Translate-URL: https://hosted.weblate.org/projects/kicad/v9/ja/
2025-10-30 02:50:56 +01:00
Marco Ciampa 632c03a874 Translated using Weblate (Italian)
Currently translated at 98.6% (9958 of 10096 strings)

Translation: KiCad EDA/v9
Translate-URL: https://hosted.weblate.org/projects/kicad/v9/it/
2025-10-30 02:50:56 +01:00
Vic 24d2eded07 Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 97.9% (9891 of 10096 strings)

Translation: KiCad EDA/v9
Translate-URL: https://hosted.weblate.org/projects/kicad/v9/zh_Hant/
2025-10-30 02:50:56 +01:00
தமிழ்நேரம் d3a5bf20db Translated using Weblate (Tamil)
Currently translated at 99.9% (10094 of 10096 strings)

Translation: KiCad EDA/v9
Translate-URL: https://hosted.weblate.org/projects/kicad/v9/ta/
2025-10-30 02:50:56 +01:00
Pferd O 099e0d1312 Translated using Weblate (German)
Currently translated at 99.9% (10093 of 10096 strings)

Translation: KiCad EDA/v9
Translate-URL: https://hosted.weblate.org/projects/kicad/v9/de/
2025-10-30 02:50:56 +01:00
Frank Sonnenberg 3c1bc31456 Translated using Weblate (German)
Currently translated at 99.9% (10093 of 10096 strings)

Translation: KiCad EDA/v9
Translate-URL: https://hosted.weblate.org/projects/kicad/v9/de/
2025-10-30 02:50:56 +01:00
Vic 2fffc9780b Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 97.8% (9874 of 10096 strings)

Translation: KiCad EDA/v9
Translate-URL: https://hosted.weblate.org/projects/kicad/v9/zh_Hant/
2025-10-30 02:50:56 +01:00
தமிழ்நேரம் 68bfa2001e Translated using Weblate (Tamil)
Currently translated at 99.8% (10078 of 10096 strings)

Translation: KiCad EDA/v9
Translate-URL: https://hosted.weblate.org/projects/kicad/v9/ta/
2025-10-30 02:50:56 +01:00
Sárkány Lőrinc ebdf4c7719 Translated using Weblate (Hungarian)
Currently translated at 39.7% (4012 of 10096 strings)

Translation: KiCad EDA/v9
Translate-URL: https://hosted.weblate.org/projects/kicad/v9/hu/
2025-10-30 02:50:55 +01:00
Toni Laiho f944b662b6 Translated using Weblate (Finnish)
Currently translated at 97.6% (9854 of 10096 strings)

Translation: KiCad EDA/v9
Translate-URL: https://hosted.weblate.org/projects/kicad/v9/fi/
2025-10-30 02:50:55 +01:00
Frank Sonnenberg 3ac9bace21 Translated using Weblate (German)
Currently translated at 99.9% (10093 of 10096 strings)

Translation: KiCad EDA/v9
Translate-URL: https://hosted.weblate.org/projects/kicad/v9/de/
2025-10-30 02:50:55 +01:00
Vic 98141d0143 Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 97.7% (9871 of 10096 strings)

Translation: KiCad EDA/v9
Translate-URL: https://hosted.weblate.org/projects/kicad/v9/zh_Hant/
2025-10-30 02:50:55 +01:00
தமிழ்நேரம் d90d86775b Translated using Weblate (Tamil)
Currently translated at 99.7% (10067 of 10096 strings)

Translation: KiCad EDA/v9
Translate-URL: https://hosted.weblate.org/projects/kicad/v9/ta/
2025-10-30 02:50:55 +01:00
dsa-t 578d0a5a4a Translated using Weblate (Russian)
Currently translated at 100.0% (10096 of 10096 strings)

Translation: KiCad EDA/v9
Translate-URL: https://hosted.weblate.org/projects/kicad/v9/ru/
2025-10-30 02:50:55 +01:00
2tama3 53075ee9f3 Translated using Weblate (Japanese)
Currently translated at 100.0% (10096 of 10096 strings)

Translation: KiCad EDA/v9
Translate-URL: https://hosted.weblate.org/projects/kicad/v9/ja/
2025-10-30 02:50:55 +01:00
Frank Sonnenberg 7f19d051ed Translated using Weblate (German)
Currently translated at 99.9% (10094 of 10096 strings)

Translation: KiCad EDA/v9
Translate-URL: https://hosted.weblate.org/projects/kicad/v9/de/
2025-10-30 02:50:55 +01:00
Seth Hillbrand 364cf0808f Ensure snaps override grid points 2025-10-29 15:22:52 -07:00
Seth Hillbrand d3cce1e35c Remove H/V/45 limits in router completely
Lots of complaints, little benefit

Fixes https://gitlab.com/kicad/code/kicad/-/issues/22147

(cherry picked from commit ab0e0abe67)
2025-10-28 17:00:55 -07:00
jean-pierre charras 1b20a932ad Fix Unroute Selected when footprint is select and filter selection pad OFF
Fixes https://gitlab.com/kicad/code/kicad/-/issues/22138

(cherry picked from commit 8ba749bf49)
2025-10-28 18:40:01 +01:00
Jeff Young 3b0dac9491 Fix typo. 2025-10-27 15:35:39 +00:00
Wayne Stambaugh 4433da15b1 Tag stable version 9.0.6 release candidate 2. 2025-10-22 18:40:21 -04:00
Alex Shvartzkop e4af447855 Update translations 2025-10-23 00:59:39 +03:00
தமிழ்நேரம் ecd4326533 Translated using Weblate (Tamil)
Currently translated at 99.5% (10050 of 10097 strings)

Translation: KiCad EDA/v9
Translate-URL: https://hosted.weblate.org/projects/kicad/v9/ta/
2025-10-23 00:57:45 +03:00
Sárkány Lőrinc 73854bc9f1 Translated using Weblate (Hungarian)
Currently translated at 39.7% (4009 of 10097 strings)

Translation: KiCad EDA/v9
Translate-URL: https://hosted.weblate.org/projects/kicad/v9/hu/
2025-10-23 00:57:30 +03:00
CloverGit 544c035298 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 99.8% (10082 of 10097 strings)

Translation: KiCad EDA/v9
Translate-URL: https://hosted.weblate.org/projects/kicad/v9/zh_Hans/
2025-10-23 00:57:18 +03:00
aris-kimi c8da489b1f Translated using Weblate (Greek)
Currently translated at 85.6% (8649 of 10097 strings)

Translation: KiCad EDA/v9
Translate-URL: https://hosted.weblate.org/projects/kicad/v9/el/
2025-10-23 00:57:18 +03:00
2tama3 da6f97b24f Translated using Weblate (Japanese)
Currently translated at 100.0% (10097 of 10097 strings)

Translation: KiCad EDA/v9
Translate-URL: https://hosted.weblate.org/projects/kicad/v9/ja/
2025-10-23 00:57:08 +03:00
Tokita, Hiroshi 464d248b8c Translated using Weblate (Japanese)
Currently translated at 100.0% (10097 of 10097 strings)

Translation: KiCad EDA/v9
Translate-URL: https://hosted.weblate.org/projects/kicad/v9/ja/
2025-10-23 00:57:08 +03:00
CloverGit b790b46c76 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 99.8% (10081 of 10097 strings)

Translation: KiCad EDA/v9
Translate-URL: https://hosted.weblate.org/projects/kicad/v9/zh_Hans/
2025-10-23 00:56:54 +03:00
Frank Sonnenberg b4a5422e54 Translated using Weblate (German)
Currently translated at 100.0% (10097 of 10097 strings)

Translation: KiCad EDA/v9
Translate-URL: https://hosted.weblate.org/projects/kicad/v9/de/
2025-10-23 00:56:43 +03:00
Mark Hämmerling 565d54a184 Translated using Weblate (German)
Currently translated at 100.0% (10097 of 10097 strings)

Translation: KiCad EDA/v9
Translate-URL: https://hosted.weblate.org/projects/kicad/v9/de/
2025-10-23 00:56:43 +03:00
Pferd O ebcf96dcd6 Translated using Weblate (German)
Currently translated at 100.0% (10097 of 10097 strings)

Translation: KiCad EDA/v9
Translate-URL: https://hosted.weblate.org/projects/kicad/v9/de/
2025-10-23 00:56:43 +03:00
Pferd O e067a8ddc8 Translated using Weblate (German)
Currently translated at 100.0% (10097 of 10097 strings)

Translation: KiCad EDA/v9
Translate-URL: https://hosted.weblate.org/projects/kicad/v9/de/
2025-10-23 00:56:43 +03:00
Temuri Doghonadze 4d8feb94bd Translated using Weblate (Georgian)
Currently translated at 27.6% (2790 of 10097 strings)

Translation: KiCad EDA/v9
Translate-URL: https://hosted.weblate.org/projects/kicad/v9/ka/
2025-10-23 00:56:27 +03:00
Seth Hillbrand 2374e5e542 Propagate lib_fields changes
Partial cherry-pick of 702f774a1f and
fef84a2c6a
2025-10-22 13:10:04 -07:00
Seth Hillbrand a3e4a001bb Fix HV45 toggle during move
Action handled externally, so trigger internal updates on flag

Fixes https://gitlab.com/kicad/code/kicad/-/issues/22025
2025-10-21 16:44:12 -07:00
Seth Hillbrand edc25f8ba0 Fix axis locking when keypresses are specific
If you immediately pressed left/right it would not unlock unless there
was a mouse movement between
2025-10-21 16:25:49 -07:00
Seth Hillbrand 10a03972d4 Re-enable axis locking on cursor key
This is an accidental feature previously but now make it explicit.
Pressing left or right keys will lock the movement to the horizontal
axis until you press the opposite key.  Same for up/down

Fixes https://gitlab.com/kicad/code/kicad/-/issues/21981
2025-10-21 15:30:26 -07:00
Wayne Stambaugh 5a3c210b7c Revert "Tag stable version 9.0.6 release candidate 2."
This reverts commit 239eb5a1ff.
2025-10-21 16:48:53 -04:00
Wayne Stambaugh 239eb5a1ff Tag stable version 9.0.6 release candidate 2. 2025-10-21 16:39:16 -04:00
Seth Hillbrand c1a1bbc96b Strongly prefer snap points over snap lines
When moving toward an intersection of snap lines that is also a snap
point, when the grid is off, the snap will always be closer to one snap
line or the other before the snap point.  This is problematic for
snapping to a center point, e.g.

Instead, if you are within the snap range of a snap point, that should
be your preference.  Zooming in will allow snapping to the snap physical
point on a line and avoiding the snap point snapping

Fixes https://gitlab.com/kicad/code/kicad/-/issues/22045
2025-10-21 12:07:27 -07:00
Seth Hillbrand c16076a5c3 Remove Local Power from v9 2025-10-21 12:04:57 -07:00
Seth Hillbrand 77ab6c29bf Ensure ERC Exclusions are maintained
After we load/resolve the exclusions, we want to ensure that the
resolved ones are re-recorded into the project file so that it always
remains consistent with the state of the system.  This way, if pcbnew
closes first and re-saves the project, our exclusions are not lost until
the schematic closes

Fixes https://gitlab.com/kicad/code/kicad/-/issues/21410

(cherry picked from commit 5442e5050e)
2025-10-21 06:27:40 -07:00
Seth Hillbrand 9366902052 Clear the keyboard movement flag on mouse move
We detect mouse movement by checking if the screen position is not the
keyboard position and if not, we clear the
m_lastKeyboardCursorPositionValid that is used for detemining keyboard
movement in snaps

Fixes https://gitlab.com/kicad/code/kicad/-/issues/21981

(cherry picked from commit 120c788ef0)
2025-10-20 16:34:11 -07:00
Jeff Young 86b687bdaf Minimal cherry-pick of ba73ce78e6. 2025-10-20 14:08:30 +01:00
Wayne Stambaugh 1da4895619 Sync shared symbol instance field values in symbol fields table dialog.
Change data store key from wxString to KIID_PATH to make it easier to look
up shared symbol instances by KIID.
2025-10-16 17:56:18 -04:00
Seth Hillbrand fbf9a45a00 Fix MSVC compile 2025-10-15 17:27:45 -07:00
Seth Hillbrand c6c2d6468d Keep movement snaps aligned with start
Prevents jumping elements when we start to move

(cherry picked from commit d4265ebff8)
2025-10-15 16:51:40 -07:00
Seth Hillbrand b349140112 Snap construction lines to grid if enabled
Nearest grid line intersection is a snap point on construction lines

Fixes https://gitlab.com/kicad/code/kicad/-/issues/21984

(cherry picked from commit ce305990e8)
2025-10-15 16:49:00 -07:00
Seth Hillbrand 5dafadb12c Prioritize anchor snapping over snapline/grid
We have a number of potential snap points and we would prefer to snap to
identified snap points on objects in the view over ethereal points
created by intersections

(cherry picked from commit ce49e9d69c)
2025-10-15 15:25:55 -07:00
Seth Hillbrand da1f71684c Use full path to match symbols in table/BOM
In the symbol fields table, we can't rely on the UUID being unique
across sheets.  So, we need to keep the full path as our key to unique
symbols

Fixes https://gitlab.com/kicad/code/kicad/-/issues/21998

N.B. This is similar to but not a direct cherry pick from 8cf33049be
since the branches have diverged
2025-10-15 15:14:50 -07:00
Seth Hillbrand 563a2d20b7 SCH_ITEMs will not always have a schematic pointer
Especially if we are updating a symbol, the pointer is removed, so we
need to be able to handle this case

Fixes https://gitlab.com/kicad/code/kicad/-/issues/21995
2025-10-15 10:01:39 -07:00
Seth Hillbrand f31450018d Add missing acknowlegement for ur-3dmodels library
(cherry picked from commit fcc25071b7)
2025-10-15 06:57:00 -07:00
Seth Hillbrand c329ba2b4c Add link to original GitHub 3D repo
(cherry picked from commit 61f33a2fef)
2025-10-15 06:57:00 -07:00
Seth Hillbrand fe42b1fd6b Fix link to Maui's GitHub
(cherry picked from commit 9067338e37)
2025-10-15 06:57:00 -07:00
Jon Evans 66628a3501 API: Do not attempt to unpack invalid layers
Fixes https://gitlab.com/kicad/code/kicad/-/issues/21743
2025-10-14 17:55:30 -04:00
Tomasz Wlostowski e21ebbff76 router: improved multidrag segment side/corner determination
Fixes https://gitlab.com/kicad/code/kicad/-/issues/21972
2025-10-14 19:16:42 +03:00
Seth Hillbrand 7df0a80eed Don't write invalid countour data in ODB++
Fixes https://gitlab.com/kicad/code/kicad/-/issues/21974

(cherry picked from commit df76a54db1)
2025-10-13 16:20:11 -07:00
Jeff Young 790dee114b Use the fully-qualified name in the library too.
(Otherwise when we save another symbol with
a different fully-qualified name, but same
elem.text, we'll delete the first instance
which we still have cached.)

Fixes https://gitlab.com/kicad/code/kicad/-/issues/21947
2025-10-12 20:30:33 +01:00
Seth Hillbrand 3f17abba60 Properly handle choices mapped
If the choice is an integer, we need to be able to handle it directly
because we can't get the wxAny to a wxString if the underlying type
doesn't map

(cherry picked from commit 42a76dd4bd)
2025-10-11 22:55:46 -07:00
Wayne Stambaugh dbca140d17 Tag stable version 9.0.6 release candidate 1. 2025-10-11 13:02:53 -04:00
Alex Shvartzkop d563588b28 Update translations 2025-10-11 04:08:44 +03:00
2tama3 4503abdf80 Translated using Weblate (Japanese)
Currently translated at 100.0% (10097 of 10097 strings)

Translation: KiCad EDA/v9
Translate-URL: https://hosted.weblate.org/projects/kicad/v9/ja/
2025-10-11 03:08:00 +02:00
Sárkány Lőrinc d670be0007 Translated using Weblate (Hungarian)
Currently translated at 39.6% (4007 of 10097 strings)

Translation: KiCad EDA/v9
Translate-URL: https://hosted.weblate.org/projects/kicad/v9/hu/
2025-10-11 03:08:00 +02:00
Pferd O f55873fc3d Translated using Weblate (German)
Currently translated at 100.0% (10097 of 10097 strings)

Translation: KiCad EDA/v9
Translate-URL: https://hosted.weblate.org/projects/kicad/v9/de/
2025-10-11 03:08:00 +02:00
Temuri Doghonadze 330437ee8d Translated using Weblate (Georgian)
Currently translated at 26.4% (2669 of 10097 strings)

Translation: KiCad EDA/v9
Translate-URL: https://hosted.weblate.org/projects/kicad/v9/ka/
2025-10-11 03:08:00 +02:00
Sárkány Lőrinc 61648be38a Translated using Weblate (Hungarian)
Currently translated at 39.5% (3998 of 10097 strings)

Translation: KiCad EDA/v9
Translate-URL: https://hosted.weblate.org/projects/kicad/v9/hu/
2025-10-11 03:08:00 +02:00
Frank Sonnenberg 58584cb227 Translated using Weblate (German)
Currently translated at 100.0% (10097 of 10097 strings)

Translation: KiCad EDA/v9
Translate-URL: https://hosted.weblate.org/projects/kicad/v9/de/
2025-10-11 03:08:00 +02:00
Pferd O 4cab605fb6 Translated using Weblate (German)
Currently translated at 100.0% (10097 of 10097 strings)

Translation: KiCad EDA/v9
Translate-URL: https://hosted.weblate.org/projects/kicad/v9/de/
2025-10-11 03:07:59 +02:00
Henrik Kauhanen 57f6d1c015 Translated using Weblate (Swedish)
Currently translated at 99.7% (10070 of 10097 strings)

Translation: KiCad EDA/v9
Translate-URL: https://hosted.weblate.org/projects/kicad/v9/sv/
2025-10-11 03:07:59 +02:00
Seth Hillbrand 57df0435bf Fix double-delete crash
9.0 uses boost to auto-manage the lifetime
2025-10-10 17:23:53 -07:00
Seth Hillbrand 46312674c6 Re-work of 5514396c for v9
All links are processed in the same order

Fixes https://gitlab.com/kicad/code/kicad/-/issues/21913
2025-10-10 17:12:00 -07:00
Quentin Freimanis 32781c3992 altium pcbs: import pad to die length
(cherry picked from commit ad07c85cea)
2025-10-10 15:35:59 -07:00
Seth Hillbrand 48b3408f9a Fix alignment QA
We actually offset by 25, so the check was wrong
2025-10-10 15:19:24 -07:00
Seth Hillbrand e892783109 Move HV45 to suggestions when moving
Snap lines shown when snapped
2025-10-10 14:44:00 -07:00
Seth Hillbrand 5865431759 Refactor grid_helper to allow testing
Make view and tool manager optional so that we can implement QA on the
actual snapping

(cherry picked from commit 29eee9f126)
2025-10-10 13:39:02 -07:00
Seth Hillbrand d75d0ef686 Allow multi-row deleting in 3d models
Removes all selected rows when hitting the trash can

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

(cherry picked from commit 7ebf5f084b)
2025-10-10 10:01:15 -07:00
Seth Hillbrand baf4843a45 Avoid minor overlaps
Some geometry creates 1-2nm overlaps.  These are not actually overlaps
because our collinear test can't correctly determine their
directionality, so we limit the overlap to at least 25 units (arbitrary)
to skip these chunks

Fixes https://gitlab.com/kicad/code/kicad/-/issues/21946

Fixes https://gitlab.com/kicad/code/kicad/-/issues/21930

(cherry picked from commit 063430e488)
2025-10-09 17:57:44 -07:00
Alex Shvartzkop 57309d4a62 Update translations 2025-10-08 13:56:58 +03:00
ZbeeGin a9ad99f513 Translated using Weblate (Polish)
Currently translated at 100.0% (10097 of 10097 strings)

Translation: KiCad EDA/v9
Translate-URL: https://hosted.weblate.org/projects/kicad/v9/pl/
2025-10-08 12:56:21 +02:00
Temuri Doghonadze 5a459ce982 Translated using Weblate (Georgian)
Currently translated at 25.4% (2572 of 10097 strings)

Translation: KiCad EDA/v9
Translate-URL: https://hosted.weblate.org/projects/kicad/v9/ka/
2025-10-08 12:56:21 +02:00
2tama3 32626dfa1d Translated using Weblate (Japanese)
Currently translated at 100.0% (10097 of 10097 strings)

Translation: KiCad EDA/v9
Translate-URL: https://hosted.weblate.org/projects/kicad/v9/ja/
2025-10-08 12:56:21 +02:00
Temuri Doghonadze 3406f20a5c Translated using Weblate (Georgian)
Currently translated at 25.4% (2571 of 10097 strings)

Translation: KiCad EDA/v9
Translate-URL: https://hosted.weblate.org/projects/kicad/v9/ka/
2025-10-08 12:56:20 +02:00
2tama3 2fedbaac2e Translated using Weblate (Japanese)
Currently translated at 100.0% (10097 of 10097 strings)

Translation: KiCad EDA/v9
Translate-URL: https://hosted.weblate.org/projects/kicad/v9/ja/
2025-10-08 12:56:20 +02:00
Pferd O b3f7e2e827 Translated using Weblate (German)
Currently translated at 99.8% (10083 of 10097 strings)

Translation: KiCad EDA/v9
Translate-URL: https://hosted.weblate.org/projects/kicad/v9/de/
2025-10-08 12:56:20 +02:00
Frank Sonnenberg 6430bd6c61 Translated using Weblate (German)
Currently translated at 99.8% (10083 of 10097 strings)

Translation: KiCad EDA/v9
Translate-URL: https://hosted.weblate.org/projects/kicad/v9/de/
2025-10-08 12:56:20 +02:00
Michal Kundrát cb51d324b7 Translated using Weblate (Czech)
Currently translated at 77.9% (7871 of 10097 strings)

Translation: KiCad EDA/v9
Translate-URL: https://hosted.weblate.org/projects/kicad/v9/cs/
2025-10-08 12:56:20 +02:00
Максим Горпиніч 1eb9accb1e Translated using Weblate (Ukrainian)
Currently translated at 100.0% (10097 of 10097 strings)

Translation: KiCad EDA/v9
Translate-URL: https://hosted.weblate.org/projects/kicad/v9/uk/
2025-10-08 12:56:20 +02:00
dsa-t fb8716f16a Translated using Weblate (Russian)
Currently translated at 100.0% (10097 of 10097 strings)

Translation: KiCad EDA/v9
Translate-URL: https://hosted.weblate.org/projects/kicad/v9/ru/
2025-10-08 12:56:19 +02:00
Temuri Doghonadze 1bdeebf13d Translated using Weblate (Georgian)
Currently translated at 19.2% (1943 of 10097 strings)

Translation: KiCad EDA/v9
Translate-URL: https://hosted.weblate.org/projects/kicad/v9/ka/
2025-10-08 12:56:19 +02:00
Jeff Young 3688a9ca61 Support translation of property grid enums.
Fixes https://gitlab.com/kicad/code/kicad/-/issues/21859

Fixes https://gitlab.com/kicad/code/kicad/-/issues/13636

(cherry picked from commit 44f932e9ec)
2025-10-07 13:49:14 +01:00
Jeff Young 94370cc6d8 Support translation in tool context menus that are long-lived.
(The specialized ones are OK as they're created
for each use.)

Also, enum maps must be untranslated.

Fixes https://gitlab.com/kicad/code/kicad/-/issues/21859

(cherry picked from commit 2fe7219474)
2025-10-07 13:46:54 +01:00
Jeff Young 186839b245 Nullptr safety.
Fixes https://gitlab.com/kicad/code/kicad/-/issues/21840

(cherry picked from commit e00bb21afd)
2025-10-07 13:44:26 +01:00
Jeff Young c70653c9dc Nullptr safety.
Fixes https://gitlab.com/kicad/code/kicad/-/issues/21841

(cherry picked from commit 0edae828df)
2025-10-07 13:38:25 +01:00
Jeff Young ed59993fc3 Fix build error. 2025-10-07 13:32:09 +01:00
Jeff Young fec37a0f79 Make sure exclusion hotkey works when dialog has focus.
(Potentially only required on MSW.  Not required
on MacOS, unknown on GTK.)

Fixes https://gitlab.com/kicad/code/kicad/-/issues/21761

(cherry picked from commit 7003c0639e)
2025-10-07 13:28:41 +01:00
Jeff Young 7a4ab8971c Auto-convert numeric values in fields when referencing them in expressions.
Fixes https://gitlab.com/kicad/code/kicad/-/issues/21723

(cherry picked from commit 2c102a62e0)
2025-10-07 13:24:21 +01:00
Jeff Young 76cff2e7aa Fix build error. 2025-10-07 13:23:14 +01:00
Jeff Young e95aab5df6 Implement netclass compare for sorting.
Fixes https://gitlab.com/kicad/code/kicad/-/issues/21345

(cherry picked from commit 3bb1aafdf3)
2025-10-07 12:41:33 +01:00
Seth Hillbrand 0b1fee9f7f Properly account for keyboard movement
We need to snap the position to the grid at the start of movement with
the keyboard because it will snap to the movement point of the item when
we are moving, so the difference between mouse position and grid
position will end up being some fractional value that appears random

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

(cherry picked from commit 4a090ca353)
2025-10-05 21:35:53 -07:00
Seth Hillbrand 8a5c51d37f Properly name Altium subsheets
Instead of using Altium extensions, we need to use KiCad extensions
otherwise, we'll never load them

Fixes https://gitlab.com/kicad/code/kicad/issues/21173
2025-10-05 14:03:15 -07:00
Seth Hillbrand d288dce1d0 Fix Altium subsheet names 2025-10-05 13:57:57 -07:00
Seth Hillbrand 89b92fe3f5 One follow-on to fix additional windows paths
We need to set the format earlier and handle internal filenames

Fixes https://gitlab.com/kicad/code/kicad/issues/20161
2025-10-05 13:53:57 -07:00
Seth Hillbrand cb7385bf0c Update Altium subfolder import
Altium projects save relative sub folder paths in the windows path
format.  To import these correctly, we need to turn off the escape
character handling in wx's config file processing otherwise
SUBFOLDER\PROJECT.SchDoc ends up looking like SUBFOLDERROJECT.SchDoc

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

(cherry picked from commit 4ae76d56c6)
2025-10-05 13:29:29 -07:00
Seth Hillbrand ec6af273bb One more fix for compiling 2025-10-05 06:58:59 -07:00
Seth Hillbrand 0dd4d0e46c Fix cherry-pick error 2025-10-05 06:57:43 -07:00
Seth Hillbrand 2d0c5dc8bd Only constrain points based on settings
There was a false fall-through that caught all points for polygons.
Now, constraint is applied only based on the user keys and settings

Fixes https://gitlab.com/kicad/code/kicad/issues/21897
2025-10-05 06:53:41 -07:00
Alex Shvartzkop 95418742e9 Fix build error. 2025-10-05 16:09:59 +03:00
Seth Hillbrand 53d0d60f33 Force clearing rtree when rebuilding
Avoid leaving stale triangle references

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

(cherry picked from commit b4f396bb2d)
2025-10-05 16:09:59 +03:00
Alex Shvartzkop bf1dbde3c3 Update translations 2025-10-05 16:04:44 +03:00
Temuri Doghonadze 2b1b1b4fcb Translated using Weblate (Georgian)
Currently translated at 17.7% (1786 of 10080 strings)

Translation: KiCad EDA/v9
Translate-URL: https://hosted.weblate.org/projects/kicad/v9/ka/
2025-10-05 15:03:47 +02:00
Sárkány Lőrinc a1066bac65 Translated using Weblate (Hungarian)
Currently translated at 39.4% (3972 of 10080 strings)

Translation: KiCad EDA/v9
Translate-URL: https://hosted.weblate.org/projects/kicad/v9/hu/
2025-10-05 15:03:47 +02:00
Temuri Doghonadze a30498a572 Translated using Weblate (Georgian)
Currently translated at 15.0% (1520 of 10080 strings)

Translation: KiCad EDA/v9
Translate-URL: https://hosted.weblate.org/projects/kicad/v9/ka/
2025-10-05 15:03:47 +02:00
YÜKSEL AÇIKGÖZ 5403990121 Translated using Weblate (Turkish)
Currently translated at 99.4% (10029 of 10080 strings)

Translation: KiCad EDA/v9
Translate-URL: https://hosted.weblate.org/projects/kicad/v9/tr/
2025-10-05 15:03:47 +02:00
2tama3 2deacd59ef Translated using Weblate (Japanese)
Currently translated at 100.0% (10080 of 10080 strings)

Translation: KiCad EDA/v9
Translate-URL: https://hosted.weblate.org/projects/kicad/v9/ja/
2025-10-05 15:03:46 +02:00
William Lin 7d67775f45 Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 97.9% (9870 of 10080 strings)

Translation: KiCad EDA/v9
Translate-URL: https://hosted.weblate.org/projects/kicad/v9/zh_Hant/
2025-10-05 15:03:46 +02:00
Henrik Kauhanen c5ef10cf2c Translated using Weblate (Swedish)
Currently translated at 99.8% (10062 of 10080 strings)

Translation: KiCad EDA/v9
Translate-URL: https://hosted.weblate.org/projects/kicad/v9/sv/
2025-10-05 15:03:46 +02:00
Frank Sonnenberg 04d0719269 Translated using Weblate (German)
Currently translated at 100.0% (10080 of 10080 strings)

Translation: KiCad EDA/v9
Translate-URL: https://hosted.weblate.org/projects/kicad/v9/de/
2025-10-05 15:03:46 +02:00
Seth Hillbrand f143ce563f Protect polygon build
If we don't have corners, then we cannot add any points or lines

(cherry picked from commit f33fd675d2)
2025-10-05 05:58:14 -07:00
Seth Hillbrand 5792a02825 Adjust the project name when importing
Ensures that the proper project is referenced after saving imported
project

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

(cherry picked from commit d0f1920ab6)
2025-10-05 04:58:46 -07:00
Seth Hillbrand 0dc0061d30 When using git, show all files
Git tracks the status of files in the repository, so we shouldn't hide
the non-root schematics

Fixes https://gitlab.com/kicad/code/kicad/-/issues/21583

Fixes https://gitlab.com/kicad/code/kicad/-/issues/21583

(cherry picked from commit d5e03741b7)
2025-10-05 04:54:13 -07:00
Seth Hillbrand 2116e272b5 Maintain units even when opening standalone
The unit data is maintained in the instances so we need a temporary
instance setting if we do not have the parent sheet

Fixes https://gitlab.com/kicad/code/kicad/-/issues/19361

(cherry picked from commit 39ed3c538f)
2025-10-05 04:53:37 -07:00
Seth Hillbrand 25c14ae7cb Ensure new symbols obey the observed sheet number
Internal numerology will not make sense when annotating, so use the
observed sheet number and let the algo ensure that numbers are not
duplicated

Fixes https://gitlab.com/kicad/code/kicad/-/issues/21637

Fixes https://gitlab.com/kicad/code/kicad/-/issues/19138

Fixes https://gitlab.com/kicad/code/kicad/-/issues/16632

(cherry picked from commit 4fcc2ac7e2)
2025-10-05 04:53:16 -07:00
Seth Hillbrand 3a8fc4dd82 Fully separate command and parameters
Ensures proper execution on all platforms

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

(cherry picked from commit 25e9464d2c)
2025-10-05 04:51:17 -07:00
Seth Hillbrand 5558dce259 Handle custom fields from netlist
Fixes https://gitlab.com/kicad/code/kicad/-/issues/21648

(cherry picked from commit 2677cae840)
2025-10-05 04:50:53 -07:00
Seth Hillbrand 8fe891a475 Prevent H/V locking when dragging
This avoids the track position locking into arbitrary 90° points.

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

(cherry picked from commit a5090c908d)
2025-10-05 04:50:36 -07:00
Seth Hillbrand 501b63028b Prevent crash in changing units
SCH_ITEM unit is set as a wxString

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

(cherry picked from commit 5b0db05ad2)
2025-10-05 04:50:36 -07:00
Seth Hillbrand b7d7403e6f Dedupe ODB++ symbol names
If we have duplicate symbol names (can happen from plugins), suffix a
number

Fixes https://gitlab.com/kicad/code/kicad/-/issues/21803

(cherry picked from commit 8cfac03444)
2025-10-05 04:50:36 -07:00
Seth Hillbrand c0648c4728 We need to clamp the index to max - 1
What did we think this was?  Pascal?

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

(cherry picked from commit 9c0727f28e)
2025-10-05 04:50:36 -07:00
Seth Hillbrand a33003cf62 Clean up third axis
Ensure that there are better displays and detects potential power
signals

Fixes https://gitlab.com/kicad/code/kicad/-/issues/21645

(cherry picked from commit c00e818688)
2025-10-05 04:33:02 -07:00
Seth Hillbrand 1d577cf917 Lazy load git credentials when needed
Prevents querying SecretStore on boot

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

(cherry picked from commit 4ed56d87a4)
2025-10-05 04:32:21 -07:00
Seth Hillbrand d189c6ddbf Enforce spice-valid netnames when parsing
Avoids prematurely trimming netnames containing numbers

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

(cherry picked from commit d6d476e39e)
2025-10-05 04:31:10 -07:00
Seth Hillbrand f781ec82c9 Avoid OtherSideView in 2581B
This was introduced in 2581C, so if we are exporting 2581B, emit the
silk elements as board-level instead of tied to a footprint

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

(cherry picked from commit 1dceb5825d)
2025-10-05 04:15:25 -07:00
Seth Hillbrand 3a33a5b506 Ensure table directories are created
Use static routines to create needed directories before copying files

Fixes https://gitlab.com/kicad/code/kicad/-/issues/18937

Fixes https://gitlab.com/kicad/code/kicad/-/issues/18938

(cherry picked from commit 3eeb2a1ad7)
2025-10-05 04:12:22 -07:00
Seth Hillbrand 4436d93446 When copying global tables, ensure writable
Copying read-only files into the user directory, the files will need to
be read/write in order to work correctly

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

(cherry picked from commit ab7c30a2a1)
2025-10-05 04:10:59 -07:00
JamesJCode 238612d2c2 Use hasExactNetclass() function for all implicit net class DRC rules
Fixes https://gitlab.com/kicad/code/kicad/-/issues/21819

(cherry picked from commit 7c8dd9bf92)
2025-10-04 10:42:00 +01:00
Seth Hillbrand f787c01b47 Clean up lib table cherry-pick and hide
For now, we place this behind the advanced config flag for v9 testing
2025-10-03 17:24:26 -07:00
Seth Hillbrand f8e60b11c9 Fix lib_fields column attributes
Need to properly display footprint selector and datasheet globe

(cherry picked from commit 05d04e665a)
2025-10-03 16:07:22 -07:00
Seth Hillbrand 0f07c4ef78 Prompt for unsaved changes in the lib fields table editor
(cherry picked from commit 344fab5741)
2025-10-03 16:07:22 -07:00
John Beard 6fcfcd28ca Symbol editor: allow to inject the symbol list into DIALOG_LIB_FIELDS
This will permit editing fields for subsets (e.g. only symbols in
a certain inheritance hierarchy)

(cherry picked from commit 9b14434fc3)
2025-10-03 16:06:08 -07:00
Seth Hillbrand 1773eb2b1c ADDED: Library Table Editor
Edits all symbols in a library at once.  Supports copy/paste, multiple
field assignment and selective coloration based on existing data

Fixes https://gitlab.com/kicad/code/kicad/-/issues/11506

(cherry picked from commit 9cba910d53)
2025-10-03 16:05:52 -07:00
Seth Hillbrand 45bdde41b3 JP's patch to fix crash in routing empty board
(cherry picked from commit 8592b2ee70)
2025-10-03 08:46:36 -07:00
Seth Hillbrand 292faaa48d Protect against invalid line access
When placing, we may have failed to generate a tail, in which case, we
will have no line to split, so just return

Fixes https://gitlab.com/kicad/code/kicad/-/issues/21883
2025-10-03 08:42:56 -07:00
Wayne Stambaugh 44c473c1b3 Only use front/back layer notation "F&B" for zone definitions.
This prevents false positive DRC footprint parity errors caused by commit
088e0e80a1.

(cherry picked from commit 8b525671b1)
2025-10-01 16:01:11 -04:00
Wayne Stambaugh 85474345d6 Begin version 9.0.6 development. 2025-10-01 15:09:57 -04:00
Wayne Stambaugh fda292bd08 Tag stable version 9.0.5. 2025-10-01 15:09:57 -04:00
Alex Shvartzkop c666bf8626 STEP export: paint board body in soldermask color if soldermask export is off
Was broken in 54e9a97b26

Fixes (part of) https://gitlab.com/kicad/code/kicad/-/issues/21865
2025-10-01 21:56:34 +03:00
Alex Shvartzkop 96f20d102b Update translations 2025-09-30 15:10:36 +03:00
Henrik Kauhanen f57cdb52dd Translated using Weblate (Swedish)
Currently translated at 99.8% (10061 of 10080 strings)

Translation: KiCad EDA/v9
Translate-URL: https://hosted.weblate.org/projects/kicad/v9/sv/
2025-09-30 14:06:53 +02:00
Frank Sonnenberg a5d2294ec3 Translated using Weblate (German)
Currently translated at 100.0% (10080 of 10080 strings)

Translation: KiCad EDA/v9
Translate-URL: https://hosted.weblate.org/projects/kicad/v9/de/
2025-09-30 14:06:53 +02:00
Frank Sonnenberg 72fdb41b73 Translated using Weblate (German)
Currently translated at 100.0% (10080 of 10080 strings)

Translation: KiCad EDA/v9
Translate-URL: https://hosted.weblate.org/projects/kicad/v9/de/
2025-09-30 14:06:53 +02:00
Pferd O 2ca04123d4 Translated using Weblate (German)
Currently translated at 100.0% (10080 of 10080 strings)

Translation: KiCad EDA/v9
Translate-URL: https://hosted.weblate.org/projects/kicad/v9/de/
2025-09-30 14:06:53 +02:00
2tama3 07a4710363 Translated using Weblate (Japanese)
Currently translated at 100.0% (10080 of 10080 strings)

Translation: KiCad EDA/v9
Translate-URL: https://hosted.weblate.org/projects/kicad/v9/ja/
2025-09-30 14:06:52 +02:00
Sárkány Lőrinc c01e37304f Translated using Weblate (Hungarian)
Currently translated at 39.2% (3960 of 10080 strings)

Translation: KiCad EDA/v9
Translate-URL: https://hosted.weblate.org/projects/kicad/v9/hu/
2025-09-30 14:06:52 +02:00
Stefan Bjornelund the Gnome 52b57b1145 Translated using Weblate (Swedish)
Currently translated at 99.8% (10060 of 10080 strings)

Translation: KiCad EDA/v9
Translate-URL: https://hosted.weblate.org/projects/kicad/v9/sv/
2025-09-30 14:06:52 +02:00
2tama3 7b4e444f6c Translated using Weblate (Japanese)
Currently translated at 100.0% (10080 of 10080 strings)

Translation: KiCad EDA/v9
Translate-URL: https://hosted.weblate.org/projects/kicad/v9/ja/
2025-09-30 14:06:52 +02:00
Sárkány Lőrinc a9f4f85746 Translated using Weblate (Hungarian)
Currently translated at 39.2% (3955 of 10080 strings)

Translation: KiCad EDA/v9
Translate-URL: https://hosted.weblate.org/projects/kicad/v9/hu/
2025-09-30 14:06:52 +02:00
Pferd O bc7ece44eb Translated using Weblate (German)
Currently translated at 99.9% (10070 of 10080 strings)

Translation: KiCad EDA/v9
Translate-URL: https://hosted.weblate.org/projects/kicad/v9/de/
2025-09-30 14:06:52 +02:00
Sárkány Lőrinc 51cc22a4f2 Translated using Weblate (Hungarian)
Currently translated at 39.1% (3951 of 10080 strings)

Translation: KiCad EDA/v9
Translate-URL: https://hosted.weblate.org/projects/kicad/v9/hu/
2025-09-30 14:06:52 +02:00
Frank Sonnenberg 38f2541a3f Translated using Weblate (German)
Currently translated at 99.9% (10070 of 10080 strings)

Translation: KiCad EDA/v9
Translate-URL: https://hosted.weblate.org/projects/kicad/v9/de/
2025-09-30 14:06:52 +02:00
Ivan Chuba a05e3de852 Translated using Weblate (Ukrainian)
Currently translated at 100.0% (10080 of 10080 strings)

Translation: KiCad EDA/v9
Translate-URL: https://hosted.weblate.org/projects/kicad/v9/uk/
2025-09-30 14:06:52 +02:00
co8 j 908e7205e7 Translated using Weblate (Japanese)
Currently translated at 100.0% (10080 of 10080 strings)

Translation: KiCad EDA/v9
Translate-URL: https://hosted.weblate.org/projects/kicad/v9/ja/
2025-09-30 14:06:52 +02:00
Sárkány Lőrinc a80e410683 Translated using Weblate (Hungarian)
Currently translated at 39.1% (3947 of 10080 strings)

Translation: KiCad EDA/v9
Translate-URL: https://hosted.weblate.org/projects/kicad/v9/hu/
2025-09-30 14:06:52 +02:00
Frank Sonnenberg fa234e4b58 Translated using Weblate (German)
Currently translated at 99.9% (10070 of 10080 strings)

Translation: KiCad EDA/v9
Translate-URL: https://hosted.weblate.org/projects/kicad/v9/de/
2025-09-30 14:06:52 +02:00
Pferd O fb82e722e1 Translated using Weblate (German)
Currently translated at 99.9% (10070 of 10080 strings)

Translation: KiCad EDA/v9
Translate-URL: https://hosted.weblate.org/projects/kicad/v9/de/
2025-09-30 14:06:52 +02:00
Максим Горпиніч b45f9e7392 Translated using Weblate (Ukrainian)
Currently translated at 100.0% (10080 of 10080 strings)

Translation: KiCad EDA/v9
Translate-URL: https://hosted.weblate.org/projects/kicad/v9/uk/
2025-09-30 14:06:52 +02:00
dsa-t d496b281ef Translated using Weblate (Russian)
Currently translated at 100.0% (10080 of 10080 strings)

Translation: KiCad EDA/v9
Translate-URL: https://hosted.weblate.org/projects/kicad/v9/ru/
2025-09-30 14:06:51 +02:00
Sárkány Lőrinc 2a46ff370a Translated using Weblate (Hungarian)
Currently translated at 39.1% (3942 of 10080 strings)

Translation: KiCad EDA/v9
Translate-URL: https://hosted.weblate.org/projects/kicad/v9/hu/
2025-09-30 14:06:51 +02:00
Pferd O 44d0b27544 Translated using Weblate (German)
Currently translated at 99.8% (10064 of 10080 strings)

Translation: KiCad EDA/v9
Translate-URL: https://hosted.weblate.org/projects/kicad/v9/de/
2025-09-30 14:06:51 +02:00
Jeff Young 7d76868c5c Fix latent bug in UpdatePins().
(It was failing to update the unit and bodystyle.)

(cherry picked from commit 3f1999795c)
2025-09-29 17:30:49 +01:00
Jeff Young e4d9d1829f Honour alternate pin definitions.
Fixes https://gitlab.com/kicad/code/kicad/-/issues/21618

(cherry picked from commit 19133bc6bd)
2025-09-27 13:36:42 +01:00
Jeff Young e585948861 Formatting.
(cherry picked from commit d140261ab1)
2025-09-27 13:15:02 +01:00
Jeff Young e31b177335 Static cast safety.
(cherry picked from commit 48c9145177)
2025-09-27 13:09:29 +01:00
jean-pierre charras 4624d57bc2 FRAME_FOOTPRINT_CHOOSER and FRAME_FOOTPRINT_VIEWER: fix incorrect save settings
They were saved in cvpcb.json instead of pcbnew.json, and especially for
FRAME_FOOTPRINT_CHOOSER, some settings were incorrectly retrieved because
not actually updated.

Fixes https://gitlab.com/kicad/code/kicad/-/issues/21818

(cherry picked from commit 8f8edf8d69)
2025-09-26 12:40:21 +02:00
jean-pierre charras 4f2d1ec5a1 French translation update 2025-09-24 08:36:57 +02:00
Alex Shvartzkop 5bcb3edae1 Update translations 2025-09-23 13:55:59 +03:00
Sárkány Lőrinc 30fbfd53c1 Translated using Weblate (Hungarian)
Currently translated at 39.0% (3931 of 10069 strings)

Translation: KiCad EDA/v9
Translate-URL: https://hosted.weblate.org/projects/kicad/v9/hu/
2025-09-23 12:53:01 +02:00
Sárkány Lőrinc dc979be459 Translated using Weblate (Hungarian)
Currently translated at 36.5% (3679 of 10069 strings)

Translation: KiCad EDA/v9
Translate-URL: https://hosted.weblate.org/projects/kicad/v9/hu/
2025-09-23 12:53:01 +02:00
Frank Sonnenberg 450c4517b5 Translated using Weblate (German)
Currently translated at 100.0% (10069 of 10069 strings)

Translation: KiCad EDA/v9
Translate-URL: https://hosted.weblate.org/projects/kicad/v9/de/
2025-09-23 12:53:01 +02:00
Sárkány Lőrinc 47cd4d6b7a Translated using Weblate (Hungarian)
Currently translated at 36.2% (3648 of 10069 strings)

Translation: KiCad EDA/v9
Translate-URL: https://hosted.weblate.org/projects/kicad/v9/hu/
2025-09-23 12:53:01 +02:00
Pferd O 8842c575c3 Translated using Weblate (German)
Currently translated at 100.0% (10069 of 10069 strings)

Translation: KiCad EDA/v9
Translate-URL: https://hosted.weblate.org/projects/kicad/v9/de/
2025-09-23 12:53:01 +02:00
CloverGit 858c23f731 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 99.9% (10063 of 10069 strings)

Translation: KiCad EDA/v9
Translate-URL: https://hosted.weblate.org/projects/kicad/v9/zh_Hans/
2025-09-23 12:53:01 +02:00
Toni Laiho 1d879d51c5 Translated using Weblate (Finnish)
Currently translated at 97.7% (9842 of 10069 strings)

Translation: KiCad EDA/v9
Translate-URL: https://hosted.weblate.org/projects/kicad/v9/fi/
2025-09-23 12:53:00 +02:00
Pferd O 6e0df489eb Translated using Weblate (German)
Currently translated at 99.9% (10060 of 10069 strings)

Translation: KiCad EDA/v9
Translate-URL: https://hosted.weblate.org/projects/kicad/v9/de/
2025-09-23 12:53:00 +02:00
Henrik Kauhanen a9be5c5759 Translated using Weblate (Swedish)
Currently translated at 99.8% (10057 of 10069 strings)

Translation: KiCad EDA/v9
Translate-URL: https://hosted.weblate.org/projects/kicad/v9/sv/
2025-09-23 12:53:00 +02:00
Stefan De Raedemaeker 258e2fd46f Translated using Weblate (Dutch)
Currently translated at 90.6% (9127 of 10069 strings)

Translation: KiCad EDA/v9
Translate-URL: https://hosted.weblate.org/projects/kicad/v9/nl/
2025-09-23 12:53:00 +02:00
Pferd O f5852f0869 Translated using Weblate (German)
Currently translated at 99.9% (10059 of 10069 strings)

Translation: KiCad EDA/v9
Translate-URL: https://hosted.weblate.org/projects/kicad/v9/de/
2025-09-23 12:53:00 +02:00
Henrik Kauhanen 1d0adbc5d6 Translated using Weblate (Swedish)
Currently translated at 99.8% (10056 of 10069 strings)

Translation: KiCad EDA/v9
Translate-URL: https://hosted.weblate.org/projects/kicad/v9/sv/
2025-09-23 12:53:00 +02:00
Pferd O 34834fd963 Translated using Weblate (German)
Currently translated at 99.8% (10058 of 10069 strings)

Translation: KiCad EDA/v9
Translate-URL: https://hosted.weblate.org/projects/kicad/v9/de/
2025-09-23 12:53:00 +02:00
Frank Sonnenberg 2f095aeafb Translated using Weblate (German)
Currently translated at 99.8% (10058 of 10069 strings)

Translation: KiCad EDA/v9
Translate-URL: https://hosted.weblate.org/projects/kicad/v9/de/
2025-09-23 12:53:00 +02:00
CloverGit 47bb72179f Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 99.9% (10063 of 10069 strings)

Translation: KiCad EDA/v9
Translate-URL: https://hosted.weblate.org/projects/kicad/v9/zh_Hans/
2025-09-23 12:53:00 +02:00
Pferd O 9f7af4a3a7 Translated using Weblate (German)
Currently translated at 99.9% (10060 of 10069 strings)

Translation: KiCad EDA/v9
Translate-URL: https://hosted.weblate.org/projects/kicad/v9/de/
2025-09-23 12:53:00 +02:00
Frank Sonnenberg dda127ceec Translated using Weblate (German)
Currently translated at 99.9% (10060 of 10069 strings)

Translation: KiCad EDA/v9
Translate-URL: https://hosted.weblate.org/projects/kicad/v9/de/
2025-09-23 12:53:00 +02:00
Максим Горпиніч 68e6e0a742 Translated using Weblate (Ukrainian)
Currently translated at 100.0% (10069 of 10069 strings)

Translation: KiCad EDA/v9
Translate-URL: https://hosted.weblate.org/projects/kicad/v9/uk/
2025-09-23 12:53:00 +02:00
2tama3 a844ba713a Translated using Weblate (Japanese)
Currently translated at 100.0% (10069 of 10069 strings)

Translation: KiCad EDA/v9
Translate-URL: https://hosted.weblate.org/projects/kicad/v9/ja/
2025-09-23 12:53:00 +02:00
Frank Sonnenberg 5d75bd0f0a Translated using Weblate (German)
Currently translated at 99.9% (10060 of 10069 strings)

Translation: KiCad EDA/v9
Translate-URL: https://hosted.weblate.org/projects/kicad/v9/de/
2025-09-23 12:53:00 +02:00
jean-pierre charras c492565ee8 DIALOG_LIB_SYMBOL_PROPERTIES: fix incorrect handling of vertical pos. of fields
The Y pos was negated twice when saving the field position.
Note also this is a fast fix. A better fix should be removing these Y pos sign
change in dialog because they are now not needed, but it will wait 9.0.6.

Fixes https://gitlab.com/kicad/code/kicad/-/issues/21781
2025-09-21 16:43:20 +02:00
Wayne Stambaugh 879d2bef4b Tag stable version 9.0.5 release candidate 1. 2025-09-20 15:52:28 -04:00
Olliver Schinagl 05376a39ac export_vrml: Skip missing 3D models with warning
(cherry picked from commit 98d77db5ae)
2025-09-20 11:43:55 -04:00
oskarwires 9c01c2aeb8 Fix pin length change and push
(cherry picked from commit abba11031a)
2025-09-20 11:36:25 -04:00
Alex Shvartzkop 72db7bfedc Fix some warnings. 2025-09-19 17:07:47 +03:00
Alex Shvartzkop 95cfe2cc2e STEP export: don't return non-zero error code on non-fatal errors. 2025-09-19 17:06:38 +03:00
Mark Roszko c6f5daf87f Make ERC/DRC jobs default to fail on violation count
(cherry picked from commit 94856f1ffa)

Co-authored-by: Mark Roszko <mark.roszko@gmail.com>
2025-09-19 12:01:51 +00:00
Seth Hillbrand b1711d692a Do not hang onto previous elements
When using multi-label input or repeat commands, the previous element
should be deselected so that we can properly transform the current
element

Fixes https://gitlab.com/kicad/code/kicad/-/issues/21765

(cherry picked from commit 5ed46b823b)
2025-09-18 12:28:55 -07:00
Seth Hillbrand d538182f1f Fix Windows Builds 2025-09-18 11:15:52 -07:00
Wayne Stambaugh b4b87b5c38 Prevent crash dereferencing null pointer when creating schematic table. 2025-09-18 14:05:05 -04:00
Seth Hillbrand eed95e612d Skip exterior segments when splitting
We need to avoid fracture points when choosing how to split exterior
segments

(cherry picked from commit 50274352b1)
2025-09-18 10:30:43 -07:00
Seth Hillbrand 68d3c7f5c2 Force type in wxString 2025-09-17 21:05:39 -07:00
Seth Hillbrand 848d5484d8 Fix mocks 2025-09-17 13:42:22 -07:00
Alexander Boehm d3b84f219c generate rule areas dialog: vertical scroll bars
With many entries the dialog could not be resized by dragging
nor were scroll bars displayed (at least under Linux).

Fixes https://gitlab.com/kicad/code/kicad/-/issues/20195

(cherry picked from commit 4111140f93)
2025-09-17 11:38:04 -07:00
Seth Hillbrand 58ccf62d2f Unify sheet name validators and apply to properties
Properties panel and properties dialog now share a validator with shared
strings

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

(cherry picked from commit 733a379ca3)
2025-09-17 11:36:53 -07:00
Seth Hillbrand 021229647f Prevent lines from drawing on netclass layer
Only wires and busses get netclasses

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

(cherry picked from commit 5fdfff2b9c)
2025-09-17 11:19:58 -07:00
Seth Hillbrand 9a812bc63c Remove noise from orthographic projection raytracing
We generally add some jitter to the raytracing lines in order to smooth
out over multiple iterations some of the imperfections.  However, when
we do this to an orthographic projection (where all lines are parallel
to start, we don't average and just introduce noticeable noise in the
render

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

(cherry picked from commit abf3438ed6)
2025-09-17 11:18:47 -07:00
Seth Hillbrand 8a9201b79c Update properties to show units
The function duplicated our built-in funcitonality and did not properly
handly outputs

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

(cherry picked from commit 3f8abe3744)
2025-09-17 11:06:25 -07:00
Jeff Young f8e9b3402f Comboboxes for units and body styles.
Also for pin-types in pad properties.

Fixes https://gitlab.com/kicad/code/kicad/-/issues/19904

Fixes https://gitlab.com/kicad/code/kicad/-/issues/19905

(cherry picked from commit ec155c00f3)
2025-09-17 11:05:57 -07:00
Seth Hillbrand 808c645933 Don't convert URI slashes on Windows
We auto-convert paths for windows boxes but this should not happen for
uri schemes that have the form <URI>://<path>

Fixes https://gitlab.com/kicad/code/kicad/-/issues/20381

(cherry picked from commit e85a8056f5)
2025-09-17 10:46:41 -07:00
Adrián García ea467c1bac Fix crash in LIB_SYMBOL::SetUnitCount when reducing unit count
When decreasing the number of units in a symbol, the previous code erased
items directly from m_drawings using a single iterator. Because m_drawings
is a MULTIVECTOR, this could invalidate iterators and attempt to erase
from the wrong bucket, leading to segmentation faults.

This patch iterates bucket by bucket and erases items belonging to units
greater than the requested count. This ensures iterator safety and avoids
accessing invalid memory.

Fixes https://gitlab.com/kicad/code/kicad/-/issues/21631

(cherry picked from commit fb558eee3c)
2025-09-17 10:46:14 -07:00
Seth Hillbrand c51b6a0cd2 Prevent GTK from providing stale position
When the library name and symbol/footprint name both match the filter,
we try to display both but ensure visible can move things to the wrong
place.  We need to ensure the filtered list is up to date prior to
moving by ensureVisible

Fixes https://gitlab.com/kicad/code/kicad/-/issues/18000

(cherry picked from commit dc7e0665c3)
2025-09-17 10:45:40 -07:00
Seth Hillbrand 10f16ed82e Prevent modifying teardrops on lock/unlock
This action doesn't affect geometry, so don't dirty the teardrops

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

(cherry picked from commit ad80113f47)
2025-09-17 10:45:17 -07:00
Seth Hillbrand ab9cf326e8 Consider visibility when colliding in DRC
Most places we check this but we should also check it in physical
clearance

Fixes https://gitlab.com/kicad/code/kicad/-/issues/21625

(cherry picked from commit d9741fd46a)
2025-09-17 10:44:53 -07:00
Seth Hillbrand 4e6087c183 Prevent main KiCad window from expanding based on DPI events
Fixes https://gitlab.com/kicad/code/kicad/-/issues/21602

(cherry picked from commit f5904cf2ac)
2025-09-17 10:44:32 -07:00
Seth Hillbrand e7abf472ba Make properties panel obey free pads setting
Pads should almost never be moved without their parent.  Only allow this
in the case where free pads has explicitly been checked

Fixes https://gitlab.com/kicad/code/kicad/-/issues/21591

(cherry picked from commit b22f259ccb)
2025-09-17 10:42:58 -07:00
Addo White f0c6b57ab9 Fix for Cursor rendering on Linux+EGL+Nvidia in accelerated graphics mode
EGL/NVidia can sometimes clip the cursor based on its plane regardless
of the depth mask.  This avoids the issue by forcing the cursor up over the existing plane.

Fixes https://gitlab.com/kicad/code/kicad/-/issues/12183

(cherry picked from commit 843eea259d)
2025-09-17 10:42:13 -07:00
Seth Hillbrand e830709cda Make Expand Connection respect the filter
Prevents expansion that would require traversing elements that are
disabled in the selection filter

Fixes https://gitlab.com/kicad/code/kicad/-/issues/21581

(cherry picked from commit a811f61c39)
2025-09-17 10:39:58 -07:00
Seth Hillbrand 415aac7fc5 Fix Chessboard splitting
Due to a bug(?) in Clipper2, 45° collinear edges may not be detected.
See https://github.com/AngusJohnson/Clipper2/issues/1008 for current
status.  In the meantime, we pre-process these to remove the extraneous
joints preventing our triangulation from getting mixed up

Fixes https://gitlab.com/kicad/code/kicad/-/issues/18176

(cherry picked from commit 408e1feae2)
2025-09-17 10:37:44 -07:00
modbw 21f15c3b2a Fix net assignment messed up in Eagle import
When there is a polygon in the Eagle project withput any pad connected
netCode was not incremented and so the wrong nets were assigned to the
following elements.

Fixes https://gitlab.com/kicad/code/kicad/-/issues/21243

(cherry picked from commit 57ad779797)
2025-09-17 10:36:17 -07:00
Seth Hillbrand 0f8df0bcee Ensure that we check tracks exiting pads for gaps
The DP gap check should look for sections of track that are coupled by
wider than a given spacing.  Our primitive check of looking for
collisions on the segment between the start poins causes tracks exiting
but not entering pads to be excluded.

Fixes https://gitlab.com/kicad/code/kicad/-/issues/21561

(cherry picked from commit 1e76f1a11d)
2025-09-17 10:34:50 -07:00
Seth Hillbrand d6ef6252a2 Maintain group membership when shoving
Keep track of the original group membership and assign this to the newly
created element as well

Fixes https://gitlab.com/kicad/code/kicad/-/issues/20862

(cherry picked from commit 2db8c6eca0)
2025-09-17 10:33:36 -07:00
Seth Hillbrand f13c9cbd49 Prevent stale names in fp browser
When switching libraries, if there is an additional footprint with the
same name, we don't want to select it by default as this will prevent
updating the footprint display.  Instead, force the update

Fixes https://gitlab.com/kicad/code/kicad/-/issues/9763

(cherry picked from commit cb620338db)
2025-09-17 10:29:31 -07:00
Seth Hillbrand c2af66a44b Specialize the pad wall drawing
Avoids slowdown when zoom/pan with many THTs as everything remains
cached.  Still slow in Cairo but this is expected

Fixes https://gitlab.com/kicad/code/kicad/-/issues/20506

(cherry picked from commit 3ef862f7b6)
2025-09-17 10:27:56 -07:00
Seth Hillbrand 40c50c94fb Help is always valid
Return 0 and no error, just help when the --help flag is present

Fixes https://gitlab.com/kicad/code/kicad/-/issues/21538

(cherry picked from commit 9dc76f658d)
2025-09-17 10:27:21 -07:00
Seth Hillbrand 0103f92d0e Add more parent safety checks
Fixes https://gitlab.com/kicad/code/kicad/-/issues/21317

(cherry picked from commit e346139301)
2025-09-17 10:26:51 -07:00
Seth Hillbrand 0f27f8b7fc Enforce board-level hole to hole on diff pairs
Makes the router behave like the DRC

Fixes https://gitlab.com/kicad/code/kicad/-/issues/21240

(cherry picked from commit cac334bb45)
2025-09-17 10:25:56 -07:00
Seth Hillbrand 5631b61dbc Find the proper line split
And avoid leaving duplicate tracks when overlapping

Fixes https://gitlab.com/kicad/code/kicad/-/issues/10422

(cherry picked from commit 8acdcafe90)
2025-09-17 10:25:32 -07:00
Seth Hillbrand da659f5d05 Manually check pad layers before inserting
We do not rely on GetEffectiveShape(layer) to return null for layers
that the pad does not exist on.

Fixes https://gitlab.com/kicad/code/kicad/-/issues/21523

(cherry picked from commit 2e1910ca86)
2025-09-17 10:23:46 -07:00
Seth Hillbrand 2029c5389f Move IPC2581 output to REPORTER
Adds a wx_reporter_panel to the 2581 output window, shunt messages
through the reporter instance

Fixes https://gitlab.com/kicad/code/kicad/-/issues/16314

(cherry picked from commit 44228bd580)
2025-09-17 10:23:21 -07:00
Seth Hillbrand 4205e70775 Update cache when modifying schematic
Fixes https://gitlab.com/kicad/code/kicad/-/issues/18297

(cherry picked from commit 2347b290cb)
2025-09-17 10:17:08 -07:00
Seth Hillbrand 4f66225de7 Allow multiple pad->single pin in 2581 correctly
Grouped pads by pin number in the IPC-2581 exporter so only one pin node
is created per number.  Still output multiple pad shapes with the same
number.

Fixes https://gitlab.com/kicad/code/kicad/-/issues/18688

(cherry picked from commit c1cd4dd157)
2025-09-17 10:16:42 -07:00
Seth Hillbrand 18e4682c3a Set embedded delegate to update view properly
When embedding a 3d model we want to be able to see it immediately but
this requires getting the embedded files from the delegate model

Fixes https://gitlab.com/kicad/code/kicad/-/issues/19991

(cherry picked from commit bd86f979ed)
2025-09-17 10:16:17 -07:00
Seth Hillbrand 6b540ae1e3 Add embed option to standard file dialog for 3dmodels
Fixes https://gitlab.com/kicad/code/kicad/-/issues/20025

(cherry picked from commit 09cdca876c)
2025-09-17 10:15:51 -07:00
Seth Hillbrand 1f12b6c17d Force overlapping wires to share labels
Crossing wires with pathological label in the center are actually
connected for the netlist.  This is an ERC error but we should keep
things consistent.

Fixes https://gitlab.com/kicad/code/kicad/-/issues/21494

(cherry picked from commit c995d47c87)
2025-09-17 10:11:43 -07:00
Seth Hillbrand e2c23c70f1 Allow soldermask bridging between nettie items
Previously we only allowed graphical items but within the net-tie we
need to allow bridging for connected items as well

Fixes https://gitlab.com/kicad/code/kicad/-/issues/19288

(cherry picked from commit 8faf1b4d0e)
2025-09-17 10:06:32 -07:00
Seth Hillbrand f60f0394be Fix preferential coordinates in rule display
Fixes https://gitlab.com/kicad/code/kicad/-/issues/11546

(cherry picked from commit eb89d7ffcc)
2025-09-17 10:06:23 -07:00
Seth Hillbrand bd64bcf446 Keep the ruler measurements on screen
Fixes https://gitlab.com/kicad/code/kicad/-/issues/11546

(cherry picked from commit b2fbb326b0)
2025-09-17 10:04:42 -07:00
Seth Hillbrand 176d0f5820 Slight modification to followTrivialPath
Now keeps track of branch points, recursing through them to find the
longest path it can in both directions.  This helps to ignore
overlapping segments

Fixes https://gitlab.com/kicad/code/kicad/-/issues/7809

(cherry picked from commit 4c5b44545f)
2025-09-17 10:04:13 -07:00
Seth Hillbrand 118ee1c072 Prevent autosave error from cluttering the screen
Once per session, per editor we can show the error.  After that, assume
that the designer has seen and knows about the issue.

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

(cherry picked from commit 9f2b04c7e2)
2025-09-17 09:57:32 -07:00
Seth Hillbrand fd15a1108b Allow wildcard matching for Netclass naming
Fixes https://gitlab.com/kicad/code/kicad/issues/21455

(cherry picked from commit fcd2da354d)
2025-09-17 09:56:46 -07:00
Seth Hillbrand 43b5d4d91f Ensure archives without ext are given .zip
Fixes https://gitlab.com/kicad/code/kicad/-/issues/21423

(cherry picked from commit 2ded7b87af)
2025-09-17 09:56:19 -07:00
Seth Hillbrand d11ab8201f Allow generator actions to affect children
Changing the generator will often modify the underlying children's
properties.  We should store these data in the stack.  Also add the
ability to change layers

Fixes https://gitlab.com/kicad/code/kicad/-/issues/21476

(cherry picked from commit 3ec380d93c)
2025-09-17 09:55:52 -07:00
Seth Hillbrand 86bae558b4 Fix broken cherry-pick 2025-09-17 09:55:52 -07:00
Seth Hillbrand 68991a7644 Make move tool obey snap settings
Fixes https://gitlab.com/kicad/code/kicad/-/issues/21192

(cherry picked from commit 8bf7975440)
2025-09-17 09:40:06 -07:00
Seth Hillbrand 0701640c5a Prevent error message when backpropagating
Need to allow only processing other fields

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

(cherry picked from commit 8a081f60b1)
2025-09-17 09:39:14 -07:00
Seth Hillbrand 9fe656a33c Remove namespacing from IPC2581 output
Because some readers maintain global namespace per the standard, we make
sure that we don't overlap names between namespaces but keep the minimum
viable name for each element

Fixes https://gitlab.com/kicad/code/kicad/-/issues/19914

(cherry picked from commit 8f625086b1)
2025-09-17 09:38:48 -07:00
Seth Hillbrand 3fb8f22fd3 Have Find dialog update its cache on board mod
We don't want to find stale references

Fixes https://gitlab.com/kicad/code/kicad/-/issues/21445

(cherry picked from commit 1a8dac9296)
2025-09-17 09:30:30 -07:00
Seth Hillbrand 929930fb3a Show inherited fields in symbols
When working with derived symbols, make sure that we show all of the
fields, not just the ones that are defined in the current level since
they are all attached to the output.

Inherited fields are shown in italics until changed

Fixes https://gitlab.com/kicad/code/kicad/-/issues/11422

(cherry picked from commit ff5a309386)
2025-09-17 09:12:09 -07:00
Seth Hillbrand 4195b874d5 Properly order netlist pages
We cannot reorder these without updating the defines.  So, keep the GUI
in line with the definitions

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

(cherry picked from commit 497afffd48)
2025-09-17 17:59:08 +02:00
Jeff Young ae0d6c80dd Don't overwrite footprint filters created from multiple tokens in footprint column.
(cherry picked from commit 9ddb5465e1)
2025-09-17 13:13:23 +01:00
Jeff Young 4e2f84727c ADDED: support for multiple footprints in the footprint json from HTTP libraries
These are semi-colon-separated.

This is different from the footprint_filters dict entry, which is space-separated.

The first footprint in the footprint dict entry
will go into the "Footprint" field, while the rest
will go into the symbol's footprint filters.

(cherry picked from commit 91405ae34d)
2025-09-17 13:13:17 +01:00
Jeff Young 35889130e8 Formatting and naming conventions.
(cherry picked from commit 2eb3518e49)
2025-09-17 13:10:56 +01:00
Jeff Young 2e7145cc4b ADDED: handling of meta-data items in REST libraries.
"description" and "keywords" must hold string values;
"footprint_filters" can either hold a (space-
separated) string value, or an array of strings.

Fixes https://gitlab.com/kicad/code/kicad/-/issues/20750

(cherry picked from commit 1f1f490887)
2025-09-17 13:02:09 +01:00
Jeff Young e0d955993c Catch all errors thrown by nanodbc.
Fixes https://gitlab.com/kicad/code/kicad/-/issues/21707

(cherry picked from commit 37df36be62)
2025-09-17 13:00:45 +01:00
Mark Roszko cd7a646fcc Fix up arm assembly compiling on windows 2025-09-15 21:01:50 -04:00
Mark Roszko cb2a09d17c Edit ConfigurePlatform.cmake
(cherry picked from commit bda994c00a)

Co-authored-by: Mark Roszko <mark.roszko@gmail.com>
2025-09-15 23:47:12 +00:00
Mark Roszko d0cb210427 Also set CMAKE_SYSTEM_PROCESSOR in win cross compile
(cherry picked from commit e02008630f)

Co-authored-by: Mark Roszko <mark.roszko@gmail.com>
2025-09-15 23:43:55 +00:00
Seth Hillbrand b89d77bf36 Do not leave stale edges floating around
We assume that all net edges are valid in too many places

Fixes https://gitlab.com/kicad/code/kicad/-/issues/21745
2025-09-15 07:01:18 -07:00
Mark Roszko 7fdeb4796a Manually set CMAKE_CROSSCOMPILING on MSVC.
(cherry picked from commit accb0ddcd1)

Co-authored-by: Mark Roszko <mark.roszko@gmail.com>
2025-09-14 15:00:49 +00:00
Roberto Fernandez Bautista e82088a59b Windows CI: custom vcpkg triplet to ensure shareable binary cache
(cherry picked from commit 8d8bd7253f)
2025-09-13 23:45:41 +02:00
Seth Hillbrand 5a5191361f Second pass at fixing warping and grids
First attempt caused additional problems for #21535

Fixes https://gitlab.com/kicad/code/kicad/-/issues/18196

(cherry picked from commit 2cdeb0cd7c)
2025-09-12 10:52:36 +02:00
jean-pierre charras b47f8f4504 Revert "Remove the forced ancillary grid"
This reverts commit 7b602142b1.
2025-09-12 10:51:29 +02:00
jean-pierre charras 00ae91d6b5 Gerbview: fix broken behavior for deprecated command IPPOS and IPNEG
Fixes https://gitlab.com/kicad/code/kicad/-/issues/21715

(cherry picked from commit 45166bf5c3)
2025-09-11 14:32:17 +02:00
Jeff Young 097e0eadf1 LIBEVAL::CONTEXT manages its own local VALUEs.
Don't use std::unique_ptr as we'll just free the
value right after storing it.

Also, don't try to execute a non-existent function.

Fixes https://gitlab.com/kicad/code/kicad/-/issues/21697

(cherry picked from commit 6ab6283e2e)
2025-09-11 12:50:31 +01:00
Jeff Young c8c293dca8 Don't allow stack addresses to escape via long-life handlers.
(cherry picked from commit cff261ce2e)
2025-09-09 14:57:13 +01:00
Jeff Young e6cfd1cdcf Formatting.
(cherry picked from commit b98621c8c8)
2025-09-09 14:57:13 +01:00
Jeff Young 905170b4f4 Only test parameters under the same conditions as we'd write them to the file.
Fixes https://gitlab.com/kicad/code/kicad/-/issues/21520

(cherry picked from commit 8ae2ad3586)
2025-09-09 14:57:12 +01:00
Jeff Young 57fa8ea2b9 Use WX_GRID::ClearRows() to avoid assertions.
Fixes KICAD-VM1.

(cherry picked from commit 0b102fc085)
2025-09-09 14:57:12 +01:00
Jeff Young c7730a00c4 Fix typo.
(cherry picked from commit 330361d0cb)
2025-09-09 14:57:12 +01:00
Alex Shvartzkop beaaf3b5be Update translations 2025-09-09 01:19:33 +03:00
dsa-t b644f15d7f Translated using Weblate (Hungarian)
Currently translated at 36.0% (3630 of 10066 strings)

Translation: KiCad EDA/v9
Translate-URL: https://hosted.weblate.org/projects/kicad/v9/hu/
2025-09-09 00:18:33 +02:00
Sárkány Lőrinc af398762db Translated using Weblate (Hungarian)
Currently translated at 36.0% (3630 of 10066 strings)

Translation: KiCad EDA/v9
Translate-URL: https://hosted.weblate.org/projects/kicad/v9/hu/
2025-09-09 00:18:33 +02:00
CloverGit dfd40b566d Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 100.0% (10066 of 10066 strings)

Translation: KiCad EDA/v9
Translate-URL: https://hosted.weblate.org/projects/kicad/v9/zh_Hans/
2025-09-09 00:16:32 +02:00
KB e056ef2693 Translated using Weblate (Hungarian)
Currently translated at 36.0% (3630 of 10066 strings)

Translation: KiCad EDA/v9
Translate-URL: https://hosted.weblate.org/projects/kicad/v9/hu/
2025-09-09 00:16:32 +02:00
ZbeeGin 02d0944546 Translated using Weblate (Polish)
Currently translated at 99.5% (10019 of 10066 strings)

Translation: KiCad EDA/v9
Translate-URL: https://hosted.weblate.org/projects/kicad/v9/pl/
2025-09-09 00:16:32 +02:00
Nguyễn Ngọc Khánh 1aba70ca37 Translated using Weblate (Vietnamese)
Currently translated at 23.5% (2368 of 10066 strings)

Translation: KiCad EDA/v9
Translate-URL: https://hosted.weblate.org/projects/kicad/v9/vi/
2025-09-09 00:16:32 +02:00
Frank Sonnenberg ff8b82d060 Translated using Weblate (German)
Currently translated at 99.9% (10065 of 10066 strings)

Translation: KiCad EDA/v9
Translate-URL: https://hosted.weblate.org/projects/kicad/v9/de/
2025-09-09 00:16:31 +02:00
ssantos 68d1e3223a Translated using Weblate (Portuguese)
Currently translated at 98.5% (9922 of 10066 strings)

Translation: KiCad EDA/v9
Translate-URL: https://hosted.weblate.org/projects/kicad/v9/pt/
2025-09-09 00:16:31 +02:00
Frank Sonnenberg 9e64d52a38 Translated using Weblate (German)
Currently translated at 99.9% (10065 of 10066 strings)

Translation: KiCad EDA/v9
Translate-URL: https://hosted.weblate.org/projects/kicad/v9/de/
2025-09-09 00:16:31 +02:00
CloverGit f7b3c0226b Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 100.0% (10066 of 10066 strings)

Translation: KiCad EDA/v9
Translate-URL: https://hosted.weblate.org/projects/kicad/v9/zh_Hans/
2025-09-09 00:16:31 +02:00
Frank Sonnenberg 17fc05ec45 Translated using Weblate (German)
Currently translated at 99.9% (10065 of 10066 strings)

Translation: KiCad EDA/v9
Translate-URL: https://hosted.weblate.org/projects/kicad/v9/de/
2025-09-09 00:16:31 +02:00
Pferd O b64f1f2bd3 Translated using Weblate (German)
Currently translated at 99.9% (10063 of 10066 strings)

Translation: KiCad EDA/v9
Translate-URL: https://hosted.weblate.org/projects/kicad/v9/de/
2025-09-09 00:16:31 +02:00
Frank Sonnenberg b32d8862da Translated using Weblate (German)
Currently translated at 99.9% (10063 of 10066 strings)

Translation: KiCad EDA/v9
Translate-URL: https://hosted.weblate.org/projects/kicad/v9/de/
2025-09-09 00:16:31 +02:00
Hesham Eina Abdalla ff061e51a0 Translated using Weblate (Arabic)
Currently translated at 1.1% (117 of 10066 strings)

Translation: KiCad EDA/v9
Translate-URL: https://hosted.weblate.org/projects/kicad/v9/ar/
2025-09-09 00:16:31 +02:00
Ivan Chuba 6020e6d6f9 Translated using Weblate (Estonian)
Currently translated at 3.5% (357 of 10066 strings)

Translation: KiCad EDA/v9
Translate-URL: https://hosted.weblate.org/projects/kicad/v9/et/
2025-09-09 00:16:31 +02:00
Frank Sonnenberg a3fffc868f Translated using Weblate (German)
Currently translated at 99.9% (10065 of 10066 strings)

Translation: KiCad EDA/v9
Translate-URL: https://hosted.weblate.org/projects/kicad/v9/de/
2025-09-09 00:16:31 +02:00
Frank Sonnenberg 9670aa1b8a Translated using Weblate (German)
Currently translated at 99.9% (10065 of 10066 strings)

Translation: KiCad EDA/v9
Translate-URL: https://hosted.weblate.org/projects/kicad/v9/de/
2025-09-09 00:16:30 +02:00
Frank Sonnenberg 85ba5ae406 Translated using Weblate (German)
Currently translated at 99.9% (10065 of 10066 strings)

Translation: KiCad EDA/v9
Translate-URL: https://hosted.weblate.org/projects/kicad/v9/de/
2025-09-09 00:16:30 +02:00
Pferd O faa3287fd6 Translated using Weblate (German)
Currently translated at 99.9% (10065 of 10066 strings)

Translation: KiCad EDA/v9
Translate-URL: https://hosted.weblate.org/projects/kicad/v9/de/
2025-09-09 00:16:30 +02:00
ZbeeGin 33ab1d9242 Translated using Weblate (Polish)
Currently translated at 99.5% (10018 of 10066 strings)

Translation: KiCad EDA/v9
Translate-URL: https://hosted.weblate.org/projects/kicad/v9/pl/
2025-09-09 00:16:30 +02:00
Frank Sonnenberg 01aa2d7e42 Translated using Weblate (German)
Currently translated at 99.9% (10065 of 10066 strings)

Translation: KiCad EDA/v9
Translate-URL: https://hosted.weblate.org/projects/kicad/v9/de/
2025-09-09 00:16:30 +02:00
Sárkány Lőrinc b24e2ac00d Translated using Weblate (Hungarian)
Currently translated at 35.9% (3617 of 10066 strings)

Translation: KiCad EDA/v9
Translate-URL: https://hosted.weblate.org/projects/kicad/v9/hu/
2025-09-09 00:16:30 +02:00
Frank Sonnenberg 2bc3ef82dc Translated using Weblate (German)
Currently translated at 99.9% (10065 of 10066 strings)

Translation: KiCad EDA/v9
Translate-URL: https://hosted.weblate.org/projects/kicad/v9/de/
2025-09-09 00:16:30 +02:00
Sárkány Lőrinc 672ba5cd41 Translated using Weblate (Hungarian)
Currently translated at 35.6% (3591 of 10066 strings)

Translation: KiCad EDA/v9
Translate-URL: https://hosted.weblate.org/projects/kicad/v9/hu/
2025-09-09 00:16:30 +02:00
Pferd O 905b9ae6c5 Translated using Weblate (German)
Currently translated at 100.0% (10066 of 10066 strings)

Translation: KiCad EDA/v9
Translate-URL: https://hosted.weblate.org/projects/kicad/v9/de/
2025-09-09 00:16:30 +02:00
CloverGit f81a203c22 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 100.0% (10066 of 10066 strings)

Translation: KiCad EDA/v9
Translate-URL: https://hosted.weblate.org/projects/kicad/v9/zh_Hans/
2025-09-09 00:16:29 +02:00
Sárkány Lőrinc 7aa0431a60 Translated using Weblate (Hungarian)
Currently translated at 34.3% (3459 of 10066 strings)

Translation: KiCad EDA/v9
Translate-URL: https://hosted.weblate.org/projects/kicad/v9/hu/
2025-09-09 00:16:29 +02:00
Pferd O 57505674f8 Translated using Weblate (German)
Currently translated at 100.0% (10066 of 10066 strings)

Translation: KiCad EDA/v9
Translate-URL: https://hosted.weblate.org/projects/kicad/v9/de/
2025-09-09 00:16:29 +02:00
2tama3 558bef00cc Translated using Weblate (Japanese)
Currently translated at 100.0% (10066 of 10066 strings)

Translation: KiCad EDA/v9
Translate-URL: https://hosted.weblate.org/projects/kicad/v9/ja/
2025-09-09 00:16:29 +02:00
Sárkány Lőrinc 28f9bd797a Translated using Weblate (Hungarian)
Currently translated at 34.2% (3446 of 10066 strings)

Translation: KiCad EDA/v9
Translate-URL: https://hosted.weblate.org/projects/kicad/v9/hu/
2025-09-09 00:16:29 +02:00
CloverGit 52d6fc66f1 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 100.0% (10066 of 10066 strings)

Translation: KiCad EDA/v9
Translate-URL: https://hosted.weblate.org/projects/kicad/v9/zh_Hans/
2025-09-09 00:16:28 +02:00
Максим Горпиніч ab49e9b29d Translated using Weblate (Ukrainian)
Currently translated at 100.0% (10066 of 10066 strings)

Translation: KiCad EDA/v9
Translate-URL: https://hosted.weblate.org/projects/kicad/v9/uk/
2025-09-09 00:16:28 +02:00
Henrik Kauhanen f6710e64de Translated using Weblate (Swedish)
Currently translated at 99.9% (10058 of 10066 strings)

Translation: KiCad EDA/v9
Translate-URL: https://hosted.weblate.org/projects/kicad/v9/sv/
2025-09-09 00:16:28 +02:00
dsa-t 804154e21d Translated using Weblate (Russian)
Currently translated at 100.0% (10066 of 10066 strings)

Translation: KiCad EDA/v9
Translate-URL: https://hosted.weblate.org/projects/kicad/v9/ru/
2025-09-09 00:16:28 +02:00
2tama3 03cb8521bc Translated using Weblate (Japanese)
Currently translated at 100.0% (10066 of 10066 strings)

Translation: KiCad EDA/v9
Translate-URL: https://hosted.weblate.org/projects/kicad/v9/ja/
2025-09-09 00:16:28 +02:00
Sárkány Lőrinc 3ee940e3fb Translated using Weblate (Hungarian)
Currently translated at 34.2% (3445 of 10066 strings)

Translation: KiCad EDA/v9
Translate-URL: https://hosted.weblate.org/projects/kicad/v9/hu/
2025-09-09 00:16:28 +02:00
Frank Sonnenberg 8b25c3b0fe Translated using Weblate (German)
Currently translated at 100.0% (10066 of 10066 strings)

Translation: KiCad EDA/v9
Translate-URL: https://hosted.weblate.org/projects/kicad/v9/de/
2025-09-09 00:16:28 +02:00
Pferd O 529cf246d2 Translated using Weblate (German)
Currently translated at 100.0% (10066 of 10066 strings)

Translation: KiCad EDA/v9
Translate-URL: https://hosted.weblate.org/projects/kicad/v9/de/
2025-09-09 00:16:27 +02:00
Mark Roszko 7e7c281a64 Fix unit binder dropdown not working on windows
Fixes https://gitlab.com/kicad/code/kicad/-/issues/20626


(cherry picked from commit 0f97f51ba1)

Co-authored-by: Mark Roszko <mark.roszko@gmail.com>
2025-09-08 10:41:03 +00:00
Mark Roszko 350925f10a Shoehorn an improvement to table sorting to keep files more stable
Fixes https://gitlab.com/kicad/code/kicad/-/issues/21652
2025-09-07 10:34:12 -04:00
Mark Roszko 5e8982600a Update ngspice to 45.2
(cherry picked from commit 922699f388)

Co-authored-by: Mark Roszko <mark.roszko@gmail.com>
2025-09-06 17:41:01 +00:00
Mark Roszko e633af9216 Update kicad-vcpkg and ngspice 2025-09-06 12:49:44 +00:00
jean-pierre charras b0f21e5452 DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR_BASE: fix a incorrect widgets type
Fixes https://gitlab.com/kicad/code/kicad/-/issues/21662

From master branch
2025-09-06 13:28:41 +02:00
jean-pierre charras d2d582cc00 PCB_DIM_CENTER: fix incorrect bounding box size for 90deg cross.
Fixes https://gitlab.com/kicad/code/kicad/-/issues/21643

From master branch
2025-09-05 10:03:44 +02:00
jean-pierre charras 4f11681c4a French translation: fix typo 2025-09-05 09:51:45 +02:00
Mark Roszko 897ebee00f Fix position of package properties that must follow packages
(cherry picked from commit 9f1aa612ec)

Co-authored-by: Mark Roszko <mark.roszko@gmail.com>
2025-09-04 11:16:28 +00:00
Mark Roszko be0a42a09a Fix typo in allegro output for nets
(cherry picked from commit 9de2548064)

Co-authored-by: Mark Roszko <mark.roszko@gmail.com>
2025-09-04 11:09:35 +00:00
Mark Roszko 3069799a2d Fix double quoting tol for some reason
(cherry picked from commit a899da7cb7)

Co-authored-by: Mark Roszko <mark.roszko@gmail.com>
2025-09-04 03:00:05 +00:00
Mark Roszko ad22e53518 Fix the allegro netlist export and move mostly to {fmt}
Weirdly $PACKAGES header got shifted out of position.
Drop generating empty references.
2025-09-03 22:56:25 -04:00
Seth Hillbrand 2ef05eb191 Fix image pasting for MacOS
Apparently, GetImage() on MacOS does not always convert the image
properly.  So do a two-step here to get the Bitmap first, forcing the
conversion and then going back to an image

(cherry picked from commit 9f06d1f66b)
2025-09-03 09:20:12 -07:00
Seth Hillbrand 235e583182 Prevent crash in nettie
We need to avoid collecting invalid layers in the net ties regardless of
their origins

(cherry picked from commit 826f15a103)
2025-09-02 19:19:50 -07:00
Seth Hillbrand 76ce4ec535 Prevent pads from moving inappropriately
Free pads is a setting unless we are in the footprint editor and needs
to be respected by the alignmen tool

Fixes https://gitlab.com/kicad/code/kicad/-/issues/21626

(cherry picked from commit 1f1f8699e0)
2025-09-02 09:11:48 -07:00
Jeff Young 0226481156 Give Mac dock icon menu a kick.
Fixes https://gitlab.com/kicad/code/kicad/-/issues/17596

(cherry picked from commit 98b63389c1)
2025-09-01 22:36:37 +01:00
Seth Hillbrand 8fab2d8ca3 Disable snap when moving with keyboard
Keyboard movement is for precision control, so avoid snapping behavior

Fixes https://gitlab.com/kicad/code/kicad/-/issues/21235

(cherry picked from commit 9e326c29db)
2025-09-01 14:23:36 -07:00
Jeff Young 1c6d8b3f5e Don't reference stack variables from a long-life lambda.
In particular, a lambda for conditional menus should
never capture more than `[this]`.  Even the tool's
frame pointer could change.

Fixes https://gitlab.com/kicad/code/kicad/-/issues/21615
2025-09-01 12:37:43 +01:00
Jeff Young 32e9ab9b75 Don't reference stack variables from a long-life lambda. 2025-09-01 12:37:43 +01:00
Jon Evans ca0207016e API: Add ability to set enabled board layers and copper layer count 2025-08-31 22:18:53 -04:00
Mark Roszko 9ca1bf63d9 jobsets: fix Replace button to overwrite existing files (#19900)
(cherry picked from commit 5fb55ccb30)

1ea009e6 jobsets: allow replacing existing jobset files

Co-authored-by: Adrián García <adrgarcia@outlook.com>
2025-09-01 01:14:25 +00:00
Jeff Young 7e13870ae3 Allow stitching of graphic shapes.
(cherry picked from commit 1309b436da)
2025-08-31 19:34:22 +01:00
Jeff Young 3c907b5589 Set free vias to graphic net if available.
Fixes https://gitlab.com/kicad/code/kicad/-/issues/21578

(cherry picked from commit c47b7459aa)
2025-08-31 19:34:19 +01:00
Jeff Young e9efd9971c Don't set point to a value we're not going to keep.
It just causes flicker.

Fixes https://gitlab.com/kicad/code/kicad/-/issues/19947

(cherry picked from commit a2e98fb53c)
2025-08-31 17:15:17 +01:00
Jeff Young 2bf9a6f5d1 Better interactive feedback.
Don't wait for mouse to move before refreshing after a command.

Also fixes a crash bug deleting an item after an
Unstage() (the Unstage() has already deleted the item).

Also fixes a crash when changing label type during
creation of a label produces a mess.

Also Keep cursor aligned to grid when not warping
back to original point.

Fixes https://gitlab.com/kicad/code/kicad/-/issues/16828

(cherry picked from commit 9d7db3d135)
2025-08-31 16:13:07 +01:00
jean-pierre charras 42c67b40b1 fix issues in ROUNDRECT: Fix incorrect ROUNDRECT Ctor.
- Do not throw  an error in CTor: this is not the place. It is much easy to
fix the value of incorrect radius.
Moreover, the Ctor is called without catching a throw-ed error in code.
- fix the test about radius validity, broken.

From master branch.
2025-08-31 08:25:14 +02:00
jean-pierre charras 5ae3c55a99 Step exporter: fix overzealous validity test.
When converting poly shapes with arcs in STEP_PCB_MODEL::MakeShapes,
when an error happens, a second try is made using a full polygonal shape.
However a fatal error was emitted at the first attempt, before the second try.
Now at first try, only a debug message is emitted on error. The fatal error
is emitted only if the second try fails.

Fixes https://gitlab.com/kicad/code/kicad/-/issues/21589

(cherry picked from commit aeafbe48fe)
2025-08-31 08:00:06 +02:00
Jeff Young 54e9a97b26 ADDED: separate front/back silk and mask colours for STEP export.
Fixes https://gitlab.com/kicad/code/kicad/-/issues/21593

(cherry picked from commit acc7b1e508)
2025-08-30 17:46:42 +01:00
Jeff Young 1e3b879d93 Run collision check on correct layer.
Fixes https://gitlab.com/kicad/code/kicad/-/issues/21586
2025-08-29 17:12:33 +01:00
Seth Hillbrand 7ca6a93436 Don't both designers with unneeded changes
If we are not asking for fields to be removed when updating, then don't
say we're doing anything if all we have to do is remove fields

(cherry picked from commit ea8206eca5)
2025-08-27 13:31:59 -07:00
jean-pierre charras 05c11d023f GERBER_JOBFILE_WRITER: fix incorrect layer id in File Attributes for inner layers.
Fixes https://gitlab.com/kicad/code/kicad/-/issues/21569

(cherry picked from commit 9725ac2215)
2025-08-27 13:28:55 +02:00
jean-pierre charras 996c3d7fa1 PAD: better HitTest( const VECTOR2I& aPosition, int aAccuracy, PCB_LAYER_ID aLayer )
(cherry picked from commit b349f1988a)
2025-08-27 13:27:45 +02:00
jean-pierre charras b204742fe3 Pcbnew: fix teardrop generation for pads having different shapes by layer.
Teardrop generator used pad::HitTest not testing the hit of a specific layer.
It created false test for some complex pads. Now use a test specific to a layer.

Fixes https://gitlab.com/kicad/code/kicad/-/issues/21560

(cherry picked from commit 963aa47778)
2025-08-27 11:35:07 +02:00
Emmanuel Vera 2b8e62e0b9 Update power filter for power symbols placement
(cherry picked from commit b5df0ad3eb)
2025-08-27 08:52:24 +02:00
jean-pierre charras c3d122becf French translation cleanup and update 2025-08-27 08:48:02 +02:00
John Beard 43c828474a Pcbnew: fix sensitivity of via placement to large grids
Another case where large grids are overly "grabby" for snaps.

In this case, because the via was moved to the grid-snap first,
and then THAT position was used to look for things like pad-snaps,
the pad snaps would not be found if a coarse grid meant the cursor
was outside the pad.

Instead, use the mouse position when looking for the non-grid snaps
in VIA_PLACER::SnapItem.

Fixes: https://gitlab.com/kicad/code/kicad/-/issues/18626
(cherry picked from commit 0f0527bd03)
2025-08-26 23:50:35 +08:00
John Beard 8073185c36 Pcbnew: use R-tree for pad checks in via place tool
Otherwise this is an O(n-pads-on-board) operation for every new
candidate via position.

(cherry picked from commit 3d8803f579)
2025-08-26 23:50:35 +08:00
Jeff Young f1ddcfe799 Expose shape in prop inspector for sheet pins.
(cherry picked from commit 3058bc6355)
2025-08-25 17:21:04 +01:00
jean-pierre charras 9d6f9c84d0 French translation update 2025-08-23 12:41:37 +02:00
jean-pierre charras 680a693c04 DIALOG_CHANGE_SYMBOLS: fix hanging is some cases and shows a better message.
When (happens after converting old schematics to the new format) trying to
update symbols having a bad lib id can hang Eeschema (infinite loop)
It can easily happens when the user has badly converted the schematic.
Also display a error message when happens.

Fixes https://gitlab.com/kicad/code/kicad/-/issues/21536

(cherry picked from commit 61aeea9237)
2025-08-23 12:40:48 +02:00
Alex Shvartzkop 4f72dd421a REPORTER's HasMessage indicates that any message got reported, not stored. 2025-08-23 00:27:41 +03:00
dsa-t bc533de0a3 Revert "Use board stackup colors by default in 3D render job."
This reverts commit f7380ae015
2025-08-23 00:09:53 +03:00
dsa-t c08109d63e Revert "Add FOLLOW_PCB, FOLLOW_PLOT_SETTINGS appearance presets to 3D render job dialog."
This reverts commit efc6c3e45e
2025-08-22 21:26:51 +03:00
Jeff Young b11f0a31b9 Read legacy tokens before current tokens.
(So current can overwrite.)

Fixes https://gitlab.com/kicad/code/kicad/-/issues/21525

(cherry picked from commit 03c230dd64)
2025-08-22 17:03:32 +01:00
Jeff Young f6fabdc8ee Don't double mirror groups.
Also removes previous fix, which had side-effects.

Fixes https://gitlab.com/kicad/code/kicad/-/issues/8121

Fixes https://gitlab.com/kicad/code/kicad/-/issues/20465

(cherry picked from commit 3f85071f91)
2025-08-22 17:03:25 +01:00
Jeff Young 965abb46d0 Avoid div-by-zero.
(cherry picked from commit c287d9a222)
2025-08-22 17:00:04 +01:00
Jeff Young c9f53c607e Fix missing initialization.
(cherry picked from commit de1c6c86ab)
2025-08-22 16:59:45 +01:00
Jeff Young 7b91b51bcf Add spacing for Mac file dialog custom controls.
(cherry picked from commit e841ca1906)
2025-08-22 16:59:29 +01:00
Jeff Young a3354dc352 Always provide a SCH_SCREEN to SCH_COMMIT.
Fixes KICAD-YKY

(cherry picked from commit a0940b10d4)
2025-08-22 16:57:17 +01:00
Jeff Young 6723964cdd Fix copy/pasta.
(cherry picked from commit c2f953e3f7)
2025-08-22 16:48:19 +01:00
Jeff Young df5f4ba541 Improve quasimodal comment.
(cherry picked from commit c85e5c08e4)
2025-08-22 16:46:39 +01:00
Jeff Young 926f41a0f5 Don't show locked shadow in pad preview.
(cherry picked from commit 60dbfd3eec)
2025-08-22 16:44:19 +01:00
Jeff Young db801c8d7e Remove stale comment.
(cherry picked from commit 3f1f9e8e72)
2025-08-22 16:43:35 +01:00
Jeff Young ad433b9468 ADDED: follow-pcb and follow-plot-settings to render job settings.
Also added Follow-board-stackup-colors to both
render job settings and render CLI arguments

Fixes https://gitlab.com/kicad/code/kicad/-/issues/21341

(cherry picked from commit 2e629ca55c)
2025-08-22 16:41:58 +01:00
Jeff Young 1eefb2b70a Allow deletion of nested embedded files.
Fixes https://gitlab.com/kicad/code/kicad/-/issues/20581

(cherry picked from commit ea84879b06)
2025-08-22 16:40:10 +01:00
Jeff Young 3d6527c1be Formatting.
(cherry picked from commit 7240128130)
2025-08-22 16:40:07 +01:00
Jeff Young 319530ad01 Grid is already updated by AddFile() callback.
Fixes https://gitlab.com/kicad/code/kicad/-/issues/20565

(cherry picked from commit 2c3408aad5)
2025-08-22 16:38:19 +01:00
Jeff Young 24efca1db1 Focus second column control after property grid navigation.
Fixes https://gitlab.com/kicad/code/kicad/-/issues/20651

(cherry picked from commit 95da436ddd)
2025-08-22 16:37:49 +01:00
Alex Shvartzkop a009d859d0 Fix some warnings. 2025-08-22 17:40:37 +03:00
Alex Shvartzkop 44a3bb9274 Prevent jobs from affecting each other via reporters when running jobsets from CLI. 2025-08-22 17:40:12 +03:00
Alex Shvartzkop 72e1904708 Fix ODB++ path creation. 2025-08-22 15:07:38 +03:00
Alex Shvartzkop 279a30974e Increase default precision in ODB++ export job dialog. 2025-08-22 14:34:43 +03:00
Alex Shvartzkop efc6c3e45e Add FOLLOW_PCB, FOLLOW_PLOT_SETTINGS appearance presets to 3D render job dialog. 2025-08-22 13:35:14 +03:00
Alex Shvartzkop f7380ae015 Use board stackup colors by default in 3D render job. 2025-08-22 13:34:25 +03:00
Alex Shvartzkop 26b6c28bef EasyEDA import: Add footprint Reference text on F_Fab. 2025-08-21 17:40:53 +03:00
Alex Shvartzkop 8cd7b73b2a EasyEDA import: Build basic Courtyard box for footprints. 2025-08-21 17:08:41 +03:00
Alex Shvartzkop c2d31699bf EasyEDA import: Place component shape and marking on F_Fab. 2025-08-21 17:04:23 +03:00
Alex Shvartzkop 47c5918c3d Add green color indication to length tuning status popup. 2025-08-21 15:38:08 +03:00
Alex Shvartzkop 12cf3f9301 router: Inline drag by track end even if cursor is slightly outside the track shape. 2025-08-21 13:56:25 +03:00
Alex Shvartzkop 013aab58d6 Update golden ERC QA files after 316a9511e8 2025-08-21 12:30:38 +03:00
Alex Shvartzkop 316a9511e8 Show errors before warnings in DRC/ERC. 2025-08-21 00:24:21 +03:00
Alex Shvartzkop 29fadcb931 Update translations 2025-08-21 00:16:37 +03:00
Pedro Moreira d73fecd2a1 Translated using Weblate (Korean)
Currently translated at 98.6% (9933 of 10065 strings)

Translation: KiCad EDA/v9
Translate-URL: https://hosted.weblate.org/projects/kicad/v9/ko/
2025-08-20 23:15:12 +02:00
CloverGit 35caf91c31 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 99.9% (10059 of 10065 strings)

Translation: KiCad EDA/v9
Translate-URL: https://hosted.weblate.org/projects/kicad/v9/zh_Hans/
2025-08-20 23:15:12 +02:00
2tama3 352cf21ffc Translated using Weblate (Japanese)
Currently translated at 100.0% (10065 of 10065 strings)

Translation: KiCad EDA/v9
Translate-URL: https://hosted.weblate.org/projects/kicad/v9/ja/
2025-08-20 23:15:12 +02:00
CloverGit 21335f604f Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 99.9% (10059 of 10065 strings)

Translation: KiCad EDA/v9
Translate-URL: https://hosted.weblate.org/projects/kicad/v9/zh_Hans/
2025-08-20 23:15:12 +02:00
Henrik Kauhanen c6b7f90408 Translated using Weblate (Swedish)
Currently translated at 99.9% (10058 of 10065 strings)

Translation: KiCad EDA/v9
Translate-URL: https://hosted.weblate.org/projects/kicad/v9/sv/
2025-08-20 23:15:12 +02:00
2tama3 a5dee0c2b1 Translated using Weblate (Japanese)
Currently translated at 100.0% (10065 of 10065 strings)

Translation: KiCad EDA/v9
Translate-URL: https://hosted.weblate.org/projects/kicad/v9/ja/
2025-08-20 23:15:12 +02:00
Ettore Atalan bf73ad42ca Translated using Weblate (German)
Currently translated at 99.9% (10062 of 10065 strings)

Translation: KiCad EDA/v9
Translate-URL: https://hosted.weblate.org/projects/kicad/v9/de/
2025-08-20 23:15:11 +02:00
John Beard 7d905948f5 Pcbnew: fix refdes ordering in arrays
The first cell of the array needs to not be reannotated, or it will
skips its own number(s) and take what we expect for the second cell.
The repeats until the last entry, which didn't reannotate anything,
leaving the original numbers. Producing a 'rotation' like 2,3,4,5,1
rather than the expected 1,2,3,4,5.

Fixes: https://gitlab.com/kicad/code/kicad/-/issues/20935
(cherry picked from commit f31a109ab4)
2025-08-21 00:26:50 +08:00
John Beard 5c8c0e0648 Pcbnew: fix occasional failure-to-select for dragging
In the Drag tool client filter function, sometimes,
GuessSelectionCandidates trims the collector's item list.
But we used the old contents of the per-type vectors to make
judgements about what was connected.

If a call came in with 2 tracks (e.g. near a knee) and one
was removed by GuessSelectionCandidates, sometimes the
other one would be the one selected for removal in the
2 tracks/0 via case. This leaves the collector empty.

The other case, where the item removed by GuessSelectionCandidates
was removed from the collector is silent, as removing an item
not in the collector is a no-op.

Fixes: https://gitlab.com/kicad/code/kicad/-/issues/21517
(cherry picked from commit 105b9fcfe8)
2025-08-20 20:40:01 +08:00
Alex Shvartzkop 4cfa2e3a38 Remove unnecessary newlines in STEP exporter logging. 2025-08-20 14:54:27 +03:00
Alex Shvartzkop eecf0cd685 Remove a Message_Printer holding a stale REPORTER pointer from OCCT.
Fixes KICAD-V8A
2025-08-20 13:57:48 +03:00
Alex Shvartzkop 91e5e81bb4 Record execute command job input and error streams in the log.
Also print the resolved command.
2025-08-20 13:07:29 +03:00
JamesJCode 5b3cd96641 Don't assume SCH_SYMBOLs have a LIB_SYMBOL when resolving embedded files
Fixes https://gitlab.com/kicad/code/kicad/-/issues/21497

(cherry picked from commit ee9e94df04)
2025-08-19 14:17:02 +01:00
John Beard db0967d5c9 Pcbnew: fix bug in private layer selection
USer-defined layers now occur in steps of 2, otherwise
illegal layers for the grid get used.
2025-08-19 16:25:02 +08:00
jean-pierre charras 5165ced528 Eeschema: Reset m_ercRun flag when cleaning all markers.
Fixes https://gitlab.com/kicad/code/kicad/-/issues/21113

(cherry picked from commit 54085c4e50)
2025-08-18 17:33:30 +02:00
Alex Shvartzkop eb4f9fa093 Wrap command text control in execute command job dialog. 2025-08-18 17:06:17 +03:00
Alex Shvartzkop 47381f3d90 Disable ibeam cursor setter for search fields on non-OSX.
The ibeam cursor gets stuck on MSW when mouse leaves the field.
2025-08-18 15:53:37 +03:00
jean-pierre charras e697339bc6 PLOT_CONTROLLER::PlotLayer(): fix bug when drill marks must be plotted.
Fixes https://gitlab.com/kicad/code/kicad/-/issues/21474

(cherry picked from commit 20d8c9c7f9) and
(cherry picked from commit 2afd752bbc)
2025-08-18 11:48:07 +02:00
jean-pierre charras 6159cee2b0 Kicad manager: display the number of GDI objects in About Dialog (Windows only)
On Windows, if the number of GDI objects reach a limit (usually 10000) some can
be not shown, thus creating  a strange behavior not easy to diagnose.
Displaying the number in use can help.

(cherry picked from commit de208b3f00)
2025-08-18 09:07:31 +02:00
jean-pierre charras 3460b33ccf DIALOG_IMPORT_SETTINGS: fix some minor issues.
From master branch.
Fixes https://gitlab.com/kicad/code/kicad/-/issues/21483
2025-08-18 08:43:40 +02:00
jean-pierre charras 5baaa89131 Reapply "SHAPE_ARC::GetCentralAngle(): better algo to calculate actual arc."
This new algo is now tested since more than 2 months, so it should be good.
This reverts commit 88ad461514.
2025-08-18 08:25:33 +02:00
Wayne Stambaugh d45a38f086 Begin version 9.0.5 development. 2025-08-17 15:48:17 -04:00
400 changed files with 139232 additions and 138091 deletions
+4
View File
@@ -8,6 +8,7 @@ win64_build:
interruptible: false
image: registry.gitlab.com/kicad/kicad-ci/windows-build-image/ltsc2022-msvc:latest
variables:
VCPKG_BINARY_SOURCES: 'nuget,gitlab,readwrite'
# Switch the compressor to fastzip and reduce the compression level
FF_USE_FASTZIP: "true"
CACHE_COMPRESSION_LEVEL: "fast"
@@ -23,6 +24,7 @@ win64_build:
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 gitlab -Source "https://gitlab.com/api/v4/projects/27426693/packages/nuget/index.json" -UserName gitlab-ci-token -Password $env:CI_JOB_TOKEN
- mkdir -p build/windows -Force
- cd build/windows
- cmake `
@@ -34,6 +36,8 @@ win64_build:
-DKICAD_BUILD_PNS_DEBUG_TOOL=ON `
-DKICAD_USE_3DCONNEXION=ON `
-DVCPKG_BUILD_TYPE=debug `
-DVCPKG_INSTALL_OPTIONS="--x-abi-tools-use-exact-versions" `
-DVCPKG_OVERLAY_TRIPLETS="$Env:CI_PROJECT_DIR/tools/custom_vcpkg_triplets" `
../../
- cmake --build . 2>&1 | tee compilation_log.txt
- cd ../../
@@ -486,9 +486,12 @@ void RENDER_3D_RAYTRACE_BASE::renderBlockTracing( uint8_t* ptrPBO, signed int iB
// Initialize ray packets
const SFVEC2UI& blockPos = m_blockPositions[iBlock];
const SFVEC2I blockPosI = SFVEC2I( blockPos.x + m_xoffset, blockPos.y + m_yoffset );
const SFVEC2F randDisp = ( m_camera.GetProjection() == PROJECTION_TYPE::ORTHO ) ?
SFVEC2F( 0.0f, 0.0f ) :
SFVEC2F( DISP_FACTOR, DISP_FACTOR );
RAYPACKET blockPacket( m_camera, (SFVEC2F) blockPosI + SFVEC2F( DISP_FACTOR, DISP_FACTOR ),
SFVEC2F( DISP_FACTOR, DISP_FACTOR ) /* Displacement random factor */ );
RAYPACKET blockPacket( m_camera, (SFVEC2F) blockPosI + randDisp,
randDisp /* Displacement random factor */ );
HITINFO_PACKET hitPacket_X0Y0[RAYPACKET_RAYS_PER_PACKET];
@@ -566,7 +569,7 @@ void RENDER_3D_RAYTRACE_BASE::renderBlockTracing( uint8_t* ptrPBO, signed int iB
HITINFO_PACKET_init( hitPacket_AA_X1Y1 );
RAYPACKET blockPacket_AA_X1Y1( m_camera, (SFVEC2F) blockPosI + SFVEC2F( 0.5f, 0.5f ),
SFVEC2F( DISP_FACTOR, DISP_FACTOR ) );
randDisp );
if( !m_accelerator->Intersect( blockPacket_AA_X1Y1, hitPacket_AA_X1Y1 ) )
{
@@ -603,16 +606,16 @@ void RENDER_3D_RAYTRACE_BASE::renderBlockTracing( uint8_t* ptrPBO, signed int iB
RAY blockRayPck_AA_X1Y1_half[RAYPACKET_RAYS_PER_PACKET];
RAYPACKET_InitRays_with2DDisplacement(
m_camera, (SFVEC2F) blockPosI + SFVEC2F( 0.5f - DISP_FACTOR, DISP_FACTOR ),
SFVEC2F( DISP_FACTOR, DISP_FACTOR ), blockRayPck_AA_X1Y0 );
m_camera, (SFVEC2F) blockPosI + SFVEC2F( 0.5f - randDisp.x, randDisp.y ),
randDisp, blockRayPck_AA_X1Y0 );
RAYPACKET_InitRays_with2DDisplacement(
m_camera, (SFVEC2F) blockPosI + SFVEC2F( DISP_FACTOR, 0.5f - DISP_FACTOR ),
SFVEC2F( DISP_FACTOR, DISP_FACTOR ), blockRayPck_AA_X0Y1 );
m_camera, (SFVEC2F) blockPosI + SFVEC2F( randDisp.x, 0.5f - randDisp.y ),
randDisp, blockRayPck_AA_X0Y1 );
RAYPACKET_InitRays_with2DDisplacement(
m_camera, (SFVEC2F) blockPosI + SFVEC2F( 0.25f - DISP_FACTOR, 0.25f - DISP_FACTOR ),
SFVEC2F( DISP_FACTOR, DISP_FACTOR ), blockRayPck_AA_X1Y1_half );
m_camera, (SFVEC2F) blockPosI + SFVEC2F( 0.25f - randDisp.x, 0.25f - randDisp.y ),
randDisp, blockRayPck_AA_X1Y1_half );
renderAntiAliasPackets( bgColor, hitPacket_X0Y0, hitPacket_AA_X1Y1, blockRayPck_AA_X1Y0,
hitColor_AA_X1Y0 );
@@ -657,6 +657,12 @@ void PANEL_PREVIEW_3D_MODEL::UpdateDummyFootprint( bool aReloadRequired )
}
void PANEL_PREVIEW_3D_MODEL::SetEmbeddedFilesDelegate( EMBEDDED_FILES* aDelegate )
{
m_dummyBoard->SetEmbeddedFilesDelegate( aDelegate );
}
void PANEL_PREVIEW_3D_MODEL::onModify()
{
KIWAY_HOLDER* kiwayHolder = dynamic_cast<KIWAY_HOLDER*>( wxGetTopLevelParent( this ) );
@@ -59,6 +59,7 @@ wxDECLARE_EVENT( wxCUSTOM_PANEL_SHOWN_EVENT, wxCommandEvent );
class WX_INFOBAR;
class S3D_CACHE;
class FILENAME_RESOLVER;
class EMBEDDED_FILES;
class BOARD;
class BOARD_ADAPTER;
class FOOTPRINT;
@@ -97,6 +98,8 @@ public:
*/
void UpdateDummyFootprint( bool aRelaodRequired = true );
void SetEmbeddedFilesDelegate( EMBEDDED_FILES* aDelegate );
/**
* Get the dummy footprint that is used for previewing the 3D model.
* We use this to hold the temporary 3D model shapes.
+6 -1
View File
@@ -22,7 +22,12 @@
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
#
cmake_minimum_required( VERSION 3.21 FATAL_ERROR )
if( MSVC )
# CMake 3.28.1 or higher required for MSVC ARM builds for armasm64.exe support
cmake_minimum_required( VERSION 3.28.1 FATAL_ERROR )
else()
cmake_minimum_required( VERSION 3.21 FATAL_ERROR )
endif()
# Generate DEPFILES without transforming relative paths
cmake_policy( SET CMP0116 OLD )
+38 -3
View File
@@ -6,7 +6,12 @@
},
{
"environment": "vcpkg",
"VcPkgDir": "D:/vcpkg/"
"VcPkgDir": "D:/vcpkg/",
"VCPKG_BINARY_SOURCES": "nuget,kicad-gitlab,read"
},
{
"environment": "swig",
"SwigExePath": "D:/swigwin-4.1.1/swig.exe"
}
],
"configurations": [
@@ -14,7 +19,7 @@
"name": "x64-Debug",
"generator": "Ninja",
"configurationType": "Debug",
"inheritEnvironments": [ "msvc_x64_x64", "vcpkg" ],
"inheritEnvironments": [ "msvc_x64_x64", "vcpkg", "swig"],
"buildRoot": "${env.BuildDir}\\${name}",
"installRoot": "${env.InstallDir}\\${name}",
"cmakeCommandArgs": "",
@@ -30,6 +35,21 @@
"name": "KICAD_WIN32_DPI_AWARE",
"value": "ON",
"type": "BOOL"
},
{
"name": "SWIG_EXECUTABLE",
"value": "${env.SwigExePath}",
"type": "STRING"
},
{
"name": "VCPKG_OVERLAY_TRIPLETS",
"value": "${workspaceRoot}/tools/custom_vcpkg_triplets",
"type": "STRING"
},
{
"name": "VCPKG_INSTALL_OPTIONS",
"value": "--x-abi-tools-use-exact-versions",
"type": "STRING"
}
],
"cmakeToolchain": "${env.VcPkgDir}/scripts/buildsystems/vcpkg.cmake"
@@ -38,7 +58,7 @@
"name": "x64-Release",
"generator": "Ninja",
"configurationType": "RelWithDebInfo",
"inheritEnvironments": [ "msvc_x64_x64", "vcpkg" ],
"inheritEnvironments": [ "msvc_x64_x64", "vcpkg", "swig"],
"buildRoot": "${env.BuildDir}\\${name}",
"installRoot": "${env.InstallDir}\\${name}",
"cmakeCommandArgs": "",
@@ -54,6 +74,21 @@
"name": "KICAD_WIN32_DPI_AWARE",
"value": "ON",
"type": "BOOL"
},
{
"name": "SWIG_EXECUTABLE",
"value": "${env.SwigExePath}",
"type": "STRING"
},
{
"name": "VCPKG_OVERLAY_TRIPLETS",
"value": "${workspaceRoot}/tools/custom_vcpkg_triplets",
"type": "STRING"
},
{
"name": "VCPKG_INSTALL_OPTIONS",
"value": "--x-abi-tools-use-exact-versions",
"type": "STRING"
}
],
"cmakeToolchain": "${env.VcPkgDir}/scripts/buildsystems/vcpkg.cmake"
+33
View File
@@ -42,12 +42,45 @@ message BoardStackupResponse
kiapi.board.BoardStackup stackup = 1;
}
// Changes the stackup for the given board according to the contents of the message (**not yet implemented**)
// WARNING: any existing content on layers that are removed by this call is deleted. This operation cannot be undone.
// Returns BoardStackupResponse with the updated stackup, in normalized form
message UpdateBoardStackup
{
kiapi.common.types.DocumentSpecifier board = 1;
kiapi.board.BoardStackup stackup = 2;
}
message GetBoardEnabledLayers
{
kiapi.common.types.DocumentSpecifier board = 1;
}
message BoardEnabledLayersResponse
{
// The number of copper layers enabled in this board.
uint32 copper_layer_count = 1;
// A list of all layers enabled in this board, including copper layers and ones which cannot be disabled.
repeated kiapi.board.types.BoardLayer layers = 2;
}
// Changes which layers are enabled in the board stackup
// WARNING: any existing content on layers that are removed by this call is deleted. This operation cannot be undone.
// Returns BoardEnabledLayersResponse with the updated layer set.
message SetBoardEnabledLayers
{
kiapi.common.types.DocumentSpecifier board = 1;
// The number of copper layers to enable in the board. Currently, this must be an even number >= 2.
uint32 copper_layer_count = 2;
// The non-copper layers to enable. Note that any copper layers in this list are ignored; copper layers are enabled
// by setting copper_layer_count. Note that the F/B.Courtyard, Edge.Cuts, and Margin layers cannot be disabled and
// will be present in the board even if they are omitted from this list.
repeated kiapi.board.types.BoardLayer layers = 3;
}
message GetGraphicsDefaults
{
kiapi.common.types.DocumentSpecifier board = 1;
+15 -29
View File
@@ -36,7 +36,13 @@ if( MSVC )
set( KICAD_HOST_ARCH "x64" )
set( KICAD_HOST_ARCH_X64 1 )
else()
message(FATAL_ERROR "Failed to determine the host architecture: ${CMAKE_SYSTEM_PROCESSOR}")
message(FATAL_ERROR "Failed to determine the host architecture: ${CMAKE_HOST_SYSTEM_PROCESSOR}")
endif()
if( NOT KICAD_BUILD_ARCH STREQUAL KICAD_HOST_ARCH )
set( CMAKE_CROSSCOMPILING TRUE )
string(TOUPPER ${KICAD_BUILD_ARCH} CMAKE_SYSTEM_PROCESSOR)
endif()
else()
if ( NOT CMAKE_SIZEOF_VOID_P EQUAL 8 )
@@ -58,38 +64,18 @@ if( MSVC )
# cmake release AND when MSVC ships said cmake release
if(KICAD_BUILD_ARCH_ARM)
message( "Configuring ARM assembler" )
# Explicitly specify the assembler to be used for Arm32 compile
file(TO_CMAKE_PATH "$ENV{VCToolsInstallDir}\\bin\\HostX86\\arm\\armasm.exe" CMAKE_ASM_COMPILER)
set(CMAKE_ASM_MASM_COMPILER ${CMAKE_ASM_COMPILER})
message("CMAKE_ASM_MASM_COMPILER explicitly set to: ${CMAKE_ASM_MASM_COMPILER}")
# Enable generic assembly compilation to avoid CMake generate VS proj files that explicitly
# use ml[64].exe as the assembler.
enable_language(ASM)
set(CMAKE_ASM_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreaded "")
set(CMAKE_ASM_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreadedDLL "")
set(CMAKE_ASM_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreadedDebug "")
set(CMAKE_ASM_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreadedDebugDLL "")
set(CMAKE_ASM_COMPILE_OBJECT "<CMAKE_ASM_COMPILER> -g <INCLUDES> <FLAGS> -o <OBJECT> <SOURCE>")
enable_language(ASM_MARMASM)
# Bugfix for CMake < 29.1
set(ASM_DIALECT "_MARMASM")
set(CMAKE_ASM${ASM_DIALECT}_COMPILE_OBJECT "<CMAKE_ASM${ASM_DIALECT}_COMPILER> <INCLUDES> <FLAGS> -o <OBJECT> <SOURCE>")
elseif(KICAD_BUILD_ARCH_ARM64)
message( "Configuring ARM64 assembler" )
# Explicitly specify the assembler to be used for Arm64 compile
file(TO_CMAKE_PATH "$ENV{VCToolsInstallDir}\\bin\\HostX86\\arm64\\armasm64.exe" CMAKE_ASM_COMPILER)
set(CMAKE_ASM_MASM_COMPILER ${CMAKE_ASM_COMPILER})
message("CMAKE_ASM_MASM_COMPILER explicitly set to: ${CMAKE_ASM_MASM_COMPILER}")
# Enable generic assembly compilation to avoid CMake generate VS proj files that explicitly
# use ml[64].exe as the assembler.
enable_language(ASM)
set(CMAKE_ASM_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreaded "")
set(CMAKE_ASM_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreadedDLL "")
set(CMAKE_ASM_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreadedDebug "")
set(CMAKE_ASM_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreadedDebugDLL "")
set(CMAKE_ASM_COMPILE_OBJECT "<CMAKE_ASM_COMPILER> -g <INCLUDES> <FLAGS> -o <OBJECT> <SOURCE>")
enable_language(ASM_MARMASM)
# Bugfix for CMake < 29.1
set(ASM_DIALECT "_MARMASM")
set(CMAKE_ASM${ASM_DIALECT}_COMPILE_OBJECT "<CMAKE_ASM${ASM_DIALECT}_COMPILER> <INCLUDES> <FLAGS> -o <OBJECT> <SOURCE>")
else()
message( "Configuring MASM assembler" )
if(KICAD_BUILD_ARCH_X86)
+2 -2
View File
@@ -2,7 +2,7 @@
# This program source code file is part of KICAD, a free EDA CAD application.
#
# Copyright (C) 2016 Wayne Stambaugh <stambaughw@gmail.com>
# Copyright (C) 2016-2023, 2024 KiCad Developers, see AUTHORS.txt for contributors.
# Copyright (C) 2016-2023, 2024, 2025 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
@@ -37,7 +37,7 @@
# KiCad.
#
# Note: This version string should follow the semantic versioning system
set( KICAD_SEMANTIC_VERSION "9.0.4" )
set( KICAD_SEMANTIC_VERSION "9.0.6" )
# Default the version to the semantic version.
# This is overridden by the git repository tag though (if using git)
-51
View File
@@ -1,51 +0,0 @@
# compile_asm(TARGET target ASM_FILES file1 [file2 ...] OUTPUT_OBJECTS [variableName])
# CMake does not support the ARM or ARM64 assemblers on Windows when using the
# MSBuild generator. When the MSBuild generator is in use, we manually compile the assembly files
# using this function.
#
# Borrowed from dotnet/runtime, licensed under MIT
# Copyright (c) .NET Foundation and Contributors
# https://github.com/dotnet/runtime/blob/main/eng/native/functions.cmake
function(compile_asm)
set(options "")
set(oneValueArgs TARGET OUTPUT_OBJECTS)
set(multiValueArgs ASM_FILES)
cmake_parse_arguments(COMPILE_ASM "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGV})
get_include_directories_asm(ASM_INCLUDE_DIRECTORIES)
set (ASSEMBLED_OBJECTS "")
foreach(ASM_FILE ${COMPILE_ASM_ASM_FILES})
get_filename_component(name ${ASM_FILE} NAME_WE)
# Produce object file where CMake would store .obj files for an OBJECT library.
# ex: artifacts\obj\coreclr\windows.arm64.Debug\src\vm\wks\cee_wks.dir\Debug\AsmHelpers.obj
set (OBJ_FILE "${CMAKE_CURRENT_BINARY_DIR}/${COMPILE_ASM_TARGET}.dir/${CMAKE_CFG_INTDIR}/${name}.obj")
# Need to compile asm file using custom command as include directories are not provided to asm compiler
add_custom_command(OUTPUT ${OBJ_FILE}
COMMAND "${CMAKE_ASM_COMPILER}" -g ${ASM_INCLUDE_DIRECTORIES} -o ${OBJ_FILE} ${ASM_FILE}
DEPENDS ${ASM_FILE}
COMMENT "Assembling ${ASM_FILE} ---> \"${CMAKE_ASM_COMPILER}\" -g ${ASM_INCLUDE_DIRECTORIES} -o ${OBJ_FILE} ${ASM_FILE}")
# mark obj as source that does not require compile
set_source_files_properties(${OBJ_FILE} PROPERTIES EXTERNAL_OBJECT TRUE)
# Add the generated OBJ in the dependency list so that it gets consumed during linkage
list(APPEND ASSEMBLED_OBJECTS ${OBJ_FILE})
endforeach()
set(${COMPILE_ASM_OUTPUT_OBJECTS} ${ASSEMBLED_OBJECTS} PARENT_SCOPE)
endfunction()
# Build a list of include directories for consumption by the assembler
function(get_include_directories_asm IncludeDirectories)
get_directory_property(dirs INCLUDE_DIRECTORIES)
foreach(dir IN LISTS dirs)
list(APPEND INC_DIRECTORIES -I${dir};)
endforeach()
set(${IncludeDirectories} ${INC_DIRECTORIES} PARENT_SCOPE)
endfunction(get_include_directories_asm)
+17
View File
@@ -102,6 +102,7 @@ static const wxChar EnableDesignBlocks[] = wxT( "EnableDesignBlocks" );
static const wxChar EnableGenerators[] = wxT( "EnableGenerators" );
static const wxChar EnableLibWithText[] = wxT( "EnableLibWithText" );
static const wxChar EnableLibDir[] = wxT( "EnableLibDir" );
static const wxChar LibraryTableEditor[] = wxT( "LibraryTableEditor" );
static const wxChar EnableEeschemaPrintCairo[] = wxT( "EnableEeschemaPrintCairo" );
static const wxChar EnableEeschemaExportClipboardCairo[] = wxT( "EnableEeschemaExportClipboardCairo" );
static const wxChar DisambiguationTime[] = wxT( "DisambiguationTime" );
@@ -120,6 +121,8 @@ static const wxChar EnableExtensionSnaps[] = wxT( "EnableExtensionSnaps" );
static const wxChar ExtensionSnapTimeoutMs[] = wxT( "ExtensionSnapTimeoutMs" );
static const wxChar ExtensionSnapActivateOnHover[] = wxT( "ExtensionSnapActivateOnHover" );
static const wxChar EnableSnapAnchorsDebug[] = wxT( "EnableSnapAnchorsDebug" );
static const wxChar SnapHysteresis[] = wxT( "SnapHysteresis" );
static const wxChar SnapToAnchorMargin[] = wxT( "SnapToAnchorMargin" );
static const wxChar MinParallelAngle[] = wxT( "MinParallelAngle" );
static const wxChar HoleWallPaintingMultiplier[] = wxT( "HoleWallPaintingMultiplier" );
static const wxChar MsgPanelShowUuids[] = wxT( "MsgPanelShowUuids" );
@@ -262,6 +265,7 @@ ADVANCED_CFG::ADVANCED_CFG()
m_EnableGenerators = false;
m_EnableLibWithText = false;
m_EnableLibDir = false;
m_LibraryTableEditor = false;
m_EnableEeschemaPrintCairo = true;
m_EnableEeschemaExportClipboardCairo = true;
@@ -299,6 +303,8 @@ ADVANCED_CFG::ADVANCED_CFG()
m_ExtensionSnapTimeoutMs = 500;
m_ExtensionSnapActivateOnHover = true;
m_EnableSnapAnchorsDebug = false;
m_SnapHysteresis = 5;
m_SnapToAnchorMargin = 1.1;
m_MinParallelAngle = 0.001;
m_HoleWallPaintingMultiplier = 1.5;
@@ -512,6 +518,9 @@ void ADVANCED_CFG::loadSettings( wxConfigBase& aCfg )
configParams.push_back( new PARAM_CFG_BOOL( true, AC_KEYS::EnableLibDir,
&m_EnableLibDir, m_EnableLibDir ) );
configParams.push_back( new PARAM_CFG_BOOL( true, AC_KEYS::LibraryTableEditor,
&m_LibraryTableEditor, m_LibraryTableEditor ) );
configParams.push_back( new PARAM_CFG_BOOL( true, AC_KEYS::EnableEeschemaPrintCairo,
&m_EnableEeschemaPrintCairo,
m_EnableEeschemaPrintCairo ) );
@@ -577,6 +586,14 @@ void ADVANCED_CFG::loadSettings( wxConfigBase& aCfg )
&m_EnableSnapAnchorsDebug,
m_EnableSnapAnchorsDebug ) );
configParams.push_back( new PARAM_CFG_INT( true, AC_KEYS::SnapHysteresis,
&m_SnapHysteresis, m_SnapHysteresis,
0, 100 ) );
configParams.push_back( new PARAM_CFG_DOUBLE( true, AC_KEYS::SnapToAnchorMargin,
&m_SnapToAnchorMargin, m_SnapToAnchorMargin,
1.0, 2.0 ) );
configParams.push_back( new PARAM_CFG_DOUBLE( true, AC_KEYS::MinParallelAngle,
&m_MinParallelAngle, m_MinParallelAngle,
0.0, 45.0 ) );
+3 -2
View File
@@ -24,6 +24,7 @@
#include "clipboard.h"
#include <wx/clipbrd.h>
#include <wx/dataobj.h>
#include <wx/image.h>
#include <wx/log.h>
@@ -84,10 +85,10 @@ std::unique_ptr<wxImage> GetImageFromClipboard()
{
if( wxTheClipboard->IsSupported( wxDF_BITMAP ) )
{
wxImageDataObject data;
wxBitmapDataObject data;
if( wxTheClipboard->GetData( data ) )
{
image = std::make_unique<wxImage>( data.GetImage() );
image = std::make_unique<wxImage>( data.GetBitmap().ConvertToImage() );
}
}
else if( wxTheClipboard->IsSupported( wxDF_FILENAME ) )
+14 -13
View File
@@ -161,7 +161,7 @@ bool DATABASE_CONNECTION::Connect()
m_conn = std::make_unique<nanodbc::connection>( cs, m_timeout );
}
}
catch( nanodbc::database_error& e )
catch( std::exception& e )
{
m_lastError = e.what();
return false;
@@ -188,7 +188,7 @@ bool DATABASE_CONNECTION::Disconnect()
{
m_conn->disconnect();
}
catch( boost::locale::conv::conversion_error& exc )
catch( std::exception& exc )
{
wxLogTrace( traceDatabase, wxT( "Disconnect() error \"%s\" occured." ), exc.what() );
return false;
@@ -250,7 +250,7 @@ bool DATABASE_CONNECTION::CacheTableInfo( const std::string& aTable,
return false;
}
}
catch( nanodbc::database_error& e )
catch( std::exception& e )
{
m_lastError = e.what();
wxLogTrace( traceDatabase, wxT( "Exception while caching table info: %s" ), m_lastError );
@@ -277,8 +277,9 @@ bool DATABASE_CONNECTION::getQuoteChar()
wxLogTrace( traceDatabase, wxT( "Quote char retrieved: %c" ), m_quoteChar );
}
catch( nanodbc::database_error& )
catch( std::exception& e )
{
m_lastError = e.what();
wxLogTrace( traceDatabase, wxT( "Exception while querying quote char: %s" ), m_lastError );
return false;
}
@@ -401,14 +402,14 @@ bool DATABASE_CONNECTION::SelectOne( const std::string& aTable,
statement.prepare( *m_conn, query );
statement.bind( 0, aWhere.second.c_str() );
}
catch( nanodbc::database_error& e )
catch( std::exception& e )
{
m_lastError = e.what();
wxLogTrace( traceDatabase, wxT( "Exception while preparing statement for SelectOne: %s" ),
m_lastError );
// Exception may be due to a connection error; nanodbc won't auto-reconnect
m_conn->disconnect();
Disconnect();
return false;
}
@@ -422,14 +423,14 @@ bool DATABASE_CONNECTION::SelectOne( const std::string& aTable,
{
results = nanodbc::execute( statement );
}
catch( nanodbc::database_error& e )
catch( std::exception& e )
{
m_lastError = e.what();
wxLogTrace( traceDatabase, wxT( "Exception while executing statement for SelectOne: %s" ),
m_lastError );
// Exception may be due to a connection error; nanodbc won't auto-reconnect
m_conn->disconnect();
Disconnect();
return false;
}
@@ -480,7 +481,7 @@ bool DATABASE_CONNECTION::SelectOne( const std::string& aTable,
}
}
}
catch( nanodbc::database_error& e )
catch( std::exception& e )
{
m_lastError = e.what();
wxLogTrace( traceDatabase, wxT( "Exception while parsing results from SelectOne: %s" ),
@@ -507,7 +508,7 @@ bool DATABASE_CONNECTION::selectAllAndCache( const std::string& aTable, const st
{
statement.prepare( query );
}
catch( nanodbc::database_error& e )
catch( std::exception& e )
{
m_lastError = e.what();
wxLogTrace( traceDatabase,
@@ -515,7 +516,7 @@ bool DATABASE_CONNECTION::selectAllAndCache( const std::string& aTable, const st
m_lastError );
// Exception may be due to a connection error; nanodbc won't auto-reconnect
m_conn->disconnect();
Disconnect();
return false;
}
@@ -526,7 +527,7 @@ bool DATABASE_CONNECTION::selectAllAndCache( const std::string& aTable, const st
{
results = nanodbc::execute( statement );
}
catch( nanodbc::database_error& e )
catch( std::exception& e )
{
m_lastError = e.what();
wxLogTrace( traceDatabase,
@@ -534,7 +535,7 @@ bool DATABASE_CONNECTION::selectAllAndCache( const std::string& aTable, const st
m_lastError );
// Exception may be due to a connection error; nanodbc won't auto-reconnect
m_conn->disconnect();
Disconnect();
return false;
}
+2 -1
View File
@@ -631,7 +631,8 @@ bool DESIGN_BLOCK_LIB_TABLE::LoadGlobalTable( DESIGN_BLOCK_LIB_TABLE& aTable )
{
tableExists = false;
if( !fn.DirExists() && !fn.Mkdir( 0x777, wxPATH_MKDIR_FULL ) )
if( !wxFileName::DirExists( fn.GetPath() )
&& !wxFileName::Mkdir( fn.GetPath(), 0x777, wxPATH_MKDIR_FULL ) )
{
THROW_IO_ERROR( wxString::Format( _( "Cannot create global library table path '%s'." ),
fn.GetPath() ) );
+7 -1
View File
@@ -909,7 +909,13 @@ static void buildKicadAboutBanner( EDA_BASE_FRAME* aParent, ABOUT_APP_INFO& aInf
#define FOOTPRINT_LIB_CONTRIBUTION _( "Footprints" )
aInfo.AddLibrarian( new CONTRIBUTOR( wxS( "Scripts by Maui" ),
MODELS_3D_CONTRIBUTION,
wxS( "https://gitlab.com/kicad/libraries/kicad-footprint-generator" ) ) );
wxS( "https://github.com/easyw" ) ) );
aInfo.AddLibrarian( new CONTRIBUTOR( wxS( "Hasan Yavuz Özderya" ),
MODELS_3D_CONTRIBUTION,
wxS( "https://bitbucket.org/hyOzd/freecad-macros/src/master/" ) ) );
aInfo.AddLibrarian( new CONTRIBUTOR( wxS( "GitHub contributors" ),
MODELS_3D_CONTRIBUTION,
wxS( "https://github.com/easyw/kicad-3d-models-in-freecad/graphs/contributors" ) ) );
aInfo.AddLibrarian( new CONTRIBUTOR( wxS( "GitLab contributors" ),
MODELS_3D_CONTRIBUTION,
wxS( "https://gitlab.com/kicad/libraries/kicad-packages3D/-/graphs/master" ) ) );
+13 -2
View File
@@ -22,7 +22,6 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include <build_version.h>
#include <eda_base_frame.h>
#include <wx/clipbrd.h>
@@ -108,8 +107,20 @@ DIALOG_ABOUT::DIALOG_ABOUT( EDA_BASE_FRAME *aParent, ABOUT_APP_INFO& aAppInfo )
m_titleName = aParent->GetAboutTitle();
m_untranslatedTitleName = aParent->GetUntranslatedAboutTitle();
m_staticTextAppTitle->SetLabel( m_titleName );
// On windows, display the number of GDI objects in use. Can be useful when some GDI objects
// are not displayed because the max count of GDI objects (usually 10000) is reached
// So displaying this number can help to diagnose strange display issues
wxString extraInfo;
#if defined( _WIN32 )
uint32_t gdi_count = GetGuiResources( GetCurrentProcess(), GR_GDIOBJECTS );
extraInfo.Printf( _( "GDI objects in use %u" ), gdi_count );
extraInfo.Prepend( wxT( "\n" ) );
#endif
m_staticTextBuildVersion->SetLabel( wxS( "Version: " ) + m_info.GetBuildVersion() );
m_staticTextLibVersion->SetLabel( m_info.GetLibVersion() );
m_staticTextLibVersion->SetLabel( m_info.GetLibVersion() + extraInfo );
SetTitle( wxString::Format( _( "About %s" ), m_titleName ) );
createNotebooks();
+5 -2
View File
@@ -494,14 +494,17 @@ int DIALOG_SHIM::ShowModal()
}
/*
Quasi-Modal Mode Explained:
QuasiModal Mode Explained:
The gtk calls in wxDialog::ShowModal() cause event routing problems if that
modal dialog then tries to use KIWAY_PLAYER::ShowModal(). The latter shows up
and mostly works but does not respond to the window decoration close button.
There is no way to get around this without reversing the gtk calls temporarily.
Quasi-Modal mode is our own almost modal mode which disables only the parent
There are also issues with the Scintilla text editor putting up autocomplete
popups, which appear behind the dialog window if QuasiModal is not used.
QuasiModal mode is our own almost modal mode which disables only the parent
of the DIALOG_SHIM, leaving other frames operable and while staying captured in the
nested event loop. This avoids the gtk calls and leaves event routing pure
and sufficient to operate the KIWAY_PLAYER::ShowModal() properly. When using
@@ -27,6 +27,8 @@
#include "design_block_lib_table.h"
#include <kiplatform/io.h>
DIALOG_GLOBAL_DESIGN_BLOCK_LIB_TABLE_CONFIG::DIALOG_GLOBAL_DESIGN_BLOCK_LIB_TABLE_CONFIG(
wxWindow* aParent ) :
@@ -106,8 +108,8 @@ bool DIALOG_GLOBAL_DESIGN_BLOCK_LIB_TABLE_CONFIG::TransferDataFromWindow()
// Create the config path if it doesn't already exist.
wxFileName designBlockTableFileName = DESIGN_BLOCK_LIB_TABLE::GetGlobalTableFileName();
if( !designBlockTableFileName.DirExists()
&& !designBlockTableFileName.Mkdir( 0x777, wxPATH_MKDIR_FULL ) )
if( !wxFileName::DirExists( designBlockTableFileName.GetPath() )
&& !wxFileName::Mkdir( designBlockTableFileName.GetPath(), 0x777, wxPATH_MKDIR_FULL ) )
{
DisplayError( this, wxString::Format( _( "Cannot create global library table '%s'." ),
designBlockTableFileName.GetPath() ) );
@@ -124,6 +126,9 @@ bool DIALOG_GLOBAL_DESIGN_BLOCK_LIB_TABLE_CONFIG::TransferDataFromWindow()
fn.GetFullPath(), designBlockTableFileName.GetFullPath() ) );
return false;
}
// Ensure the copied file is writable
KIPLATFORM::IO::MakeWriteable( designBlockTableFileName.GetFullPath() );
}
// Load the successfully copied design block library table file. This should not fail since the
+48 -8
View File
@@ -21,6 +21,8 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include <eda_item.h>
#include <confirm.h>
#include <bitmaps.h>
#include <dialogs/panel_embedded_files.h>
#include <embedded_files.h>
@@ -161,9 +163,7 @@ void PANEL_EMBEDDED_FILES::resizeGrid()
bool PANEL_EMBEDDED_FILES::TransferDataToWindow()
{
m_files_grid->ClearGrid();
if( m_files_grid->GetNumberRows() > 0 )
m_files_grid->DeleteRows( 0, m_files_grid->GetNumberRows() );
m_files_grid->ClearRows();
int ii = 0;
for( auto& [name, file] : m_localFiles->EmbeddedFileMap() )
@@ -187,6 +187,51 @@ bool PANEL_EMBEDDED_FILES::TransferDataToWindow()
bool PANEL_EMBEDDED_FILES::TransferDataFromWindow()
{
std::optional<bool> deleteReferences;
auto confirmDelete =
[&]() -> bool
{
if( EDA_ITEM* parent = dynamic_cast<EDA_ITEM*>( m_files ) )
{
if( parent->Type() == PCB_T )
{
return IsOK( m_parent, _( "Deleted embedded files are also referenced in some footprints.\n"
"Delete from footprints as well?" ) );
}
else if( parent->Type() == SCHEMATIC_T )
{
return IsOK( m_parent, _( "Deleted embedded files are also referenced in some symbols.\n"
"Delete from symbols as well?" ) );
}
}
wxFAIL_MSG( wxT( "Unexpected embedded files owner" ) );
return false;
};
for( const auto& [name, file] : m_files->EmbeddedFileMap() )
{
if( !m_localFiles->HasFile( name ) )
{
m_files->RunOnNestedEmbeddedFiles(
[&]( EMBEDDED_FILES* nested_files )
{
if( nested_files->HasFile( name ) )
{
if( !deleteReferences.has_value() )
deleteReferences = confirmDelete();
if( deleteReferences.value() )
nested_files->RemoveFile( name, true );
}
} );
}
if( deleteReferences.has_value() && deleteReferences.value() == false )
break;
}
m_files->ClearEmbeddedFiles();
std::vector<EMBEDDED_FILES::EMBEDDED_FILE*> files;
@@ -247,11 +292,6 @@ void PANEL_EMBEDDED_FILES::onFontEmbedClick( wxCommandEvent& event )
font->GetFileName() ) );
continue;
}
m_files_grid->AppendRows( 1 );
int ii = m_files_grid->GetNumberRows() - 1;
m_files_grid->SetCellValue( ii, 0, result->name );
m_files_grid->SetCellValue( ii, 1, result->GetLink() );
}
}
+1
View File
@@ -141,6 +141,7 @@ void EDA_BASE_FRAME::commonInit( FRAME_T aFrameType )
m_isNonUserClose = false;
m_autoSaveTimer = new wxTimer( this, ID_AUTO_SAVE_TIMER );
m_autoSaveRequired = false;
m_autoSavePermissionError = false;
m_mruPath = PATHS::GetDefaultUserProjectsPath();
m_frameSize = defaultSize( aFrameType, this );
m_displayIndex = -1;
+4 -4
View File
@@ -2339,10 +2339,10 @@ static struct EDA_SHAPE_DESC
if( lineStyleEnum.Choices().GetCount() == 0 )
{
lineStyleEnum.Map( LINE_STYLE::SOLID, _HKI( "Solid" ) )
.Map( LINE_STYLE::DASH, _HKI( "Dashed" ) )
.Map( LINE_STYLE::DOT, _HKI( "Dotted" ) )
.Map( LINE_STYLE::DASHDOT, _HKI( "Dash-Dot" ) )
lineStyleEnum.Map( LINE_STYLE::SOLID, _HKI( "Solid" ) )
.Map( LINE_STYLE::DASH, _HKI( "Dashed" ) )
.Map( LINE_STYLE::DOT, _HKI( "Dotted" ) )
.Map( LINE_STYLE::DASHDOT, _HKI( "Dash-Dot" ) )
.Map( LINE_STYLE::DASHDOTDOT, _HKI( "Dash-Dot-Dot" ) );
}
+6 -6
View File
@@ -1323,18 +1323,18 @@ static struct EDA_TEXT_DESC
if( h_inst.Choices().GetCount() == 0)
{
h_inst.Map( GR_TEXT_H_ALIGN_LEFT, _( "Left" ) );
h_inst.Map( GR_TEXT_H_ALIGN_CENTER, _( "Center" ) );
h_inst.Map( GR_TEXT_H_ALIGN_RIGHT, _( "Right" ) );
h_inst.Map( GR_TEXT_H_ALIGN_LEFT, _HKI( "Left" ) );
h_inst.Map( GR_TEXT_H_ALIGN_CENTER, _HKI( "Center" ) );
h_inst.Map( GR_TEXT_H_ALIGN_RIGHT, _HKI( "Right" ) );
}
auto& v_inst = ENUM_MAP<GR_TEXT_V_ALIGN_T>::Instance();
if( v_inst.Choices().GetCount() == 0)
{
v_inst.Map( GR_TEXT_V_ALIGN_TOP, _( "Top" ) );
v_inst.Map( GR_TEXT_V_ALIGN_CENTER, _( "Center" ) );
v_inst.Map( GR_TEXT_V_ALIGN_BOTTOM, _( "Bottom" ) );
v_inst.Map( GR_TEXT_V_ALIGN_TOP, _HKI( "Top" ) );
v_inst.Map( GR_TEXT_V_ALIGN_CENTER, _HKI( "Center" ) );
v_inst.Map( GR_TEXT_V_ALIGN_BOTTOM, _HKI( "Bottom" ) );
}
PROPERTY_MANAGER& propMgr = PROPERTY_MANAGER::Instance();
+79
View File
@@ -599,6 +599,85 @@ double EDA_UNIT_UTILS::UI::DoubleValueFromString( const EDA_IU_SCALE& aIuScale,
}
bool EDA_UNIT_UTILS::UI::DoubleValueFromString( const EDA_IU_SCALE& aIuScale, const wxString& aTextValue,
double& aDoubleValue )
{
double dtmp = 0;
// Acquire the 'right' decimal point separator
const struct lconv* lc = localeconv();
wxChar decimal_point = lc->decimal_point[0];
wxString buf( aTextValue.Strip( wxString::both ) );
// Convert any entered decimal point separators to the 'right' one
buf.Replace( wxT( "." ), wxString( decimal_point, 1 ) );
buf.Replace( wxT( "," ), wxString( decimal_point, 1 ) );
// Find the end of the numeric part
unsigned brk_point = 0;
while( brk_point < buf.Len() )
{
wxChar ch = buf[brk_point];
if( !( (ch >= '0' && ch <= '9') || (ch == decimal_point) || (ch == '-') || (ch == '+') ) )
break;
++brk_point;
}
if( brk_point == 0 )
return false;
// Extract the numeric part
buf.Left( brk_point ).ToDouble( &dtmp );
// Check the unit designator
wxString unit( buf.Mid( brk_point ).Strip( wxString::both ).Lower() );
EDA_UNITS units;
//check for um, μm (µ is MICRO SIGN) and µm (µ is GREEK SMALL LETTER MU) for micrometre
if( unit == wxT( "um" ) || unit == wxT( "\u00B5m" ) || unit == wxT( "\u03BCm" ) )
{
units = EDA_UNITS::UM;
}
else if( unit == wxT( "mm" ) )
{
units = EDA_UNITS::MM;
}
else if( unit == wxT( "cm" ) )
{
units = EDA_UNITS::CM;
}
else if( unit == wxT( "mil" ) || unit == wxT( "mils" ) || unit == wxT( "thou" ) )
{
units = EDA_UNITS::MILS;
}
else if( unit == wxT( "in" ) || unit == wxT( "\"" ) )
{
units = EDA_UNITS::INCH;
}
else if( unit == wxT( "oz" ) ) // 1 oz = 1.37 mils
{
units = EDA_UNITS::MILS;
dtmp *= 1.37;
}
else if( unit == wxT( "ra" ) ) // Radians
{
units = EDA_UNITS::DEGREES;
dtmp *= 180.0f / M_PI;
}
else
{
return false;
}
aDoubleValue = FromUserUnit( aIuScale, units, dtmp );
return true;
}
long long int EDA_UNIT_UTILS::UI::ValueFromString( const EDA_IU_SCALE& aIuScale, EDA_UNITS aUnits,
const wxString& aTextValue, EDA_DATA_TYPE aType )
{
+2 -1
View File
@@ -628,7 +628,8 @@ bool FP_LIB_TABLE::LoadGlobalTable( FP_LIB_TABLE& aTable )
{
tableExists = false;
if( !fn.DirExists() && !fn.Mkdir( 0x777, wxPATH_MKDIR_FULL ) )
if( !wxFileName::DirExists( fn.GetPath() )
&& !wxFileName::Mkdir( fn.GetPath(), 0x777, wxPATH_MKDIR_FULL ) )
{
THROW_IO_ERROR( wxString::Format( _( "Cannot create global library table path '%s'." ),
fn.GetPath() ) );
+8
View File
@@ -322,6 +322,12 @@ void CAIRO_GAL_BASE::DrawSegment( const VECTOR2D& aStartPoint, const VECTOR2D& a
}
void CAIRO_GAL_BASE::DrawHoleWall( const VECTOR2D& aCenterPoint, double aRadius, double aWallWidth )
{
DrawCircle( aCenterPoint, aRadius + aWallWidth );
}
void CAIRO_GAL_BASE::DrawCircle( const VECTOR2D& aCenterPoint, double aRadius )
{
syncLineWidth();
@@ -1740,6 +1746,8 @@ void CAIRO_GAL_BASE::DrawGrid()
return;
VECTOR2D gridScreenSize( m_gridSize );
gridScreenSize = VECTOR2D( std::max( 1.0, gridScreenSize.x ),
std::max( 1.0, gridScreenSize.y ) );
double gridThreshold = KiROUND( computeMinGridSpacing() / m_worldScale );
@@ -67,6 +67,7 @@ GAL::GAL( GAL_DISPLAY_OPTIONS& aDisplayOptions ) :
SetLayerDepth( 0.0 );
SetFlip( false, false );
SetLineWidth( 1.0f );
SetMinLineWidth( 1.0f );
computeWorldScale();
SetAxesEnabled( false );
@@ -75,6 +76,8 @@ GAL::GAL( GAL_DISPLAY_OPTIONS& aDisplayOptions ) :
SetCoarseGrid( 10 );
m_gridLineWidth = 0.5f;
m_gridStyle = GRID_STYLE::LINES;
m_gridSize = VECTOR2D( 1.0, 1.0 );
m_gridOffset = VECTOR2D( 0.0, 0.0 );
m_gridMinSpacing = 10;
// Initialize the cursor shape
+61 -12
View File
@@ -413,10 +413,13 @@ OPENGL_GAL::OPENGL_GAL( const KIGFX::VC_SETTINGS& aVcSettings, GAL_DISPLAY_OPTIO
SetTarget( TARGET_NONCACHED );
// Avoid uninitialized variables:
ufm_worldPixelSize = 1;
ufm_screenPixelSize = 1;
ufm_pixelSizeMultiplier = 1;
ufm_antialiasingOffset = 1;
ufm_worldPixelSize = -1;
ufm_screenPixelSize = -1;
ufm_pixelSizeMultiplier = -1;
ufm_antialiasingOffset = -1;
ufm_minLinePixelWidth = -1;
ufm_fontTexture = -1;
ufm_fontTextureWidth = -1;
m_swapInterval = 0;
}
@@ -672,14 +675,6 @@ void OPENGL_GAL::BeginDrawing()
glActiveTexture( GL_TEXTURE0 );
}
// Set shader parameter
GLint ufm_fontTexture = m_shader->AddParameter( "u_fontTexture" );
GLint ufm_fontTextureWidth = m_shader->AddParameter( "u_fontTextureWidth" );
ufm_worldPixelSize = m_shader->AddParameter( "u_worldPixelSize" );
ufm_screenPixelSize = m_shader->AddParameter( "u_screenPixelSize" );
ufm_pixelSizeMultiplier = m_shader->AddParameter( "u_pixelSizeMultiplier" );
ufm_antialiasingOffset = m_shader->AddParameter( "u_antialiasingOffset" );
m_shader->Use();
m_shader->SetParameter( ufm_fontTexture, (int) FONT_TEXTURE_UNIT );
m_shader->SetParameter( ufm_fontTextureWidth, (int) font_image.width );
@@ -700,6 +695,7 @@ void OPENGL_GAL::BeginDrawing()
renderingOffset.x *= screenPixelSize.x;
renderingOffset.y *= screenPixelSize.y;
m_shader->SetParameter( ufm_antialiasingOffset, renderingOffset );
m_shader->SetParameter( ufm_minLinePixelWidth, GetMinLineWidth() );
m_shader->Deactivate();
// Something between BeginDrawing and EndDrawing seems to depend on
@@ -716,6 +712,18 @@ void OPENGL_GAL::BeginDrawing()
#endif /* KICAD_GAL_PROFILE */
}
void OPENGL_GAL::SetMinLineWidth( float aLineWidth )
{
GAL::SetMinLineWidth( aLineWidth );
if( m_shader && ufm_minLinePixelWidth != -1 )
{
m_shader->Use();
m_shader->SetParameter( ufm_minLinePixelWidth, aLineWidth );
m_shader->Deactivate();
}
}
void OPENGL_GAL::EndDrawing()
{
@@ -907,6 +915,25 @@ void OPENGL_GAL::DrawCircle( const VECTOR2D& aCenterPoint, double aRadius )
}
void OPENGL_GAL::DrawHoleWall( const VECTOR2D& aCenterPoint, double aHoleRadius,
double aWallWidth )
{
if( m_isFillEnabled )
{
m_currentManager->Color( m_fillColor.r, m_fillColor.g, m_fillColor.b, m_fillColor.a );
m_currentManager->Shader( SHADER_HOLE_WALL, 1.0, aHoleRadius, aWallWidth );
m_currentManager->Vertex( aCenterPoint.x, aCenterPoint.y, m_layerDepth );
m_currentManager->Shader( SHADER_HOLE_WALL, 2.0, aHoleRadius, aWallWidth );
m_currentManager->Vertex( aCenterPoint.x, aCenterPoint.y, m_layerDepth );
m_currentManager->Shader( SHADER_HOLE_WALL, 3.0, aHoleRadius, aWallWidth );
m_currentManager->Vertex( aCenterPoint.x, aCenterPoint.y, m_layerDepth );
}
}
void OPENGL_GAL::drawCircle( const VECTOR2D& aCenterPoint, double aRadius, bool aReserve )
{
if( m_isFillEnabled )
@@ -2662,6 +2689,10 @@ void OPENGL_GAL::blitCursor()
glLineWidth( 1.0 );
glColor4d( color.r, color.g, color.b, color.a );
glMatrixMode( GL_PROJECTION );
glPushMatrix();
glTranslated( 0, 0, -0.5 );
glBegin( GL_LINES );
glVertex2d( cursorCenter.x, cursorBegin.y );
glVertex2d( cursorCenter.x, cursorEnd.y );
@@ -2669,6 +2700,8 @@ void OPENGL_GAL::blitCursor()
glVertex2d( cursorBegin.x, cursorCenter.y );
glVertex2d( cursorEnd.x, cursorCenter.y );
glEnd();
glPopMatrix();
}
@@ -2753,6 +2786,9 @@ void OPENGL_GAL::init()
if( !m_shader->IsLinked() && !m_shader->Link() )
throw std::runtime_error( "Cannot link the shaders!" );
// Set up shader parameters after linking
setupShaderParameters();
// Check if video card supports textures big enough to fit the font atlas
int maxTextureSize;
glGetIntegerv( GL_MAX_TEXTURE_SIZE, &maxTextureSize );
@@ -2781,6 +2817,19 @@ void OPENGL_GAL::init()
}
void OPENGL_GAL::setupShaderParameters()
{
// Initialize shader uniform parameter locations
ufm_fontTexture = m_shader->AddParameter( "u_fontTexture" );
ufm_fontTextureWidth = m_shader->AddParameter( "u_fontTextureWidth" );
ufm_worldPixelSize = m_shader->AddParameter( "u_worldPixelSize" );
ufm_screenPixelSize = m_shader->AddParameter( "u_screenPixelSize" );
ufm_pixelSizeMultiplier = m_shader->AddParameter( "u_pixelSizeMultiplier" );
ufm_antialiasingOffset = m_shader->AddParameter( "u_antialiasingOffset" );
ufm_minLinePixelWidth = m_shader->AddParameter( "u_minLinePixelWidth" );
}
// Callback functions for the tesselator. Compare Redbook Chapter 11.
void CALLBACK VertexCallback( GLvoid* aVertexPtr, void* aData )
{
+5
View File
@@ -35,6 +35,7 @@ const float SHADER_FILLED_CIRCLE = 2.0;
const float SHADER_STROKED_CIRCLE = 3.0;
const float SHADER_FONT = 4.0;
const float SHADER_LINE_A = 5.0;
const float SHADER_HOLE_WALL = 11.0;
varying vec4 v_shaderParams;
varying vec2 v_circleCoords;
@@ -124,6 +125,10 @@ void main()
{
strokedCircle( v_circleCoords, v_shaderParams[2], v_shaderParams[3] );
}
else if( mode == SHADER_HOLE_WALL )
{
strokedCircle( v_circleCoords, v_shaderParams[2], v_shaderParams[3] );
}
else if( mode == SHADER_FONT )
{
vec2 tex = v_shaderParams.yz;
+58 -4
View File
@@ -36,6 +36,7 @@ const float SHADER_LINE_C = 7.0;
const float SHADER_LINE_D = 8.0;
const float SHADER_LINE_E = 9.0;
const float SHADER_LINE_F = 10.0;
const float SHADER_HOLE_WALL = 11.0;
// Minimum line width
const float MIN_WIDTH = 1.0;
@@ -72,8 +73,8 @@ void computeLineCoords( bool posture, vec2 vs, vec2 vp, vec2 texcoord, vec2 dir,
vec2 s = sign( vec2( gl_ModelViewProjectionMatrix[0][0], gl_ModelViewProjectionMatrix[1][1] ) );
if( pixelWidth < 1.0 )
pixelWidth = 1.0;
if( pixelWidth < u_minLinePixelWidth )
pixelWidth = u_minLinePixelWidth;
if ( pixelWidth > 1.0 || u_pixelSizeMultiplier > 1.0 )
{
@@ -126,8 +127,59 @@ void computeCircleCoords( float mode, float vertexIndex, float radius, float lin
vec4 adjust = vec4(-1, -1, 0, 0);
if( pixelWidth < 1.0 )
pixelWidth = 1.0;
if( pixelWidth < u_minLinePixelWidth )
pixelWidth = u_minLinePixelWidth;
if( vertexIndex == 1.0 )
{
v_circleCoords = vec2( -sqrt( 3.0 ), -1.0 );
delta = vec4( -pixelR * sqrt(3.0), -pixelR, 0, 0 );
}
else if( vertexIndex == 2.0 )
{
v_circleCoords = vec2( sqrt( 3.0 ), -1.0 );
delta = vec4( pixelR * sqrt( 3.0 ), -pixelR, 0, 0 );
}
else if( vertexIndex == 3.0 )
{
v_circleCoords = vec2( 0.0, 2.0 );
delta = vec4( 0, 2 * pixelR, 0, 0 );
}
else if( vertexIndex == 4.0 )
{
v_circleCoords = vec2( -sqrt( 3.0 ), 0.0 );
delta = vec4( 0, 0, 0, 0 );
}
else if( vertexIndex == 5.0 )
{
v_circleCoords = vec2( sqrt( 3.0 ), 0.0 );
delta = vec4( 0, 0, 0, 0 );
}
else if( vertexIndex == 6.0 )
{
v_circleCoords = vec2( 0.0, 2.0 );
delta = vec4( 0, 0, 0, 0 );
}
v_shaderParams[2] = pixelR;
v_shaderParams[3] = pixelWidth;
delta.x *= u_screenPixelSize.x;
delta.y *= u_screenPixelSize.y;
gl_Position = center + delta + adjust;
gl_FrontColor = gl_Color;
}
void computeHoleWallCoords( float vertexIndex, float radius, float lineWidth )
{
vec4 delta;
vec4 center = roundv( gl_ModelViewProjectionMatrix * gl_Vertex + vec4(1, 1, 0, 0), u_screenPixelSize );
float pixelWidth = roundr( lineWidth / u_worldPixelSize, 1.0 );
if( pixelWidth < u_minLinePixelWidth )
pixelWidth = u_minLinePixelWidth;
float pixelR = roundr( radius / u_worldPixelSize, 1.0 ) + pixelWidth;
vec4 adjust = vec4(-1, -1, 0, 0);
if( vertexIndex == 1.0 )
{
@@ -195,6 +247,8 @@ void main()
computeLineCoords( posture, vs, vp, vec2( -1, 1 ), vec2( -1, 0 ), lineWidth, true );
else if( mode == SHADER_LINE_F )
computeLineCoords( posture, -vs, vp, vec2( 1, 1 ), vec2( -1, 0 ), lineWidth, false );
else if( mode == SHADER_HOLE_WALL )
computeHoleWallCoords( v_shaderParams.y, v_shaderParams.z, v_shaderParams.w );
else if( mode == SHADER_FILLED_CIRCLE || mode == SHADER_STROKED_CIRCLE)
computeCircleCoords( mode, v_shaderParams.y, v_shaderParams.z, v_shaderParams.w );
else
+28 -5
View File
@@ -40,7 +40,7 @@
KIGIT_COMMON::KIGIT_COMMON( git_repository* aRepo ) :
m_repo( aRepo ), m_connType( GIT_CONN_TYPE::GIT_CONN_LOCAL ), m_testedTypes( 0 ),
m_nextPublicKey( 0 )
m_nextPublicKey( 0 ), m_secretFetched( false )
{}
KIGIT_COMMON::KIGIT_COMMON( const KIGIT_COMMON& aOther ) :
@@ -55,7 +55,8 @@ KIGIT_COMMON::KIGIT_COMMON( const KIGIT_COMMON& aOther ) :
// The mutex is default-initialized, not copied
m_gitActionMutex(),
m_publicKeys( aOther.m_publicKeys ),
m_nextPublicKey( aOther.m_nextPublicKey )
m_nextPublicKey( aOther.m_nextPublicKey ),
m_secretFetched( aOther.m_secretFetched )
{
}
@@ -100,6 +101,25 @@ wxString KIGIT_COMMON::GetCurrentBranchName() const
}
wxString KIGIT_COMMON::GetPassword()
{
if( !m_secretFetched )
{
if( m_connType != GIT_CONN_TYPE::GIT_CONN_LOCAL && !m_remote.IsEmpty() )
{
wxString secret;
if( KIPLATFORM::SECRETS::GetSecret( m_remote, m_username, secret ) )
m_password = secret;
}
m_secretFetched = true;
}
return m_password;
}
std::vector<wxString> KIGIT_COMMON::GetBranchNames() const
{
if( !m_repo )
@@ -645,6 +665,10 @@ void KIGIT_COMMON::UpdateCurrentBranchInfo()
wxString remote_name = GetRemotename();
git_remote* remote = nullptr;
m_remote.clear();
m_password.clear();
m_secretFetched = false;
if( git_remote_lookup( &remote, m_repo, remote_name.ToStdString().c_str() ) == GIT_OK )
{
const char* url = git_remote_url( remote );
@@ -655,9 +679,6 @@ void KIGIT_COMMON::UpdateCurrentBranchInfo()
git_remote_free( remote );
}
// Find the stored password if it exists
KIPLATFORM::SECRETS::GetSecret( m_remote, m_username, m_password );
updateConnectionType();
updatePublicKeys();
}
@@ -748,6 +769,8 @@ void KIGIT_COMMON::updateConnectionType()
m_hostname = host;
}
}
m_secretFetched = !m_password.IsEmpty();
}
+6 -3
View File
@@ -89,11 +89,11 @@ public:
};
wxString GetUsername() const { return m_username; }
wxString GetPassword() const { return m_password; }
wxString GetPassword();
GIT_CONN_TYPE GetConnType() const;
void SetUsername( const wxString& aUsername ) { m_username = aUsername; }
void SetPassword( const wxString& aPassword ) { m_password = aPassword; }
void SetUsername( const wxString& aUsername ) { m_username = aUsername; m_secretFetched = false; }
void SetPassword( const wxString& aPassword ) { m_password = aPassword; m_secretFetched = true; }
void SetSSHKey( const wxString& aSSHKey );
// Holds a temporary variable that can be used by the authentication callback
@@ -127,6 +127,8 @@ public:
void SetRemote( const wxString& aRemote )
{
m_remote = aRemote;
m_password.clear();
m_secretFetched = false;
updateConnectionType();
}
@@ -170,6 +172,7 @@ private:
std::vector<wxString> m_publicKeys;
int m_nextPublicKey;
bool m_secretFetched;
// Create a dummy flag to tell if we have tested ssh agent credentials separately
// from the ssh key credentials
+38 -62
View File
@@ -40,19 +40,11 @@ HTTP_LIB_CONNECTION::HTTP_LIB_CONNECTION( const HTTP_LIB_SOURCE& aSource, bool a
m_source = aSource;
if( aTestConnectionNow )
{
ValidateHTTPLibraryEndpoints();
}
validateHttpLibraryEndpoints();
}
HTTP_LIB_CONNECTION::~HTTP_LIB_CONNECTION()
{
// Do nothing
}
bool HTTP_LIB_CONNECTION::ValidateHTTPLibraryEndpoints()
bool HTTP_LIB_CONNECTION::validateHttpLibraryEndpoints()
{
m_endpointValid = false;
std::string res = "";
@@ -78,11 +70,8 @@ bool HTTP_LIB_CONNECTION::ValidateHTTPLibraryEndpoints()
nlohmann::json response = nlohmann::json::parse( res );
// Check that the endpoints exist, if not fail.
if( !response.at( http_endpoint_categories ).empty()
&& !response.at( http_endpoint_parts ).empty() )
{
if( !response.at( "categories" ).empty() && !response.at( "parts" ).empty() )
m_endpointValid = true;
}
}
}
catch( const std::exception& e )
@@ -90,29 +79,19 @@ bool HTTP_LIB_CONNECTION::ValidateHTTPLibraryEndpoints()
m_lastError += wxString::Format( _( "Error: %s" ) + "\n" + _( "API Response: %s" ) + "\n",
e.what(), res );
wxLogTrace( traceHTTPLib,
wxT( "ValidateHTTPLibraryEndpoints: Exception occurred while testing the API "
"connection: %s" ),
wxLogTrace( traceHTTPLib, wxT( "validateHttpLibraryEndpoints: Exception while testing API connection: %s" ),
m_lastError );
m_endpointValid = false;
}
if( m_endpointValid )
{
syncCategories();
}
return m_endpointValid;
}
bool HTTP_LIB_CONNECTION::IsValidEndpoint() const
{
return m_endpointValid;
}
bool HTTP_LIB_CONNECTION::syncCategories()
{
if( !IsValidEndpoint() )
@@ -124,7 +103,7 @@ bool HTTP_LIB_CONNECTION::syncCategories()
std::string res = "";
std::unique_ptr<KICAD_CURL_EASY> curl = createCurlEasyObject();
curl->SetURL( m_source.root_url + http_endpoint_categories + ".json" );
curl->SetURL( m_source.root_url + "categories.json" );
try
{
@@ -133,9 +112,7 @@ bool HTTP_LIB_CONNECTION::syncCategories()
res = curl->GetBuffer();
if( !checkServerResponse( curl ) )
{
return false;
}
nlohmann::json response = nlohmann::json::parse( res );
@@ -162,9 +139,7 @@ bool HTTP_LIB_CONNECTION::syncCategories()
m_lastError += wxString::Format( _( "Error: %s" ) + "\n" + _( "API Response: %s" ) + "\n",
e.what(), res );
wxLogTrace( traceHTTPLib,
wxT( "syncCategories: Exception occurred while syncing categories: %s" ),
m_lastError );
wxLogTrace( traceHTTPLib, wxT( "syncCategories: Exception while syncing categories: %s" ), m_lastError );
m_categories.clear();
@@ -187,8 +162,7 @@ bool HTTP_LIB_CONNECTION::SelectOne( const std::string& aPartID, HTTP_LIB_PART&
if( m_cachedParts.find( aPartID ) != m_cachedParts.end() )
{
// check if it's outdated, if so re-fetch
if( std::difftime( std::time( nullptr ), m_cachedParts[aPartID].lastCached )
< m_source.timeout_parts )
if( std::difftime( std::time( nullptr ), m_cachedParts[aPartID].lastCached ) < m_source.timeout_parts )
{
aFetchedPart = m_cachedParts[aPartID];
return true;
@@ -198,7 +172,7 @@ bool HTTP_LIB_CONNECTION::SelectOne( const std::string& aPartID, HTTP_LIB_PART&
std::string res = "";
std::unique_ptr<KICAD_CURL_EASY> curl = createCurlEasyObject();
std::string url = m_source.root_url + fmt::format( "{}/{}.json", http_endpoint_parts, aPartID );
std::string url = m_source.root_url + fmt::format( "parts/{}.json", aPartID );
curl->SetURL( url );
try
@@ -208,9 +182,7 @@ bool HTTP_LIB_CONNECTION::SelectOne( const std::string& aPartID, HTTP_LIB_PART&
res = curl->GetBuffer();
if( !checkServerResponse( curl ) )
{
return false;
}
nlohmann::ordered_json response = nlohmann::ordered_json::parse( res );
std::string key = "";
@@ -225,13 +197,9 @@ bool HTTP_LIB_CONNECTION::SelectOne( const std::string& aPartID, HTTP_LIB_PART&
// API might not want to return an optional name.
if( response.contains( "name" ) )
{
aFetchedPart.name = response.at( "name" );
}
else
{
aFetchedPart.name = aFetchedPart.id;
}
aFetchedPart.symbolIdStr = response.at( "symbolIdStr" );
@@ -285,18 +253,36 @@ bool HTTP_LIB_CONNECTION::SelectOne( const std::string& aPartID, HTTP_LIB_PART&
}
// Add field to fields list
aFetchedPart.fields.push_back(
std::make_pair( key, std::make_tuple( value, visible ) ) );
aFetchedPart.fields.push_back( std::make_pair( key, std::make_tuple( value, visible ) ) );
}
if( response.contains( "description" ) )
aFetchedPart.desc = response.at( "description" );
if( response.contains( "keywords" ) )
aFetchedPart.keywords = response.at( "keywords" );
if( response.contains( "footprint_filters" ) )
{
nlohmann::json filters_json = response.at( "footprint_filters" );
if( filters_json.is_array() )
{
for( const auto& val : filters_json )
aFetchedPart.fp_filters.push_back( val );
}
else
{
aFetchedPart.fp_filters.push_back( filters_json );
}
}
}
catch( const std::exception& e )
{
m_lastError += wxString::Format( _( "Error: %s" ) + "\n" + _( "API Response: %s" ) + "\n",
m_lastError += wxString::Format( _( "Error: %s" ) + "\n" + _( "API Response: %s" ) + "\n",
e.what(), res );
wxLogTrace( traceHTTPLib,
wxT( "SelectOne: Exception occurred while retrieving part from REST API: %s" ),
m_lastError );
wxLogTrace( traceHTTPLib, wxT( "SelectOne: Exception while fetching part: %s" ), m_lastError );
return false;
}
@@ -307,8 +293,7 @@ bool HTTP_LIB_CONNECTION::SelectOne( const std::string& aPartID, HTTP_LIB_PART&
}
bool HTTP_LIB_CONNECTION::SelectAll( const HTTP_LIB_CATEGORY& aCategory,
std::vector<HTTP_LIB_PART>& aParts )
bool HTTP_LIB_CONNECTION::SelectAll( const HTTP_LIB_CATEGORY& aCategory, std::vector<HTTP_LIB_PART>& aParts )
{
if( !IsValidEndpoint() )
{
@@ -320,8 +305,7 @@ bool HTTP_LIB_CONNECTION::SelectAll( const HTTP_LIB_CATEGORY& aCategory,
std::unique_ptr<KICAD_CURL_EASY> curl = createCurlEasyObject();
curl->SetURL( m_source.root_url
+ fmt::format( "{}/category/{}.json", http_endpoint_parts, aCategory.id ) );
curl->SetURL( m_source.root_url + fmt::format( "parts/category/{}.json", aCategory.id ) );
try
{
@@ -339,21 +323,13 @@ bool HTTP_LIB_CONNECTION::SelectAll( const HTTP_LIB_CATEGORY& aCategory,
part.id = item.at( "id" );
if( item.contains( "description" ) )
{
// At this point we don't display anything so just set it to false
part.fields.push_back( std::make_pair(
"description", std::make_tuple( item.at( "description" ), false ) ) );
}
part.desc = item.at( "description" );
// API might not want to return an optional name.
if( item.contains( "name" ) )
{
part.name = item.at( "name" );
}
else
{
part.name = part.id;
}
// add to cache
m_cache[part.name] = std::make_tuple( part.id, aCategory.id );
@@ -363,11 +339,10 @@ bool HTTP_LIB_CONNECTION::SelectAll( const HTTP_LIB_CATEGORY& aCategory,
}
catch( const std::exception& e )
{
m_lastError += wxString::Format( _( "Error: %s" ) + "\n" + _( "API Response: %s" ) + "\n",
m_lastError += wxString::Format( _( "Error: %s" ) + "\n" + _( "API Response: %s" ) + "\n",
e.what(), res );
wxLogTrace( traceHTTPLib, wxT( "Exception occurred while syncing parts from REST API: %s" ),
m_lastError );
wxLogTrace( traceHTTPLib, wxT( "Exception occurred while syncing parts: %s" ), m_lastError );
return false;
}
@@ -379,6 +354,7 @@ bool HTTP_LIB_CONNECTION::SelectAll( const HTTP_LIB_CATEGORY& aCategory,
bool HTTP_LIB_CONNECTION::checkServerResponse( std::unique_ptr<KICAD_CURL_EASY>& aCurl )
{
int statusCode = aCurl->GetResponseStatusCode();
if( statusCode != 200 )
{
m_lastError += wxString::Format( _( "API responded with error code: %s" ) + "\n",
+3 -5
View File
@@ -35,10 +35,9 @@ const int httplibSchemaVersion = 1;
HTTP_LIB_SETTINGS::HTTP_LIB_SETTINGS( const std::string& aFilename ) :
JSON_SETTINGS( aFilename, SETTINGS_LOC::NONE, httplibSchemaVersion )
{
m_params.emplace_back( new PARAM<std::string>( "source.type", &sourceType, "" ) );
m_params.emplace_back( new PARAM<std::string>( "source.type", &m_sourceType, "" ) );
m_params.emplace_back(
new PARAM<std::string>( "source.api_version", &m_Source.api_version, "" ) );
m_params.emplace_back( new PARAM<std::string>( "source.api_version", &m_Source.api_version, "" ) );
m_params.emplace_back( new PARAM<std::string>( "source.root_url", &m_Source.root_url, "" ) );
@@ -46,8 +45,7 @@ HTTP_LIB_SETTINGS::HTTP_LIB_SETTINGS( const std::string& aFilename ) :
m_params.emplace_back( new PARAM<int>( "source.timeout_parts_seconds", &m_Source.timeout_parts, 30 ) );
m_params.emplace_back( new PARAM<int>( "source.timeout_categories_seconds",
&m_Source.timeout_categories, 600 ) );
m_params.emplace_back( new PARAM<int>( "source.timeout_categories_seconds", &m_Source.timeout_categories, 600 ) );
}
+4 -1
View File
@@ -119,7 +119,10 @@ std::map<wxString, wxString> ALTIUM_ASCII_PARSER::ReadProperties()
if( canonicalKey == wxT( "DESIGNATOR" ) || canonicalKey == wxT( "NAME" )
|| canonicalKey == wxT( "TEXT" ) )
{
if( kv[ wxT( "RECORD" ) ] != wxT( "4" ) )
wxString recordType = kv[ wxT( "RECORD" ) ];
// RECORD=33 (FILE_NAME) stores Windows-formatted paths; keep the backslashes intact.
if( recordType != wxT( "4" ) && recordType != wxT( "33" ) )
value = AltiumPropertyToKiCadString( value );
}
}
+1 -1
View File
@@ -41,7 +41,7 @@ JOB_EXPORT_PCB_ODB::JOB_EXPORT_PCB_ODB() :
m_filename(),
m_drawingSheet(),
m_units( ODB_UNITS::MM ),
m_precision( 2 ),
m_precision( 4 ),
m_compressionMode( ODB_COMPRESSION::ZIP )
{
m_params.emplace_back( new JOB_PARAM<wxString>( "drawing_sheet", &m_drawingSheet, m_drawingSheet ) );
+1
View File
@@ -85,6 +85,7 @@ JOB_PCB_RENDER::JOB_PCB_RENDER() :
{
m_params.emplace_back( new JOB_PARAM<FORMAT>( "format", &m_format, m_format ) );
m_params.emplace_back( new JOB_PARAM<std::string>( "preset", &m_appearancePreset, m_appearancePreset ) );
m_params.emplace_back( new JOB_PARAM<bool>( "use_board_stackup_colors", &m_useBoardStackupColors, m_useBoardStackupColors ) );
m_params.emplace_back( new JOB_PARAM<QUALITY>( "quality", &m_quality, m_quality ) );
m_params.emplace_back( new JOB_PARAM<BG_STYLE>( "bg_style", &m_bgStyle, m_bgStyle ) );
m_params.emplace_back( new JOB_PARAM<SIDE>( "side", &m_side, m_side ) );
+1
View File
@@ -87,6 +87,7 @@ public:
int m_width = 0;
int m_height = 0;
std::string m_appearancePreset;
bool m_useBoardStackupColors = true;
SIDE m_side = SIDE::TOP;
double m_zoom = 1.0;
bool m_perspective = false;
+1 -1
View File
@@ -39,7 +39,7 @@ JOB_RC::JOB_RC( const std::string& aType ) :
m_units( JOB_RC::UNITS::MM ),
m_severity( RPT_SEVERITY_ERROR | RPT_SEVERITY_WARNING ),
m_format( OUTPUT_FORMAT::REPORT ),
m_exitCodeViolations( false )
m_exitCodeViolations( true ) // this ensures GUI jobs default to treat violations as job failure, cli will default false elsewhere
{
m_params.emplace_back( new JOB_PARAM<UNITS>( "units", &m_units, m_units ) );
m_params.emplace_back( new JOB_PARAM<int>( "severity", &m_severity, m_severity ) );
+3
View File
@@ -24,6 +24,7 @@
#include <wx/zipstrm.h>
#include <gestfich.h>
#include <common.h>
#include <wildcards_and_files_ext.h>
JOBS_OUTPUT_ARCHIVE::JOBS_OUTPUT_ARCHIVE() :
JOBS_OUTPUT_HANDLER(),
@@ -52,6 +53,8 @@ bool JOBS_OUTPUT_ARCHIVE::HandleOutputs( const wxString& baseTempPath, PROJECT*
if( outputPath.StartsWith( "~" ) )
outputPath.Replace( "~", wxGetHomeDir(), false );
outputPath = EnsureFileExtension( outputPath, FILEEXT::ArchiveFileExtension );
wxFFileOutputStream ostream( outputPath );
if( !ostream.IsOk() ) // issue to create the file. Perhaps not writable dir
+1 -18
View File
@@ -134,29 +134,12 @@ LIB_TREE_NODE::LIB_TREE_NODE()
LIB_TREE_NODE_UNIT::LIB_TREE_NODE_UNIT( LIB_TREE_NODE* aParent, LIB_TREE_ITEM* aItem, int aUnit )
{
static void* locale = nullptr;
static wxString namePrefix;
// Fetching translations can take a surprising amount of time when loading libraries,
// so only do it when necessary.
if( Pgm().GetLocale() != locale )
{
namePrefix = _( "Unit" );
locale = Pgm().GetLocale();
}
m_Parent = aParent;
m_Type = TYPE::UNIT;
m_Unit = aUnit;
m_LibId = aParent->m_LibId;
m_Name = namePrefix + " " + aItem->GetUnitReference( aUnit );
if( aItem->HasUnitDisplayName( aUnit ) )
m_Desc = aItem->GetUnitDisplayName( aUnit );
else
m_Desc = wxEmptyString;
m_Name = aItem->GetUnitName( aUnit );
m_IntrinsicRank = -aUnit;
}
+10
View File
@@ -32,6 +32,7 @@
#include <wx/wupdlock.h>
#include <wx/settings.h>
#include <wx/dc.h>
#include <wx/log.h>
#include <string_utils.h>
@@ -308,6 +309,15 @@ void LIB_TREE_MODEL_ADAPTER::UpdateSearchString( const wxString& aSearch, bool a
const LIB_TREE_NODE* firstMatch = ShowResults();
#ifdef __WXGTK__
// Ensure the control is repainted with the updated data. Without an explicit
// refresh the Gtk port can display stale rows until the user interacts with
// them, leading to mismatched tree contents.
m_widget->Refresh();
m_widget->Update();
wxYield();
#endif
if( firstMatch )
{
wxDataViewItem item = ToItem( firstMatch );
+6 -6
View File
@@ -1150,7 +1150,9 @@ void UOP::Exec( CONTEXT* ctx )
return;
case TR_OP_METHOD_CALL:
m_func( ctx, m_ref.get() );
if( m_func )
m_func( ctx, m_ref.get() );
return;
default:
@@ -1283,9 +1285,8 @@ VALUE* UCODE::Run( CONTEXT* ctx )
}
catch(...)
{
// rules which fail outright should not be fired
std::unique_ptr<VALUE> temp_false = std::make_unique<VALUE>( 0 );
return ctx->StoreValue( temp_false.get() );
// rules which fail outright should not be fired; return 0/false
return ctx->StoreValue( new VALUE( 0 ) );
}
if( ctx->SP() == 1 )
@@ -1301,8 +1302,7 @@ VALUE* UCODE::Run( CONTEXT* ctx )
wxASSERT( ctx->SP() == 1 );
// non-well-formed rules should not be fired on a release build
std::unique_ptr<VALUE> temp_false = std::make_unique<VALUE>( 0 );
return ctx->StoreValue( temp_false.get() );
return ctx->StoreValue( new VALUE( 0 ) );
}
}
+1 -1
View File
@@ -278,7 +278,7 @@ bool NETCLASS::ContainsNetclassWithName( const wxString& netclass ) const
return std::any_of( m_constituents.begin(), m_constituents.end(),
[&netclass]( const NETCLASS* nc )
{
return nc && nc->GetName() == netclass;
return nc && nc->GetName().Matches( netclass );
} );
}
+25
View File
@@ -55,6 +55,31 @@ enum class ELECTRICAL_PINTYPE
#define ELECTRICAL_PINTYPES_TOTAL ( static_cast<int>( ELECTRICAL_PINTYPE::PT_LAST_OPTION ) + 1 )
inline wxString GetCanonicalElectricalTypeName( ELECTRICAL_PINTYPE aType )
{
// These strings are the canonical name of the electrictal type
// Not translated, no space in name, only ASCII chars.
// to use when the string name must be known and well defined
// must have same order than enum ELECTRICAL_PINTYPE (see sch_pin.h)
static const wxChar* msgPinElectricType[] =
{
wxT( "input" ),
wxT( "output" ),
wxT( "bidirectional" ),
wxT( "tri_state" ),
wxT( "passive" ),
wxT( "free" ),
wxT( "unspecified" ),
wxT( "power_in" ),
wxT( "power_out" ),
wxT( "open_collector" ),
wxT( "open_emitter" ),
wxT( "no_connect" )
};
return msgPinElectricType[static_cast<int>( aType )];
}
enum class GRAPHIC_PINSHAPE
{
LINE,
+18 -2
View File
@@ -24,6 +24,7 @@
#include "preview_items/construction_geom.h"
#include <layer_ids.h>
#include <utility>
#include <gal/graphics_abstraction_layer.h>
#include <geometry/shape_utils.h>
#include <preview_items/item_drawing_utils.h>
@@ -39,9 +40,15 @@ CONSTRUCTION_GEOM::CONSTRUCTION_GEOM() :
}
void CONSTRUCTION_GEOM::AddDrawable( const DRAWABLE& aItem, bool aPersistent )
void CONSTRUCTION_GEOM::AddDrawable( const DRAWABLE& aItem, bool aPersistent, int aLineWidth )
{
m_drawables.push_back( { aItem, aPersistent } );
m_drawables.push_back( { aItem, aPersistent, aLineWidth } );
}
void CONSTRUCTION_GEOM::SetSnapGuides( std::vector<SNAP_GUIDE> aGuides )
{
m_snapGuides = std::move( aGuides );
}
@@ -90,6 +97,7 @@ void CONSTRUCTION_GEOM::ViewDraw( int aLayer, VIEW* aView ) const
for( const DRAWABLE_INFO& drawable : m_drawables )
{
gal.SetStrokeColor( drawable.IsPersistent ? m_persistentColor : m_color );
gal.SetLineWidth( drawable.LineWidth );
std::visit(
[&]( const auto& visited )
@@ -139,9 +147,17 @@ void CONSTRUCTION_GEOM::ViewDraw( int aLayer, VIEW* aView ) const
drawable.Item );
}
for( const SNAP_GUIDE& guide : m_snapGuides )
{
gal.SetStrokeColor( guide.Color );
gal.SetLineWidth( guide.LineWidth );
gal.DrawLine( guide.Segment.A, guide.Segment.B );
}
if( haveSnapLine )
{
gal.SetStrokeColor( m_persistentColor );
gal.SetLineWidth( 2 );
const int dashSizeBasis = aView->ToWorld( 12 );
const int snapOriginMarkerSize = aView->ToWorld( 16 );
+80 -1
View File
@@ -335,7 +335,86 @@ void RULER_ITEM::ViewDraw( int aLayer, KIGFX::VIEW* aView ) const
VECTOR2D rulerVec( end - origin );
wxArrayString cursorStrings = GetDimensionStrings();
DrawTextNextToCursor( aView, end, -rulerVec, cursorStrings, drawingDropShadows );
// Choose a text quadrant that keeps the measurement text on-screen while avoiding
// overlapping the ruler geometry. Start with the preferred direction (away from the
// origin) and fall back to other quadrants as needed to keep the label visible.
int prefX = rulerVec.y < 0.0 ? -1 : 1;
int prefY = rulerVec.x < 0.0 ? 1 : -1;
double scale = gal->GetWorldScale();
TEXT_DIMS dims = GetConstantGlyphHeight( gal );
KIFONT::FONT* font = KIFONT::FONT::GetFont();
double width = 0.0;
for( const wxString& s : cursorStrings )
{
VECTOR2I extents = font->StringBoundaryLimits( s, dims.GlyphSize, dims.StrokeWidth, false, false,
KIFONT::METRICS::Default() );
width = std::max( width, (double) extents.x );
}
double height = dims.LinePitch * cursorStrings.size();
// Convert to screen coordinates for visibility checks
VECTOR2D cursorScreen = gal->ToScreen( end );
VECTOR2I screenSize = gal->GetScreenPixelSize();
double offsetX = 15.0; // same as DrawTextNextToCursor()
double offsetY = dims.LinePitch * scale; // vertical spacing from cursor
auto fits = [&]( int sx, int sy )
{
double left, right, top, bottom;
double xStart = cursorScreen.x + ( sx < 0 ? offsetX : -offsetX );
if( sx < 0 )
{
left = xStart;
right = left + width * scale;
}
else
{
right = xStart;
left = right - width * scale;
}
if( sy > 0 ) // above cursor
{
bottom = cursorScreen.y - offsetY;
top = bottom - height * scale;
}
else // below cursor
{
top = cursorScreen.y + offsetY;
bottom = top + height * scale;
}
return left >= 0 && right <= screenSize.x && top >= 0 && bottom <= screenSize.y;
};
std::vector<VECTOR2I> candidates = { { prefX, prefY }, { -prefX, prefY },
{ prefX, -prefY }, { -prefX, -prefY } };
VECTOR2I chosen = candidates[0];
double bestDot = -1.0;
for( const VECTOR2I& c : candidates )
{
double dot = c.x * prefX + c.y * prefY;
if( dot >= 0 && fits( c.x, c.y ) )
{
if( dot > bestDot )
{
bestDot = dot;
chosen = c;
}
}
}
VECTOR2D quadrant( chosen.x, chosen.y );
DrawTextNextToCursor( aView, end, quadrant, cursorStrings, drawingDropShadows );
// basic tick size
double minorTickLen = 5.0 / gal->GetWorldScale();
+3 -1
View File
@@ -254,9 +254,11 @@ wxPGProperty* PGPropertyFactory( const PROPERTY_BASE* aProperty, EDA_DRAW_FRAME*
// Enum property
if( aProperty->HasChoices() )
{
const_cast<PROPERTY_BASE*>( aProperty )->TranslateChoices();
// I do not know why enum property takes a non-const reference to wxPGChoices..
ret = new wxEnumProperty( wxPG_LABEL, wxPG_LABEL,
const_cast<wxPGChoices&>( aProperty->Choices() ) );
const_cast<wxPGChoices&>( aProperty->Choices() ) );
}
else if( typeId == TYPE_HASH( int ) || typeId == TYPE_HASH( long ) )
{
+46 -77
View File
@@ -25,10 +25,15 @@
#include <properties/property.h>
#include <algorithm>
#include <ranges>
#include <utility>
#include <wx/wx.h>
static wxString EMPTY_STRING( wxEmptyString );
// Global to prevent simultaneous multi-threaded static initialization
static const std::vector<PROPERTY_BASE*> EMPTY_PROP_LIST;
static const std::map<PROPERTY_BASE*, int> EMPTY_PROP_DISPLAY_ORDER;
std::vector<wxString> EMPTY_GROUP_DISPLAY_ORDER;
void PROPERTY_MANAGER::RegisterType( TYPE_ID aType, const wxString& aName )
@@ -38,13 +43,6 @@ void PROPERTY_MANAGER::RegisterType( TYPE_ID aType, const wxString& aName )
}
const wxString& PROPERTY_MANAGER::ResolveType( TYPE_ID aType ) const
{
auto it = m_classNames.find( aType );
return it != m_classNames.end() ? it->second : EMPTY_STRING;
}
PROPERTY_BASE* PROPERTY_MANAGER::GetProperty( TYPE_ID aType, const wxString& aProperty ) const
{
if( m_dirty )
@@ -67,31 +65,29 @@ PROPERTY_BASE* PROPERTY_MANAGER::GetProperty( TYPE_ID aType, const wxString& aPr
}
const PROPERTY_LIST& PROPERTY_MANAGER::GetProperties( TYPE_ID aType ) const
const std::vector<PROPERTY_BASE*>& PROPERTY_MANAGER::GetProperties( TYPE_ID aType ) const
{
if( m_dirty )
const_cast<PROPERTY_MANAGER*>( this )->Rebuild();
static const PROPERTY_LIST empty;
auto it = m_classes.find( aType );
if( it == m_classes.end() )
return empty;
return EMPTY_PROP_LIST;
return it->second.m_allProperties;
}
const PROPERTY_DISPLAY_ORDER& PROPERTY_MANAGER::GetDisplayOrder( TYPE_ID aType ) const
const std::map<PROPERTY_BASE*, int>& PROPERTY_MANAGER::GetDisplayOrder( TYPE_ID aType ) const
{
if( m_dirty )
const_cast<PROPERTY_MANAGER*>( this )->Rebuild();
static const PROPERTY_DISPLAY_ORDER empty;
auto it = m_classes.find( aType );
if( it == m_classes.end() )
return empty;
return EMPTY_PROP_DISPLAY_ORDER;
return it->second.m_displayOrder;
}
@@ -102,11 +98,10 @@ const std::vector<wxString>& PROPERTY_MANAGER::GetGroupDisplayOrder( TYPE_ID aTy
if( m_dirty )
const_cast<PROPERTY_MANAGER*>( this )->Rebuild();
static const std::vector<wxString> empty;
auto it = m_classes.find( aType );
if( it == m_classes.end() )
return empty;
return EMPTY_GROUP_DISPLAY_ORDER;
return it->second.m_groupDisplayOrder;
}
@@ -122,7 +117,7 @@ const void* PROPERTY_MANAGER::TypeCast( const void* aSource, TYPE_ID aBase, TYPE
if( classDesc == m_classes.end() )
return aSource;
auto& converters = classDesc->second.m_typeCasts;
const std::map<TYPE_ID, std::unique_ptr<TYPE_CAST_BASE>>& converters = classDesc->second.m_typeCasts;
auto converter = converters.find( aTarget );
if( converter == converters.end() ) // explicit type cast not found
@@ -135,8 +130,9 @@ const void* PROPERTY_MANAGER::TypeCast( const void* aSource, TYPE_ID aBase, TYPE
PROPERTY_BASE& PROPERTY_MANAGER::AddProperty( PROPERTY_BASE* aProperty, const wxString& aGroup )
{
const wxString& name = aProperty->Name();
TYPE_ID hash = aProperty->OwnerHash();
CLASS_DESC& classDesc = getClass( hash );
TYPE_ID hash = aProperty->OwnerHash();
CLASS_DESC& classDesc = getClass( hash );
classDesc.m_ownProperties.emplace( name, aProperty );
classDesc.m_ownDisplayOrder.emplace_back( aProperty );
@@ -153,8 +149,8 @@ PROPERTY_BASE& PROPERTY_MANAGER::AddProperty( PROPERTY_BASE* aProperty, const wx
}
PROPERTY_BASE& PROPERTY_MANAGER::ReplaceProperty( size_t aBase, const wxString& aName,
PROPERTY_BASE* aNew, const wxString& aGroup )
PROPERTY_BASE& PROPERTY_MANAGER::ReplaceProperty( size_t aBase, const wxString& aName, PROPERTY_BASE* aNew,
const wxString& aGroup )
{
CLASS_DESC& classDesc = getClass( aNew->OwnerHash() );
classDesc.m_replaced.insert( std::make_pair( aBase, aName ) );
@@ -164,31 +160,30 @@ PROPERTY_BASE& PROPERTY_MANAGER::ReplaceProperty( size_t aBase, const wxString&
void PROPERTY_MANAGER::AddTypeCast( TYPE_CAST_BASE* aCast )
{
TYPE_ID derivedHash = aCast->DerivedHash();
TYPE_ID derivedHash = aCast->DerivedHash();
CLASS_DESC& classDesc = getClass( aCast->BaseHash() );
auto& typeCasts = classDesc.m_typeCasts;
wxASSERT_MSG( typeCasts.count( derivedHash ) == 0, "Such converter already exists" );
typeCasts.emplace( derivedHash, aCast );
wxASSERT_MSG( classDesc.m_typeCasts.count( derivedHash ) == 0, wxT( "Such converter already exists" ) );
classDesc.m_typeCasts.emplace( derivedHash, aCast );
}
void PROPERTY_MANAGER::InheritsAfter( TYPE_ID aDerived, TYPE_ID aBase )
{
wxASSERT_MSG( aDerived != aBase, "Class cannot inherit from itself" );
wxASSERT_MSG( aDerived != aBase, wxT( "Class cannot inherit from itself" ) );
CLASS_DESC& derived = getClass( aDerived );
CLASS_DESC& base = getClass( aBase );
derived.m_bases.push_back( base );
derived.m_bases.push_back( getClass( aBase ) );
m_dirty = true;
wxASSERT_MSG( derived.m_bases.size() == 1 || derived.m_typeCasts.count( aBase ) == 1,
"You need to add a TYPE_CAST for classes inheriting from multiple bases" );
wxT( "You need to add a TYPE_CAST for classes inheriting from multiple bases" ) );
}
void PROPERTY_MANAGER::Mask( TYPE_ID aDerived, TYPE_ID aBase, const wxString& aName )
{
wxASSERT_MSG( aDerived != aBase, "Class cannot mask from itself" );
wxASSERT_MSG( aDerived != aBase, wxT( "Class cannot mask from itself" ) );
CLASS_DESC& derived = getClass( aDerived );
derived.m_maskedBaseProperties.insert( std::make_pair( aBase, aName ) );
@@ -196,11 +191,10 @@ void PROPERTY_MANAGER::Mask( TYPE_ID aDerived, TYPE_ID aBase, const wxString& aN
}
void PROPERTY_MANAGER::OverrideAvailability( TYPE_ID aDerived, TYPE_ID aBase,
const wxString& aName,
void PROPERTY_MANAGER::OverrideAvailability( TYPE_ID aDerived, TYPE_ID aBase, const wxString& aName,
std::function<bool( INSPECTABLE* )> aFunc )
{
wxASSERT_MSG( aDerived != aBase, "Class cannot override from itself" );
wxASSERT_MSG( aDerived != aBase, wxT( "Class cannot override from itself" ) );
CLASS_DESC& derived = getClass( aDerived );
derived.m_availabilityOverrides[std::make_pair( aBase, aName )] = std::move( aFunc );
@@ -208,11 +202,10 @@ void PROPERTY_MANAGER::OverrideAvailability( TYPE_ID aDerived, TYPE_ID aBase,
}
void PROPERTY_MANAGER::OverrideWriteability( TYPE_ID aDerived, TYPE_ID aBase,
const wxString& aName,
void PROPERTY_MANAGER::OverrideWriteability( TYPE_ID aDerived, TYPE_ID aBase, const wxString& aName,
std::function<bool( INSPECTABLE* )> aFunc )
{
wxASSERT_MSG( aDerived != aBase, "Class cannot override from itself" );
wxASSERT_MSG( aDerived != aBase, wxT( "Class cannot override from itself" ) );
CLASS_DESC& derived = getClass( aDerived );
derived.m_writeabilityOverrides[std::make_pair( aBase, aName )] = std::move( aFunc );
@@ -220,16 +213,14 @@ void PROPERTY_MANAGER::OverrideWriteability( TYPE_ID aDerived, TYPE_ID aBase,
}
bool PROPERTY_MANAGER::IsAvailableFor( TYPE_ID aItemClass, PROPERTY_BASE* aProp,
INSPECTABLE* aItem )
bool PROPERTY_MANAGER::IsAvailableFor( TYPE_ID aItemClass, PROPERTY_BASE* aProp, INSPECTABLE* aItem )
{
if( !aProp->Available( aItem ) )
return false;
CLASS_DESC& derived = getClass( aItemClass );
auto it = derived.m_availabilityOverrides.find( std::make_pair( aProp->BaseHash(),
aProp->Name() ) );
auto it = derived.m_availabilityOverrides.find( std::make_pair( aProp->BaseHash(), aProp->Name() ) );
if( it != derived.m_availabilityOverrides.end() )
return it->second( aItem );
@@ -238,16 +229,14 @@ bool PROPERTY_MANAGER::IsAvailableFor( TYPE_ID aItemClass, PROPERTY_BASE* aProp,
}
bool PROPERTY_MANAGER::IsWriteableFor( TYPE_ID aItemClass, PROPERTY_BASE* aProp,
INSPECTABLE* aItem )
bool PROPERTY_MANAGER::IsWriteableFor( TYPE_ID aItemClass, PROPERTY_BASE* aProp, INSPECTABLE* aItem )
{
if( !aProp->Writeable( aItem ) )
return false;
CLASS_DESC& derived = getClass( aItemClass );
auto it = derived.m_writeabilityOverrides.find( std::make_pair( aProp->BaseHash(),
aProp->Name() ) );
auto it = derived.m_writeabilityOverrides.find( std::make_pair( aProp->BaseHash(), aProp->Name() ) );
if( it != derived.m_writeabilityOverrides.end() )
return it->second( aItem );
@@ -265,7 +254,7 @@ bool PROPERTY_MANAGER::IsOfType( TYPE_ID aDerived, TYPE_ID aBase ) const
wxCHECK( derived != m_classes.end(), false ); // missing class description
// traverse the hierarchy seeking for the base class
for( auto& base : derived->second.m_bases )
for( const std::reference_wrapper<CLASS_DESC>& base : derived->second.m_bases )
{
if( IsOfType( base.get().m_id, aBase ) )
return true;
@@ -297,8 +286,8 @@ PROPERTY_MANAGER::CLASS_DESC& PROPERTY_MANAGER::getClass( TYPE_ID aTypeId )
void PROPERTY_MANAGER::CLASS_DESC::rebuild()
{
PROPERTY_SET replaced;
PROPERTY_SET masked;
std::set<std::pair<size_t, wxString>> replaced;
std::set<std::pair<size_t, wxString>> masked;
m_allProperties.clear();
collectPropsRecur( m_allProperties, replaced, m_displayOrder, masked );
@@ -338,10 +327,10 @@ void PROPERTY_MANAGER::CLASS_DESC::rebuild()
}
void PROPERTY_MANAGER::CLASS_DESC::collectPropsRecur( PROPERTY_LIST& aResult,
PROPERTY_SET& aReplaced,
PROPERTY_DISPLAY_ORDER& aDisplayOrder,
PROPERTY_SET& aMasked ) const
void PROPERTY_MANAGER::CLASS_DESC::collectPropsRecur( std::vector<PROPERTY_BASE*>& aResult,
std::set<std::pair<size_t, wxString>>& aReplaced,
std::map<PROPERTY_BASE*, int>& aDisplayOrder,
std::set<std::pair<size_t, wxString>>& aMasked ) const
{
for( const std::pair<size_t, wxString>& replacedEntry : m_replaced )
aReplaced.emplace( replacedEntry );
@@ -371,8 +360,8 @@ void PROPERTY_MANAGER::CLASS_DESC::collectPropsRecur( PROPERTY_LIST& aResult,
for( PROPERTY_BASE* property : m_ownDisplayOrder )
{
PROPERTY_SET::key_type propertyKey = std::make_pair( property->OwnerHash(),
property->Name() );
std::set<std::pair<size_t, wxString>>::key_type propertyKey = std::make_pair( property->OwnerHash(),
property->Name() );
// Do not store replaced properties
if( aReplaced.count( propertyKey ) )
continue;
@@ -386,28 +375,8 @@ void PROPERTY_MANAGER::CLASS_DESC::collectPropsRecur( PROPERTY_LIST& aResult,
}
// Iterate backwards so that replaced properties appear before base properties
for( auto it = m_bases.rbegin(); it != m_bases.rend(); ++it )
it->get().collectPropsRecur( aResult, aReplaced, aDisplayOrder, aMasked );
}
std::vector<TYPE_ID> PROPERTY_MANAGER::GetMatchingClasses( PROPERTY_BASE* aProperty )
{
std::vector<TYPE_ID> ids;
/*
for( auto& cls : m_classes )
{
CLASS_INFO info;
for( auto prop : cls.second.m_allProperties )
info.properties.push_back(prop);
}
*/
return ids;
for( std::reference_wrapper<CLASS_DESC> base : std::ranges::reverse_view( m_bases ) )
base.get().collectPropsRecur( aResult, aReplaced, aDisplayOrder, aMasked );
}
@@ -458,7 +427,7 @@ void PROPERTY_MANAGER::PropertyChanged( INSPECTABLE* aObject, PROPERTY_BASE* aPr
PROPERTY_COMMIT_HANDLER::PROPERTY_COMMIT_HANDLER( COMMIT* aCommit )
{
wxCHECK2_MSG( PROPERTY_MANAGER::Instance().m_managedCommit == nullptr,
return, "Can't have more than one managed commit at a time!" );
return, wxT( "Can't have more than one managed commit at a time!" ) );
PROPERTY_MANAGER::Instance().m_managedCommit = aCommit;
}
@@ -467,7 +436,7 @@ PROPERTY_COMMIT_HANDLER::PROPERTY_COMMIT_HANDLER( COMMIT* aCommit )
PROPERTY_COMMIT_HANDLER::~PROPERTY_COMMIT_HANDLER()
{
wxASSERT_MSG( PROPERTY_MANAGER::Instance().m_managedCommit != nullptr,
"Something went wrong: m_managedCommit already null!" );
wxT( "Something went wrong: m_managedCommit already null!" ) );
PROPERTY_MANAGER::Instance().m_managedCommit = nullptr;
}
+11 -21
View File
@@ -65,12 +65,6 @@ REPORTER& WX_TEXT_CTRL_REPORTER::Report( const wxString& aText, SEVERITY aSeveri
}
bool WX_TEXT_CTRL_REPORTER::HasMessage() const
{
return !m_textCtrl->IsEmpty();
}
REPORTER& WX_STRING_REPORTER::Report( const wxString& aText, SEVERITY aSeverity )
{
REPORTER::Report( aText, aSeverity );
@@ -93,12 +87,6 @@ void WX_STRING_REPORTER::Clear()
}
bool WX_STRING_REPORTER::HasMessage() const
{
return !m_string.IsEmpty();
}
REPORTER& NULL_REPORTER::Report( const wxString& aText, SEVERITY aSeverity )
{
return REPORTER::Report( aText, aSeverity );
@@ -211,6 +199,17 @@ REPORTER& WXLOG_REPORTER::GetInstance()
}
REPORTER& REDIRECT_REPORTER::Report( const wxString& aText, SEVERITY aSeverity )
{
REPORTER::Report( aText, aSeverity );
if( m_redirectTarget )
m_redirectTarget->Report( aText, aSeverity );
return *this;
}
REPORTER& STATUSBAR_REPORTER::Report( const wxString& aText, SEVERITY aSeverity )
{
REPORTER::Report( aText, aSeverity );
@@ -220,12 +219,3 @@ REPORTER& STATUSBAR_REPORTER::Report( const wxString& aText, SEVERITY aSeverity
return *this;
}
bool STATUSBAR_REPORTER::HasMessage() const
{
if( m_statusBar )
return !m_statusBar->GetStatusText( m_position ).IsEmpty();
return false;
}
+6
View File
@@ -799,6 +799,12 @@ TOOL_ACTION ACTIONS::unpinLibrary( TOOL_ACTION_ARGS()
.FriendlyName( _( "Unpin Library" ) )
.Tooltip( _( "No longer keep the library at the top of the list" ) ) );
TOOL_ACTION ACTIONS::showLibraryTable( TOOL_ACTION_ARGS()
.Name( "common.Control.showLibraryTable" )
.Scope( AS_GLOBAL )
.FriendlyName( _( "Library Table" ) )
.Icon( BITMAPS::table ) );
TOOL_ACTION ACTIONS::showLibraryTree( TOOL_ACTION_ARGS()
.Name( "common.Control.showLibraryTree" )
.Scope( AS_GLOBAL )
+365 -77
View File
@@ -23,12 +23,21 @@
#include "tool/construction_manager.h"
#include <algorithm>
#include <chrono>
#include <cmath>
#include <limits>
#include <numeric>
#include <utility>
#include <wx/timer.h>
#include <wx/debug.h>
#include <wx/log.h>
#include <advanced_config.h>
#include <math/util.h>
#include <hash.h>
#include <trace_helpers.h>
/**
@@ -329,9 +338,9 @@ void CONSTRUCTION_MANAGER::acceptConstructionItems( std::unique_ptr<PENDING_BATC
{
for( const CONSTRUCTION_ITEM& item : batch )
{
for( const KIGFX::CONSTRUCTION_GEOM::DRAWABLE& drawable : item.Constructions )
for( const CONSTRUCTION_ITEM::DRAWABLE_ENTRY& drawable : item.Constructions )
{
geom.AddDrawable( drawable, aIsPersistent );
geom.AddDrawable( drawable.Drawable, aIsPersistent, drawable.LineWidth );
}
}
}
@@ -383,16 +392,111 @@ bool CONSTRUCTION_MANAGER::HasActiveConstruction() const
SNAP_LINE_MANAGER::SNAP_LINE_MANAGER( CONSTRUCTION_VIEW_HANDLER& aViewHandler ) :
m_viewHandler( aViewHandler )
m_viewHandler( aViewHandler ), m_snapManager( static_cast<SNAP_MANAGER*>( &aViewHandler ) )
{
wxASSERT( m_snapManager );
SetDirections( { VECTOR2I( 1, 0 ), VECTOR2I( 0, 1 ) } );
}
static VECTOR2I normalizeDirection( const VECTOR2I& aDir )
{
if( aDir.x == 0 && aDir.y == 0 )
return VECTOR2I( 0, 0 );
int dx = aDir.x;
int dy = aDir.y;
int gcd = std::gcd( std::abs( dx ), std::abs( dy ) );
if( gcd > 0 )
{
dx /= gcd;
dy /= gcd;
}
if( dx < 0 || ( dx == 0 && dy < 0 ) )
{
dx = -dx;
dy = -dy;
}
return VECTOR2I( dx, dy );
}
static std::optional<int> findDirectionIndex( const std::vector<VECTOR2I>& aDirections,
const VECTOR2I& aDelta )
{
VECTOR2I normalized = normalizeDirection( aDelta );
if( normalized.x == 0 && normalized.y == 0 )
return std::nullopt;
for( size_t i = 0; i < aDirections.size(); ++i )
{
if( aDirections[i] == normalized )
return static_cast<int>( i );
}
return std::nullopt;
}
void SNAP_LINE_MANAGER::SetDirections( const std::vector<VECTOR2I>& aDirections )
{
std::vector<VECTOR2I> uniqueDirections;
uniqueDirections.reserve( aDirections.size() );
for( const VECTOR2I& direction : aDirections )
{
VECTOR2I normalized = normalizeDirection( direction );
if( normalized.x == 0 && normalized.y == 0 )
continue;
if( std::find( uniqueDirections.begin(), uniqueDirections.end(), normalized )
== uniqueDirections.end() )
{
uniqueDirections.push_back( normalized );
}
}
if( uniqueDirections != m_directions )
{
m_directions = std::move( uniqueDirections );
m_activeDirection.reset();
if( m_snapLineOrigin && m_snapLineEnd )
{
if( !findDirectionIndex( m_directions, *m_snapLineEnd - *m_snapLineOrigin ) )
m_snapLineEnd.reset();
}
if( m_directions.empty() )
{
ClearSnapLine();
return;
}
notifyGuideChange();
}
}
void SNAP_LINE_MANAGER::SetSnapLineOrigin( const VECTOR2I& aOrigin )
{
// Setting the origin clears the snap line as the end point is no longer valid
ClearSnapLine();
if( m_snapLineOrigin && *m_snapLineOrigin == aOrigin && !m_snapLineEnd )
{
notifyGuideChange();
return;
}
m_snapLineOrigin = aOrigin;
m_snapLineEnd.reset();
m_activeDirection.reset();
m_viewHandler.GetViewItem().ClearSnapLine();
notifyGuideChange();
}
@@ -402,12 +506,17 @@ void SNAP_LINE_MANAGER::SetSnapLineEnd( const OPT_VECTOR2I& aSnapEnd )
{
m_snapLineEnd = aSnapEnd;
if( m_snapLineEnd )
m_activeDirection = findDirectionIndex( m_directions, *m_snapLineEnd - *m_snapLineOrigin );
else
m_activeDirection.reset();
if( m_snapLineEnd )
m_viewHandler.GetViewItem().SetSnapLine( SEG{ *m_snapLineOrigin, *m_snapLineEnd } );
else
m_viewHandler.GetViewItem().ClearSnapLine();
m_viewHandler.updateView();
notifyGuideChange();
}
}
@@ -416,8 +525,9 @@ void SNAP_LINE_MANAGER::ClearSnapLine()
{
m_snapLineOrigin.reset();
m_snapLineEnd.reset();
m_activeDirection.reset();
m_viewHandler.GetViewItem().ClearSnapLine();
m_viewHandler.updateView();
notifyGuideChange();
}
@@ -425,7 +535,7 @@ void SNAP_LINE_MANAGER::SetSnappedAnchor( const VECTOR2I& aAnchorPos )
{
if( m_snapLineOrigin.has_value() )
{
if( aAnchorPos.x == m_snapLineOrigin->x || aAnchorPos.y == m_snapLineOrigin->y )
if( findDirectionIndex( m_directions, aAnchorPos - *m_snapLineOrigin ) )
{
SetSnapLineEnd( aAnchorPos );
}
@@ -444,93 +554,206 @@ void SNAP_LINE_MANAGER::SetSnappedAnchor( const VECTOR2I& aAnchorPos )
}
/**
* Check if the cursor has moved far enough away from the snap line origin to escape snapping
* in the X direction.
*
* This is defined as within aEscapeRange of the snap line origin, and within aLongRangeEscapeAngle
* of the vertical line passing through the snap line origin.
*/
static bool pointHasEscapedSnapLineX( const VECTOR2I& aCursor, const VECTOR2I& aSnapLineOrigin,
int aEscapeRange, EDA_ANGLE aLongRangeEscapeAngle )
{
if( std::abs( aCursor.x - aSnapLineOrigin.x ) < aEscapeRange )
{
return false;
}
EDA_ANGLE angle = EDA_ANGLE( aCursor - aSnapLineOrigin ) + EDA_ANGLE( 90, DEGREES_T );
return std::abs( angle.Normalize90() ) > aLongRangeEscapeAngle;
}
/**
* As above, but for the Y direction.
*/
static bool pointHasEscapedSnapLineY( const VECTOR2I& aCursor, const VECTOR2I& aSnapLineOrigin,
int aEscapeRange, EDA_ANGLE aLongRangeEscapeAngle )
{
if( std::abs( aCursor.y - aSnapLineOrigin.y ) < aEscapeRange )
{
return false;
}
EDA_ANGLE angle = EDA_ANGLE( aCursor - aSnapLineOrigin );
return std::abs( angle.Normalize90() ) > aLongRangeEscapeAngle;
}
OPT_VECTOR2I SNAP_LINE_MANAGER::GetNearestSnapLinePoint( const VECTOR2I& aCursor,
const VECTOR2I& aNearestGrid,
std::optional<int> aDistToNearest,
int aSnapRange ) const
int aSnapRange,
const VECTOR2D& aGridSize,
const VECTOR2I& aGridOrigin ) const
{
// return std::nullopt;
if( m_snapLineOrigin )
wxLogTrace( traceSnap, "GetNearestSnapLinePoint: cursor=(%d, %d), nearestGrid=(%d, %d), distToNearest=%s, snapRange=%d",
aCursor.x, aCursor.y, aNearestGrid.x, aNearestGrid.y,
aDistToNearest ? wxString::Format( "%d", *aDistToNearest ) : wxString( "none" ), aSnapRange );
if( !m_snapLineOrigin || m_directions.empty() )
{
bool snapLine = false;
VECTOR2I bestSnapPoint = aNearestGrid;
wxLogTrace( traceSnap, " No snap line origin or no directions, returning nullopt" );
return std::nullopt;
}
// If there's no snap anchor, or it's too far away, prefer the grid
const bool gridBetterThanNearest = !aDistToNearest || *aDistToNearest > aSnapRange;
const bool gridBetterThanNearest = !aDistToNearest || *aDistToNearest > aSnapRange;
const bool gridActive = aGridSize.x > 0 && aGridSize.y > 0;
// The escape range is how far you go before the snap line is de-activated.
// Make this a bit more forgiving than the snap range, as you can easily cancel
// deliberately with a mouse move.
// These are both a bit arbitrary, and can be adjusted as preferred
const int escapeRange = 2 * aSnapRange;
const EDA_ANGLE longRangeEscapeAngle( 4, DEGREES_T );
wxLogTrace( traceSnap, " snapLineOrigin=(%d, %d), directions count=%zu, gridBetterThanNearest=%d, gridActive=%d",
m_snapLineOrigin->x, m_snapLineOrigin->y, m_directions.size(), gridBetterThanNearest, gridActive );
const bool escapedX = pointHasEscapedSnapLineX( aCursor, *m_snapLineOrigin, escapeRange,
longRangeEscapeAngle );
const bool escapedY = pointHasEscapedSnapLineY( aCursor, *m_snapLineOrigin, escapeRange,
longRangeEscapeAngle );
if( !gridBetterThanNearest )
{
wxLogTrace( traceSnap, " Grid not better than nearest, returning nullopt" );
return std::nullopt;
}
/// Allows de-snapping from the line if you are closer to another snap point
/// Or if you have moved far enough away from the line
if( !escapedX && gridBetterThanNearest )
const int escapeRange = 2 * aSnapRange;
const EDA_ANGLE longRangeEscapeAngle( 4, DEGREES_T );
wxLogTrace( traceSnap, " escapeRange=%d, longRangeEscapeAngle=%.1f deg",
escapeRange, longRangeEscapeAngle.AsDegrees() );
const VECTOR2D origin( *m_snapLineOrigin );
const VECTOR2D cursor( aCursor );
const VECTOR2D delta = cursor - origin;
double bestPerpDistance = std::numeric_limits<double>::max();
std::optional<VECTOR2I> bestSnapPoint;
for( size_t ii = 0; ii < m_directions.size(); ++ii )
{
const VECTOR2I& direction = m_directions[ii];
VECTOR2D dirVector( direction );
double dirLength = dirVector.EuclideanNorm();
if( dirLength == 0.0 )
{
bestSnapPoint.x = m_snapLineOrigin->x;
snapLine = true;
wxLogTrace( traceSnap, " Direction %zu: zero length, skipping", ii );
continue;
}
if( !escapedY && gridBetterThanNearest )
VECTOR2D dirUnit = dirVector / dirLength;
double distanceAlong = delta.Dot( dirUnit );
VECTOR2D projection = origin + dirUnit * distanceAlong;
VECTOR2D offset = delta - dirUnit * distanceAlong;
double perpDistance = offset.EuclideanNorm();
wxLogTrace( traceSnap, " Direction %zu: dir=(%d, %d), perpDist=%.1f, distAlong=%.1f",
ii, direction.x, direction.y, perpDistance, distanceAlong );
if( perpDistance > aSnapRange )
{
bestSnapPoint.y = m_snapLineOrigin->y;
snapLine = true;
wxLogTrace( traceSnap, " perpDistance > snapRange, skipping" );
continue;
}
if( snapLine )
bool escaped = false;
if( perpDistance >= escapeRange )
{
return bestSnapPoint;
EDA_ANGLE deltaAngle( delta );
EDA_ANGLE directionAngle( dirVector );
double angleDiff = ( deltaAngle - directionAngle ).Normalize180().AsDegrees();
wxLogTrace( traceSnap, " In escape range: deltaAngle=%.1f, dirAngle=%.1f, angleDiff=%.1f",
deltaAngle.AsDegrees(), directionAngle.AsDegrees(), angleDiff );
if( std::abs( angleDiff ) > longRangeEscapeAngle.AsDegrees() )
{
escaped = true;
wxLogTrace( traceSnap, " ESCAPED (angle diff too large)" );
}
}
if( escaped )
{
wxLogTrace( traceSnap, " Not updating (escaped)" );
continue;
}
// Now snap the projection to the grid if the grid is active
VECTOR2D snapPoint = projection;
if( gridActive )
{
// For horizontal/vertical lines, snap to grid intersections
if( direction.x == 0 && direction.y != 0 )
{
// Vertical line: keep origin X, snap Y to grid
snapPoint.x = origin.x;
snapPoint.y = aNearestGrid.y;
wxLogTrace( traceSnap, " Vertical line: snapping to grid Y, snapPoint=(%.1f, %.1f)",
snapPoint.x, snapPoint.y );
}
else if( direction.y == 0 && direction.x != 0 )
{
// Horizontal line: snap X to grid, keep origin Y
snapPoint.x = aNearestGrid.x;
snapPoint.y = origin.y;
wxLogTrace( traceSnap, " Horizontal line: snapping to grid X, snapPoint=(%.1f, %.1f)",
snapPoint.x, snapPoint.y );
}
else
{
// Diagonal line: find nearest grid intersection along the line
VECTOR2D gridOriginD( aGridOrigin );
VECTOR2D relProjection = projection - gridOriginD;
// Find nearby grid points (check 3x3 grid around projection)
double bestGridScore = std::numeric_limits<double>::max();
VECTOR2D bestGridPoint = projection;
for( int dx = -1; dx <= 1; ++dx )
{
for( int dy = -1; dy <= 1; ++dy )
{
double gridX = std::round( relProjection.x / aGridSize.x ) * aGridSize.x + dx * aGridSize.x;
double gridY = std::round( relProjection.y / aGridSize.y ) * aGridSize.y + dy * aGridSize.y;
VECTOR2D gridPt( gridX + gridOriginD.x, gridY + gridOriginD.y );
// Calculate perpendicular distance from grid point to construction line
VECTOR2D gridDelta = gridPt - origin;
double gridDistAlong = gridDelta.Dot( dirUnit );
VECTOR2D gridProjection = origin + dirUnit * gridDistAlong;
double gridPerpDist = ( gridPt - gridProjection ).EuclideanNorm();
// Also consider distance from cursor
double distFromCursor = ( gridPt - cursor ).EuclideanNorm();
// Prefer grid points that are close to the line and close to cursor
double score = gridPerpDist + distFromCursor * 0.1;
if( score < bestGridScore )
{
bestGridScore = score;
bestGridPoint = gridPt;
}
}
}
snapPoint = bestGridPoint;
wxLogTrace( traceSnap, " Diagonal line: snapping to grid intersection, snapPoint=(%.1f, %.1f)",
snapPoint.x, snapPoint.y );
}
}
else
{
wxLogTrace( traceSnap, " Grid not active, using projection" );
}
if( perpDistance < bestPerpDistance )
{
bestPerpDistance = perpDistance;
bestSnapPoint = VECTOR2I( KiROUND( snapPoint.x ), KiROUND( snapPoint.y ) );
wxLogTrace( traceSnap, " NEW BEST: perpDist=%.1f, snapPoint=(%d, %d)",
bestPerpDistance, bestSnapPoint->x, bestSnapPoint->y );
}
else
{
wxLogTrace( traceSnap, " Not updating (perpDist=%.1f >= bestPerp=%.1f)",
perpDistance, bestPerpDistance );
}
}
if( bestSnapPoint )
{
wxLogTrace( traceSnap, " RETURNING bestSnapPoint=(%d, %d)", bestSnapPoint->x, bestSnapPoint->y );
return *bestSnapPoint;
}
wxLogTrace( traceSnap, " RETURNING nullopt (no valid snap found)" );
return std::nullopt;
}
void SNAP_LINE_MANAGER::notifyGuideChange()
{
if( m_snapManager )
m_snapManager->UpdateSnapGuides();
}
SNAP_MANAGER::SNAP_MANAGER( KIGFX::CONSTRUCTION_GEOM& aHelper ) :
CONSTRUCTION_VIEW_HANDLER( aHelper ), m_snapLineManager( *this ),
m_constructionManager( *this )
m_constructionManager( *this ), m_snapGuideColor( KIGFX::COLOR4D::WHITE ),
m_snapGuideHighlightColor( KIGFX::COLOR4D::WHITE )
{
}
@@ -540,13 +763,67 @@ void SNAP_MANAGER::updateView()
if( m_updateCallback )
{
bool showAnything = m_constructionManager.HasActiveConstruction()
|| m_snapLineManager.HasCompleteSnapLine();
|| m_snapLineManager.HasCompleteSnapLine()
|| ( m_snapLineManager.GetSnapLineOrigin()
&& !m_snapLineManager.GetDirections().empty() );
m_updateCallback( showAnything );
}
}
void SNAP_MANAGER::SetSnapGuideColors( const KIGFX::COLOR4D& aBase, const KIGFX::COLOR4D& aHighlight )
{
m_snapGuideColor = aBase;
m_snapGuideHighlightColor = aHighlight;
UpdateSnapGuides();
}
void SNAP_MANAGER::UpdateSnapGuides()
{
std::vector<KIGFX::CONSTRUCTION_GEOM::SNAP_GUIDE> guides;
const OPT_VECTOR2I& origin = m_snapLineManager.GetSnapLineOrigin();
const std::vector<VECTOR2I>& directions = m_snapLineManager.GetDirections();
if( origin && !directions.empty() )
{
const std::optional<int> activeDirection = m_snapLineManager.GetActiveDirection();
const int guideLength = 500000;
for( size_t ii = 0; ii < directions.size(); ++ii )
{
const VECTOR2I& direction = directions[ii];
if( direction.x == 0 && direction.y == 0 )
continue;
VECTOR2I scaled = direction * guideLength;
KIGFX::CONSTRUCTION_GEOM::SNAP_GUIDE guide;
guide.Segment = SEG( *origin - scaled, *origin + scaled );
if( activeDirection && *activeDirection == static_cast<int>( ii ) )
{
guide.LineWidth = 2;
guide.Color = m_snapGuideHighlightColor;
}
else
{
guide.LineWidth = 1;
guide.Color = m_snapGuideColor;
}
guides.push_back( guide );
}
}
GetViewItem().SetSnapGuides( std::move( guides ) );
updateView();
}
std::vector<CONSTRUCTION_MANAGER::CONSTRUCTION_ITEM_BATCH>
SNAP_MANAGER::GetConstructionItems() const
{
@@ -566,13 +843,24 @@ SNAP_MANAGER::GetConstructionItems() const
{},
} );
// One horizontal and one vertical infinite line from the snap point
snapPointItem.Constructions.push_back(
LINE{ *snapLineOrigin, *snapLineOrigin + VECTOR2I( 100000, 0 ) } );
snapPointItem.Constructions.push_back(
LINE{ *snapLineOrigin, *snapLineOrigin + VECTOR2I( 0, 100000 ) } );
const std::vector<VECTOR2I>& directions = m_snapLineManager.GetDirections();
const std::optional<int> activeDirection = m_snapLineManager.GetActiveDirection();
batches.push_back( std::move( batch ) );
for( size_t ii = 0; ii < directions.size(); ++ii )
{
const VECTOR2I& direction = directions[ii];
VECTOR2I scaledDirection = direction * 100000;
CONSTRUCTION_MANAGER::CONSTRUCTION_ITEM::DRAWABLE_ENTRY entry;
entry.Drawable = LINE{ *snapLineOrigin, *snapLineOrigin + scaledDirection };
entry.LineWidth = ( activeDirection && *activeDirection == static_cast<int>( ii ) ) ? 2 : 1;
snapPointItem.Constructions.push_back( entry );
}
if( !snapPointItem.Constructions.empty() )
batches.push_back( std::move( batch ) );
}
return batches;
+1 -1
View File
@@ -61,7 +61,7 @@ void EC_45DEGREE::Apply( EDIT_POINT& aHandle, const GRID_HELPER& aGrid )
VECTOR2I lineVector( aHandle.GetPosition() - m_constrainer.GetPosition() );
VECTOR2I newLineVector = GetVectorSnapped45( lineVector );
if( aHandle.GetGridConstraint() == SNAP_TO_GRID
if( aHandle.GetGridConstraint() == SNAP_TO_GRID && !aGrid.GetSnappedPoint()
&& ( newLineVector.x == 0 || newLineVector.y == 0 ) )
{
VECTOR2I snap = aGrid.AlignGrid( m_constrainer.GetPosition() + newLineVector );
+273 -28
View File
@@ -24,21 +24,23 @@
#include "tool/grid_helper.h"
#include <functional>
#include <cmath>
#include <limits>
#include <advanced_config.h>
#include <trace_helpers.h>
#include <wx/log.h>
#include <gal/graphics_abstraction_layer.h>
#include <gal/painter.h>
#include <math/util.h> // for KiROUND
#include <math/vector2d.h>
#include <render_settings.h>
#include <tool/tool_manager.h>
#include <tool/tools_holder.h>
#include <view/view.h>
#include <settings/app_settings.h>
GRID_HELPER::GRID_HELPER( TOOL_MANAGER* aToolMgr, int aConstructionLayer ) :
m_toolMgr( aToolMgr ), m_snapManager( m_constructionGeomPreview )
GRID_HELPER::GRID_HELPER() :
m_toolMgr( nullptr ), m_snapManager( m_constructionGeomPreview )
{
m_maskTypes = ALL;
m_enableSnap = true;
@@ -46,12 +48,23 @@ GRID_HELPER::GRID_HELPER( TOOL_MANAGER* aToolMgr, int aConstructionLayer ) :
m_enableGrid = true;
m_snapItem = std::nullopt;
KIGFX::VIEW* view = m_toolMgr->GetView();
KIGFX::RENDER_SETTINGS* settings = view->GetPainter()->GetSettings();
m_manualGrid = VECTOR2D( 1, 1 );
m_manualVisibleGrid = VECTOR2D( 1, 1 );
m_manualOrigin = VECTOR2I( 0, 0 );
m_manualGridSnapping = true;
}
const KIGFX::COLOR4D constructionColour = settings->GetLayerColor( aConstructionLayer );
m_constructionGeomPreview.SetPersistentColor( constructionColour );
m_constructionGeomPreview.SetColor( constructionColour.WithAlpha( 0.7 ) );
GRID_HELPER::GRID_HELPER( TOOL_MANAGER* aToolMgr, int aConstructionLayer ) :
GRID_HELPER()
{
m_toolMgr = aToolMgr;
if( !m_toolMgr )
return;
KIGFX::VIEW* view = m_toolMgr->GetView();
wxUnusedVar( aConstructionLayer );
view->Add( &m_constructionGeomPreview );
view->SetVisible( &m_constructionGeomPreview, false );
@@ -72,11 +85,20 @@ GRID_HELPER::GRID_HELPER( TOOL_MANAGER* aToolMgr, int aConstructionLayer ) :
m_toolMgr->GetToolHolder()->RefreshCanvas();
} );
// Initialise manual values from view for compatibility
m_manualGrid = view->GetGAL()->GetGridSize();
m_manualVisibleGrid = view->GetGAL()->GetVisibleGridSize();
m_manualOrigin = VECTOR2I( view->GetGAL()->GetGridOrigin() );
m_manualGridSnapping = view->GetGAL()->GetGridSnapping();
}
GRID_HELPER::~GRID_HELPER()
{
if( !m_toolMgr )
return;
KIGFX::VIEW& view = *m_toolMgr->GetView();
view.Remove( &m_constructionGeomPreview );
@@ -89,6 +111,9 @@ KIGFX::ANCHOR_DEBUG* GRID_HELPER::enableAndGetAnchorDebug()
{
static bool permitted = ADVANCED_CFG::GetCfg().m_EnableSnapAnchorsDebug;
if( !m_toolMgr )
return nullptr;
if( permitted && !m_anchorDebug )
{
KIGFX::VIEW& view = *m_toolMgr->GetView();
@@ -103,12 +128,223 @@ KIGFX::ANCHOR_DEBUG* GRID_HELPER::enableAndGetAnchorDebug()
void GRID_HELPER::showConstructionGeometry( bool aShow )
{
m_toolMgr->GetView()->SetVisible( &m_constructionGeomPreview, aShow );
if( m_toolMgr )
m_toolMgr->GetView()->SetVisible( &m_constructionGeomPreview, aShow );
}
void GRID_HELPER::SetSnapLineDirections( const std::vector<VECTOR2I>& aDirections )
{
m_snapManager.GetSnapLineManager().SetDirections( aDirections );
}
void GRID_HELPER::SetSnapLineOrigin( const VECTOR2I& aOrigin )
{
m_snapManager.GetSnapLineManager().SetSnapLineOrigin( aOrigin );
}
void GRID_HELPER::ClearSnapLine()
{
m_snapManager.GetSnapLineManager().ClearSnapLine();
}
std::optional<VECTOR2I> GRID_HELPER::SnapToConstructionLines( const VECTOR2I& aPoint,
const VECTOR2I& aNearestGrid,
const VECTOR2D& aGrid,
double aSnapRange ) const
{
const SNAP_LINE_MANAGER& snapLineManager = m_snapManager.GetSnapLineManager();
const OPT_VECTOR2I& snapOrigin = snapLineManager.GetSnapLineOrigin();
wxLogTrace( traceSnap, "SnapToConstructionLines: aPoint=(%d, %d), nearestGrid=(%d, %d), snapRange=%.1f",
aPoint.x, aPoint.y, aNearestGrid.x, aNearestGrid.y, aSnapRange );
if( !snapOrigin || snapLineManager.GetDirections().empty() )
{
wxLogTrace( traceSnap, " No snap origin or no directions, returning nullopt" );
return std::nullopt;
}
const VECTOR2I& origin = *snapOrigin;
wxLogTrace( traceSnap, " snapOrigin=(%d, %d), directions count=%zu",
origin.x, origin.y, snapLineManager.GetDirections().size() );
const std::vector<VECTOR2I>& directions = snapLineManager.GetDirections();
const std::optional<int> activeDirection = snapLineManager.GetActiveDirection();
if( activeDirection )
wxLogTrace( traceSnap, " activeDirection=%d", *activeDirection );
const VECTOR2D originVec( origin );
const VECTOR2D cursorVec( aPoint );
const VECTOR2D delta = cursorVec - originVec;
std::optional<VECTOR2I> bestPoint;
double bestPerp = std::numeric_limits<double>::max();
double bestDistance = std::numeric_limits<double>::max();
for( size_t ii = 0; ii < directions.size(); ++ii )
{
const VECTOR2I& dir = directions[ii];
VECTOR2D dirVector( dir );
double dirLength = dirVector.EuclideanNorm();
if( dirLength == 0.0 )
{
wxLogTrace( traceSnap, " Direction %zu: zero length, skipping", ii );
continue;
}
VECTOR2D dirUnit = dirVector / dirLength;
double distanceAlong = delta.Dot( dirUnit );
VECTOR2D projection = originVec + dirUnit * distanceAlong;
VECTOR2D offset = delta - dirUnit * distanceAlong;
double perpDistance = offset.EuclideanNorm();
double snapThreshold = aSnapRange;
if( activeDirection && *activeDirection == static_cast<int>( ii ) )
{
snapThreshold *= 1.5;
wxLogTrace( traceSnap, " Direction %zu: ACTIVE, increased snapThreshold=%.1f", ii, snapThreshold );
}
wxLogTrace( traceSnap, " Direction %zu: dir=(%d, %d), perpDist=%.1f, threshold=%.1f",
ii, dir.x, dir.y, perpDistance, snapThreshold );
if( perpDistance > snapThreshold )
{
wxLogTrace( traceSnap, " perpDistance > threshold, skipping" );
continue;
}
VECTOR2D candidate = projection;
if( canUseGrid() )
{
if( dir.x == 0 && dir.y != 0 )
{
// Vertical construction line: snap to grid intersection
candidate.x = origin.x;
candidate.y = aNearestGrid.y;
wxLogTrace( traceSnap, " Vertical snap: candidate=(%d, %d)",
(int)candidate.x, (int)candidate.y );
}
else if( dir.y == 0 && dir.x != 0 )
{
// Horizontal construction line: snap to grid intersection
candidate.x = aNearestGrid.x;
candidate.y = origin.y;
wxLogTrace( traceSnap, " Horizontal snap: candidate=(%d, %d)",
(int)candidate.x, (int)candidate.y );
}
else
{
// Diagonal construction line: find nearest grid intersection along the line
// We need to find grid points near the projection point and pick the closest
// one that lies on the construction line
// Get the grid origin for proper alignment
VECTOR2D gridOrigin( GetOrigin() );
// Calculate the projection point relative to grid
VECTOR2D relProjection = projection - gridOrigin;
// Find nearby grid points (check 9 points in a 3x3 grid around the projection)
std::vector<VECTOR2D> gridPoints;
for( int dx = -1; dx <= 1; ++dx )
{
for( int dy = -1; dy <= 1; ++dy )
{
double gridX = std::round( relProjection.x / aGrid.x ) * aGrid.x + dx * aGrid.x;
double gridY = std::round( relProjection.y / aGrid.y ) * aGrid.y + dy * aGrid.y;
gridPoints.push_back( VECTOR2D( gridX + gridOrigin.x, gridY + gridOrigin.y ) );
}
}
// Find the grid point closest to the construction line
double bestGridDist = std::numeric_limits<double>::max();
VECTOR2D bestGridPt = projection;
for( const VECTOR2D& gridPt : gridPoints )
{
// Calculate perpendicular distance from grid point to construction line
VECTOR2D gridDelta = gridPt - originVec;
double gridDistAlong = gridDelta.Dot( dirUnit );
VECTOR2D gridProjection = originVec + dirUnit * gridDistAlong;
double gridPerpDist = ( gridPt - gridProjection ).EuclideanNorm();
// Also consider distance from cursor
double distFromCursor = ( gridPt - cursorVec ).EuclideanNorm();
// Prefer grid points that are close to the line and close to cursor
double score = gridPerpDist + distFromCursor * 0.1;
if( score < bestGridDist )
{
bestGridDist = score;
bestGridPt = gridPt;
}
}
candidate = bestGridPt;
wxLogTrace( traceSnap, " Diagonal snap: candidate=(%.1f, %.1f), perpDist=%.1f",
candidate.x, candidate.y, bestGridDist );
}
}
else
{
wxLogTrace( traceSnap, " Grid disabled, using projection candidate=(%.1f, %.1f)",
candidate.x, candidate.y );
}
VECTOR2I candidateInt( KiROUND( candidate.x ), KiROUND( candidate.y ) );
if( candidateInt == m_skipPoint )
{
wxLogTrace( traceSnap, " candidateInt matches m_skipPoint, skipping" );
continue;
}
VECTOR2D candidateDelta( candidateInt.x - aPoint.x, candidateInt.y - aPoint.y );
double candidateDistance = candidateDelta.EuclideanNorm();
wxLogTrace( traceSnap, " candidateInt=(%d, %d), candidateDist=%.1f",
candidateInt.x, candidateInt.y, candidateDistance );
if( perpDistance < bestPerp
|| ( std::abs( perpDistance - bestPerp ) < 1e-9 && candidateDistance < bestDistance ) )
{
wxLogTrace( traceSnap, " NEW BEST: perpDist=%.1f, candDist=%.1f", perpDistance, candidateDistance );
bestPerp = perpDistance;
bestDistance = candidateDistance;
bestPoint = candidateInt;
}
}
if( bestPoint )
{
wxLogTrace( traceSnap, " RETURNING bestPoint=(%d, %d)", bestPoint->x, bestPoint->y );
}
else
{
wxLogTrace( traceSnap, " RETURNING nullopt (no valid snap found)" );
}
return bestPoint;
}
void GRID_HELPER::updateSnapPoint( const TYPED_POINT2I& aPoint )
{
if( !m_toolMgr )
return;
m_viewSnapPoint.SetPosition( aPoint.m_point );
m_viewSnapPoint.SetSnapTypes( aPoint.m_types );
@@ -121,23 +357,26 @@ void GRID_HELPER::updateSnapPoint( const TYPED_POINT2I& aPoint )
VECTOR2I GRID_HELPER::GetGrid() const
{
VECTOR2D size = m_toolMgr->GetView()->GetGAL()->GetGridSize();
VECTOR2D size = m_toolMgr ? m_toolMgr->GetView()->GetGAL()->GetGridSize() : m_manualGrid;
return VECTOR2I( KiROUND( size.x ), KiROUND( size.y ) );
}
VECTOR2D GRID_HELPER::GetVisibleGrid() const
{
return m_toolMgr->GetView()->GetGAL()->GetVisibleGridSize();
return m_toolMgr ? m_toolMgr->GetView()->GetGAL()->GetVisibleGridSize() : m_manualVisibleGrid;
}
VECTOR2I GRID_HELPER::GetOrigin() const
{
VECTOR2D origin = m_toolMgr->GetView()->GetGAL()->GetGridOrigin();
if( m_toolMgr )
{
VECTOR2D origin = m_toolMgr->GetView()->GetGAL()->GetGridOrigin();
return VECTOR2I( origin );
}
return VECTOR2I( origin );
return m_manualOrigin;
}
@@ -160,7 +399,7 @@ GRID_HELPER_GRIDS GRID_HELPER::GetSelectionGrid( const SELECTION& aSelection ) c
VECTOR2D GRID_HELPER::GetGridSize( GRID_HELPER_GRIDS aGrid ) const
{
return m_toolMgr->GetView()->GetGAL()->GetGridSize();
return m_toolMgr ? m_toolMgr->GetView()->GetGAL()->GetGridSize() : m_manualGrid;
}
@@ -170,47 +409,52 @@ void GRID_HELPER::SetAuxAxes( bool aEnable, const VECTOR2I& aOrigin )
{
m_auxAxis = aOrigin;
m_viewAxis.SetPosition( aOrigin );
m_toolMgr->GetView()->SetVisible( &m_viewAxis, true );
if( m_toolMgr )
m_toolMgr->GetView()->SetVisible( &m_viewAxis, true );
}
else
{
m_auxAxis = std::optional<VECTOR2I>();
m_toolMgr->GetView()->SetVisible( &m_viewAxis, false );
if( m_toolMgr )
m_toolMgr->GetView()->SetVisible( &m_viewAxis, false );
}
}
VECTOR2I GRID_HELPER::AlignGrid( const VECTOR2I& aPoint ) const
{
return computeNearest( aPoint, GetGrid() );
return computeNearest( aPoint, GetGrid(), GetOrigin() );
}
VECTOR2I GRID_HELPER::AlignGrid( const VECTOR2I& aPoint, const VECTOR2D& aGrid ) const
VECTOR2I GRID_HELPER::AlignGrid( const VECTOR2I& aPoint, const VECTOR2D& aGrid,
const VECTOR2D& aOffset ) const
{
return computeNearest( aPoint, aGrid );
return computeNearest( aPoint, aGrid, aOffset );
}
VECTOR2I GRID_HELPER::computeNearest( const VECTOR2I& aPoint, const VECTOR2I& aGrid ) const
VECTOR2I GRID_HELPER::computeNearest( const VECTOR2I& aPoint, const VECTOR2I& aGrid,
const VECTOR2I& aOffset ) const
{
return VECTOR2I( KiROUND( static_cast<double>( aPoint.x ) / aGrid.x ) * aGrid.x,
KiROUND( static_cast<double>( aPoint.y ) / aGrid.y ) * aGrid.y );
return VECTOR2I( KiROUND( (double) ( aPoint.x - aOffset.x ) / aGrid.x ) * aGrid.x + aOffset.x,
KiROUND( (double) ( aPoint.y - aOffset.y ) / aGrid.y ) * aGrid.y + aOffset.y );
}
VECTOR2I GRID_HELPER::Align( const VECTOR2I& aPoint ) const
{
return Align( aPoint, GetGrid() );
return Align( aPoint, GetGrid(), GetOrigin() );
}
VECTOR2I GRID_HELPER::Align( const VECTOR2I& aPoint, const VECTOR2D& aGrid ) const
VECTOR2I GRID_HELPER::Align( const VECTOR2I& aPoint, const VECTOR2D& aGrid,
const VECTOR2D& aOffset ) const
{
if( !canUseGrid() )
return aPoint;
VECTOR2I nearest = AlignGrid( aPoint, aGrid );
VECTOR2I nearest = AlignGrid( aPoint, aGrid, aOffset );
if( !m_auxAxis )
return nearest;
@@ -227,7 +471,8 @@ VECTOR2I GRID_HELPER::Align( const VECTOR2I& aPoint, const VECTOR2D& aGrid ) con
bool GRID_HELPER::canUseGrid() const
{
return m_enableGrid && m_toolMgr->GetView()->GetGAL()->GetGridSnapping();
return m_enableGrid && ( m_toolMgr ? m_toolMgr->GetView()->GetGAL()->GetGridSnapping()
: m_manualGridSnapping );
}
+3
View File
@@ -31,6 +31,9 @@ void POLYGON_POINT_EDIT_BEHAVIOR::BuildForPolyOutline( EDIT_POINTS& aPo
{
const int cornersCount = aOutline.TotalVertices();
if( cornersCount == 0 )
return;
for( auto iterator = aOutline.CIterateWithHoles(); iterator; iterator++ )
{
aPoints.AddPoint( *iterator );
+2
View File
@@ -59,6 +59,8 @@ const wxChar* const traceUiProfile = wxT( "KICAD_UI_PROFILE" );
const wxChar* const traceGit = wxT( "KICAD_GIT" );
const wxChar* const traceEagleIo = wxT( "KICAD_EAGLE_IO" );
const wxChar* const traceDesignBlocks = wxT( "KICAD_DESIGN_BLOCK" );
const wxChar* const traceLibFieldTable = wxT( "KICAD_LIB_FIELD_TABLE" );
const wxChar* const traceSnap = wxT( "KICAD_SNAP" );
wxString dump( const wxArrayString& aArray )
+79 -56
View File
@@ -362,18 +362,26 @@ bool FIELD_VALIDATOR::Validate( wxWindow* aParent )
}
bool FIELD_VALIDATOR::DoValidate( const wxString& aValue, wxWindow* aParent )
wxString GetFieldValidationErrorMessage( int aFieldId, const wxString& aValue )
{
wxString msg;
FIELD_VALIDATOR validator( aFieldId );
wxString msg;
if( HasFlag( wxFILTER_EMPTY ) && aValue.empty() )
msg.Printf( _( "The value of the field cannot be empty." ) );
if( validator.HasFlag( wxFILTER_EMPTY ) && aValue.empty() )
{
switch( aFieldId )
{
case SHEETNAME_V: msg = _( "A sheet must have a name." ); break;
case SHEETFILENAME_V: msg = _( "A sheet must have a file specified." ); break;
default: msg = _( "The value of the field cannot be empty." ); break;
}
}
if( HasFlag( wxFILTER_EXCLUDE_CHAR_LIST ) && ContainsExcludedCharacters( aValue ) )
if( msg.empty() && validator.HasFlag( wxFILTER_EXCLUDE_CHAR_LIST ) )
{
wxArrayString badCharsFound;
for( const wxUniCharRef& excludeChar : GetCharExcludes() )
for( const wxUniCharRef& excludeChar : validator.GetCharExcludes() )
{
if( aValue.Find( excludeChar ) != wxNOT_FOUND )
{
@@ -390,68 +398,83 @@ bool FIELD_VALIDATOR::DoValidate( const wxString& aValue, wxWindow* aParent )
}
}
wxString badChars;
for( size_t i = 0; i < badCharsFound.GetCount(); i++ )
if( !badCharsFound.IsEmpty() )
{
if( !badChars.IsEmpty() )
wxString badChars;
for( size_t i = 0; i < badCharsFound.GetCount(); i++ )
{
if( badCharsFound.GetCount() == 2 )
if( !badChars.IsEmpty() )
{
badChars += _( " or " );
}
else
{
if( i < badCharsFound.GetCount() - 2 )
badChars += _( ", or " );
if( badCharsFound.GetCount() == 2 )
{
badChars += _( " or " );
}
else
badChars += wxT( ", " );
{
if( i < badCharsFound.GetCount() - 2 )
badChars += _( ", or " );
else
badChars += wxT( ", " );
}
}
badChars += badCharsFound.Item( i );
}
badChars += badCharsFound.Item( i );
switch( aFieldId )
{
case REFERENCE_FIELD:
msg.Printf( _( "The reference designator cannot contain %s character(s)." ), badChars );
break;
case VALUE_FIELD:
msg.Printf( _( "The value field cannot contain %s character(s)." ), badChars );
break;
case FOOTPRINT_FIELD:
msg.Printf( _( "The footprint field cannot contain %s character(s)." ), badChars );
break;
case DATASHEET_FIELD:
msg.Printf( _( "The datasheet field cannot contain %s character(s)." ), badChars );
break;
case SHEETNAME_V:
msg.Printf( _( "The sheet name cannot contain %s character(s)." ), badChars );
break;
case SHEETFILENAME_V:
msg.Printf( _( "The sheet filename cannot contain %s character(s)." ), badChars );
break;
default:
msg.Printf( _( "The field cannot contain %s character(s)." ), badChars );
break;
};
}
}
switch( m_fieldId )
if( msg.empty() )
{
if( aFieldId == REFERENCE_FIELD && aValue.Contains( wxT( "${" ) ) )
{
case REFERENCE_FIELD:
msg.Printf( _( "The reference designator cannot contain %s character(s)." ), badChars );
break;
case VALUE_FIELD:
msg.Printf( _( "The value field cannot contain %s character(s)." ), badChars );
break;
case FOOTPRINT_FIELD:
msg.Printf( _( "The footprint field cannot contain %s character(s)." ), badChars );
break;
case DATASHEET_FIELD:
msg.Printf( _( "The datasheet field cannot contain %s character(s)." ), badChars );
break;
case SHEETNAME_V:
msg.Printf( _( "The sheet name cannot contain %s character(s)." ), badChars );
break;
case SHEETFILENAME_V:
msg.Printf( _( "The sheet filename cannot contain %s character(s)." ), badChars );
break;
default:
msg.Printf( _( "The field cannot contain %s character(s)." ), badChars );
break;
};
}
else if( m_fieldId == REFERENCE_FIELD && aValue.Contains( wxT( "${" ) ) )
{
msg.Printf( _( "The reference designator cannot contain text variable references" ) );
}
else if( m_fieldId == REFERENCE_FIELD && UTIL::GetRefDesPrefix( aValue ).IsEmpty() )
{
msg.Printf( _( "References must start with a letter." ) );
msg.Printf( _( "The reference designator cannot contain text variable references" ) );
}
else if( aFieldId == REFERENCE_FIELD && UTIL::GetRefDesPrefix( aValue ).IsEmpty() )
{
msg.Printf( _( "References must start with a letter." ) );
}
}
return msg;
}
bool FIELD_VALIDATOR::DoValidate( const wxString& aValue, wxWindow* aParent )
{
wxString msg = GetFieldValidationErrorMessage( m_fieldId, aValue );
if( !msg.empty() )
{
if( m_validatorWindow )
+16
View File
@@ -214,6 +214,22 @@ void WX_VIEW_CONTROLS::onMotion( wxMouseEvent& aEvent )
int y = mouseRel.y;
VECTOR2D mousePos( x, y );
// Clear keyboard cursor position flag when actual mouse motion is detected
// (i.e., not from cursor warping and position has changed)
if( !m_cursorWarped && m_settings.m_lastKeyboardCursorPositionValid )
{
VECTOR2I screenPos( x, y );
VECTOR2I keyboardScreenPos = m_view->ToScreen( m_settings.m_lastKeyboardCursorPosition );
// If mouse has moved to a different position than the keyboard cursor position,
// clear the keyboard position flag to allow mouse control
if( screenPos != keyboardScreenPos )
{
m_settings.m_lastKeyboardCursorPositionValid = false;
m_settings.m_lastKeyboardCursorPosition = { 0.0, 0.0 };
}
}
// Automatic focus switching between SCH and PCB windows on canvas mouse motion
if( m_settings.m_focusFollowSchPcb )
{
+4 -2
View File
@@ -326,7 +326,9 @@ void COLOR_SWATCH::GetNewSwatchColor()
void COLOR_SWATCH::OnDarkModeToggle()
{
m_checkerboardBg = m_parent->GetBackgroundColour();
wxWindow* parent = GetParent();
m_checkerboardBg = parent ? parent->GetBackgroundColour() : wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOW );
m_swatch->SetBitmap( makeBitmap() );
if( m_swatch )
m_swatch->SetBitmap( makeBitmap() );
}
+47
View File
@@ -0,0 +1,47 @@
#include <widgets/grid_striped_renderer.h>
void STRIPED_CELL_RENDERER::Draw(wxGrid& grid, wxGridCellAttr& attr, wxDC& dc,
const wxRect& rect, int row, int col, bool isSelected)
{
// First draw the striped background for empty cells
wxString cellValue = grid.GetCellValue(row, col);
if (cellValue.IsEmpty())
{
DrawStripedBackground(dc, rect, isSelected);
}
// Then draw the text content using the parent class
wxGridCellStringRenderer::Draw(grid, attr, dc, rect, row, col, isSelected);
}
void STRIPED_CELL_RENDERER::drawStripedBackground(wxDC& dc, const wxRect& rect, bool isSelected) const
{
if (isSelected)
{
// For selected cells, use the selection color
dc.SetBrush(wxBrush(wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHT)));
dc.SetPen(*wxTRANSPARENT_PEN);
dc.DrawRectangle(rect);
return;
}
// Draw horizontal stripes
const int stripeHeight = 3;
wxColour color1 = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW);
wxColour color2(240, 240, 240); // Light gray
dc.SetPen(*wxTRANSPARENT_PEN);
bool useColor1 = true;
for (int y = rect.GetTop(); y < rect.GetBottom(); y += stripeHeight)
{
wxColour currentColor = useColor1 ? color1 : color2;
dc.SetBrush(wxBrush(currentColor));
int stripeBottom = wxMin(y + stripeHeight, rect.GetBottom());
dc.DrawRectangle(rect.GetLeft(), y, rect.GetWidth(), stripeBottom - y);
useColor1 = !useColor1;
}
}
+27 -7
View File
@@ -443,7 +443,8 @@ public:
TEXT_BUTTON_FILE_BROWSER( wxWindow* aParent, DIALOG_SHIM* aParentDlg, WX_GRID* aGrid,
wxString* aCurrentDir, const wxString& aFileFilter = wxEmptyString,
bool aNormalize = false,
const wxString& aNormalizeBasePath = wxEmptyString ) :
const wxString& aNormalizeBasePath = wxEmptyString,
std::function<wxString( const wxString& )> aEmbedCallback = nullptr ) :
wxComboCtrl( aParent, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize( 0, 0 ),
wxTE_PROCESS_ENTER | wxBORDER_NONE ),
m_dlg( aParentDlg ),
@@ -451,7 +452,8 @@ public:
m_currentDir( aCurrentDir ),
m_normalize( aNormalize ),
m_normalizeBasePath( aNormalizeBasePath ),
m_fileFilter( aFileFilter )
m_fileFilter( aFileFilter ),
m_embedCallback( std::move( aEmbedCallback ) )
{
SetButtonBitmaps( KiBitmapBundle( BITMAPS::small_folder ) );
@@ -463,7 +465,8 @@ public:
wxString* aCurrentDir,
std::function<wxString( WX_GRID* grid, int row )> aFileFilterFn,
bool aNormalize = false,
const wxString& aNormalizeBasePath = wxEmptyString ) :
const wxString& aNormalizeBasePath = wxEmptyString,
std::function<wxString( const wxString& )> aEmbedCallback = nullptr ) :
wxComboCtrl( aParent, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize( 0, 0 ),
wxTE_PROCESS_ENTER | wxBORDER_NONE ),
m_dlg( aParentDlg ),
@@ -471,7 +474,8 @@ public:
m_currentDir( aCurrentDir ),
m_normalize( aNormalize ),
m_normalizeBasePath( aNormalizeBasePath ),
m_fileFilterFn( std::move( aFileFilterFn ) )
m_fileFilterFn( std::move( aFileFilterFn ) ),
m_embedCallback( std::move( aEmbedCallback ) )
{
SetButtonBitmaps( KiBitmapBundle( BITMAPS::small_folder ) );
@@ -502,16 +506,30 @@ protected:
if( !m_fileFilter.IsEmpty() )
{
FILEDLG_OPEN_EMBED_FILE customize( false );
wxFileDialog dlg( m_dlg, _( "Select a File" ), fn.GetPath(), fn.GetFullName(),
m_fileFilter, wxFD_FILE_MUST_EXIST | wxFD_OPEN );
if( m_embedCallback )
dlg.SetCustomizeHook( customize );
if( dlg.ShowModal() == wxID_OK )
{
wxString filePath = dlg.GetPath();
wxString lastPath = dlg.GetDirectory();
wxString relPath = wxEmptyString;
if( m_normalize )
if( m_embedCallback && customize.GetEmbed() )
{
relPath = m_embedCallback( filePath );
if( relPath.IsEmpty() )
{
m_dlg->CleanupAfterModalSubDialog();
return;
}
}
else if( m_normalize )
{
relPath = NormalizePath( filePath, &Pgm().GetLocalEnvVariables(),
m_normalizeBasePath );
@@ -573,6 +591,7 @@ protected:
wxString m_fileFilter;
std::function<wxString( WX_GRID* aGrid, int aRow )> m_fileFilterFn;
std::function<wxString( const wxString& )> m_embedCallback;
};
@@ -583,12 +602,13 @@ void GRID_CELL_PATH_EDITOR::Create( wxWindow* aParent, wxWindowID aId,
{
m_control = new TEXT_BUTTON_FILE_BROWSER( aParent, m_dlg, m_grid, m_currentDir,
m_fileFilterFn, m_normalize,
m_normalizeBasePath );
m_normalizeBasePath, m_embedCallback );
}
else
{
m_control = new TEXT_BUTTON_FILE_BROWSER( aParent, m_dlg, m_grid, m_currentDir,
m_fileFilter, m_normalize, m_normalizeBasePath );
m_fileFilter, m_normalize, m_normalizeBasePath,
m_embedCallback );
}
WX_GRID::CellEditorSetMargins( Combo() );
+53 -33
View File
@@ -122,17 +122,14 @@ PROPERTIES_PANEL::PROPERTIES_PANEL( wxWindow* aParent, EDA_BASE_FRAME* aFrame )
m_grid->CenterSplitter();
Connect( wxEVT_CHAR_HOOK, wxKeyEventHandler( PROPERTIES_PANEL::onCharHook ), nullptr, this );
Connect( wxEVT_PG_CHANGED, wxPropertyGridEventHandler( PROPERTIES_PANEL::valueChanged ),
nullptr, this );
Connect( wxEVT_PG_CHANGING, wxPropertyGridEventHandler( PROPERTIES_PANEL::valueChanging ),
nullptr, this );
Connect( wxEVT_PG_CHANGED, wxPropertyGridEventHandler( PROPERTIES_PANEL::valueChanged ), nullptr, this );
Connect( wxEVT_PG_CHANGING, wxPropertyGridEventHandler( PROPERTIES_PANEL::valueChanging ), nullptr, this );
Connect( wxEVT_SHOW, wxShowEventHandler( PROPERTIES_PANEL::onShow ), nullptr, this );
Bind( wxEVT_PG_COL_END_DRAG,
[&]( wxPropertyGridEvent& )
{
m_splitter_key_proportion =
static_cast<float>( m_grid->GetSplitterPosition() ) / m_grid->GetSize().x;
m_splitter_key_proportion = static_cast<float>( m_grid->GetSplitterPosition() ) / m_grid->GetSize().x;
} );
Bind( wxEVT_SIZE,
@@ -225,33 +222,27 @@ void PROPERTIES_PANEL::rebuildProperties( const SELECTION& aSelection )
wxCHECK( !types.empty(), /* void */ ); // already guarded above, but Coverity doesn't know that
PROPERTY_MANAGER& propMgr = PROPERTY_MANAGER::Instance();
std::set<PROPERTY_BASE*> commonProps;
const PROPERTY_LIST& allProperties = propMgr.GetProperties( *types.begin() );
PROPERTY_MANAGER& propMgr = PROPERTY_MANAGER::Instance();
std::set<PROPERTY_BASE*> commonProps;
const std::vector<PROPERTY_BASE*>& allProperties = propMgr.GetProperties( *types.begin() );
copy( allProperties.begin(), allProperties.end(),
inserter( commonProps, commonProps.begin() ) );
copy( allProperties.begin(), allProperties.end(), inserter( commonProps, commonProps.begin() ) );
PROPERTY_DISPLAY_ORDER displayOrder = propMgr.GetDisplayOrder( *types.begin() );
std::vector<wxString> groupDisplayOrder = propMgr.GetGroupDisplayOrder( *types.begin() );
std::set<wxString> groups( groupDisplayOrder.begin(), groupDisplayOrder.end() );
std::map<PROPERTY_BASE*, int> displayOrder = propMgr.GetDisplayOrder( *types.begin() );
std::vector<wxString> groupDisplayOrder = propMgr.GetGroupDisplayOrder( *types.begin() );
std::set<wxString> groups( groupDisplayOrder.begin(), groupDisplayOrder.end() );
std::set<PROPERTY_BASE*> availableProps;
// Get all possible properties
for( const TYPE_ID& type : types )
{
const PROPERTY_LIST& itemProps = propMgr.GetProperties( type );
const std::vector<PROPERTY_BASE*>& itemProps = propMgr.GetProperties( type );
const std::map<PROPERTY_BASE*, int>& itemDisplayOrder = propMgr.GetDisplayOrder( type );
const PROPERTY_DISPLAY_ORDER& itemDisplayOrder = propMgr.GetDisplayOrder( type );
copy( itemDisplayOrder.begin(), itemDisplayOrder.end(), inserter( displayOrder, displayOrder.begin() ) );
copy( itemDisplayOrder.begin(), itemDisplayOrder.end(),
inserter( displayOrder, displayOrder.begin() ) );
const std::vector<wxString>& itemGroups = propMgr.GetGroupDisplayOrder( type );
for( const wxString& group : itemGroups )
for( const wxString& group : propMgr.GetGroupDisplayOrder( type ) )
{
if( !groups.count( group ) )
{
@@ -305,9 +296,14 @@ void PROPERTIES_PANEL::rebuildProperties( const SELECTION& aSelection )
if( !property )
continue;
wxVariant commonVal;
wxVariant commonVal;
wxPGChoices choices;
extractValueAndWritability( aSelection, property, commonVal, writeable, choices );
if( choices.GetCount() > 0 )
pgProp->SetChoices( choices );
extractValueAndWritability( aSelection, property, commonVal, writeable );
pgProp->SetValue( commonVal );
pgProp->Enable( writeable );
@@ -326,13 +322,17 @@ void PROPERTIES_PANEL::rebuildProperties( const SELECTION& aSelection )
for( PROPERTY_BASE* property : availableProps )
{
wxPGProperty* pgProp = createPGProperty( property );
wxVariant commonVal;
wxVariant commonVal;
wxPGChoices choices;
if( !extractValueAndWritability( aSelection, property, commonVal, writeable ) )
if( !extractValueAndWritability( aSelection, property, commonVal, writeable, choices ) )
continue;
if( pgProp )
{
if( choices.GetCount() )
pgProp->SetChoices( choices );
pgProp->SetValue( commonVal );
pgProp->Enable( writeable );
m_displayed.push_back( property );
@@ -403,13 +403,12 @@ bool PROPERTIES_PANEL::getItemValue( EDA_ITEM* aItem, PROPERTY_BASE* aProperty,
}
bool PROPERTIES_PANEL::extractValueAndWritability( const SELECTION& aSelection,
PROPERTY_BASE* aProperty,
wxVariant& aValue, bool& aWritable )
bool PROPERTIES_PANEL::extractValueAndWritability( const SELECTION& aSelection, PROPERTY_BASE* aProperty,
wxVariant& aValue, bool& aWritable, wxPGChoices& aChoices )
{
PROPERTY_MANAGER& propMgr = PROPERTY_MANAGER::Instance();
bool different = false;
wxVariant commonVal;
bool first = true;
aWritable = true;
@@ -421,6 +420,22 @@ bool PROPERTIES_PANEL::extractValueAndWritability( const SELECTION& aSelection,
if( aProperty->IsHiddenFromPropertiesManager() )
return false;
wxPGChoices choices = aProperty->GetChoices( item );
if( first )
{
aChoices = choices;
first = false;
}
else
{
wxArrayString labels = choices.GetLabels();
wxArrayInt values = choices.GetValuesForStrings( labels );
if( labels != aChoices.GetLabels() || values != aChoices.GetValuesForStrings( labels ) )
return false;
}
// If read-only for any of the selection, read-only for the whole selection.
if( !propMgr.IsWriteableFor( TYPE_HASH( *item ), aProperty, item ) )
aWritable = false;
@@ -494,10 +509,15 @@ void PROPERTIES_PANEL::onCharHook( wxKeyEvent& aEvent )
}
}
if( aEvent.GetKeyCode() == WXK_RETURN || aEvent.GetKeyCode() == WXK_NUMPAD_ENTER )
if( aEvent.GetKeyCode() == WXK_RETURN || aEvent.GetKeyCode() == WXK_NUMPAD_ENTER
|| aEvent.GetKeyCode() == WXK_DOWN || aEvent.GetKeyCode() == WXK_UP )
{
m_grid->CommitChangesFromEditor();
/* don't skip this one; if we're not the last property we'll also go to the next row */
CallAfter( [this]()
{
m_grid->SelectProperty( m_grid->GetSelectedProperty(), true );
} );
}
aEvent.Skip();
+1 -1
View File
@@ -102,7 +102,7 @@ protected:
* @return true if the property is available for all the items in the selection
*/
bool extractValueAndWritability( const SELECTION& aSelection, PROPERTY_BASE* aProperty,
wxVariant& aValue, bool& aWritable );
wxVariant& aValue, bool& aWritable, wxPGChoices& aChoices );
public:
int m_SuppressGridChangeEvents;
+5 -1
View File
@@ -230,7 +230,11 @@ void UNIT_BINDER::onComboBox( wxCommandEvent& aEvent )
const long long int conv =
EDA_UNIT_UTILS::UI::ValueFromString( *m_iuScale, m_units, value, m_dataType );
SetValue( conv );
CallAfter(
[this, conv]
{
SetValue( conv );
} );
aEvent.Skip();
}
+3
View File
@@ -124,6 +124,8 @@ set( EESCHEMA_DLGS
dialogs/dialog_label_properties_base.cpp
dialogs/dialog_lib_edit_pin_table.cpp
dialogs/dialog_lib_edit_pin_table_base.cpp
dialogs/dialog_lib_fields_base.cpp
dialogs/dialog_lib_fields.cpp
dialogs/dialog_lib_new_symbol.cpp
dialogs/dialog_lib_new_symbol_base.cpp
dialogs/dialog_lib_symbol_properties.cpp
@@ -369,6 +371,7 @@ set( EESCHEMA_SRCS
generate_alias_info.cpp
gfx_import_utils.cpp
junction_helpers.cpp
lib_fields_data_model.cpp
lib_symbol.cpp
libarch.cpp
menubar.cpp
+2 -2
View File
@@ -253,7 +253,7 @@ HANDLER_RESULT<ItemRequestStatus> API_HANDLER_SCH::handleCreateUpdateItemsIntern
if( aCreate )
{
item->Serialize( newItem );
commit->Add( item.release() );
commit->Add( item.release(), screen );
if( !m_activeClients.count( aClientName ) )
pushCurrentCommit( aClientName, _( "Added items via API" ) );
@@ -266,7 +266,7 @@ HANDLER_RESULT<ItemRequestStatus> API_HANDLER_SCH::handleCreateUpdateItemsIntern
{
schItem->SwapData( static_cast<SCH_ITEM*>( item.get() ) );
schItem->Serialize( newItem );
commit->Modify( schItem );
commit->Modify( schItem, screen );
}
else
{
+100 -71
View File
@@ -563,12 +563,22 @@ CONNECTION_SUBGRAPH::PRIORITY CONNECTION_SUBGRAPH::GetDriverPriority( SCH_ITEM*
if( !aDriver )
return PRIORITY::NONE;
auto libSymbolRef =
[]( const SCH_SYMBOL* symbol ) -> wxString
{
if( const std::unique_ptr<LIB_SYMBOL>& part = symbol->GetLibSymbolRef() )
return part->GetReferenceField().GetText();
return wxEmptyString;
};
switch( aDriver->Type() )
{
case SCH_SHEET_PIN_T: return PRIORITY::SHEET_PIN;
case SCH_HIER_LABEL_T: return PRIORITY::HIER_LABEL;
case SCH_LABEL_T: return PRIORITY::LOCAL_LABEL;
case SCH_GLOBAL_LABEL_T: return PRIORITY::GLOBAL;
case SCH_PIN_T:
{
SCH_PIN* sch_pin = static_cast<SCH_PIN*>( aDriver );
@@ -576,14 +586,14 @@ CONNECTION_SUBGRAPH::PRIORITY CONNECTION_SUBGRAPH::GetDriverPriority( SCH_ITEM*
if( sch_pin->IsGlobalPower() )
return PRIORITY::POWER_PIN;
else if( !sym || sym->GetExcludedFromBoard()
|| sym->GetLibSymbolRef()->GetReferenceField().GetText().StartsWith( '#' ) )
else if( !sym || sym->GetExcludedFromBoard() || libSymbolRef( sym ).StartsWith( '#' ) )
return PRIORITY::NONE;
else
return PRIORITY::PIN;
}
default: return PRIORITY::NONE;
default:
return PRIORITY::NONE;
}
}
@@ -591,13 +601,13 @@ CONNECTION_SUBGRAPH::PRIORITY CONNECTION_SUBGRAPH::GetDriverPriority( SCH_ITEM*
void CONNECTION_GRAPH::Merge( CONNECTION_GRAPH& aGraph )
{
std::copy( aGraph.m_items.begin(), aGraph.m_items.end(),
std::back_inserter( m_items ) );
std::back_inserter( m_items ) );
for( SCH_ITEM* item : aGraph.m_items )
item->SetConnectionGraph( this );
std::copy( aGraph.m_subgraphs.begin(), aGraph.m_subgraphs.end(),
std::back_inserter( m_subgraphs ) );
std::back_inserter( m_subgraphs ) );
for( CONNECTION_SUBGRAPH* sg : aGraph.m_subgraphs )
{
@@ -607,13 +617,11 @@ void CONNECTION_GRAPH::Merge( CONNECTION_GRAPH& aGraph )
sg->m_graph = this;
}
std::copy( aGraph.m_driver_subgraphs.begin(),
aGraph.m_driver_subgraphs.end(),
std::back_inserter( m_driver_subgraphs ) );
std::copy( aGraph.m_driver_subgraphs.begin(), aGraph.m_driver_subgraphs.end(),
std::back_inserter( m_driver_subgraphs ) );
std::copy( aGraph.m_global_power_pins.begin(),
aGraph.m_global_power_pins.end(),
std::back_inserter( m_global_power_pins ) );
std::copy( aGraph.m_global_power_pins.begin(), aGraph.m_global_power_pins.end(),
std::back_inserter( m_global_power_pins ) );
for( auto& [key, value] : aGraph.m_net_name_to_subgraphs_map )
m_net_name_to_subgraphs_map.insert_or_assign( key, value );
@@ -1141,21 +1149,22 @@ void CONNECTION_GRAPH::updateItemConnectivity( const SCH_SHEET_PATH& aSheet,
aSheet.Last()->GetFileName(), aItemList.size() );
std::map<VECTOR2I, std::vector<SCH_ITEM*>> connection_map;
auto updatePin = [&]( SCH_PIN* aPin, SCH_CONNECTION* aConn )
{
aConn->SetType( CONNECTION_TYPE::NET );
auto updatePin =
[&]( SCH_PIN* aPin, SCH_CONNECTION* aConn )
{
aConn->SetType( CONNECTION_TYPE::NET );
// because calling the first time is not thread-safe
wxString name = aPin->GetDefaultNetName( aSheet );
aPin->ClearConnectedItems( aSheet );
// because calling the first time is not thread-safe
wxString name = aPin->GetDefaultNetName( aSheet );
aPin->ClearConnectedItems( aSheet );
// power symbol pins need to be post-processed later
if( aPin->IsGlobalPower() )
{
aConn->SetName( name );
m_global_power_pins.emplace_back( std::make_pair( aSheet, aPin ) );
}
};
// power symbol pins need to be post-processed later
if( aPin->IsGlobalPower() )
{
aConn->SetName( name );
m_global_power_pins.emplace_back( std::make_pair( aSheet, aPin ) );
}
};
for( SCH_ITEM* item : aItemList )
{
@@ -1227,17 +1236,41 @@ void CONNECTION_GRAPH::updateItemConnectivity( const SCH_SHEET_PATH& aSheet,
for( const VECTOR2I& point : points )
connection_map[ point ].push_back( item );
/// Special case for labels that overlap wires
/// While this is an ERC error as there is not an explicit junction,
/// we want to enforce connectivity for all items under the label position.
if( dynamic_cast<SCH_LABEL_BASE*>( item ) )
{
VECTOR2I point = item->GetPosition();
SCH_SCREEN* screen = aSheet.LastScreen();
auto items = screen->Items().Overlapping( point );
std::vector<SCH_ITEM*> overlapping_items;
std::copy_if( items.begin(), items.end(), std::back_inserter( overlapping_items ),
[&]( SCH_ITEM* test_item )
{
return test_item->Type() == SCH_LINE_T
&& test_item->HitTest( point, -1 );
} );
// We need at least two connnectable lines that are not the label here
// Otherwise, the label will be normally assigned to one or the other
if( overlapping_items.size() < 2 ) continue;
for( SCH_ITEM* test_item : overlapping_items )
connection_map[point].push_back( test_item );
}
}
}
for( const auto& it : connection_map )
for( auto& [point, connection_vec] : connection_map )
{
std::vector<SCH_ITEM*> connection_vec = it.second;
std::sort( connection_vec.begin(), connection_vec.end() );
alg::remove_duplicates( connection_vec );
// Pre-scan to see if we have a bus at this location
SCH_LINE* busLine = aSheet.LastScreen()->GetBus( it.first );
SCH_LINE* busLine = aSheet.LastScreen()->GetBus( point );
std::mutex update_mutex;
@@ -1264,7 +1297,6 @@ void CONNECTION_GRAPH::updateItemConnectivity( const SCH_SHEET_PATH& aSheet,
}
}
}
// Bus-to-bus entries are treated just like bus wires
else if( connected_item->Type() == SCH_BUS_BUS_ENTRY_T )
{
@@ -1274,7 +1306,7 @@ void CONNECTION_GRAPH::updateItemConnectivity( const SCH_SHEET_PATH& aSheet,
{
auto bus_entry = static_cast<SCH_BUS_BUS_ENTRY*>( connected_item );
if( it.first == bus_entry->GetPosition() )
if( point == bus_entry->GetPosition() )
bus_entry->m_connected_bus_items[0] = busLine;
else
bus_entry->m_connected_bus_items[1] = busLine;
@@ -1285,7 +1317,6 @@ void CONNECTION_GRAPH::updateItemConnectivity( const SCH_SHEET_PATH& aSheet,
}
}
}
// Change junctions to be on bus junction layer if they are touching a bus
else if( connected_item->Type() == SCH_JUNCTION_T )
{
@@ -1321,9 +1352,9 @@ void CONNECTION_GRAPH::updateItemConnectivity( const SCH_SHEET_PATH& aSheet,
bus_connection_ok = !busLine || connected_item->GetLayer() == LAYER_BUS;
}
if( connected_item->ConnectionPropagatesTo( test_item ) &&
test_item->ConnectionPropagatesTo( connected_item ) &&
bus_connection_ok )
if( connected_item->ConnectionPropagatesTo( test_item )
&& test_item->ConnectionPropagatesTo( connected_item )
&& bus_connection_ok )
{
connected_item->AddConnectionTo( aSheet, test_item );
}
@@ -1339,7 +1370,7 @@ void CONNECTION_GRAPH::updateItemConnectivity( const SCH_SHEET_PATH& aSheet,
if( !bus_entry->m_connected_bus_item )
{
SCH_SCREEN* screen = aSheet.LastScreen();
SCH_LINE* bus = screen->GetBus( it.first );
SCH_LINE* bus = screen->GetBus( point );
if( bus )
bus_entry->m_connected_bus_item = bus;
@@ -1378,11 +1409,8 @@ void CONNECTION_GRAPH::buildItemSubGraphs()
// Build subgraphs from items (on a per-sheet basis)
for( SCH_ITEM* item : m_items )
{
for( const auto& it : item->m_connection_map )
for( const auto& [sheet, connection] : item->m_connection_map )
{
const SCH_SHEET_PATH& sheet = it.first;
SCH_CONNECTION* connection = it.second;
if( connection->SubgraphCode() == 0 )
{
CONNECTION_SUBGRAPH* subgraph = new CONNECTION_SUBGRAPH( this );
@@ -1448,7 +1476,6 @@ void CONNECTION_GRAPH::buildItemSubGraphs()
}
}
}
}
@@ -1467,44 +1494,45 @@ void CONNECTION_GRAPH::resolveAllDrivers()
std::vector<std::future<size_t>> returns( dirty_graphs.size() );
auto update_lambda = []( CONNECTION_SUBGRAPH* subgraph ) -> size_t
{
if( !subgraph->m_dirty )
return 0;
// Special processing for some items
for( SCH_ITEM* item : subgraph->m_items )
{
switch( item->Type() )
auto update_lambda =
[]( CONNECTION_SUBGRAPH* subgraph ) -> size_t
{
case SCH_NO_CONNECT_T:
subgraph->m_no_connect = item;
break;
if( !subgraph->m_dirty )
return 0;
case SCH_BUS_WIRE_ENTRY_T:
subgraph->m_bus_entry = item;
break;
// Special processing for some items
for( SCH_ITEM* item : subgraph->m_items )
{
switch( item->Type() )
{
case SCH_NO_CONNECT_T:
subgraph->m_no_connect = item;
break;
case SCH_PIN_T:
{
auto pin = static_cast<SCH_PIN*>( item );
case SCH_BUS_WIRE_ENTRY_T:
subgraph->m_bus_entry = item;
break;
if( pin->GetType() == ELECTRICAL_PINTYPE::PT_NC )
subgraph->m_no_connect = item;
case SCH_PIN_T:
{
auto pin = static_cast<SCH_PIN*>( item );
break;
}
if( pin->GetType() == ELECTRICAL_PINTYPE::PT_NC )
subgraph->m_no_connect = item;
default:
break;
}
}
break;
}
subgraph->ResolveDrivers( true );
subgraph->m_dirty = false;
default:
break;
}
}
return 1;
};
subgraph->ResolveDrivers( true );
subgraph->m_dirty = false;
return 1;
};
thread_pool& tp = GetKiCadThreadPool();
@@ -2304,8 +2332,9 @@ void CONNECTION_GRAPH::buildConnectionGraph( std::function<void( SCH_ITEM* )>* a
[&]( CONNECTION_SUBGRAPH* subgraph ) -> size_t
{
// Make sure weakly-driven single-pin nets get the unconnected_ prefix
if( !subgraph->m_strong_driver && subgraph->m_drivers.size() == 1 &&
subgraph->m_driver->Type() == SCH_PIN_T )
if( !subgraph->m_strong_driver
&& subgraph->m_drivers.size() == 1
&& subgraph->m_driver->Type() == SCH_PIN_T )
{
SCH_PIN* pin = static_cast<SCH_PIN*>( subgraph->m_driver );
wxString name = pin->GetDefaultNetName( subgraph->m_sheet, true );
+14 -2
View File
@@ -590,7 +590,16 @@ int DIALOG_CHANGE_SYMBOLS::processSymbols( SCH_COMMIT* aCommit,
{
SCH_SYMBOL* symbol = it->first;
wxCHECK2( symbol && it->second.m_LibId.IsValid(), continue );
wxCHECK2( symbol, ++it; continue );
if( !it->second.m_LibId.IsValid() )
{
msg = getSymbolReferences( *symbol, it->second.m_LibId );
msg << wxT( ": " ) << _( "*** symbol lib id not valid ***" );
m_messagePanel->Report( msg, RPT_SEVERITY_ERROR );
it = symbols.erase( it );
continue;
}
LIB_SYMBOL* libSymbol = frame->GetLibSymbol( it->second.m_LibId );
@@ -647,10 +656,13 @@ int DIALOG_CHANGE_SYMBOLS::processSymbols( SCH_COMMIT* aCommit,
// Remember initial link before changing for diags purpose
wxString initialLibLinkName = UnescapeString( symbol->GetLibId().Format() );
LIB_SYMBOL* libSymbol = frame->GetLibSymbol( symbol_change_info.m_LibId );
wxCHECK2( libSymbol, continue );
if( symbol_change_info.m_LibId != symbol->GetLibId() )
symbol->SetLibId( symbol_change_info.m_LibId );
LIB_SYMBOL* libSymbol = frame->GetLibSymbol( symbol_change_info.m_LibId );
std::unique_ptr<LIB_SYMBOL> flattenedSymbol = libSymbol->Flatten();
SCH_SCREEN* screen = symbol_change_info.m_Instances[0].LastScreen();
+23
View File
@@ -195,6 +195,28 @@ void DIALOG_ERC::UpdateAnnotationWarning()
}
void DIALOG_ERC::OnCharHook( wxKeyEvent& aEvt )
{
if( int hotkey = aEvt.GetKeyCode() )
{
if( aEvt.ControlDown() )
hotkey |= MD_CTRL;
if( aEvt.ShiftDown() )
hotkey |= MD_SHIFT;
if( aEvt.AltDown() )
hotkey |= MD_ALT;
if( hotkey == ACTIONS::excludeMarker.GetHotKey() )
{
ExcludeMarker();
return;
}
}
DIALOG_SHIM::OnCharHook( aEvt );
}
bool DIALOG_ERC::updateUI()
{
// If ERC checks ever get slow enough we'll want a progress indicator...
@@ -325,6 +347,7 @@ void DIALOG_ERC::OnDeleteAllClick( wxCommandEvent& event )
}
deleteAllMarkers( includeExclusions );
m_ercRun = false;
// redraw the schematic
redrawDrawPanel();
+2 -7
View File
@@ -22,8 +22,7 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#ifndef _DIALOG_ERC_H_
#define _DIALOG_ERC_H_
#pragma once
#include <wx/htmllbox.h>
@@ -70,6 +69,7 @@ public:
private:
// from DIALOG_ERC_BASE:
void OnCharHook( wxKeyEvent& aEvt ) override;
void OnCloseErcDialog( wxCloseEvent& event ) override;
void OnRunERCClick( wxCommandEvent& event ) override;
void OnDeleteOneClick( wxCommandEvent& event ) override;
@@ -116,8 +116,3 @@ private:
int m_severities;
};
#endif
// _DIALOG_ERC_H_
+156 -52
View File
@@ -53,10 +53,63 @@
#include <wx/checkbox.h>
#include <wx/filedlg.h>
#include <wx/msgdlg.h>
#include <wx/process.h>
#include <wx/regex.h>
#include <wx/txtstrm.h>
#include <wx/utils.h>
#include <thread>
#include <vector>
namespace
{
std::vector<wxString> SplitCommandLine( const wxString& aCommand )
{
std::vector<wxString> args;
wxString current;
bool inSingle = false;
bool inDouble = false;
bool argStarted = false;
for( wxUniChar c : aCommand )
{
if( c == '"' && !inSingle )
{
inDouble = !inDouble;
argStarted = true;
continue;
}
if( c == '\'' && !inDouble )
{
inSingle = !inSingle;
argStarted = true;
continue;
}
if( ( c == ' ' || c == '\t' || c == '\n' || c == '\r' ) && !inSingle && !inDouble )
{
if( argStarted || !current.IsEmpty() )
{
args.emplace_back( current );
current.clear();
argStarted = false;
}
continue;
}
current.Append( c );
argStarted = true;
}
if( argStarted || !current.IsEmpty() )
args.emplace_back( current );
return args;
}
} // namespace
#define CUSTOMPANEL_COUNTMAX 8 // Max number of netlist plugins
@@ -232,16 +285,16 @@ DIALOG_EXPORT_NETLIST::DIALOG_EXPORT_NETLIST( SCH_EDIT_FRAME* aEditFrame, wxWind
page->m_LeftBoxSizer->Add( label, 0, wxBOTTOM, 10 );
m_PanelNetType[PANELALLEGRO] = page;
page = new EXPORT_NETLIST_PAGE( m_NoteBook, wxT( "PADS" ), NET_TYPE_PADS, false );
label = new wxStaticText( page, wxID_ANY, _( "Export netlist in PADS format" ) );
page->m_LeftBoxSizer->Add( label, 0, wxBOTTOM, 10 );
m_PanelNetType[PANELPADS] = page;
page = new EXPORT_NETLIST_PAGE( m_NoteBook, wxT( "CadStar" ), NET_TYPE_CADSTAR, false );
label = new wxStaticText( page, wxID_ANY, _( "Export netlist in CadStar format" ) );
page->m_LeftBoxSizer->Add( label, 0, wxBOTTOM, 10 );
m_PanelNetType[PANELCADSTAR] = page;
page = new EXPORT_NETLIST_PAGE( m_NoteBook, wxT( "PADS" ), NET_TYPE_PADS, false );
label = new wxStaticText( page, wxID_ANY, _( "Export netlist in PADS format" ) );
page->m_LeftBoxSizer->Add( label, 0, wxBOTTOM, 10 );
m_PanelNetType[PANELPADS] = page;
InstallPageSpice();
InstallPageSpiceModel();
@@ -616,68 +669,119 @@ bool DIALOG_EXPORT_NETLIST::TransferDataFromWindow()
if( !commandLine.IsEmpty() )
{
wxProcess* process = new wxProcess( GetEventHandler(), wxID_ANY );
process->Redirect();
wxExecute( commandLine, wxEXEC_ASYNC, process );
std::vector<wxString> argsStrings = SplitCommandLine( commandLine );
reporter.ReportHead( commandLine, RPT_SEVERITY_ACTION );
process->Activate();
std::this_thread::sleep_for( std::chrono::seconds( 1 ) ); // give the process time to start and output any data or errors
if( process->IsInputAvailable() )
if( !argsStrings.empty() )
{
wxInputStream* in = process->GetInputStream();
wxTextInputStream textstream( *in );
std::vector<const wxChar*> argv;
argv.reserve( argsStrings.size() + 1 );
while( in->CanRead() )
for( wxString& arg : argsStrings )
argv.emplace_back( arg.wc_str() );
argv.emplace_back( nullptr );
wxExecuteEnv env;
wxGetEnvMap( &env.env );
const ENV_VAR_MAP& envVars = Pgm().GetLocalEnvVariables();
for( const auto& [key, value] : envVars )
{
wxString line = textstream.ReadLine();
if( !line.IsEmpty() )
reporter.Report( line, RPT_SEVERITY_INFO );
if( !value.GetValue().IsEmpty() )
env.env[key] = value.GetValue();
}
}
if( process->IsErrorAvailable() )
{
wxInputStream* err = process->GetErrorStream();
wxTextInputStream textstream( *err );
wxFileName netlistFile( fullpath );
while( err->CanRead() )
if( !netlistFile.IsAbsolute() )
netlistFile.MakeAbsolute( Prj().GetProjectPath() );
else
netlistFile.MakeAbsolute();
wxString cwd = netlistFile.GetPath();
if( cwd.IsEmpty() )
cwd = Prj().GetProjectPath();
env.cwd = cwd;
wxProcess* process = new wxProcess( GetEventHandler(), wxID_ANY );
process->Redirect();
long pid = wxExecute( argv.data(), wxEXEC_ASYNC, process, &env );
reporter.ReportHead( commandLine, RPT_SEVERITY_ACTION );
if( pid <= 0 )
{
wxString line = textstream.ReadLine();
reporter.Report( _( "external simulator not found" ), RPT_SEVERITY_ERROR );
reporter.Report( _( "Note: command line is usually: "
"<tt>&lt;path to SPICE binary&gt; \"%I\"</tt>" ),
RPT_SEVERITY_INFO );
delete process;
}
else
{
process->Activate();
if( !line.IsEmpty() )
std::this_thread::sleep_for( std::chrono::seconds( 1 ) ); // give the process time to start and output any data or errors
if( process->IsInputAvailable() )
{
if( line.EndsWith( wxS( "failed with error 2!" ) ) ) // ENOENT
wxInputStream* in = process->GetInputStream();
wxTextInputStream textstream( *in );
while( in->CanRead() )
{
reporter.Report( _( "external simulator not found" ), RPT_SEVERITY_ERROR );
reporter.Report( _( "Note: command line is usually: "
"<tt>&lt;path to SPICE binary&gt; \"%I\"</tt>" ),
RPT_SEVERITY_INFO );
}
else if( line.EndsWith( wxS( "failed with error 8!" ) ) ) // ENOEXEC
{
reporter.Report( _( "external simulator has the wrong format or "
"architecture" ), RPT_SEVERITY_ERROR );
}
else if( line.EndsWith( "failed with error 13!" ) ) // EACCES
{
reporter.Report( _( "permission denied" ), RPT_SEVERITY_ERROR );
}
else
{
reporter.Report( line, RPT_SEVERITY_ERROR );
wxString line = textstream.ReadLine();
if( !line.IsEmpty() )
reporter.Report( line, RPT_SEVERITY_INFO );
}
}
if( process->IsErrorAvailable() )
{
wxInputStream* err = process->GetErrorStream();
wxTextInputStream textstream( *err );
while( err->CanRead() )
{
wxString line = textstream.ReadLine();
if( !line.IsEmpty() )
{
if( line.EndsWith( wxS( "failed with error 2!" ) ) ) // ENOENT
{
reporter.Report( _( "external simulator not found" ), RPT_SEVERITY_ERROR );
reporter.Report( _( "Note: command line is usually: "
"<tt>&lt;path to SPICE binary&gt; \"%I\"</tt>" ),
RPT_SEVERITY_INFO );
}
else if( line.EndsWith( wxS( "failed with error 8!" ) ) ) // ENOEXEC
{
reporter.Report( _( "external simulator has the wrong format or "
"architecture" ), RPT_SEVERITY_ERROR );
}
else if( line.EndsWith( "failed with error 13!" ) ) // EACCES
{
reporter.Report( _( "permission denied" ), RPT_SEVERITY_ERROR );
}
else
{
reporter.Report( line, RPT_SEVERITY_ERROR );
}
}
}
}
process->CloseOutput();
process->Detach();
// Do not delete process, it will delete itself when it terminates
}
}
process->CloseOutput();
process->Detach();
// Do not delete process, it will delete itself when it terminates
}
}
+1 -6
View File
@@ -463,12 +463,7 @@ bool DIALOG_FIELD_PROPERTIES::TransferDataToWindow()
const SCH_SYMBOL* symbol = static_cast<const SCH_SYMBOL*>( m_field->GetParentSymbol() );
for( int ii = 1; ii <= symbol->GetUnitCount(); ii++ )
{
if( symbol->HasUnitDisplayName( ii ) )
m_unitChoice->Append( symbol->GetUnitDisplayName( ii ) );
else
m_unitChoice->Append( symbol->SubReference( ii, false ) );
}
m_unitChoice->Append( symbol->GetUnitDisplayName( ii, false ) );
if( symbol->GetUnit() <= ( int )m_unitChoice->GetCount() )
m_unitChoice->SetSelection( symbol->GetUnit() - 1 );
@@ -25,6 +25,7 @@
#include <kiway.h>
#include <macros.h>
#include <kiplatform/io.h>
#include "symbol_lib_table.h"
@@ -102,7 +103,8 @@ bool DIALOG_GLOBAL_SYM_LIB_TABLE_CONFIG::TransferDataFromWindow()
// Create the config path if it doesn't already exist.
wxFileName symTableFileName = SYMBOL_LIB_TABLE::GetGlobalTableFileName();
if( !symTableFileName.DirExists() && !symTableFileName.Mkdir( 0x777, wxPATH_MKDIR_FULL ) )
if( !wxFileName::DirExists( symTableFileName.GetPath() )
&& !wxFileName::Mkdir( symTableFileName.GetPath(), 0x777, wxPATH_MKDIR_FULL ) )
{
DisplayError( this, wxString::Format( _( "Cannot create global library table '%s'." ),
symTableFileName.GetPath() ) );
@@ -118,6 +120,9 @@ bool DIALOG_GLOBAL_SYM_LIB_TABLE_CONFIG::TransferDataFromWindow()
fn.GetFullPath(), symTableFileName.GetFullPath() ) );
return false;
}
// Ensure the copied file is writable
KIPLATFORM::IO::MakeWriteable( symTableFileName.GetFullPath() );
}
// Load the successfully copied symbol library table file. This should not fail since the
@@ -827,7 +827,7 @@ DIALOG_LIB_EDIT_PIN_TABLE::DIALOG_LIB_EDIT_PIN_TABLE( SYMBOL_EDIT_FRAME* parent,
m_unitFilter->Append( UNITS_ALL );
for( int ii = 0; ii < aSymbol->GetUnitCount(); ++ii )
m_unitFilter->Append( aSymbol->GetUnitReference( ii + 1 ) );
m_unitFilter->Append( LIB_SYMBOL::LetterSubReference( ii + 1, 'A' ) );
m_unitFilter->SetSelection( -1 );
}
File diff suppressed because it is too large Load Diff
+87
View File
@@ -0,0 +1,87 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2024 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef DIALOG_LIB_FIELDS_H
#define DIALOG_LIB_FIELDS_H
#include <dialog_lib_fields_base.h>
#include <sch_reference_list.h>
#include <widgets/grid_text_button_helpers.h>
class SYMBOL_EDIT_FRAME;
class LIB_FIELDS_EDITOR_GRID_DATA_MODEL;
class LIB_SYMBOL;
class DIALOG_LIB_FIELDS : public DIALOG_LIB_FIELDS_BASE
{
public:
DIALOG_LIB_FIELDS( SYMBOL_EDIT_FRAME* parent, wxString libId, const wxArrayString& aSymbolNames );
~DIALOG_LIB_FIELDS() override;
void OnInit();
protected:
void OnClose( wxCloseEvent& event ) override;
void OnColumnItemToggled( wxDataViewEvent& event ) override;
void OnFieldsCtrlSelectionChanged( wxDataViewEvent& event ) override;
void OnSizeFieldList( wxSizeEvent& event ) override;
void OnAddField( wxCommandEvent& event ) override;
void OnRenameField( wxCommandEvent& event ) override;
void OnRemoveField( wxCommandEvent& event ) override;
void OnFilterMouseMoved( wxMouseEvent& event ) override;
void OnFilterText( wxCommandEvent& event ) override;
void OnRegroupSymbols( wxCommandEvent& event ) override;
void OnTableValueChanged( wxGridEvent& event ) override;
void OnTableCellClick( wxGridEvent& event ) override;
void OnTableItemContextMenu( wxGridEvent& event ) override;
void OnTableColSize( wxGridSizeEvent& event ) override;
void OnCancel( wxCommandEvent& event ) override;
void OnOk( wxCommandEvent& event ) override;
void OnApply( wxCommandEvent& event ) override;
bool TransferDataFromWindow() override;
private:
void UpdateFieldList();
void AddField( const wxString& aFieldName, const wxString& aLabelValue, bool show, bool groupBy, bool addedByUser = false, bool aIsCheckbox = false );
void RemoveField( const wxString& fieldName );
void RenameField( const wxString& oldName, const wxString& newName );
void RegroupSymbols();
void OnColSort( wxGridEvent& aEvent );
void OnColMove( wxGridEvent& aEvent );
void OnColLabelChange( wxDataViewEvent& aEvent );
void SetupColumnProperties( int aCol );
void SetupAllColumnProperties();
void loadSymbols( const wxArrayString& aSymbolNames );
wxString m_libId;
SYMBOL_EDIT_FRAME* m_parent;
int m_fieldNameColWidth;
int m_labelColWidth;
int m_showColWidth;
int m_groupByColWidth;
LIB_FIELDS_EDITOR_GRID_DATA_MODEL* m_dataModel;
std::vector<LIB_SYMBOL*> m_symbolsList;
};
#endif // DIALOG_LIB_FIELDS_H
+203
View File
@@ -0,0 +1,203 @@
///////////////////////////////////////////////////////////////////////////
// C++ code generated with wxFormBuilder (version 4.2.1-0-g80c4cb6a-dirty)
// http://www.wxformbuilder.org/
//
// PLEASE DO *NOT* EDIT THIS FILE!
///////////////////////////////////////////////////////////////////////////
#include "widgets/std_bitmap_button.h"
#include "widgets/wx_grid.h"
#include "dialog_lib_fields_base.h"
///////////////////////////////////////////////////////////////////////////
DIALOG_LIB_FIELDS_BASE::DIALOG_LIB_FIELDS_BASE( wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style ) : DIALOG_SHIM( parent, id, title, pos, size, style )
{
this->SetSizeHints( wxSize( -1,-1 ), wxDefaultSize );
wxBoxSizer* bMainSizer;
bMainSizer = new wxBoxSizer( wxVERTICAL );
wxBoxSizer* bEditSizer;
bEditSizer = new wxBoxSizer( wxVERTICAL );
m_splitterMainWindow = new wxSplitterWindow( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSP_3DSASH|wxSP_LIVE_UPDATE|wxSP_NO_XP_THEME );
m_splitterMainWindow->SetMinimumPaneSize( 200 );
m_leftPanel = new wxPanel( m_splitterMainWindow, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL );
wxBoxSizer* bLeftSizer;
bLeftSizer = new wxBoxSizer( wxVERTICAL );
m_fieldsCtrl = new wxDataViewListCtrl( m_leftPanel, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0 );
m_fieldsCtrl->SetMinSize( wxSize( -1,250 ) );
bLeftSizer->Add( m_fieldsCtrl, 1, wxBOTTOM|wxEXPAND|wxLEFT|wxRIGHT|wxTOP, 5 );
wxBoxSizer* bFieldsButtons;
bFieldsButtons = new wxBoxSizer( wxHORIZONTAL );
m_addFieldButton = new STD_BITMAP_BUTTON( m_leftPanel, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxDefaultSize, wxBU_AUTODRAW|0 );
bFieldsButtons->Add( m_addFieldButton, 0, wxBOTTOM|wxLEFT, 5 );
m_renameFieldButton = new STD_BITMAP_BUTTON( m_leftPanel, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxDefaultSize, wxBU_AUTODRAW|0 );
bFieldsButtons->Add( m_renameFieldButton, 0, wxBOTTOM|wxLEFT, 5 );
bFieldsButtons->Add( 15, 0, 0, wxEXPAND, 5 );
m_removeFieldButton = new STD_BITMAP_BUTTON( m_leftPanel, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxDefaultSize, wxBU_AUTODRAW|0 );
bFieldsButtons->Add( m_removeFieldButton, 0, wxBOTTOM|wxLEFT, 5 );
bLeftSizer->Add( bFieldsButtons, 0, wxEXPAND, 5 );
m_leftPanel->SetSizer( bLeftSizer );
m_leftPanel->Layout();
bLeftSizer->Fit( m_leftPanel );
m_rightPanel = new wxPanel( m_splitterMainWindow, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL );
wxBoxSizer* bRightSizer;
bRightSizer = new wxBoxSizer( wxVERTICAL );
wxBoxSizer* bControls;
bControls = new wxBoxSizer( wxHORIZONTAL );
m_filter = new wxSearchCtrl( m_rightPanel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
#ifndef __WXMAC__
m_filter->ShowSearchButton( true );
#endif
m_filter->ShowCancelButton( true );
m_filter->SetFont( wxFont( wxNORMAL_FONT->GetPointSize(), wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL, false, wxEmptyString ) );
m_filter->SetMinSize( wxSize( 140,-1 ) );
bControls->Add( m_filter, 1, wxALIGN_CENTER_VERTICAL|wxRIGHT, 5 );
m_staticline31 = new wxStaticLine( m_rightPanel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_VERTICAL );
bControls->Add( m_staticline31, 0, wxEXPAND | wxALL, 3 );
m_bRefresh = new STD_BITMAP_BUTTON( m_rightPanel, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxDefaultSize, wxBU_AUTODRAW|0 );
m_bRefresh->SetMinSize( wxSize( 30,30 ) );
bControls->Add( m_bRefresh, 0, wxALIGN_CENTER_VERTICAL|wxLEFT|wxRIGHT, 5 );
bRightSizer->Add( bControls, 0, wxEXPAND|wxLEFT|wxTOP, 5 );
m_grid = new WX_GRID( m_rightPanel, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0 );
// Grid
m_grid->CreateGrid( 5, 5 );
m_grid->EnableEditing( true );
m_grid->EnableGridLines( true );
m_grid->EnableDragGridSize( false );
m_grid->SetMargins( 0, 0 );
// Columns
m_grid->EnableDragColMove( true );
m_grid->EnableDragColSize( true );
m_grid->SetColLabelSize( 24 );
m_grid->SetColLabelAlignment( wxALIGN_CENTER, wxALIGN_CENTER );
// Rows
m_grid->EnableDragRowSize( false );
m_grid->SetRowLabelSize( 0 );
m_grid->SetRowLabelAlignment( wxALIGN_CENTER, wxALIGN_CENTER );
// Label Appearance
// Cell Defaults
m_grid->SetDefaultCellAlignment( wxALIGN_LEFT, wxALIGN_CENTER );
m_grid->SetMinSize( wxSize( 400,200 ) );
bRightSizer->Add( m_grid, 1, wxBOTTOM|wxEXPAND|wxLEFT|wxRIGHT|wxTOP, 5 );
m_rightPanel->SetSizer( bRightSizer );
m_rightPanel->Layout();
bRightSizer->Fit( m_rightPanel );
m_splitterMainWindow->SplitVertically( m_leftPanel, m_rightPanel, -1 );
bEditSizer->Add( m_splitterMainWindow, 1, wxEXPAND|wxTOP|wxBOTTOM, 5 );
bMainSizer->Add( bEditSizer, 1, wxEXPAND, 5 );
wxBoxSizer* bButtonsSizer;
bButtonsSizer = new wxBoxSizer( wxHORIZONTAL );
bButtonsSizer->Add( 0, 0, 9, wxEXPAND, 5 );
m_sdbSizer = new wxStdDialogButtonSizer();
m_sdbSizerOK = new wxButton( this, wxID_OK );
m_sdbSizer->AddButton( m_sdbSizerOK );
m_sdbSizerApply = new wxButton( this, wxID_APPLY );
m_sdbSizer->AddButton( m_sdbSizerApply );
m_sdbSizerCancel = new wxButton( this, wxID_CANCEL );
m_sdbSizer->AddButton( m_sdbSizerCancel );
m_sdbSizer->Realize();
bButtonsSizer->Add( m_sdbSizer, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 );
bMainSizer->Add( bButtonsSizer, 0, wxEXPAND, 5 );
this->SetSizer( bMainSizer );
this->Layout();
bMainSizer->Fit( this );
this->Centre( wxBOTH );
// Connect Events
this->Connect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( DIALOG_LIB_FIELDS_BASE::OnClose ) );
m_fieldsCtrl->Connect( wxEVT_COMMAND_DATAVIEW_ITEM_VALUE_CHANGED, wxDataViewEventHandler( DIALOG_LIB_FIELDS_BASE::OnColumnItemToggled ), NULL, this );
m_fieldsCtrl->Connect( wxEVT_COMMAND_DATAVIEW_SELECTION_CHANGED, wxDataViewEventHandler( DIALOG_LIB_FIELDS_BASE::OnFieldsCtrlSelectionChanged ), NULL, this );
m_fieldsCtrl->Connect( wxEVT_SIZE, wxSizeEventHandler( DIALOG_LIB_FIELDS_BASE::OnSizeFieldList ), NULL, this );
m_addFieldButton->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_LIB_FIELDS_BASE::OnAddField ), NULL, this );
m_renameFieldButton->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_LIB_FIELDS_BASE::OnRenameField ), NULL, this );
m_removeFieldButton->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_LIB_FIELDS_BASE::OnRemoveField ), NULL, this );
m_filter->Connect( wxEVT_MOTION, wxMouseEventHandler( DIALOG_LIB_FIELDS_BASE::OnFilterMouseMoved ), NULL, this );
m_filter->Connect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( DIALOG_LIB_FIELDS_BASE::OnFilterText ), NULL, this );
m_bRefresh->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_LIB_FIELDS_BASE::OnRegroupSymbols ), NULL, this );
m_grid->Connect( wxEVT_GRID_CELL_CHANGED, wxGridEventHandler( DIALOG_LIB_FIELDS_BASE::OnTableValueChanged ), NULL, this );
m_grid->Connect( wxEVT_GRID_CELL_LEFT_CLICK, wxGridEventHandler( DIALOG_LIB_FIELDS_BASE::OnTableCellClick ), NULL, this );
m_grid->Connect( wxEVT_GRID_CELL_LEFT_DCLICK, wxGridEventHandler( DIALOG_LIB_FIELDS_BASE::OnTableCellClick ), NULL, this );
m_grid->Connect( wxEVT_GRID_CELL_RIGHT_CLICK, wxGridEventHandler( DIALOG_LIB_FIELDS_BASE::OnTableItemContextMenu ), NULL, this );
m_grid->Connect( wxEVT_GRID_CELL_LEFT_CLICK, wxGridEventHandler( DIALOG_LIB_FIELDS_BASE::OnTableCmdCellClick ), NULL, this );
m_grid->Connect( wxEVT_GRID_CELL_LEFT_DCLICK, wxGridEventHandler( DIALOG_LIB_FIELDS_BASE::OnTableCmdCellClick ), NULL, this );
m_grid->Connect( wxEVT_GRID_COL_SIZE, wxGridSizeEventHandler( DIALOG_LIB_FIELDS_BASE::OnTableColSize ), NULL, this );
m_grid->Connect( wxEVT_GRID_EDITOR_SHOWN, wxGridEventHandler( DIALOG_LIB_FIELDS_BASE::OnEditorShown ), NULL, this );
m_grid->Connect( wxEVT_GRID_SELECT_CELL, wxGridEventHandler( DIALOG_LIB_FIELDS_BASE::OnTableSelectCell ), NULL, this );
m_sdbSizerApply->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_LIB_FIELDS_BASE::OnApply ), NULL, this );
m_sdbSizerCancel->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_LIB_FIELDS_BASE::OnCancel ), NULL, this );
m_sdbSizerOK->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_LIB_FIELDS_BASE::OnOk ), NULL, this );
}
DIALOG_LIB_FIELDS_BASE::~DIALOG_LIB_FIELDS_BASE()
{
// Disconnect Events
this->Disconnect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( DIALOG_LIB_FIELDS_BASE::OnClose ) );
m_fieldsCtrl->Disconnect( wxEVT_COMMAND_DATAVIEW_ITEM_VALUE_CHANGED, wxDataViewEventHandler( DIALOG_LIB_FIELDS_BASE::OnColumnItemToggled ), NULL, this );
m_fieldsCtrl->Disconnect( wxEVT_COMMAND_DATAVIEW_SELECTION_CHANGED, wxDataViewEventHandler( DIALOG_LIB_FIELDS_BASE::OnFieldsCtrlSelectionChanged ), NULL, this );
m_fieldsCtrl->Disconnect( wxEVT_SIZE, wxSizeEventHandler( DIALOG_LIB_FIELDS_BASE::OnSizeFieldList ), NULL, this );
m_addFieldButton->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_LIB_FIELDS_BASE::OnAddField ), NULL, this );
m_renameFieldButton->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_LIB_FIELDS_BASE::OnRenameField ), NULL, this );
m_removeFieldButton->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_LIB_FIELDS_BASE::OnRemoveField ), NULL, this );
m_filter->Disconnect( wxEVT_MOTION, wxMouseEventHandler( DIALOG_LIB_FIELDS_BASE::OnFilterMouseMoved ), NULL, this );
m_filter->Disconnect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( DIALOG_LIB_FIELDS_BASE::OnFilterText ), NULL, this );
m_bRefresh->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_LIB_FIELDS_BASE::OnRegroupSymbols ), NULL, this );
m_grid->Disconnect( wxEVT_GRID_CELL_CHANGED, wxGridEventHandler( DIALOG_LIB_FIELDS_BASE::OnTableValueChanged ), NULL, this );
m_grid->Disconnect( wxEVT_GRID_CELL_LEFT_CLICK, wxGridEventHandler( DIALOG_LIB_FIELDS_BASE::OnTableCellClick ), NULL, this );
m_grid->Disconnect( wxEVT_GRID_CELL_LEFT_DCLICK, wxGridEventHandler( DIALOG_LIB_FIELDS_BASE::OnTableCellClick ), NULL, this );
m_grid->Disconnect( wxEVT_GRID_CELL_RIGHT_CLICK, wxGridEventHandler( DIALOG_LIB_FIELDS_BASE::OnTableItemContextMenu ), NULL, this );
m_grid->Disconnect( wxEVT_GRID_CELL_LEFT_CLICK, wxGridEventHandler( DIALOG_LIB_FIELDS_BASE::OnTableCmdCellClick ), NULL, this );
m_grid->Disconnect( wxEVT_GRID_CELL_LEFT_DCLICK, wxGridEventHandler( DIALOG_LIB_FIELDS_BASE::OnTableCmdCellClick ), NULL, this );
m_grid->Disconnect( wxEVT_GRID_COL_SIZE, wxGridSizeEventHandler( DIALOG_LIB_FIELDS_BASE::OnTableColSize ), NULL, this );
m_grid->Disconnect( wxEVT_GRID_EDITOR_SHOWN, wxGridEventHandler( DIALOG_LIB_FIELDS_BASE::OnEditorShown ), NULL, this );
m_grid->Disconnect( wxEVT_GRID_SELECT_CELL, wxGridEventHandler( DIALOG_LIB_FIELDS_BASE::OnTableSelectCell ), NULL, this );
m_sdbSizerApply->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_LIB_FIELDS_BASE::OnApply ), NULL, this );
m_sdbSizerCancel->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_LIB_FIELDS_BASE::OnCancel ), NULL, this );
m_sdbSizerOK->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_LIB_FIELDS_BASE::OnOk ), NULL, this );
}
+898
View File
@@ -0,0 +1,898 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<wxFormBuilder_Project>
<FileVersion major="1" minor="18"/>
<object class="Project" expanded="true">
<property name="code_generation">C++</property>
<property name="cpp_class_decoration"></property>
<property name="cpp_disconnect_events">1</property>
<property name="cpp_event_generation">connect</property>
<property name="cpp_help_provider">none</property>
<property name="cpp_namespace"></property>
<property name="cpp_precompiled_header"></property>
<property name="cpp_use_array_enum">0</property>
<property name="cpp_use_enum">0</property>
<property name="embedded_files_path">res</property>
<property name="encoding">UTF-8</property>
<property name="file">dialog_lib_fields_base</property>
<property name="first_id">1000</property>
<property name="internationalize">1</property>
<property name="lua_skip_events">1</property>
<property name="lua_ui_table">UI</property>
<property name="name">dialog_lib_fields_base</property>
<property name="path">.</property>
<property name="php_disconnect_events">0</property>
<property name="php_disconnect_mode">source_name</property>
<property name="php_skip_events">1</property>
<property name="python_disconnect_events">0</property>
<property name="python_disconnect_mode">source_name</property>
<property name="python_image_path_wrapper_function_name"></property>
<property name="python_indent_with_spaces"></property>
<property name="python_skip_events">1</property>
<property name="relative_path">1</property>
<property name="use_microsoft_bom">0</property>
<property name="use_native_eol">0</property>
<object class="Dialog" expanded="true">
<property name="aui_managed">0</property>
<property name="aui_manager_style">wxAUI_MGR_DEFAULT</property>
<property name="bg"></property>
<property name="center">wxBOTH</property>
<property name="context_help"></property>
<property name="context_menu">1</property>
<property name="drag_accept_files">0</property>
<property name="enabled">1</property>
<property name="event_handler">impl_virtual</property>
<property name="extra_style"></property>
<property name="fg"></property>
<property name="font"></property>
<property name="hidden">0</property>
<property name="id">wxID_ANY</property>
<property name="maximum_size"></property>
<property name="minimum_size">-1,-1</property>
<property name="name">DIALOG_LIB_FIELDS_BASE</property>
<property name="pos"></property>
<property name="size">-1,-1</property>
<property name="style">wxDEFAULT_DIALOG_STYLE|wxMAXIMIZE_BOX|wxRESIZE_BORDER</property>
<property name="subclass">DIALOG_SHIM; dialog_shim.h</property>
<property name="title">Library Fields Editor</property>
<property name="tooltip"></property>
<property name="two_step_creation">0</property>
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style"></property>
<event name="OnClose">OnClose</event>
<object class="wxBoxSizer" expanded="true">
<property name="minimum_size">-1,-1</property>
<property name="name">bMainSizer</property>
<property name="orient">wxVERTICAL</property>
<property name="permission">none</property>
<object class="sizeritem" expanded="true">
<property name="border">5</property>
<property name="flag">wxEXPAND</property>
<property name="proportion">1</property>
<object class="wxBoxSizer" expanded="true">
<property name="minimum_size"></property>
<property name="name">bEditSizer</property>
<property name="orient">wxVERTICAL</property>
<property name="permission">none</property>
<object class="sizeritem" expanded="true">
<property name="border">5</property>
<property name="flag">wxEXPAND|wxTOP|wxBOTTOM</property>
<property name="proportion">1</property>
<object class="wxSplitterWindow" expanded="true">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
<property name="TopDockable">1</property>
<property name="aui_layer">0</property>
<property name="aui_name"></property>
<property name="aui_position">0</property>
<property name="aui_row">0</property>
<property name="best_size"></property>
<property name="bg"></property>
<property name="caption"></property>
<property name="caption_visible">1</property>
<property name="center_pane">0</property>
<property name="close_button">1</property>
<property name="context_help"></property>
<property name="context_menu">1</property>
<property name="default_pane">0</property>
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="drag_accept_files">0</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
<property name="font"></property>
<property name="gripper">0</property>
<property name="hidden">0</property>
<property name="id">wxID_ANY</property>
<property name="max_size"></property>
<property name="maximize_button">0</property>
<property name="maximum_size"></property>
<property name="min_pane_size">200</property>
<property name="min_size"></property>
<property name="minimize_button">0</property>
<property name="minimum_size">-1,-1</property>
<property name="moveable">1</property>
<property name="name">m_splitterMainWindow</property>
<property name="pane_border">1</property>
<property name="pane_position"></property>
<property name="pane_size"></property>
<property name="permission">protected</property>
<property name="pin_button">1</property>
<property name="pos"></property>
<property name="resize">Resizable</property>
<property name="sashgravity">0.0</property>
<property name="sashpos">-1</property>
<property name="sashsize">-1</property>
<property name="show">1</property>
<property name="size"></property>
<property name="splitmode">wxSPLIT_VERTICAL</property>
<property name="style">wxSP_3DSASH|wxSP_LIVE_UPDATE|wxSP_NO_XP_THEME</property>
<property name="subclass"></property>
<property name="toolbar_pane">0</property>
<property name="tooltip"></property>
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style"></property>
<object class="splitteritem" expanded="true">
<object class="wxPanel" expanded="true">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
<property name="TopDockable">1</property>
<property name="aui_layer">0</property>
<property name="aui_name"></property>
<property name="aui_position">0</property>
<property name="aui_row">0</property>
<property name="best_size"></property>
<property name="bg"></property>
<property name="caption"></property>
<property name="caption_visible">1</property>
<property name="center_pane">0</property>
<property name="close_button">1</property>
<property name="context_help"></property>
<property name="context_menu">1</property>
<property name="default_pane">0</property>
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="drag_accept_files">0</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
<property name="font"></property>
<property name="gripper">0</property>
<property name="hidden">0</property>
<property name="id">wxID_ANY</property>
<property name="max_size"></property>
<property name="maximize_button">0</property>
<property name="maximum_size"></property>
<property name="min_size"></property>
<property name="minimize_button">0</property>
<property name="minimum_size"></property>
<property name="moveable">1</property>
<property name="name">m_leftPanel</property>
<property name="pane_border">1</property>
<property name="pane_position"></property>
<property name="pane_size"></property>
<property name="permission">protected</property>
<property name="pin_button">1</property>
<property name="pos"></property>
<property name="resize">Resizable</property>
<property name="show">1</property>
<property name="size"></property>
<property name="subclass"></property>
<property name="toolbar_pane">0</property>
<property name="tooltip"></property>
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style">wxTAB_TRAVERSAL</property>
<object class="wxBoxSizer" expanded="true">
<property name="minimum_size"></property>
<property name="name">bLeftSizer</property>
<property name="orient">wxVERTICAL</property>
<property name="permission">none</property>
<object class="sizeritem" expanded="false">
<property name="border">5</property>
<property name="flag">wxBOTTOM|wxEXPAND|wxLEFT|wxRIGHT|wxTOP</property>
<property name="proportion">1</property>
<object class="wxDataViewListCtrl" expanded="false">
<property name="bg"></property>
<property name="context_help"></property>
<property name="context_menu">1</property>
<property name="drag_accept_files">0</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="font"></property>
<property name="hidden">0</property>
<property name="id">wxID_ANY</property>
<property name="maximum_size"></property>
<property name="minimum_size">-1,250</property>
<property name="name">m_fieldsCtrl</property>
<property name="permission">protected</property>
<property name="pos"></property>
<property name="size"></property>
<property name="style"></property>
<property name="subclass"></property>
<property name="tooltip"></property>
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style"></property>
<event name="OnDataViewListCtrlItemValueChanged">OnColumnItemToggled</event>
<event name="OnDataViewListCtrlSelectionChanged">OnFieldsCtrlSelectionChanged</event>
<event name="OnSize">OnSizeFieldList</event>
</object>
</object>
<object class="sizeritem" expanded="true">
<property name="border">5</property>
<property name="flag">wxEXPAND</property>
<property name="proportion">0</property>
<object class="wxBoxSizer" expanded="true">
<property name="minimum_size"></property>
<property name="name">bFieldsButtons</property>
<property name="orient">wxHORIZONTAL</property>
<property name="permission">none</property>
<object class="sizeritem" expanded="false">
<property name="border">5</property>
<property name="flag">wxBOTTOM|wxLEFT</property>
<property name="proportion">0</property>
<object class="wxBitmapButton" expanded="false">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
<property name="TopDockable">1</property>
<property name="aui_layer">0</property>
<property name="aui_name"></property>
<property name="aui_position">0</property>
<property name="aui_row">0</property>
<property name="auth_needed">0</property>
<property name="best_size"></property>
<property name="bg"></property>
<property name="bitmap"></property>
<property name="caption"></property>
<property name="caption_visible">1</property>
<property name="center_pane">0</property>
<property name="close_button">1</property>
<property name="context_help"></property>
<property name="context_menu">1</property>
<property name="current"></property>
<property name="default">0</property>
<property name="default_pane">0</property>
<property name="disabled"></property>
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="drag_accept_files">0</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
<property name="focus"></property>
<property name="font"></property>
<property name="gripper">0</property>
<property name="hidden">0</property>
<property name="id">wxID_ANY</property>
<property name="label">MyButton</property>
<property name="margins"></property>
<property name="markup">0</property>
<property name="max_size"></property>
<property name="maximize_button">0</property>
<property name="maximum_size"></property>
<property name="min_size"></property>
<property name="minimize_button">0</property>
<property name="minimum_size"></property>
<property name="moveable">1</property>
<property name="name">m_addFieldButton</property>
<property name="pane_border">1</property>
<property name="pane_position"></property>
<property name="pane_size"></property>
<property name="permission">protected</property>
<property name="pin_button">1</property>
<property name="pos"></property>
<property name="position"></property>
<property name="pressed"></property>
<property name="resize">Resizable</property>
<property name="show">1</property>
<property name="size"></property>
<property name="style"></property>
<property name="subclass">STD_BITMAP_BUTTON; widgets/std_bitmap_button.h; forward_declare</property>
<property name="toolbar_pane">0</property>
<property name="tooltip"></property>
<property name="validator_data_type"></property>
<property name="validator_style">wxFILTER_NONE</property>
<property name="validator_type">wxDefaultValidator</property>
<property name="validator_variable"></property>
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style"></property>
<event name="OnButtonClick">OnAddField</event>
</object>
</object>
<object class="sizeritem" expanded="false">
<property name="border">5</property>
<property name="flag">wxBOTTOM|wxLEFT</property>
<property name="proportion">0</property>
<object class="wxBitmapButton" expanded="false">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
<property name="TopDockable">1</property>
<property name="aui_layer">0</property>
<property name="aui_name"></property>
<property name="aui_position">0</property>
<property name="aui_row">0</property>
<property name="auth_needed">0</property>
<property name="best_size"></property>
<property name="bg"></property>
<property name="bitmap"></property>
<property name="caption"></property>
<property name="caption_visible">1</property>
<property name="center_pane">0</property>
<property name="close_button">1</property>
<property name="context_help"></property>
<property name="context_menu">1</property>
<property name="current"></property>
<property name="default">0</property>
<property name="default_pane">0</property>
<property name="disabled"></property>
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="drag_accept_files">0</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
<property name="focus"></property>
<property name="font"></property>
<property name="gripper">0</property>
<property name="hidden">0</property>
<property name="id">wxID_ANY</property>
<property name="label">Rename Field...</property>
<property name="margins"></property>
<property name="markup">0</property>
<property name="max_size"></property>
<property name="maximize_button">0</property>
<property name="maximum_size"></property>
<property name="min_size"></property>
<property name="minimize_button">0</property>
<property name="minimum_size"></property>
<property name="moveable">1</property>
<property name="name">m_renameFieldButton</property>
<property name="pane_border">1</property>
<property name="pane_position"></property>
<property name="pane_size"></property>
<property name="permission">protected</property>
<property name="pin_button">1</property>
<property name="pos"></property>
<property name="position"></property>
<property name="pressed"></property>
<property name="resize">Resizable</property>
<property name="show">1</property>
<property name="size"></property>
<property name="style"></property>
<property name="subclass">STD_BITMAP_BUTTON; widgets/std_bitmap_button.h; forward_declare</property>
<property name="toolbar_pane">0</property>
<property name="tooltip"></property>
<property name="validator_data_type"></property>
<property name="validator_style">wxFILTER_NONE</property>
<property name="validator_type">wxDefaultValidator</property>
<property name="validator_variable"></property>
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style"></property>
<event name="OnButtonClick">OnRenameField</event>
</object>
</object>
<object class="sizeritem" expanded="true">
<property name="border">5</property>
<property name="flag">wxEXPAND</property>
<property name="proportion">0</property>
<object class="spacer" expanded="true">
<property name="height">0</property>
<property name="permission">protected</property>
<property name="width">15</property>
</object>
</object>
<object class="sizeritem" expanded="false">
<property name="border">5</property>
<property name="flag">wxBOTTOM|wxLEFT</property>
<property name="proportion">0</property>
<object class="wxBitmapButton" expanded="false">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
<property name="TopDockable">1</property>
<property name="aui_layer">0</property>
<property name="aui_name"></property>
<property name="aui_position">0</property>
<property name="aui_row">0</property>
<property name="auth_needed">0</property>
<property name="best_size"></property>
<property name="bg"></property>
<property name="bitmap"></property>
<property name="caption"></property>
<property name="caption_visible">1</property>
<property name="center_pane">0</property>
<property name="close_button">1</property>
<property name="context_help"></property>
<property name="context_menu">1</property>
<property name="current"></property>
<property name="default">0</property>
<property name="default_pane">0</property>
<property name="disabled"></property>
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="drag_accept_files">0</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
<property name="focus"></property>
<property name="font"></property>
<property name="gripper">0</property>
<property name="hidden">0</property>
<property name="id">wxID_ANY</property>
<property name="label">Remove Field...</property>
<property name="margins"></property>
<property name="markup">0</property>
<property name="max_size"></property>
<property name="maximize_button">0</property>
<property name="maximum_size"></property>
<property name="min_size"></property>
<property name="minimize_button">0</property>
<property name="minimum_size"></property>
<property name="moveable">1</property>
<property name="name">m_removeFieldButton</property>
<property name="pane_border">1</property>
<property name="pane_position"></property>
<property name="pane_size"></property>
<property name="permission">protected</property>
<property name="pin_button">1</property>
<property name="pos"></property>
<property name="position"></property>
<property name="pressed"></property>
<property name="resize">Resizable</property>
<property name="show">1</property>
<property name="size"></property>
<property name="style"></property>
<property name="subclass">STD_BITMAP_BUTTON; widgets/std_bitmap_button.h; forward_declare</property>
<property name="toolbar_pane">0</property>
<property name="tooltip"></property>
<property name="validator_data_type"></property>
<property name="validator_style">wxFILTER_NONE</property>
<property name="validator_type">wxDefaultValidator</property>
<property name="validator_variable"></property>
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style"></property>
<event name="OnButtonClick">OnRemoveField</event>
</object>
</object>
</object>
</object>
</object>
</object>
</object>
<object class="splitteritem" expanded="true">
<object class="wxPanel" expanded="true">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
<property name="TopDockable">1</property>
<property name="aui_layer">0</property>
<property name="aui_name"></property>
<property name="aui_position">0</property>
<property name="aui_row">0</property>
<property name="best_size"></property>
<property name="bg"></property>
<property name="caption"></property>
<property name="caption_visible">1</property>
<property name="center_pane">0</property>
<property name="close_button">1</property>
<property name="context_help"></property>
<property name="context_menu">1</property>
<property name="default_pane">0</property>
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="drag_accept_files">0</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
<property name="font"></property>
<property name="gripper">0</property>
<property name="hidden">0</property>
<property name="id">wxID_ANY</property>
<property name="max_size"></property>
<property name="maximize_button">0</property>
<property name="maximum_size"></property>
<property name="min_size"></property>
<property name="minimize_button">0</property>
<property name="minimum_size"></property>
<property name="moveable">1</property>
<property name="name">m_rightPanel</property>
<property name="pane_border">1</property>
<property name="pane_position"></property>
<property name="pane_size"></property>
<property name="permission">protected</property>
<property name="pin_button">1</property>
<property name="pos"></property>
<property name="resize">Resizable</property>
<property name="show">1</property>
<property name="size"></property>
<property name="subclass"></property>
<property name="toolbar_pane">0</property>
<property name="tooltip"></property>
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style">wxTAB_TRAVERSAL</property>
<object class="wxBoxSizer" expanded="true">
<property name="minimum_size"></property>
<property name="name">bRightSizer</property>
<property name="orient">wxVERTICAL</property>
<property name="permission">none</property>
<object class="sizeritem" expanded="true">
<property name="border">5</property>
<property name="flag">wxEXPAND|wxLEFT|wxTOP</property>
<property name="proportion">0</property>
<object class="wxBoxSizer" expanded="true">
<property name="minimum_size"></property>
<property name="name">bControls</property>
<property name="orient">wxHORIZONTAL</property>
<property name="permission">none</property>
<object class="sizeritem" expanded="false">
<property name="border">5</property>
<property name="flag">wxALIGN_CENTER_VERTICAL|wxRIGHT</property>
<property name="proportion">1</property>
<object class="wxSearchCtrl" expanded="false">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
<property name="TopDockable">1</property>
<property name="aui_layer">0</property>
<property name="aui_name"></property>
<property name="aui_position">0</property>
<property name="aui_row">0</property>
<property name="best_size"></property>
<property name="bg"></property>
<property name="cancel_button">1</property>
<property name="caption"></property>
<property name="caption_visible">1</property>
<property name="center_pane">0</property>
<property name="close_button">1</property>
<property name="context_help"></property>
<property name="context_menu">1</property>
<property name="default_pane">0</property>
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="drag_accept_files">0</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
<property name="font">,90,400,-1,70,0</property>
<property name="gripper">0</property>
<property name="hidden">0</property>
<property name="id">wxID_ANY</property>
<property name="max_size"></property>
<property name="maximize_button">0</property>
<property name="maximum_size"></property>
<property name="min_size"></property>
<property name="minimize_button">0</property>
<property name="minimum_size">140,-1</property>
<property name="moveable">1</property>
<property name="name">m_filter</property>
<property name="pane_border">1</property>
<property name="pane_position"></property>
<property name="pane_size"></property>
<property name="permission">protected</property>
<property name="pin_button">1</property>
<property name="pos"></property>
<property name="resize">Resizable</property>
<property name="search_button">1</property>
<property name="show">1</property>
<property name="size"></property>
<property name="style"></property>
<property name="subclass">; ; forward_declare</property>
<property name="toolbar_pane">0</property>
<property name="tooltip"></property>
<property name="validator_data_type"></property>
<property name="validator_style">wxFILTER_NONE</property>
<property name="validator_type">wxDefaultValidator</property>
<property name="validator_variable"></property>
<property name="value"></property>
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style"></property>
<event name="OnMotion">OnFilterMouseMoved</event>
<event name="OnText">OnFilterText</event>
</object>
</object>
<object class="sizeritem" expanded="true">
<property name="border">3</property>
<property name="flag">wxEXPAND | wxALL</property>
<property name="proportion">0</property>
<object class="wxStaticLine" expanded="true">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
<property name="TopDockable">1</property>
<property name="aui_layer">0</property>
<property name="aui_name"></property>
<property name="aui_position">0</property>
<property name="aui_row">0</property>
<property name="best_size"></property>
<property name="bg"></property>
<property name="caption"></property>
<property name="caption_visible">1</property>
<property name="center_pane">0</property>
<property name="close_button">1</property>
<property name="context_help"></property>
<property name="context_menu">1</property>
<property name="default_pane">0</property>
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="drag_accept_files">0</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
<property name="font"></property>
<property name="gripper">0</property>
<property name="hidden">0</property>
<property name="id">wxID_ANY</property>
<property name="max_size"></property>
<property name="maximize_button">0</property>
<property name="maximum_size"></property>
<property name="min_size"></property>
<property name="minimize_button">0</property>
<property name="minimum_size"></property>
<property name="moveable">1</property>
<property name="name">m_staticline31</property>
<property name="pane_border">1</property>
<property name="pane_position"></property>
<property name="pane_size"></property>
<property name="permission">protected</property>
<property name="pin_button">1</property>
<property name="pos"></property>
<property name="resize">Resizable</property>
<property name="show">1</property>
<property name="size"></property>
<property name="style">wxLI_VERTICAL</property>
<property name="subclass">; ; forward_declare</property>
<property name="toolbar_pane">0</property>
<property name="tooltip"></property>
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style"></property>
</object>
</object>
<object class="sizeritem" expanded="false">
<property name="border">5</property>
<property name="flag">wxALIGN_CENTER_VERTICAL|wxLEFT|wxRIGHT</property>
<property name="proportion">0</property>
<object class="wxBitmapButton" expanded="false">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
<property name="TopDockable">1</property>
<property name="aui_layer">0</property>
<property name="aui_name"></property>
<property name="aui_position">0</property>
<property name="aui_row">0</property>
<property name="auth_needed">0</property>
<property name="best_size"></property>
<property name="bg"></property>
<property name="bitmap"></property>
<property name="caption"></property>
<property name="caption_visible">1</property>
<property name="center_pane">0</property>
<property name="close_button">1</property>
<property name="context_help"></property>
<property name="context_menu">1</property>
<property name="current"></property>
<property name="default">0</property>
<property name="default_pane">0</property>
<property name="disabled"></property>
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="drag_accept_files">0</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
<property name="focus"></property>
<property name="font"></property>
<property name="gripper">0</property>
<property name="hidden">0</property>
<property name="id">wxID_ANY</property>
<property name="label">Refresh Grouping</property>
<property name="margins"></property>
<property name="markup">0</property>
<property name="max_size"></property>
<property name="maximize_button">0</property>
<property name="maximum_size"></property>
<property name="min_size"></property>
<property name="minimize_button">0</property>
<property name="minimum_size">30,30</property>
<property name="moveable">1</property>
<property name="name">m_bRefresh</property>
<property name="pane_border">1</property>
<property name="pane_position"></property>
<property name="pane_size"></property>
<property name="permission">protected</property>
<property name="pin_button">1</property>
<property name="pos"></property>
<property name="position"></property>
<property name="pressed"></property>
<property name="resize">Resizable</property>
<property name="show">1</property>
<property name="size"></property>
<property name="style"></property>
<property name="subclass">STD_BITMAP_BUTTON; widgets/std_bitmap_button.h; forward_declare</property>
<property name="toolbar_pane">0</property>
<property name="tooltip"></property>
<property name="validator_data_type"></property>
<property name="validator_style">wxFILTER_NONE</property>
<property name="validator_type">wxDefaultValidator</property>
<property name="validator_variable"></property>
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style"></property>
<event name="OnButtonClick">OnRegroupSymbols</event>
</object>
</object>
</object>
</object>
<object class="sizeritem" expanded="false">
<property name="border">5</property>
<property name="flag">wxBOTTOM|wxEXPAND|wxLEFT|wxRIGHT|wxTOP</property>
<property name="proportion">1</property>
<object class="wxGrid" expanded="false">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
<property name="TopDockable">1</property>
<property name="aui_layer">0</property>
<property name="aui_name"></property>
<property name="aui_position">0</property>
<property name="aui_row">0</property>
<property name="autosize_cols">0</property>
<property name="autosize_rows">0</property>
<property name="best_size"></property>
<property name="bg"></property>
<property name="caption"></property>
<property name="caption_visible">1</property>
<property name="cell_bg"></property>
<property name="cell_font"></property>
<property name="cell_horiz_alignment">wxALIGN_LEFT</property>
<property name="cell_text"></property>
<property name="cell_vert_alignment">wxALIGN_CENTER</property>
<property name="center_pane">0</property>
<property name="close_button">1</property>
<property name="col_label_horiz_alignment">wxALIGN_CENTER</property>
<property name="col_label_size">24</property>
<property name="col_label_values"></property>
<property name="col_label_vert_alignment">wxALIGN_CENTER</property>
<property name="cols">5</property>
<property name="column_sizes"></property>
<property name="context_help"></property>
<property name="context_menu">1</property>
<property name="default_pane">0</property>
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="drag_accept_files">0</property>
<property name="drag_col_move">1</property>
<property name="drag_col_size">1</property>
<property name="drag_grid_size">0</property>
<property name="drag_row_size">0</property>
<property name="editing">1</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
<property name="font"></property>
<property name="grid_line_color"></property>
<property name="grid_lines">1</property>
<property name="gripper">0</property>
<property name="hidden">0</property>
<property name="id">wxID_ANY</property>
<property name="label_bg"></property>
<property name="label_font"></property>
<property name="label_text"></property>
<property name="margin_height">0</property>
<property name="margin_width">0</property>
<property name="max_size"></property>
<property name="maximize_button">0</property>
<property name="maximum_size"></property>
<property name="min_size"></property>
<property name="minimize_button">0</property>
<property name="minimum_size">400,200</property>
<property name="moveable">1</property>
<property name="name">m_grid</property>
<property name="pane_border">1</property>
<property name="pane_position"></property>
<property name="pane_size"></property>
<property name="permission">protected</property>
<property name="pin_button">1</property>
<property name="pos"></property>
<property name="resize">Resizable</property>
<property name="row_label_horiz_alignment">wxALIGN_CENTER</property>
<property name="row_label_size">0</property>
<property name="row_label_values"></property>
<property name="row_label_vert_alignment">wxALIGN_CENTER</property>
<property name="row_sizes"></property>
<property name="rows">5</property>
<property name="show">1</property>
<property name="size"></property>
<property name="subclass">WX_GRID; widgets/wx_grid.h; forward_declare</property>
<property name="toolbar_pane">0</property>
<property name="tooltip"></property>
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style"></property>
<event name="OnGridCellChange">OnTableValueChanged</event>
<event name="OnGridCellLeftClick">OnTableCellClick</event>
<event name="OnGridCellLeftDClick">OnTableCellClick</event>
<event name="OnGridCellRightClick">OnTableItemContextMenu</event>
<event name="OnGridCmdCellLeftClick">OnTableCmdCellClick</event>
<event name="OnGridCmdCellLeftDClick">OnTableCmdCellClick</event>
<event name="OnGridColSize">OnTableColSize</event>
<event name="OnGridEditorShown">OnEditorShown</event>
<event name="OnGridSelectCell">OnTableSelectCell</event>
</object>
</object>
</object>
</object>
</object>
</object>
</object>
</object>
</object>
<object class="sizeritem" expanded="true">
<property name="border">5</property>
<property name="flag">wxEXPAND</property>
<property name="proportion">0</property>
<object class="wxBoxSizer" expanded="true">
<property name="minimum_size"></property>
<property name="name">bButtonsSizer</property>
<property name="orient">wxHORIZONTAL</property>
<property name="permission">none</property>
<object class="sizeritem" expanded="false">
<property name="border">5</property>
<property name="flag">wxEXPAND</property>
<property name="proportion">9</property>
<object class="spacer" expanded="false">
<property name="height">0</property>
<property name="permission">protected</property>
<property name="width">0</property>
</object>
</object>
<object class="sizeritem" expanded="false">
<property name="border">5</property>
<property name="flag">wxALIGN_CENTER_VERTICAL|wxALL</property>
<property name="proportion">0</property>
<object class="wxStdDialogButtonSizer" expanded="false">
<property name="Apply">1</property>
<property name="Cancel">1</property>
<property name="ContextHelp">0</property>
<property name="Help">0</property>
<property name="No">0</property>
<property name="OK">1</property>
<property name="Save">0</property>
<property name="Yes">0</property>
<property name="minimum_size"></property>
<property name="name">m_sdbSizer</property>
<property name="permission">protected</property>
<event name="OnApplyButtonClick">OnApply</event>
<event name="OnCancelButtonClick">OnCancel</event>
<event name="OnOKButtonClick">OnOk</event>
</object>
</object>
</object>
</object>
</object>
</object>
</object>
</wxFormBuilder_Project>
+92
View File
@@ -0,0 +1,92 @@
///////////////////////////////////////////////////////////////////////////
// C++ code generated with wxFormBuilder (version 4.2.1-0-g80c4cb6a-dirty)
// http://www.wxformbuilder.org/
//
// PLEASE DO *NOT* EDIT THIS FILE!
///////////////////////////////////////////////////////////////////////////
#pragma once
#include <wx/artprov.h>
#include <wx/xrc/xmlres.h>
#include <wx/intl.h>
class STD_BITMAP_BUTTON;
class WX_GRID;
#include "dialog_shim.h"
#include <wx/dataview.h>
#include <wx/gdicmn.h>
#include <wx/font.h>
#include <wx/colour.h>
#include <wx/settings.h>
#include <wx/string.h>
#include <wx/bmpbuttn.h>
#include <wx/bitmap.h>
#include <wx/image.h>
#include <wx/icon.h>
#include <wx/button.h>
#include <wx/sizer.h>
#include <wx/panel.h>
#include <wx/srchctrl.h>
#include <wx/statline.h>
#include <wx/grid.h>
#include <wx/splitter.h>
#include <wx/dialog.h>
///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
/// Class DIALOG_LIB_FIELDS_BASE
///////////////////////////////////////////////////////////////////////////////
class DIALOG_LIB_FIELDS_BASE : public DIALOG_SHIM
{
private:
protected:
wxSplitterWindow* m_splitterMainWindow;
wxPanel* m_leftPanel;
wxDataViewListCtrl* m_fieldsCtrl;
STD_BITMAP_BUTTON* m_addFieldButton;
STD_BITMAP_BUTTON* m_renameFieldButton;
STD_BITMAP_BUTTON* m_removeFieldButton;
wxPanel* m_rightPanel;
wxSearchCtrl* m_filter;
wxStaticLine* m_staticline31;
STD_BITMAP_BUTTON* m_bRefresh;
WX_GRID* m_grid;
wxStdDialogButtonSizer* m_sdbSizer;
wxButton* m_sdbSizerOK;
wxButton* m_sdbSizerApply;
wxButton* m_sdbSizerCancel;
// Virtual event handlers, override them in your derived class
virtual void OnClose( wxCloseEvent& event ) { event.Skip(); }
virtual void OnColumnItemToggled( wxDataViewEvent& event ) { event.Skip(); }
virtual void OnFieldsCtrlSelectionChanged( wxDataViewEvent& event ) { event.Skip(); }
virtual void OnSizeFieldList( wxSizeEvent& event ) { event.Skip(); }
virtual void OnAddField( wxCommandEvent& event ) { event.Skip(); }
virtual void OnRenameField( wxCommandEvent& event ) { event.Skip(); }
virtual void OnRemoveField( wxCommandEvent& event ) { event.Skip(); }
virtual void OnFilterMouseMoved( wxMouseEvent& event ) { event.Skip(); }
virtual void OnFilterText( wxCommandEvent& event ) { event.Skip(); }
virtual void OnRegroupSymbols( wxCommandEvent& event ) { event.Skip(); }
virtual void OnTableValueChanged( wxGridEvent& event ) { event.Skip(); }
virtual void OnTableCellClick( wxGridEvent& event ) { event.Skip(); }
virtual void OnTableItemContextMenu( wxGridEvent& event ) { event.Skip(); }
virtual void OnTableCmdCellClick( wxGridEvent& event ) { event.Skip(); }
virtual void OnTableColSize( wxGridSizeEvent& event ) { event.Skip(); }
virtual void OnEditorShown( wxGridEvent& event ) { event.Skip(); }
virtual void OnTableSelectCell( wxGridEvent& event ) { event.Skip(); }
virtual void OnApply( wxCommandEvent& event ) { event.Skip(); }
virtual void OnCancel( wxCommandEvent& event ) { event.Skip(); }
virtual void OnOk( wxCommandEvent& event ) { event.Skip(); }
public:
DIALOG_LIB_FIELDS_BASE( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("Library Fields Editor"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( -1,-1 ), long style = wxDEFAULT_DIALOG_STYLE|wxMAXIMIZE_BOX|wxRESIZE_BORDER );
~DIALOG_LIB_FIELDS_BASE();
};
+106 -20
View File
@@ -84,6 +84,7 @@ DIALOG_LIB_SYMBOL_PROPERTIES::DIALOG_LIB_SYMBOL_PROPERTIES( SYMBOL_EDIT_FRAME* a
} ) );
m_grid->SetSelectionMode( wxGrid::wxGridSelectRows );
// Show/hide columns according to the user's preference
SYMBOL_EDITOR_SETTINGS* cfg = m_Parent->GetSettings();
m_grid->ShowHideColumns( cfg->m_EditSymbolVisibleColumns );
@@ -110,8 +111,11 @@ DIALOG_LIB_SYMBOL_PROPERTIES::DIALOG_LIB_SYMBOL_PROPERTIES( SYMBOL_EDIT_FRAME* a
// wxFormBuilder doesn't include this event...
m_grid->Connect( wxEVT_GRID_CELL_CHANGING,
wxGridEventHandler( DIALOG_LIB_SYMBOL_PROPERTIES::OnGridCellChanging ),
nullptr, this );
wxGridEventHandler( DIALOG_LIB_SYMBOL_PROPERTIES::OnGridCellChanging ), nullptr, this );
m_grid->Connect( wxEVT_GRID_CELL_CHANGED,
wxGridEventHandler( DIALOG_LIB_SYMBOL_PROPERTIES::OnGridCellChanged ), nullptr, this );
m_grid->GetGridWindow()->Bind( wxEVT_MOTION, &DIALOG_LIB_SYMBOL_PROPERTIES::OnGridMotion, this );
// Forward the delete button to the tricks
m_deleteFilterButton->Bind( wxEVT_BUTTON,
@@ -161,8 +165,10 @@ DIALOG_LIB_SYMBOL_PROPERTIES::~DIALOG_LIB_SYMBOL_PROPERTIES()
m_grid->DestroyTable( m_fields );
m_grid->Disconnect( wxEVT_GRID_CELL_CHANGING,
wxGridEventHandler( DIALOG_LIB_SYMBOL_PROPERTIES::OnGridCellChanging ),
nullptr, this );
wxGridEventHandler( DIALOG_LIB_SYMBOL_PROPERTIES::OnGridCellChanging ), nullptr, this );
m_grid->Disconnect( wxEVT_GRID_CELL_CHANGED,
wxGridEventHandler( DIALOG_LIB_SYMBOL_PROPERTIES::OnGridCellChanged ), nullptr, this );
m_grid->GetGridWindow()->Unbind( wxEVT_MOTION, &DIALOG_LIB_SYMBOL_PROPERTIES::OnGridMotion, this );
// Delete the GRID_TRICKS.
m_grid->PopEventHandler( true );
@@ -174,9 +180,58 @@ bool DIALOG_LIB_SYMBOL_PROPERTIES::TransferDataToWindow()
if( !wxDialog::TransferDataToWindow() )
return false;
// Push a copy of each field into m_updateFields
// Ensure the fields vector is empty before (re)loading. Constructor no longer
// pre-populates fields to avoid double insertion of mandatory fields.
if( m_fields->size() > 0 )
{
// Clear existing entries; we recreate inheritance metadata via push_back()
// Note: We cannot simply reuse existing entries because alias inheritance
// state may have changed if the parent was edited prior to dialog open.
m_fields->clear();
}
// Load current symbol fields (mandatory first, then user fields)
m_libEntry->CopyFields( *m_fields );
// Handle alias (derived) symbol inherited fields. We only inherit non-mandatory fields
// and mark any matching names as inherited rather than duplicating them.
if( m_libEntry->IsAlias() )
{
if( LIB_SYMBOL_SPTR parent = m_libEntry->GetParent().lock() )
{
std::vector<SCH_FIELD*> parentFields;
parent->GetFields( parentFields );
for( SCH_FIELD* pf : parentFields )
{
if( pf->IsMandatory() )
continue; // Never inherit mandatory fields
bool found = false;
for( size_t jj = 0; jj < m_fields->size(); ++jj )
{
SCH_FIELD& f = m_fields->at( jj );
if( f.IsMandatory() )
continue; // Skip mandatory in child list for inheritance match
if( f.GetCanonicalName() == pf->GetCanonicalName() )
{
m_fields->SetFieldInherited( jj, *pf );
found = true;
break;
}
}
if( !found )
m_fields->AddInheritedField( *pf );
}
}
}
// Fields already loaded above; avoid re-copying to prevent duplication.
std::set<wxString> defined;
for( SCH_FIELD& field : *m_fields )
@@ -416,37 +471,40 @@ bool DIALOG_LIB_SYMBOL_PROPERTIES::TransferDataFromWindow()
m_Parent->SaveCopyInUndoList( _( "Edit Symbol Properties" ), m_libEntry );
}
// The Y axis for components in lib is from bottom to top while the screen axis is top
// to bottom: we must change the y coord sign when writing back to the library
for( int ii = 0; ii < (int) m_fields->size(); ++ii )
{
VECTOR2I pos = m_fields->at( ii ).GetPosition();
pos.y = -pos.y;
m_fields->at( ii ).SetPosition( pos );
m_fields->at( ii ).SetId( ii );
}
std::vector<SCH_FIELD> fieldsToSave;
for( int ii = m_fields->GetNumberRows() - 1; ii >= 0; ii-- )
{
SCH_FIELD& field = m_fields->at( ii );
if( field.IsMandatory() )
continue;
// The Y axis for components in lib is from bottom to top while the screen axis is top
// to bottom: we must change the y coord sign when writing back to the library
VECTOR2I pos = field.GetPosition();
pos.y = -pos.y;
field.SetPosition( pos );
const wxString& fieldName = field.GetCanonicalName();
// if( !field.IsMandatory() )
field.SetId( ii );
wxString fieldName = field.GetCanonicalName();
if( m_fields->IsInherited( ii ) && field == m_fields->ParentField( ii ) )
continue; // Skip inherited fields
if( field.GetText().IsEmpty() )
{
if( fieldName.IsEmpty() || m_addedTemplateFields.contains( fieldName ) )
m_fields->erase( m_fields->begin() + ii );
continue; // Skip empty fields that are not mandatory or template fields
}
else if( fieldName.IsEmpty() )
{
field.SetName( _( "untitled" ) );
field.SetName( _( "untitled" ) ); // Set a default name for unnamed fields
}
fieldsToSave.push_back( field );
}
m_libEntry->SetFields( *m_fields );
m_libEntry->SetFields( fieldsToSave );
// Update the parent for inherited symbols
if( m_libEntry->IsAlias() )
@@ -517,6 +575,27 @@ bool DIALOG_LIB_SYMBOL_PROPERTIES::TransferDataFromWindow()
}
void DIALOG_LIB_SYMBOL_PROPERTIES::OnGridMotion( wxMouseEvent& aEvent )
{
aEvent.Skip();
wxPoint pos = aEvent.GetPosition();
wxPoint unscolled_pos = m_grid->CalcUnscrolledPosition( pos );
int row = m_grid->YToRow( unscolled_pos.y );
int col = m_grid->XToCol( unscolled_pos.x );
if( row == wxNOT_FOUND || col == wxNOT_FOUND || !m_fields->IsInherited( row ) )
{
m_grid->SetToolTip( "" );
return;
}
m_grid->SetToolTip(
wxString::Format( _( "This field is inherited from '%s'." ),
m_fields->ParentField( row ).GetName() ) );
}
void DIALOG_LIB_SYMBOL_PROPERTIES::OnGridCellChanging( wxGridEvent& event )
{
wxGridCellEditor* editor = m_grid->GetCellEditor( event.GetRow(), event.GetCol() );
@@ -555,6 +634,13 @@ void DIALOG_LIB_SYMBOL_PROPERTIES::OnGridCellChanging( wxGridEvent& event )
}
void DIALOG_LIB_SYMBOL_PROPERTIES::OnGridCellChanged( wxGridEvent& event )
{
m_grid->ForceRefresh();
OnModify();
}
void DIALOG_LIB_SYMBOL_PROPERTIES::OnSymbolNameText( wxCommandEvent& event )
{
if( m_OptionPower->IsChecked() )
@@ -68,6 +68,8 @@ private:
void OnEditFootprintFilter( wxCommandEvent& event ) override;
void OnSizeGrid( wxSizeEvent& event ) override;
void OnGridCellChanging( wxGridEvent& event );
void OnGridCellChanged( wxGridEvent& event );
void OnGridMotion( wxMouseEvent& event );
void OnEditSpiceModel( wxCommandEvent& event ) override;
void OnUpdateUI( wxUpdateUIEvent& event ) override;
void OnCancelButtonClick( wxCommandEvent& event ) override;
+2
View File
@@ -1003,6 +1003,7 @@ void DIALOG_SIM_COMMAND::OnFilterText( wxCommandEvent& aEvent )
void DIALOG_SIM_COMMAND::OnFilterMouseMoved( wxMouseEvent& aEvent )
{
#if defined( __WXOSX__ ) || wxCHECK_VERSION( 3, 3, 0 ) // Doesn't work properly on other ports
wxPoint pos = aEvent.GetPosition();
wxRect ctrlRect = m_inputSignalsFilter->GetScreenRect();
int buttonWidth = ctrlRect.GetHeight(); // Presume buttons are square
@@ -1014,6 +1015,7 @@ void DIALOG_SIM_COMMAND::OnFilterMouseMoved( wxMouseEvent& aEvent )
SetCursor( wxCURSOR_ARROW );
else
SetCursor( wxCURSOR_IBEAM );
#endif
}
+2 -1
View File
@@ -88,7 +88,8 @@ DIALOG_SIM_MODEL<T>::DIALOG_SIM_MODEL( wxWindow* aParent, EDA_BASE_FRAME* aFrame
m_filesStack.push_back( symbol->Schematic()->GetEmbeddedFiles() );
}
m_filesStack.push_back( aSymbol.GetEmbeddedFiles() );
if( EMBEDDED_FILES* symbolEmbeddedFiles = aSymbol.GetEmbeddedFiles() )
m_filesStack.push_back( symbolEmbeddedFiles );
m_libraryModelsMgr.SetFilesStack( m_filesStack );
m_builtinModelsMgr.SetFilesStack( m_filesStack );
@@ -878,6 +878,7 @@ void DIALOG_SYMBOL_FIELDS_TABLE::OnFilterText( wxCommandEvent& aEvent )
void DIALOG_SYMBOL_FIELDS_TABLE::OnFilterMouseMoved( wxMouseEvent& aEvent )
{
#if defined( __WXOSX__ ) || wxCHECK_VERSION( 3, 3, 0 ) // Doesn't work properly on other ports
wxPoint pos = aEvent.GetPosition();
wxRect ctrlRect = m_filter->GetScreenRect();
int buttonWidth = ctrlRect.GetHeight(); // Presume buttons are square
@@ -889,6 +890,7 @@ void DIALOG_SYMBOL_FIELDS_TABLE::OnFilterMouseMoved( wxMouseEvent& aEvent )
SetCursor( wxCURSOR_ARROW );
else
SetCursor( wxCURSOR_IBEAM );
#endif
}
+9 -12
View File
@@ -103,7 +103,7 @@ public:
SCH_PIN* lib_pin = pin.GetLibPin();
wxGridCellAttr* attr = nullptr;
if( lib_pin->GetAlternates().empty() )
if( !lib_pin || lib_pin->GetAlternates().empty() )
{
attr = new wxGridCellAttr;
attr->SetReadOnly( true );
@@ -177,7 +177,7 @@ public:
{
if( aCol == COL_ALT_NAME )
{
if( aPin.GetLibPin()->GetAlternates().empty() )
if( !aPin.GetLibPin() || aPin.GetLibPin()->GetAlternates().empty() )
return wxEmptyString;
else if( aPin.GetAlt().IsEmpty() )
return aPin.GetName();
@@ -188,7 +188,7 @@ public:
switch( aCol )
{
case COL_NUMBER: return aPin.GetNumber();
case COL_BASE_NAME: return aPin.GetLibPin()->GetName();
case COL_BASE_NAME: return aPin.GetBaseName();
case COL_TYPE: return PinTypeNames()[static_cast<int>( aPin.GetType() )];
case COL_SHAPE: return PinShapeNames()[static_cast<int>( aPin.GetShape() )];
default: wxFAIL; return wxEmptyString;
@@ -224,13 +224,15 @@ public:
void SetValue( int aRow, int aCol, const wxString &aValue ) override
{
SCH_PIN& pin = at( aRow );
switch( aCol )
{
case COL_ALT_NAME:
if( aValue == at( aRow ).GetLibPin()->GetName() )
at( aRow ).SetAlt( wxEmptyString );
if( pin.GetLibPin() && aValue == pin.GetLibPin()->GetName() )
pin.SetAlt( wxEmptyString );
else
at( aRow ).SetAlt( aValue );
pin.SetAlt( aValue );
break;
case COL_NUMBER:
@@ -484,12 +486,7 @@ bool DIALOG_SYMBOL_PROPERTIES::TransferDataToWindow()
m_symbol->SetUnit( m_symbol->GetUnitSelection( &GetParent()->GetCurrentSheet() ) );
for( int ii = 1; ii <= m_symbol->GetUnitCount(); ii++ )
{
if( m_symbol->HasUnitDisplayName( ii ) )
m_unitChoice->Append( m_symbol->GetUnitDisplayName( ii ) );
else
m_unitChoice->Append( m_symbol->SubReference( ii, false ) );
}
m_unitChoice->Append( m_symbol->GetUnitDisplayName( ii, false ) );
if( m_symbol->GetUnit() <= ( int )m_unitChoice->GetCount() )
m_unitChoice->SetSelection( m_symbol->GetUnit() - 1 );
@@ -131,7 +131,7 @@ void DIALOG_UPDATE_SYMBOL_FIELDS::onOkButtonClicked( wxCommandEvent& aEvent )
wxBusyCursor dummy;
SCH_COMMIT commit( m_editFrame );
commit.Modify( m_symbol );
commit.Modify( m_symbol, m_editFrame->GetScreen() );
// Create the set of fields to be updated
m_updateFields.clear();
+31 -39
View File
@@ -112,28 +112,28 @@ const wxString CommentERC_V[] =
// i.e. pin type = ELECTRICAL_PINTYPE::PT_INPUT, but not PT_POWER_IN
// that need only a PT_POWER_OUT pin type to be driven
const std::set<ELECTRICAL_PINTYPE> DrivingPinTypes =
{
ELECTRICAL_PINTYPE::PT_OUTPUT,
ELECTRICAL_PINTYPE::PT_POWER_OUT,
ELECTRICAL_PINTYPE::PT_PASSIVE,
ELECTRICAL_PINTYPE::PT_TRISTATE,
ELECTRICAL_PINTYPE::PT_BIDI
};
{
ELECTRICAL_PINTYPE::PT_OUTPUT,
ELECTRICAL_PINTYPE::PT_POWER_OUT,
ELECTRICAL_PINTYPE::PT_PASSIVE,
ELECTRICAL_PINTYPE::PT_TRISTATE,
ELECTRICAL_PINTYPE::PT_BIDI
};
// List of pin types that are considered drivers for power pins
// In fact only a ELECTRICAL_PINTYPE::PT_POWER_OUT pin type can drive
// power input pins
const std::set<ELECTRICAL_PINTYPE> DrivingPowerPinTypes =
{
ELECTRICAL_PINTYPE::PT_POWER_OUT
};
{
ELECTRICAL_PINTYPE::PT_POWER_OUT
};
// List of pin types that require a driver elsewhere on the net
const std::set<ELECTRICAL_PINTYPE> DrivenPinTypes =
{
ELECTRICAL_PINTYPE::PT_INPUT,
ELECTRICAL_PINTYPE::PT_POWER_IN
};
{
ELECTRICAL_PINTYPE::PT_INPUT,
ELECTRICAL_PINTYPE::PT_POWER_IN
};
extern void CheckDuplicatePins( LIB_SYMBOL* aSymbol, std::vector<wxString>& aMessages,
UNITS_PROVIDER* aUnitsProvider );
@@ -574,11 +574,11 @@ int ERC_TESTER::TestMissingUnits()
{
if( ii++ == 3 )
{
missing_pin_units += wxS( "....." );
missing_pin_units += wxS( "..." );
break;
}
missing_pin_units += libSymbol->GetUnitDisplayName( missing_unit ) + ", " ;
missing_pin_units += libSymbol->GetUnitDisplayName( missing_unit, false ) + ", " ;
}
missing_pin_units.Truncate( missing_pin_units.length() - 2 );
@@ -692,8 +692,7 @@ int ERC_TESTER::TestMissingNetclasses()
std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( ERCE_UNDEFINED_NETCLASS );
ercItem->SetItems( item );
ercItem->SetErrorMessage( wxString::Format( _( "Netclass %s is not defined" ),
netclass ) );
ercItem->SetErrorMessage( wxString::Format( _( "Netclass %s is not defined" ), netclass ) );
SCH_MARKER* marker = new SCH_MARKER( ercItem, item->GetPosition() );
sheet.LastScreen()->Append( marker );
@@ -886,7 +885,7 @@ int ERC_TESTER::TestNoConnectPins()
for( SCH_PIN* pin : symbol->GetPins( &sheet ) )
{
if( pin->GetLibPin()->GetType() == ELECTRICAL_PINTYPE::PT_NC )
if( pin->GetType() == ELECTRICAL_PINTYPE::PT_NC )
pinMap[pin->GetPosition()].emplace_back( pin );
}
}
@@ -899,7 +898,7 @@ int ERC_TESTER::TestNoConnectPins()
for( SCH_PIN* pin : symbol->GetPins( &sheet ) )
{
if( pin->GetLibPin()->GetType() != ELECTRICAL_PINTYPE::PT_NC )
if( pin->GetType() != ELECTRICAL_PINTYPE::PT_NC )
addOther( pin->GetPosition(), pin );
}
}
@@ -1042,16 +1041,12 @@ int ERC_TESTER::TestPinToPin()
if( erc != PIN_ERROR::OK && m_settings.IsTestEnabled( ERCE_PIN_TO_PIN_WARNING ) )
{
pin_mismatches.emplace_back(
std::tuple<iterator_t, iterator_t, PIN_ERROR>{ refIt, testIt, erc } );
pin_mismatches.emplace_back( std::tuple<iterator_t, iterator_t, PIN_ERROR>{ refIt, testIt, erc } );
if( m_settings.GetERCSortingMetric() == ERC_PIN_SORTING_METRIC::SM_HEURISTICS )
{
pin_mismatch_counts[refIt] =
m_settings.GetPinTypeWeight( ( *refIt ).Pin()->GetType() );
pin_mismatch_counts[testIt] =
m_settings.GetPinTypeWeight( ( *testIt ).Pin()->GetType() );
pin_mismatch_counts[refIt] = m_settings.GetPinTypeWeight( ( *refIt ).Pin()->GetType() );
pin_mismatch_counts[testIt] = m_settings.GetPinTypeWeight( ( *testIt ).Pin()->GetType() );
}
else
{
@@ -1132,17 +1127,15 @@ int ERC_TESTER::TestPinToPin()
{
SCH_PIN* other_pin = ( *nearest_pin ).Pin();
std::shared_ptr<ERC_ITEM> ercItem =
ERC_ITEM::Create( erc == PIN_ERROR::WARNING ? ERCE_PIN_TO_PIN_WARNING
: ERCE_PIN_TO_PIN_ERROR );
auto ercItem = ERC_ITEM::Create( erc == PIN_ERROR::WARNING ? ERCE_PIN_TO_PIN_WARNING
: ERCE_PIN_TO_PIN_ERROR );
ercItem->SetItems( pin, other_pin );
ercItem->SetSheetSpecificPath( ( *pinIt ).Sheet() );
ercItem->SetItemsSheetPaths( ( *pinIt ).Sheet(), ( *nearest_pin ).Sheet() );
ercItem->SetErrorMessage(
wxString::Format( _( "Pins of type %s and %s are connected" ),
ElectricalPinTypeGetText( pin->GetType() ),
ElectricalPinTypeGetText( other_pin->GetType() ) ) );
ercItem->SetErrorMessage( wxString::Format( _( "Pins of type %s and %s are connected" ),
ElectricalPinTypeGetText( pin->GetType() ),
ElectricalPinTypeGetText( other_pin->GetType() ) ) );
SCH_MARKER* marker = new SCH_MARKER( ercItem, pin->GetPosition() );
pinToScreenMap[pin]->Append( marker );
@@ -1162,7 +1155,7 @@ int ERC_TESTER::TestPinToPin()
ercItem->SetSheetSpecificPath( needsDriver.Sheet() );
ercItem->SetItemsSheetPaths( needsDriver.Sheet() );
SCH_MARKER* marker = new SCH_MARKER( ercItem, needsDriver.Pin()->GetPosition() );
SCH_MARKER* marker = new SCH_MARKER( std::move( ercItem ), needsDriver.Pin()->GetPosition() );
pinToScreenMap[needsDriver.Pin()]->Append( marker );
errors++;
}
@@ -1195,8 +1188,7 @@ int ERC_TESTER::TestMultUnitPinConflicts()
if( !pin->GetLibPin()->GetParentSymbol()->IsMulti() )
continue;
wxString name = pin->GetParentSymbol()->GetRef( &sheet ) +
+ ":" + pin->GetShownNumber();
wxString name = pin->GetParentSymbol()->GetRef( &sheet ) + ":" + pin->GetShownNumber();
if( !pinToNetMap.count( name ) )
{
@@ -1273,7 +1265,7 @@ int ERC_TESTER::TestSameLocalGlobalLabel()
ercItem->SetSheetSpecificPath( globalItem.second );
ercItem->SetItemsSheetPaths( globalItem.second, localItem.second );
SCH_MARKER* marker = new SCH_MARKER( ercItem, globalItem.first->GetPosition() );
SCH_MARKER* marker = new SCH_MARKER( std::move( ercItem ), globalItem.first->GetPosition() );
globalItem.second.LastScreen()->Append( marker );
errCount++;
@@ -1670,7 +1662,7 @@ int ERC_TESTER::TestFootprintFilters()
wxJoin( filters, ' ' ) );
ercItem->SetErrorMessage( msg );
ercItem->SetItems( sch_symbol );
markers.emplace_back( new SCH_MARKER( ercItem, sch_symbol->GetPosition() ) );
markers.emplace_back( new SCH_MARKER( std::move( ercItem ), sch_symbol->GetPosition() ) );
}
}
+8
View File
@@ -19,6 +19,7 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <algorithm>
#include <erc/erc_item.h>
#include <erc/erc_settings.h>
#include <schematic.h>
@@ -397,6 +398,13 @@ void SHEETLIST_ERC_ITEMS_PROVIDER::SetSeverities( int aSeverities )
if( markerSeverity & m_severities )
m_filteredMarkers.push_back( aMarker );
} );
// Sort markers so that errors appear before warnings
std::stable_sort( m_filteredMarkers.begin(), m_filteredMarkers.end(),
[]( const SCH_MARKER* a, const SCH_MARKER* b )
{
return a->GetSeverity() > b->GetSeverity();
} );
}
+136 -36
View File
@@ -45,8 +45,10 @@ void FIELDS_EDITOR_GRID_DATA_MODEL::AddColumn( const wxString& aFieldName, const
for( unsigned i = 0; i < m_symbolsList.GetCount(); ++i )
{
if( SCH_SYMBOL* symbol = m_symbolsList[i].GetSymbol() )
updateDataStoreSymbolField( *symbol, aFieldName );
const SCH_REFERENCE& ref = m_symbolsList[i];
if( SCH_SYMBOL* symbol = ref.GetSymbol() )
updateDataStoreSymbolField( *symbol, aFieldName, &ref.GetSheetPath() );
}
}
@@ -54,30 +56,54 @@ void FIELDS_EDITOR_GRID_DATA_MODEL::AddColumn( const wxString& aFieldName, const
void FIELDS_EDITOR_GRID_DATA_MODEL::updateDataStoreSymbolField( const SCH_SYMBOL& aSymbol,
const wxString& aFieldName )
{
// Call the overloaded version with nullptr for sheet path (will use current sheet)
updateDataStoreSymbolField( aSymbol, aFieldName, nullptr );
}
void FIELDS_EDITOR_GRID_DATA_MODEL::updateDataStoreSymbolField( const SCH_SYMBOL& aSymbol,
const wxString& aFieldName,
const SCH_SHEET_PATH* aSheetPath )
{
// Get the sheet path - use the one provided or fall back to m_path
const SCH_SHEET_PATH& sheetPath = aSheetPath ? *aSheetPath : m_path;
KIID_PATH key = makeDataStoreKey( sheetPath, aSymbol );
if( isAttribute( aFieldName ) )
{
m_dataStore[aSymbol.m_Uuid][aFieldName] = getAttributeValue( aSymbol, aFieldName );
m_dataStore[key][aFieldName] = getAttributeValue( aSymbol, aFieldName );
}
else if( const SCH_FIELD* field = aSymbol.GetFieldByName( aFieldName ) )
{
if( field->IsPrivate() )
{
m_dataStore[aSymbol.m_Uuid][aFieldName] = wxEmptyString;
m_dataStore[key][aFieldName] = wxEmptyString;
return;
}
wxString value = aSymbol.Schematic()->ConvertKIIDsToRefs( field->GetText() );
m_dataStore[aSymbol.m_Uuid][aFieldName] = value;
// Use GetShownText() instead of GetText() to get the properly resolved value
// that includes text variable resolution and inherited library symbol values.
// This ensures BOM exports show the correct value that users see in the schematic.
wxString getText = field->GetText();
wxString getShownText = field->GetShownText( aSheetPath, false );
wxString value = aSymbol.Schematic()->ConvertKIIDsToRefs( getShownText );
wxLogTrace( "KICAD_FIELDS",
"Fields Table updateDataStore: Symbol %s, Field %s: GetText()='%s', "
"GetShownText()='%s', final='%s'",
aSymbol.GetRef( aSheetPath ), aFieldName, getText, getShownText, value );
m_dataStore[key][aFieldName] = value;
}
else if( IsGeneratedField( aFieldName ) )
{
// Handle generated fields with variables as names (e.g. ${QUANTITY}) that are not present in
// the symbol by giving them the correct value
m_dataStore[aSymbol.m_Uuid][aFieldName] = aFieldName;
m_dataStore[key][aFieldName] = aFieldName;
}
else
{
m_dataStore[aSymbol.m_Uuid][aFieldName] = wxEmptyString;
m_dataStore[key][aFieldName] = wxEmptyString;
}
}
@@ -86,8 +112,13 @@ void FIELDS_EDITOR_GRID_DATA_MODEL::RemoveColumn( int aCol )
{
for( unsigned i = 0; i < m_symbolsList.GetCount(); ++i )
{
if( SCH_SYMBOL* symbol = m_symbolsList[i].GetSymbol() )
m_dataStore[symbol->m_Uuid].erase( m_cols[aCol].m_fieldName );
const SCH_REFERENCE& ref = m_symbolsList[i];
if( SCH_SYMBOL* symbol = ref.GetSymbol() )
{
KIID_PATH key = makeDataStoreKey( ref );
m_dataStore[key].erase( m_cols[aCol].m_fieldName );
}
}
m_cols.erase( m_cols.begin() + aCol );
@@ -98,13 +129,14 @@ void FIELDS_EDITOR_GRID_DATA_MODEL::RenameColumn( int aCol, const wxString& newN
{
for( unsigned i = 0; i < m_symbolsList.GetCount(); ++i )
{
SCH_SYMBOL* symbol = m_symbolsList[i].GetSymbol();
const SCH_REFERENCE& ref = m_symbolsList[i];
KIID_PATH key = makeDataStoreKey( ref );
// Careful; field may have already been renamed from another sheet instance
if( auto node = m_dataStore[symbol->m_Uuid].extract( m_cols[aCol].m_fieldName ) )
if( auto node = m_dataStore[key].extract( m_cols[aCol].m_fieldName ) )
{
node.key() = newName;
m_dataStore[symbol->m_Uuid].insert( std::move( node ) );
m_dataStore[key].insert( std::move( node ) );
}
}
@@ -220,15 +252,20 @@ wxString FIELDS_EDITOR_GRID_DATA_MODEL::GetValue( const DATA_MODEL_ROW& group, i
}
else // Other columns are either a single value or ROW_MULTI_ITEMS
{
const KIID& symbolID = ref.GetSymbol()->m_Uuid;
KIID_PATH key = makeDataStoreKey( ref );
if( !m_dataStore.count( symbolID )
|| !m_dataStore[symbolID].count( m_cols[aCol].m_fieldName ) )
if( !m_dataStore.count( key )
|| !m_dataStore[key].count( m_cols[aCol].m_fieldName ) )
{
return INDETERMINATE_STATE;
}
wxString refFieldValue = m_dataStore[symbolID][m_cols[aCol].m_fieldName];
wxString refFieldValue = m_dataStore[key][m_cols[aCol].m_fieldName];
wxLogTrace( "KICAD_FIELDS",
"GetValue: Symbol %s (UUID %s, Path %s), Field %s = '%s' (from m_dataStore)",
ref.GetRef(), ref.GetSymbol()->m_Uuid.AsString(),
ref.GetSheetPath().PathAsString(), m_cols[aCol].m_fieldName, refFieldValue );
if( resolveVars )
{
@@ -310,6 +347,10 @@ wxString FIELDS_EDITOR_GRID_DATA_MODEL::GetValue( const DATA_MODEL_ROW& group, i
else if( ColIsItemNumber( aCol ) && group.m_Flag != CHILD_ITEM )
fieldValue = wxString::Format( wxT( "%d" ), group.m_ItemNumber );
wxLogTrace( "KICAD_FIELDS",
"GetValue returning: Col %d (%s), Group refs=%zu, Final Value = '%s'",
aCol, m_cols[aCol].m_fieldName, group.m_Refs.size(), fieldValue );
return fieldValue;
}
@@ -327,8 +368,45 @@ void FIELDS_EDITOR_GRID_DATA_MODEL::SetValue( int aRow, int aCol, const wxString
DATA_MODEL_ROW& rowGroup = m_rows[aRow];
const SCH_SYMBOL* sharedSymbol = nullptr;
bool isSharedInstance = false;
for( const SCH_REFERENCE& ref : rowGroup.m_Refs )
m_dataStore[ref.GetSymbol()->m_Uuid][m_cols[aCol].m_fieldName] = aValue;
{
const SCH_SCREEN* screen = nullptr;
// Check to see if the symbol associated with this row has more than one instance.
if( const SCH_SYMBOL* symbol = ref.GetSymbol() )
{
screen = static_cast<const SCH_SCREEN*>( symbol->GetParent() );
isSharedInstance = ( screen && ( screen->GetRefCount() > 1 ) );
sharedSymbol = symbol;
}
KIID_PATH key = makeDataStoreKey( ref.GetSheetPath(), *ref.GetSymbol() );
m_dataStore[key][m_cols[aCol].m_fieldName] = aValue;
}
// Update all of the other instances for the shared symbol as required.
if( isSharedInstance
&& ( ( rowGroup.m_Flag == GROUP_SINGLETON ) || ( rowGroup.m_Flag == CHILD_ITEM ) ) )
{
for( DATA_MODEL_ROW& row : m_rows )
{
if( row.m_ItemNumber == aRow + 1 )
continue;
for( const SCH_REFERENCE& ref : row.m_Refs )
{
if( ref.GetSymbol() != sharedSymbol )
continue;
KIID_PATH key = makeDataStoreKey( ref.GetSheetPath(), *ref.GetSymbol() );
m_dataStore[key][m_cols[aCol].m_fieldName] = aValue;
}
}
}
m_edited = true;
}
@@ -436,6 +514,7 @@ void FIELDS_EDITOR_GRID_DATA_MODEL::Sort()
// Time to renumber the item numbers
int itemNumber = 1;
for( DATA_MODEL_ROW& row : m_rows )
{
row.m_ItemNumber = itemNumber++;
@@ -477,8 +556,8 @@ bool FIELDS_EDITOR_GRID_DATA_MODEL::groupMatch( const SCH_REFERENCE& lhRef,
matchFound = true;
}
const KIID& lhRefID = lhRef.GetSymbol()->m_Uuid;
const KIID& rhRefID = rhRef.GetSymbol()->m_Uuid;
KIID_PATH lhKey = makeDataStoreKey( lhRef );
KIID_PATH rhKey = makeDataStoreKey( rhRef );
// Now check all the other columns.
for( size_t i = 0; i < m_cols.size(); ++i )
@@ -496,23 +575,23 @@ bool FIELDS_EDITOR_GRID_DATA_MODEL::groupMatch( const SCH_REFERENCE& lhRef,
wxString lh, rh;
if( IsGeneratedField( m_cols[i].m_fieldName )
|| IsGeneratedField( m_dataStore[lhRefID][m_cols[i].m_fieldName] ) )
|| IsGeneratedField( m_dataStore[lhKey][m_cols[i].m_fieldName] ) )
{
lh = getFieldShownText( lhRef, m_cols[i].m_fieldName );
}
else
{
lh = m_dataStore[lhRefID][m_cols[i].m_fieldName];
lh = m_dataStore[lhKey][m_cols[i].m_fieldName];
}
if( IsGeneratedField( m_cols[i].m_fieldName )
|| IsGeneratedField( m_dataStore[rhRefID][m_cols[i].m_fieldName] ) )
|| IsGeneratedField( m_dataStore[rhKey][m_cols[i].m_fieldName] ) )
{
rh = getFieldShownText( rhRef, m_cols[i].m_fieldName );
}
else
{
rh = m_dataStore[rhRefID][m_cols[i].m_fieldName];
rh = m_dataStore[rhKey][m_cols[i].m_fieldName];
}
wxString fieldName = m_cols[i].m_fieldName;
@@ -805,11 +884,13 @@ void FIELDS_EDITOR_GRID_DATA_MODEL::ApplyData( SCH_COMMIT& aCommit, TEMPLATES& a
{
for( unsigned i = 0; i < m_symbolsList.GetCount(); ++i )
{
SCH_SYMBOL& symbol = *m_symbolsList[i].GetSymbol();
const SCH_REFERENCE& ref = m_symbolsList[i];
SCH_SYMBOL& symbol = *ref.GetSymbol();
aCommit.Modify( &symbol, m_symbolsList[i].GetSheetPath().LastScreen() );
aCommit.Modify( &symbol, ref.GetSheetPath().LastScreen() );
const std::map<wxString, wxString>& fieldStore = m_dataStore[symbol.m_Uuid];
KIID_PATH key = makeDataStoreKey( ref );
const std::map<wxString, wxString>& fieldStore = m_dataStore[key];
for( const auto& [srcName, srcValue] : fieldStore )
{
@@ -894,8 +975,8 @@ int FIELDS_EDITOR_GRID_DATA_MODEL::GetDataWidth( int aCol )
for( unsigned symbolRef = 0; symbolRef < m_symbolsList.GetCount(); ++symbolRef )
{
const KIID& symbolID = m_symbolsList[symbolRef].GetSymbol()->m_Uuid;
wxString text = m_dataStore[symbolID][fieldName];
KIID_PATH key = makeDataStoreKey( m_symbolsList[symbolRef] );
wxString text = m_dataStore[key][fieldName];
width = std::max( width, KIUI::GetTextSize( text, GetView() ).x );
}
@@ -1077,9 +1158,14 @@ void FIELDS_EDITOR_GRID_DATA_MODEL::AddReferences( const SCH_REFERENCE_LIST& aRe
if( !field.IsPrivate() )
{
wxString name = field.GetCanonicalName();
wxString value = symbol->Schematic()->ConvertKIIDsToRefs( field.GetText() );
// Use GetShownText() instead of GetText() to get the properly resolved value
// that includes text variable resolution and inherited library symbol values.
// This ensures BOM exports show the correct value that users see in the schematic.
wxString value = symbol->Schematic()->ConvertKIIDsToRefs(
field.GetShownText( &ref.GetSheetPath(), false ) );
m_dataStore[symbol->m_Uuid][name] = value;
KIID_PATH key = makeDataStoreKey( ref );
m_dataStore[key][name] = value;
}
}
}
@@ -1092,7 +1178,21 @@ void FIELDS_EDITOR_GRID_DATA_MODEL::RemoveSymbol( const SCH_SYMBOL& aSymbol )
// The schematic event listener passes us the symbol after it has been removed,
// so we can't just work with a SCH_REFERENCE_LIST like the other handlers as the
// references are already gone. Instead we need to prune our list.
m_dataStore[aSymbol.m_Uuid].clear();
// We need to remove all instances of this symbol from all sheet paths.
auto it = m_dataStore.begin();
while( it != m_dataStore.end() )
{
// The key is a KIID_PATH string; check if it ends with this symbol's UUID
// by checking if the key ends with "/" + UUID
wxString symbolUuidStr = "/" + aSymbol.m_Uuid.AsString();
if( it->first.EndsWith( symbolUuidStr ) )
it = m_dataStore.erase( it );
else
++it;
}
// Remove all refs that match this symbol using remove_if
m_symbolsList.erase( std::remove_if( m_symbolsList.begin(), m_symbolsList.end(),
@@ -1114,9 +1214,9 @@ void FIELDS_EDITOR_GRID_DATA_MODEL::RemoveReferences( const SCH_REFERENCE_LIST&
{
m_symbolsList.RemoveItem( index );
// If we're out of instances then remove the symbol, too
if( ref.GetSymbol()->GetInstances().empty() )
m_dataStore.erase( ref.GetSymbol()->m_Uuid );
// Remove this specific instance from the data store
KIID_PATH key = makeDataStoreKey( ref );
m_dataStore.erase( key );
}
}
}
@@ -1130,7 +1230,7 @@ void FIELDS_EDITOR_GRID_DATA_MODEL::UpdateReferences( const SCH_REFERENCE_LIST&
// columns; we must have all fields in the symbol added to the data model at this point,
// and some of the data model columns may be variables that are not present in the symbol
for( const DATA_MODEL_COL& col : m_cols )
updateDataStoreSymbolField( *ref.GetSymbol(), col.m_fieldName );
updateDataStoreSymbolField( *ref.GetSymbol(), col.m_fieldName, &ref.GetSheetPath() );
if( !m_symbolsList.Contains( ref ) )
m_symbolsList.AddItem( ref );
+25 -2
View File
@@ -302,11 +302,32 @@ private:
* Example: BOM template provides ${DNP} as a field, but they symbol doesn't have the field. */
wxString getFieldShownText( const SCH_REFERENCE& aRef, const wxString& aFieldName );
/**
* Create a composite key for the data store using sheet path and symbol UUID.
* This is necessary for hierarchical designs where the same symbol (same UUID)
* is instantiated in multiple sheets with different field values.
*
* The key is a string representation of the full KIID_PATH including the symbol's UUID.
*/
KIID_PATH makeDataStoreKey( const SCH_SHEET_PATH& aSheetPath, const SCH_SYMBOL& aSymbol ) const
{
KIID_PATH path = aSheetPath.Path();
path.push_back( aSymbol.m_Uuid );
return path;
}
KIID_PATH makeDataStoreKey( const SCH_REFERENCE& aRef ) const
{
return makeDataStoreKey( aRef.GetSheetPath(), *aRef.GetSymbol() );
}
void Sort();
SCH_REFERENCE_LIST getSymbolReferences( SCH_SYMBOL* aSymbol );
void storeReferenceFields( SCH_REFERENCE& aRef );
void updateDataStoreSymbolField( const SCH_SYMBOL& aSymbol, const wxString& aFieldName );
void updateDataStoreSymbolField( const SCH_SYMBOL& aSymbol, const wxString& aFieldName,
const SCH_SHEET_PATH* aSheetPath );
protected:
SCH_REFERENCE_LIST m_symbolsList;
@@ -329,6 +350,8 @@ protected:
// Data store
// The data model is fundamentally m_componentRefs X m_fieldNames.
// A map of compID : fieldSet, where fieldSet is a map of fieldName : fieldValue
std::map<KIID, std::map<wxString, wxString>> m_dataStore;
// For hierarchical designs, symbols can be instantiated in multiple sheets with the same UUID,
// so we use a composite key containing the full KIID_PATH (sheet path + symbol UUID).
// This ensures each hierarchical instance maintains its own distinct field values.
std::map<KIID_PATH, std::map<wxString, wxString>> m_dataStore;
};
+144 -24
View File
@@ -225,6 +225,15 @@ int FIELDS_GRID_TABLE::GetMandatoryRowCount() const
}
void FIELDS_GRID_TABLE::push_back( const SCH_FIELD& aField )
{
std::vector<SCH_FIELD>::push_back( aField );
m_isInherited.resize( size() );
m_parentFields.resize( size() );
}
void FIELDS_GRID_TABLE::initGrid( WX_GRID* aGrid )
{
// Build the various grid cell attributes.
@@ -399,6 +408,9 @@ FIELDS_GRID_TABLE::~FIELDS_GRID_TABLE()
m_fontAttr->DecRef();
m_colorAttr->DecRef();
for( SCH_FIELD& field : m_parentFields )
field.SetParent( nullptr );
m_frame->Unbind( EDA_EVT_UNITS_CHANGED, &FIELDS_GRID_TABLE::onUnitsChanged, this );
}
@@ -538,33 +550,34 @@ wxGridCellAttr* FIELDS_GRID_TABLE::GetAttr( int aRow, int aCol, wxGridCellAttr::
wxCHECK( aRow < GetNumberRows(), nullptr );
const SCH_FIELD& field = getField( aRow );
wxGridCellAttr* tmp;
wxGridCellAttr* attr = nullptr;
switch( aCol )
{
case FDC_NAME:
if( field.IsMandatory() )
{
tmp = m_fieldNameAttr->Clone();
tmp->SetReadOnly( true );
return enhanceAttr( tmp, aRow, aCol, aKind );
attr = m_fieldNameAttr->Clone();
attr->SetReadOnly( true );
}
else
{
m_fieldNameAttr->IncRef();
return enhanceAttr( m_fieldNameAttr, aRow, aCol, aKind );
attr = m_fieldNameAttr;
}
break;
case FDC_VALUE:
if( m_parentType == SCH_SYMBOL_T && field.GetId() == REFERENCE_FIELD )
{
m_referenceAttr->IncRef();
return enhanceAttr( m_referenceAttr, aRow, aCol, aKind );
attr = m_referenceAttr;
}
else if( m_parentType == SCH_SYMBOL_T && field.GetId() == VALUE_FIELD )
{
m_valueAttr->IncRef();
return enhanceAttr( m_valueAttr, aRow, aCol, aKind );
attr = m_valueAttr;
}
else if( m_parentType == SCH_SYMBOL_T && field.GetId() == FOOTPRINT_FIELD )
{
@@ -574,34 +587,34 @@ wxGridCellAttr* FIELDS_GRID_TABLE::GetAttr( int aRow, int aCol, wxGridCellAttr::
if( m_part && m_part->IsPower() )
{
m_readOnlyAttr->IncRef();
return enhanceAttr( m_readOnlyAttr, aRow, aCol, aKind );
attr = m_readOnlyAttr;
}
else
{
m_footprintAttr->IncRef();
return enhanceAttr( m_footprintAttr, aRow, aCol, aKind );
attr = m_footprintAttr;
}
}
else if( m_parentType == SCH_SYMBOL_T && field.GetId() == DATASHEET_FIELD )
{
m_urlAttr->IncRef();
return enhanceAttr( m_urlAttr, aRow, aCol, aKind );
attr = m_urlAttr;
}
else if( m_parentType == SCH_SHEET_T && field.GetId() == SHEETNAME )
{
m_referenceAttr->IncRef();
return enhanceAttr( m_referenceAttr, aRow, aCol, aKind );
attr = m_referenceAttr;
}
else if( m_parentType == SCH_SHEET_T && field.GetId() == SHEETFILENAME )
{
m_filepathAttr->IncRef();
return enhanceAttr( m_filepathAttr, aRow, aCol, aKind );
attr = m_filepathAttr;
}
else if( ( m_parentType == SCH_LABEL_LOCATE_ANY_T )
&& field.GetCanonicalName() == wxT( "Netclass" ) )
{
m_netclassAttr->IncRef();
return enhanceAttr( m_netclassAttr, aRow, aCol, aKind );
attr = m_netclassAttr;
}
else
{
@@ -615,31 +628,36 @@ wxGridCellAttr* FIELDS_GRID_TABLE::GetAttr( int aRow, int aCol, wxGridCellAttr::
if( ( templateFn && templateFn->m_URL ) || field.IsHypertext() )
{
m_urlAttr->IncRef();
return enhanceAttr( m_urlAttr, aRow, aCol, aKind );
attr = m_urlAttr;
}
else
{
m_nonUrlAttr->IncRef();
return enhanceAttr( m_nonUrlAttr, aRow, aCol, aKind );
attr = m_nonUrlAttr;
}
}
break;
case FDC_TEXT_SIZE:
case FDC_POSX:
case FDC_POSY:
return enhanceAttr( nullptr, aRow, aCol, aKind );
break;
case FDC_H_ALIGN:
m_hAlignAttr->IncRef();
return enhanceAttr( m_hAlignAttr, aRow, aCol, aKind );
attr = m_hAlignAttr;
break;
case FDC_V_ALIGN:
m_vAlignAttr->IncRef();
return enhanceAttr( m_vAlignAttr, aRow, aCol, aKind );
attr = m_vAlignAttr;
break;
case FDC_ORIENTATION:
m_orientationAttr->IncRef();
return enhanceAttr( m_orientationAttr, aRow, aCol, aKind );
attr = m_orientationAttr;
break;
case FDC_SHOWN:
case FDC_SHOW_NAME:
@@ -648,20 +666,50 @@ wxGridCellAttr* FIELDS_GRID_TABLE::GetAttr( int aRow, int aCol, wxGridCellAttr::
case FDC_ALLOW_AUTOPLACE:
case FDC_PRIVATE:
m_boolAttr->IncRef();
return enhanceAttr( m_boolAttr, aRow, aCol, aKind );
attr = m_boolAttr;
break;
case FDC_FONT:
m_fontAttr->IncRef();
return enhanceAttr( m_fontAttr, aRow, aCol, aKind );
attr = m_fontAttr;
break;
case FDC_COLOR:
m_colorAttr->IncRef();
return enhanceAttr( m_colorAttr, aRow, aCol, aKind );
attr = m_colorAttr;
break;
default:
wxFAIL;
return enhanceAttr( nullptr, aRow, aCol, aKind );
attr = nullptr;
break;
}
if( !attr )
return nullptr;
attr = enhanceAttr( attr, aRow, aCol, aKind );
if( IsInherited( aRow ) )
{
wxGridCellAttr* text_attr = attr ? attr->Clone() : new wxGridCellAttr;
wxFont font;
if( !text_attr->HasFont() )
font = wxSystemSettings::GetFont( wxSYS_DEFAULT_GUI_FONT );
else
font = text_attr->GetFont();
font.MakeItalic();
text_attr->SetFont( font );
text_attr->SetTextColour( wxSystemSettings::GetColour( wxSYS_COLOUR_GRAYTEXT ) );
if( attr )
attr->DecRef();
attr = text_attr;
}
return attr;
}
@@ -1042,10 +1090,82 @@ bool FIELDS_GRID_TABLE::BoolFromString( const wxString& aValue ) const
}
SCH_FIELD* FIELDS_GRID_TABLE::GetField( MANDATORY_FIELD_T aFieldId )
{
for( SCH_FIELD& field : *this )
{
if( field.GetId() == aFieldId )
return &field;
}
return nullptr;
}
int FIELDS_GRID_TABLE::GetFieldRow( MANDATORY_FIELD_T aFieldId )
{
for( int ii = 0; ii < (int) this->size(); ++ii )
{
if( this->at( ii ).GetId() == aFieldId )
return ii;
}
return -1;
}
void FIELDS_GRID_TABLE::AddInheritedField( const SCH_FIELD& aParent )
{
push_back( aParent );
back().SetParent( m_part );
m_isInherited.back() = true;
m_parentFields.back() = aParent;
}
bool FIELDS_GRID_TABLE::EraseRow( size_t aRow )
{
if( m_isInherited.size() > aRow )
{
// You can't erase inherited fields, but you can reset them to the parent value.
if( m_isInherited[aRow] )
{
at( aRow ) = m_parentFields[aRow];
return false;
}
m_isInherited.erase( m_isInherited.begin() + aRow );
}
if( m_parentFields.size() > aRow )
m_parentFields.erase( m_parentFields.begin() + aRow );
std::vector<SCH_FIELD>::erase( begin() + aRow );
return true;
}
void FIELDS_GRID_TABLE::SwapRows( size_t a, size_t b )
{
wxCHECK( a < this->size() && b < this->size(), /*void*/ );
std::swap( at( a ), at( b ) );
bool tmpInherited = m_isInherited[a];
m_isInherited[a] = m_isInherited[b];
m_isInherited[b] = tmpInherited;
std::swap( m_parentFields[a], m_parentFields[b] );
}
void FIELDS_GRID_TABLE::DetachFields()
{
for( SCH_FIELD& field : *this )
field.SetParent( nullptr );
for( SCH_FIELD& field : m_parentFields )
field.SetParent( nullptr );
}
+35
View File
@@ -28,6 +28,7 @@
#include <sch_symbol.h>
#include <grid_tricks.h>
#include <validators.h>
#include <vector>
class SCH_BASE_FRAME;
class DIALOG_SHIM;
@@ -120,6 +121,37 @@ public:
wxString StringFromBool( bool aValue ) const;
bool BoolFromString( const wxString& aValue ) const;
SCH_FIELD* GetField( MANDATORY_FIELD_T aFieldId );
int GetFieldRow( MANDATORY_FIELD_T aFieldId );
void AddInheritedField( const SCH_FIELD& aParent );
void SetFieldInherited( size_t aRow, const SCH_FIELD& aParent )
{
m_isInherited.resize( aRow + 1, false );
m_parentFields.resize( aRow + 1 );
m_parentFields[aRow] = aParent;
m_isInherited[aRow] = true;
}
bool IsInherited( size_t aRow ) const
{
if( aRow >= m_isInherited.size() || aRow >= m_parentFields.size() )
return false;
return m_isInherited[aRow] && m_parentFields[aRow].GetText() == at( aRow ).GetText();
}
const SCH_FIELD& ParentField( size_t row ) const { return m_parentFields[row]; }
void push_back( const SCH_FIELD& field );
// For std::vector compatibility, but we don't use it directly.
void emplace_back( const SCH_FIELD& field ) { push_back( field ); }
bool EraseRow( size_t row );
void SwapRows( size_t a, size_t b );
void DetachFields();
protected:
@@ -164,6 +196,9 @@ private:
wxGridCellAttr* m_fontAttr;
wxGridCellAttr* m_colorAttr;
std::vector<bool> m_isInherited;
std::vector<SCH_FIELD> m_parentFields;
std::unique_ptr<NUMERIC_EVALUATOR> m_eval;
std::map< std::pair<int, int>, wxString > m_evalOriginal;
};
+25 -1
View File
@@ -1230,8 +1230,18 @@ bool SCH_EDIT_FRAME::doAutoSave()
if( !tmp.IsOk() )
return false;
if( !IsWritable( tmp ) )
if( !IsWritable( tmp, false ) )
{
if( !m_autoSavePermissionError )
{
DisplayError( this, wxString::Format(
_( "Could not autosave files to read-only folder: '%s'" ),
tmp.GetPath() ) );
m_autoSavePermissionError = true;
}
return false;
}
wxString title = GetTitle(); // Save frame title, that can be modified by the save process
@@ -1246,6 +1256,20 @@ bool SCH_EDIT_FRAME::doAutoSave()
// Auto save file name is the normal file name prefixed with GetAutoSavePrefix().
fn.SetName( FILEEXT::AutoSaveFilePrefix + fn.GetName() );
if( !IsWritable( fn, false ) )
{
if( !m_autoSavePermissionError )
{
DisplayError( this, wxString::Format(
_( "Could not autosave files to read-only folder: '%s'" ),
fn.GetPath() ) );
m_autoSavePermissionError = true;
}
autoSaveOk = false;
continue;
}
if( saveSchematicFile( screens.GetSheet( i ), fn.GetFullPath() ) )
{
// This was only an auto-save, not a real save. Reset the modified flag.
File diff suppressed because it is too large Load Diff
+344
View File
@@ -0,0 +1,344 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2024 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <sch_reference_list.h>
#include <wx/grid.h>
#include <wx/arrstr.h>
#include <widgets/grid_striped_renderer.h>
// The field name in the data model (translated)
#define DISPLAY_NAME_COLUMN 0
// The field name's label for exporting (CSV, etc.)
#define LABEL_COLUMN 1
#define SHOW_FIELD_COLUMN 2
#define GROUP_BY_COLUMN 3
// The internal field name (untranslated)
#define FIELD_NAME_COLUMN 4
struct BOM_FIELD;
struct BOM_PRESET;
struct BOM_FMT_PRESET;
enum GROUP_TYPE
{
GROUP_SINGLETON,
GROUP_COLLAPSED,
GROUP_COLLAPSED_DURING_SORT,
GROUP_EXPANDED,
CHILD_ITEM
};
struct LIB_DATA_MODEL_ROW
{
LIB_DATA_MODEL_ROW( const LIB_SYMBOL* aFirstReference, GROUP_TYPE aType )
: m_ItemNumber( 0 ), m_Flag( aType ), m_Refs( { aFirstReference } )
{
}
int m_ItemNumber;
GROUP_TYPE m_Flag;
std::vector<const LIB_SYMBOL*> m_Refs;
};
struct LIB_DATA_MODEL_COL
{
wxString m_fieldName;
wxString m_label;
bool m_userAdded;
bool m_show;
bool m_group;
bool m_isCheckbox;
};
struct LIB_DATA_ELEMENT
{
LIB_DATA_ELEMENT()
{
m_originalData = wxEmptyString;
m_currentData = wxEmptyString;
m_originallyEmpty = false;
m_currentlyEmpty = false;
m_isModified = false;
m_isStriped = false;
m_createDerivedSymbol = false;
m_derivedSymbolName = wxEmptyString;
}
wxString m_originalData;
wxString m_currentData;
bool m_originallyEmpty;
bool m_currentlyEmpty;
bool m_isModified;
bool m_isStriped;
bool m_createDerivedSymbol;
wxString m_derivedSymbolName;
};
class LIB_FIELDS_EDITOR_GRID_DATA_MODEL : public wxGridTableBase
{
public:
enum SCOPE : int
{
SCOPE_ALL = 0,
SCOPE_SHEET = 1,
SCOPE_SHEET_RECURSIVE = 2
};
LIB_FIELDS_EDITOR_GRID_DATA_MODEL( const std::vector<LIB_SYMBOL*>& aSymbolsList ) :
m_symbolsList( aSymbolsList ), m_edited( false ), m_sortColumn( 0 ),
m_sortAscending( false ), m_filter( wxEmptyString ), m_scope( SCOPE_ALL ),
m_path(), m_groupingEnabled( false ), m_cols(), m_rows(),
m_dataStore(), m_stripedStringRenderer( nullptr )
{
}
~LIB_FIELDS_EDITOR_GRID_DATA_MODEL()
{
for (auto& pair : m_stripedRenderers)
pair.second->DecRef();
m_stripedRenderers.clear();
for( const auto& [col, attr] : m_colAttrs )
wxSafeDecRef( attr );
}
static const wxString QUANTITY_VARIABLE;
static const wxString ITEM_NUMBER_VARIABLE;
void CreateDerivedSymbol( int aRow, int aCol, wxString& aNewSymbolName );
void CreateDerivedSymbolImmediate( int aRow, int aCol, wxString& aNewSymbolName );
void AddColumn( const wxString& aFieldName, const wxString& aLabel, bool aAddedByUser, bool aIsCheckbox );
void RemoveColumn( int aCol );
void RenameColumn( int aCol, const wxString& newName );
void MoveColumn( int aCol, int aNewPos )
{
wxCHECK_RET( aCol >= 0 && aCol < (int) m_cols.size(), "Invalid Column Number" );
if( aCol == aNewPos )
return;
else if( aCol < aNewPos )
std::rotate( std::begin( m_cols ) + aCol, std::begin( m_cols ) + aCol + 1,
std::begin( m_cols ) + aNewPos + 1 );
else
std::rotate( std::begin( m_cols ) + aNewPos, std::begin( m_cols ) + aCol,
std::begin( m_cols ) + aCol + 1 );
}
int GetNumberRows() override { return (int) m_rows.size(); }
int GetNumberCols() override { return (int) m_cols.size(); }
void SetColLabelValue( int aCol, const wxString& aLabel ) override
{
wxCHECK_RET( aCol >= 0 && aCol < (int) m_cols.size(), "Invalid Column Number" );
m_cols[aCol].m_label = aLabel;
}
wxString GetColLabelValue( int aCol ) override
{
wxCHECK( aCol >= 0 && aCol < (int) m_cols.size(), wxString() );
return m_cols[aCol].m_label;
}
wxString GetColFieldName( int aCol )
{
wxCHECK( aCol >= 0 && aCol < (int) m_cols.size(), wxString() );
return m_cols[aCol].m_fieldName;
}
int GetFieldNameCol( wxString aFieldName );
void SetFieldsOrder( const std::vector<wxString>& aNewOrder );
bool IsEmptyCell( int aRow, int aCol ) override
{
return false; // don't allow adjacent cell overflow, even if we are actually empty
}
wxString GetValue( int aRow, int aCol ) override;
wxString GetTypeName( int row, int col ) override;
wxString GetValue( const LIB_DATA_MODEL_ROW& group, int aCol );
void SetValue( int aRow, int aCol, const wxString& aValue ) override;
wxGridCellAttr* GetAttr( int row, int col, wxGridCellAttr::wxAttrKind kind ) override;
void RevertRow( int aRow );
void ClearCell( int aRow, int aCol );
bool ColIsValue( int aCol );
bool ColIsCheck( int aCol );
void SetSorting( int aCol, bool ascending )
{
wxCHECK_RET( aCol >= 0 && aCol < (int) m_cols.size(), "Invalid Column Number" );
m_sortColumn = aCol;
m_sortAscending = ascending;
}
int GetSortCol() { return m_sortColumn; }
bool GetSortAsc() { return m_sortAscending; }
const LIB_SYMBOL* GetSymbolForRow( int aRow )
{
wxCHECK( aRow >= 0 && aRow < (int) m_rows.size(), nullptr );
return m_rows[aRow].m_Refs[0];
}
void GetSymbolNames( wxArrayString& aList )
{
aList.Clear();
for( const LIB_SYMBOL* symbol : m_symbolsList )
aList.Add( symbol->GetName() );
}
void RebuildRows();
void ExpandRow( int aRow );
void CollapseRow( int aRow );
void ExpandCollapseRow( int aRow );
void CollapseForSort();
void ExpandAfterSort();
void ApplyData( std::function<void( LIB_SYMBOL* )> symbolChangeHandler,
std::function<void()> postApplyHandler = nullptr );
/// Get and clear the list of newly created derived symbols for library manager processing
std::vector<std::pair<LIB_SYMBOL*, wxString>> GetAndClearCreatedDerivedSymbols()
{
auto result = std::move( m_createdDerivedSymbols );
m_createdDerivedSymbols.clear();
return result;
}
bool IsEdited() { return m_edited; }
int GetDataWidth( int aCol );
void SetFilter( const wxString& aFilter ) { m_filter = aFilter; }
const wxString& GetFilter() { return m_filter; }
void SetGroupingEnabled( bool group ) { m_groupingEnabled = group; }
bool GetGroupingEnabled() { return m_groupingEnabled; }
void SetGroupColumn( int aCol, bool group )
{
wxCHECK_RET( aCol >= 0 && aCol < (int) m_cols.size(), "Invalid Column Number" );
m_cols[aCol].m_group = group;
}
bool GetGroupColumn( int aCol )
{
wxCHECK_MSG( aCol >= 0 && aCol < (int) m_cols.size(), false, "Invalid Column Number" );
return m_cols[aCol].m_group;
}
void SetShowColumn( int aCol, bool show )
{
wxCHECK_RET( aCol >= 0 && aCol < (int) m_cols.size(), "Invalid Column Number" );
m_cols[aCol].m_show = show;
}
bool GetShowColumn( int aCol )
{
wxCHECK_MSG( aCol >= 0 && aCol < (int) m_cols.size(), false, "Invalid Column Number" );
return m_cols[aCol].m_show;
}
bool IsRowEditable( int aRow )
{
wxCHECK_MSG( aRow >= 0 && aRow < (int) m_rows.size(), false, "Invalid Row Number" );
return m_rows[aRow].m_Flag == GROUP_SINGLETON || m_rows[aRow].m_Flag == GROUP_SINGLETON;
}
bool IsCellEdited( int aRow, int aCol )
{
wxCHECK_MSG( aRow >= 0 && aRow < (int) m_rows.size(), false, "Invalid Row Number" );
wxCHECK_MSG( aCol >= 0 && aCol < (int) m_cols.size(), false, "Invalid Column Number" );
return m_dataStore[m_rows[aRow].m_Refs[0]->m_Uuid][m_cols[aCol].m_fieldName].m_isModified;
}
bool IsCellClear( int aRow, int aCol )
{
wxCHECK_MSG( aRow >= 0 && aRow < (int) m_rows.size(), false, "Invalid Row Number" );
wxCHECK_MSG( aCol >= 0 && aCol < (int) m_cols.size(), false, "Invalid Column Number" );
return m_dataStore[m_rows[aRow].m_Refs[0]->m_Uuid][m_cols[aCol].m_fieldName].m_currentlyEmpty;
}
bool IsRowSingleSymbol( int aRow )
{
wxCHECK_MSG( aRow >= 0 && aRow < (int) m_rows.size(), false, "Invalid Row Number" );
return m_rows[aRow].m_Flag == GROUP_SINGLETON || m_rows[aRow].m_Flag == CHILD_ITEM;
}
void SetColAttr( wxGridCellAttr* aAttr, int aCol ) override
{
wxSafeDecRef( m_colAttrs[aCol] );
m_colAttrs[aCol] = aAttr;
}
private:
static bool cmp( const LIB_DATA_MODEL_ROW& lhGroup, const LIB_DATA_MODEL_ROW& rhGroup,
LIB_FIELDS_EDITOR_GRID_DATA_MODEL* dataModel, int sortCol, bool ascending );
bool groupMatch( const LIB_SYMBOL* lhRef, const LIB_SYMBOL* rhRef );
wxString getAttributeValue( const LIB_SYMBOL*, const wxString& aAttributeName );
void setAttributeValue( LIB_SYMBOL* aSymbol, const wxString& aAttributeName,
const wxString& aValue );
void createActualDerivedSymbol( const LIB_SYMBOL* aParentSymbol, const wxString& aNewSymbolName,
const KIID& aNewSymbolUuid );
void Sort();
void updateDataStoreSymbolField( const LIB_SYMBOL* aSymbol, const wxString& aFieldName );
bool isStripeableField( int aCol );
wxGridCellRenderer* getStripedRenderer( int aCol ) const;
protected:
std::vector<LIB_SYMBOL*> m_symbolsList;
bool m_edited;
int m_sortColumn;
bool m_sortAscending;
wxString m_filter;
enum SCOPE m_scope;
SCH_SHEET_PATH m_path;
bool m_groupingEnabled;
std::vector<LIB_DATA_MODEL_COL> m_cols;
std::vector<LIB_DATA_MODEL_ROW> m_rows;
// Data store
// The data model is fundamentally m_componentRefs X m_fieldNames.
// A map of compID : fieldSet, where fieldSet is a map of fieldName : LIB_DATA_ELEMENT
std::map<KIID, std::map<wxString, LIB_DATA_ELEMENT>> m_dataStore;
// Track newly created derived symbols for library manager integration
std::vector<std::pair<LIB_SYMBOL*, wxString>> m_createdDerivedSymbols; // symbol, library name
// stripe bitmap support
mutable STRIPED_STRING_RENDERER* m_stripedStringRenderer;
mutable std::map<wxString, wxGridCellRenderer*> m_stripedRenderers;
// Column attributes storage
std::map<int, wxGridCellAttr*> m_colAttrs;
};
+31 -20
View File
@@ -281,24 +281,31 @@ LIB_SYMBOL_SPTR LIB_SYMBOL::GetRootSymbol() const
}
wxString LIB_SYMBOL::GetUnitReference( int aUnit )
{
return LIB_SYMBOL::LetterSubReference( aUnit, 'A' );
}
bool LIB_SYMBOL::HasUnitDisplayName( int aUnit )
bool LIB_SYMBOL::HasUnitDisplayName( int aUnit ) const
{
return ( m_unitDisplayNames.count( aUnit ) == 1 );
}
wxString LIB_SYMBOL::GetUnitDisplayName( int aUnit )
wxString LIB_SYMBOL::GetUnitDisplayName( int aUnit, bool aLabel ) const
{
if( HasUnitDisplayName( aUnit ) )
return m_unitDisplayNames[aUnit];
if( m_unitDisplayNames.contains( aUnit ) )
return m_unitDisplayNames.at( aUnit );
else if( aLabel )
return wxString::Format( _( "Unit %s" ), LIB_SYMBOL::LetterSubReference( aUnit, 'A' ) );
else
return wxString::Format( _( "Unit %s" ), GetUnitReference( aUnit ) );
return LIB_SYMBOL::LetterSubReference( aUnit, 'A' );
}
wxString LIB_SYMBOL::GetBodyStyleDescription( int aBodyStyle, bool aLabel ) const
{
if( aBodyStyle == BODY_STYLE::DEMORGAN )
return aLabel ? _( "Alternate" ) : wxString( _HKI( "Alternate" ) );
else if( aBodyStyle == BODY_STYLE::BASE )
return aLabel ? _( "Standard" ) : wxString( _HKI( "Standard" ) );
else
return wxT( "?" );
}
@@ -480,7 +487,7 @@ void LIB_SYMBOL::SetNormal()
}
wxString LIB_SYMBOL::LetterSubReference( int aUnit, int aFirstId )
wxString LIB_SYMBOL::LetterSubReference( int aUnit, wxChar aInitialLetter )
{
// use letters as notation. To allow more than 26 units, the sub ref
// use one letter if letter = A .. Z or a ... z, and 2 letters otherwise
@@ -491,7 +498,7 @@ wxString LIB_SYMBOL::LetterSubReference( int aUnit, int aFirstId )
do
{
u = ( aUnit - 1 ) % 26;
suffix = wxChar( aFirstId + u ) + suffix;
suffix = wxChar( aInitialLetter + u ) + suffix;
aUnit = ( aUnit - u ) / 26;
} while( aUnit > 0 );
@@ -1419,14 +1426,18 @@ void LIB_SYMBOL::SetUnitCount( int aCount, bool aDuplicateDrawItems )
if( aCount < m_unitCount )
{
LIB_ITEMS_CONTAINER::ITERATOR i = m_drawings.begin();
while( i != m_drawings.end() )
// Iterate each drawing-type bucket and erase items that belong to units > aCount.
for( int type = LIB_ITEMS_CONTAINER::FIRST_TYPE; type <= LIB_ITEMS_CONTAINER::LAST_TYPE; ++type )
{
if( i->m_unit > aCount )
i = m_drawings.erase( i );
else
++i;
auto it = m_drawings.begin( type );
while( it != m_drawings.end( type ) )
{
if( it->m_unit > aCount )
it = m_drawings.erase( it ); // returns next iterator
else
++it;
}
}
}
else if( aDuplicateDrawItems )
+10 -8
View File
@@ -554,20 +554,22 @@ public:
void SetUnitCount( int aCount, bool aDuplicateDrawItems = true );
int GetUnitCount() const override;
/**
* Return an identifier for \a aUnit for symbols with units.
*/
wxString GetUnitReference( int aUnit ) override;
/**
* Return true if the given unit \a aUnit has a display name defined
*/
bool HasUnitDisplayName( int aUnit ) override;
bool HasUnitDisplayName( int aUnit ) const;
wxString GetUnitName( int aUnit ) const override
{
return GetUnitDisplayName( aUnit, true );
}
/**
* Return the user-defined display name for \a aUnit for symbols with units.
*/
wxString GetUnitDisplayName( int aUnit ) override;
wxString GetUnitDisplayName( int aUnit, bool aLabel ) const override;
wxString GetBodyStyleDescription( int aBodyStyle, bool aLabel ) const override;
/**
* Copy all unit display names into the given map \a aTarget
@@ -585,7 +587,7 @@ public:
*/
bool IsMulti() const override { return m_unitCount > 1; }
static wxString LetterSubReference( int aUnit, int aFirstId );
static wxString LetterSubReference( int aUnit, wxChar aInitialLetter );
/**
* Set or clear the alternate body style (DeMorgan) for the symbol.
@@ -34,17 +34,15 @@
#include "netlist_exporter_allegro.h"
#include "netlist_exporter_xml.h"
#include <regex>
#include <fmt.h>
#include <fmt/ranges.h>
bool NETLIST_EXPORTER_ALLEGRO::WriteNetlist( const wxString& aOutFileName,
unsigned /* aNetlistOptions */,
REPORTER& aReporter )
{
m_f = nullptr;
wxString field;
wxString footprint;
int ret = 0; // zero now, OR in the sign bit on error
wxString netName;
bool success = true;
// Create the devices directory
m_exportPath = wxFileName( aOutFileName ).GetPath( wxPATH_GET_VOLUME | wxPATH_GET_SEPARATOR )
@@ -67,31 +65,41 @@ bool NETLIST_EXPORTER_ALLEGRO::WriteNetlist( const wxString& aOutFileName,
return false;
}
ret |= fprintf( m_f, "(Source: %s)\n", TO_UTF8( m_schematic->GetFileName() ) );
ret |= fprintf( m_f, "(Date: %s)\n", TO_UTF8( GetISO8601CurrentDateTime() ) );
try
{
fmt::print( m_f, "(NETLIST)\n" );
fmt::print( m_f, "(Source: {})\n", TO_UTF8( m_schematic->GetFileName() ) );
fmt::print( m_f, "(Date: {})\n", TO_UTF8( GetISO8601CurrentDateTime() ) );
m_packageProperties.clear();
m_componentGroups.clear();
m_orderedSymbolsSheetpath.clear();
m_netNameNodes.clear();
m_packageProperties.clear();
m_componentGroups.clear();
m_orderedSymbolsSheetpath.clear();
m_netNameNodes.clear();
extractComponentsInfo();
extractComponentsInfo();
// Start with package definitions, which we create from component groups.
toAllegroPackages();
// Start with package definitions, which we create from component groups.
toAllegroPackages();
// Write out nets
toAllegroNets();
// Write out package properties. NOTE: Allegro doesn't recognize much...
toAllegroPackageProperties();
// Write out package properties. NOTE: Allegro doesn't recognize much...
toAllegroPackageProperties();
// Write out nets
toAllegroNets();
fmt::print( m_f, "$END\n" );
}
catch (...)
{
success = false;
}
// Done with the netlist
fclose( m_f );
m_f = nullptr;
return ret >= 0;
return success;
}
@@ -437,8 +445,8 @@ void NETLIST_EXPORTER_ALLEGRO::toAllegroPackages()
}
}
fprintf( d, "PACKAGE '%s'\n", TO_UTF8( formatDevice( footprintText ) ) );
fprintf( d, "CLASS IC\n" );
fmt::print( d, "PACKAGE '{}'\n", TO_UTF8( formatDevice( footprintText ) ) );
fmt::print( d, "CLASS IC\n" );
std::vector<SCH_PIN*> pinList = sym->GetLibSymbolRef()->GetPins();
@@ -463,36 +471,26 @@ void NETLIST_EXPORTER_ALLEGRO::toAllegroPackages()
}
unsigned int pinCount = pinList.size();
fprintf( d, "PINCOUNT %u\n", pinCount );
fmt::print( d, "PINCOUNT {}\n", pinCount );
if( pinCount > 0 )
{
fprintf( d, "%s", TO_UTF8( formatFunction( "main", pinList ) ) );
fmt::print( d, "{}", TO_UTF8( formatFunction( "main", pinList ) ) );
}
if( !value.IsEmpty() )
{
fprintf( d, "PACKAGEPROP VALUE %s\n", TO_UTF8( value ) );
fmt::print( d, "PACKAGEPROP VALUE {}\n", TO_UTF8( value ) );
}
if( !tol.IsEmpty() )
{
fprintf( d, "PACKAGEPROP TOL %s\n", TO_UTF8( tol ) );
fmt::print( d, "PACKAGEPROP TOL {}\n", TO_UTF8( tol ) );
}
if( !footprintAlt.IsEmpty() )
{
fprintf( d, "PACKAGEPROP ALT_SYMBOLS '(" );
wxString footprintAltSymbolsText;
for( const wxString& fp : footprintAlt )
{
footprintAltSymbolsText += fp + wxString( "," );
}
footprintAltSymbolsText.Truncate( footprintAltSymbolsText.Length() - 1 );
fprintf( d, "%s)'\n", TO_UTF8( footprintAltSymbolsText ) );
fmt::print( d, "PACKAGEPROP ALT_SYMBOLS '({})'\n", fmt::join( footprintAlt, "," ) );
}
wxArrayString propArray;
@@ -503,7 +501,7 @@ void NETLIST_EXPORTER_ALLEGRO::toAllegroPackages()
if(!data.IsEmpty())
{
fprintf( d, "PACKAGEPROP %s %s\n", TO_UTF8( propArray[0] ), TO_UTF8( data ) );
fmt::print( d, "PACKAGEPROP {} {}\n", TO_UTF8( propArray[0] ), TO_UTF8( data ) );
}
propArray.clear();
@@ -512,14 +510,16 @@ void NETLIST_EXPORTER_ALLEGRO::toAllegroPackages()
if(!data.IsEmpty())
{
fprintf( d, "PACKAGEPROP %s %s\n", TO_UTF8( propArray[0] ), TO_UTF8( data ) );
fmt::print( d, "PACKAGEPROP {} {}\n", TO_UTF8( propArray[0] ), TO_UTF8( data ) );
}
fprintf( d, "END\n" );
fmt::print( d, "END\n" );
fclose( d );
}
fmt::print( m_f, "$PACKAGES\n" );
for( auto iter = compPackageMap.begin(); iter != compPackageMap.end(); iter++ )
{
wxString deviceType = iter->first;
@@ -528,25 +528,28 @@ void NETLIST_EXPORTER_ALLEGRO::toAllegroPackages()
if( value.IsEmpty() && tolerance.IsEmpty() )
{
fprintf( m_f, "!%s;", TO_UTF8( deviceType ) );
fmt::print( m_f, "! '{}' ; ", TO_UTF8( deviceType ) );
}
else if( tolerance.IsEmpty() )
{
fprintf( m_f, "!%s!%s;", TO_UTF8( deviceType ), TO_UTF8( value ) );
fmt::print( m_f, "! '{}' ! '{}' ; ", TO_UTF8( deviceType ), TO_UTF8( value ) );
}
else
{
fprintf( m_f, "!%s!%s!%s;", TO_UTF8( deviceType ), TO_UTF8( value ),
fmt::print( m_f, "! '{}' ! '{}' ! {} ; ", TO_UTF8( deviceType ), TO_UTF8( value ),
TO_UTF8( tolerance ) );
}
std::vector<std::pair<SCH_SYMBOL*, SCH_SHEET_PATH>> symbolSheetpaths =
iter->second.m_symbolSheetpaths;
std::vector<wxString> refTexts;
for( const auto& [ sym, sheetPath ] : symbolSheetpaths)
fprintf( m_f, ",\n\t%s", TO_UTF8( sym->GetRef( &sheetPath ) ) );
refTexts.push_back( sym->GetRef( &sheetPath ) );
fprintf( m_f, "\n" );
fmt::print( m_f, "{}", fmt::join( refTexts, ",\n\t" ) );
fmt::print( m_f, "\n" );
}
if( !deviceFileCreatingError.IsEmpty() )
@@ -680,15 +683,14 @@ wxString NETLIST_EXPORTER_ALLEGRO::formatDevice( wxString aString )
void NETLIST_EXPORTER_ALLEGRO::toAllegroPackageProperties()
{
fprintf( m_f, "%s\n", "$PACKAGES" );
fprintf( m_f, "%s\n", "$A_PROPERTIES" );
fmt::print( m_f, "$A_PROPERTIES\n" );
while( !m_packageProperties.empty() )
{
std::multimap<wxString, wxString>::iterator iter = m_packageProperties.begin();
wxString sheetPathText = iter->first;
fprintf( m_f, "ROOM %s;", TO_UTF8( formatText( sheetPathText ) ) );
fmt::print( m_f, "'ROOM' '{}' ; ", TO_UTF8( formatText( sheetPathText ) ) );
std::vector<wxString> refTexts;
@@ -705,17 +707,16 @@ void NETLIST_EXPORTER_ALLEGRO::toAllegroPackageProperties()
std::stable_sort( refTexts.begin(), refTexts.end(),
NETLIST_EXPORTER_ALLEGRO::CompareSymbolRef );
for( const wxString& ref : refTexts )
fprintf( m_f, ",\n\t%s", TO_UTF8( ref ) );
fmt::print( m_f, "{}", fmt::join( refTexts, ",\n\t" ) );
fprintf( m_f, "\n" );
fmt::print( m_f, "\n" );
}
}
void NETLIST_EXPORTER_ALLEGRO::toAllegroNets()
{
fprintf( m_f, "%s\n", "$NETS" );
fmt::print( m_f, "$NETS\n" );
while( !m_netNameNodes.empty() )
{
@@ -724,7 +725,7 @@ void NETLIST_EXPORTER_ALLEGRO::toAllegroNets()
wxString netName = iter->first;
fprintf( m_f, "%s;", TO_UTF8( formatText( netName ).MakeUpper() ) );
fmt::print( m_f, "{}; ", TO_UTF8( formatText( netName ).MakeUpper() ) );
auto pairIter = m_netNameNodes.equal_range( netName );
@@ -738,14 +739,17 @@ void NETLIST_EXPORTER_ALLEGRO::toAllegroNets()
std::stable_sort( netNodes.begin(), netNodes.end() );
std::vector<wxString> nets;
for( const NET_NODE& netNode : netNodes )
{
wxString refText = netNode.m_Pin->GetParentSymbol()->GetRef( &netNode.m_Sheet );
wxString pinText = netNode.m_Pin->GetShownNumber();
fprintf( m_f, ",\n\t%s.%s", TO_UTF8( refText ), TO_UTF8( pinText ) );
nets.push_back( refText + wxString( "." ) + pinText );
}
fprintf( m_f, "\n" );
fmt::print( m_f, "{}", fmt::join( nets, ",\n\t" ) );
fmt::print( m_f, "\n" );
}
}
+2 -2
View File
@@ -119,8 +119,8 @@ void SCH_EDIT_FRAME::SelectUnit( SCH_SYMBOL* aSymbol, int aUnit )
if( otherSymbolRef )
{
const wxString targetUnitName = symbol->GetUnitDisplayName( aUnit );
const wxString currUnitName = symbol->GetUnitDisplayName( currentUnit );
const wxString targetUnitName = symbol->GetUnitDisplayName( aUnit, false );
const wxString currUnitName = symbol->GetUnitDisplayName( currentUnit, false );
wxString otherSheetName = otherSymbolRef->GetSheetPath().PathHumanReadable( true, true );
if( otherSheetName.IsEmpty() )
+25 -30
View File
@@ -82,42 +82,37 @@ void InitTables()
{
// clang-format off
g_pinElectricalTypes = {
{ ELECTRICAL_PINTYPE::PT_INPUT, { _( "Input" ), BITMAPS::pintype_input } },
{ ELECTRICAL_PINTYPE::PT_OUTPUT, { _( "Output" ), BITMAPS::pintype_output } },
{ ELECTRICAL_PINTYPE::PT_BIDI, { _( "Bidirectional" ), BITMAPS::pintype_bidi } },
{ ELECTRICAL_PINTYPE::PT_TRISTATE, { _( "Tri-state" ), BITMAPS::pintype_3states } },
{ ELECTRICAL_PINTYPE::PT_PASSIVE, { _( "Passive" ), BITMAPS::pintype_passive } },
{ ELECTRICAL_PINTYPE::PT_NIC, { _( "Free" ), BITMAPS::pintype_nic } },
{ ELECTRICAL_PINTYPE::PT_UNSPECIFIED, { _( "Unspecified" ), BITMAPS::pintype_notspecif } },
{ ELECTRICAL_PINTYPE::PT_POWER_IN, { _( "Power input" ), BITMAPS::pintype_powerinput } },
{ ELECTRICAL_PINTYPE::PT_POWER_OUT, { _( "Power output" ), BITMAPS::pintype_poweroutput } },
{ ELECTRICAL_PINTYPE::PT_OPENCOLLECTOR, { _( "Open collector" ),
BITMAPS::pintype_opencoll } },
{ ELECTRICAL_PINTYPE::PT_OPENEMITTER, { _( "Open emitter" ), BITMAPS::pintype_openemit } },
{ ELECTRICAL_PINTYPE::PT_NC, { _( "Unconnected" ), BITMAPS::pintype_noconnect } },
{ ELECTRICAL_PINTYPE::PT_INPUT, { _( "Input" ), BITMAPS::pintype_input } },
{ ELECTRICAL_PINTYPE::PT_OUTPUT, { _( "Output" ), BITMAPS::pintype_output } },
{ ELECTRICAL_PINTYPE::PT_BIDI, { _( "Bidirectional" ), BITMAPS::pintype_bidi } },
{ ELECTRICAL_PINTYPE::PT_TRISTATE, { _( "Tri-state" ), BITMAPS::pintype_3states } },
{ ELECTRICAL_PINTYPE::PT_PASSIVE, { _( "Passive" ), BITMAPS::pintype_passive } },
{ ELECTRICAL_PINTYPE::PT_NIC, { _( "Free" ), BITMAPS::pintype_nic } },
{ ELECTRICAL_PINTYPE::PT_UNSPECIFIED, { _( "Unspecified" ), BITMAPS::pintype_notspecif } },
{ ELECTRICAL_PINTYPE::PT_POWER_IN, { _( "Power input" ), BITMAPS::pintype_powerinput } },
{ ELECTRICAL_PINTYPE::PT_POWER_OUT, { _( "Power output" ), BITMAPS::pintype_poweroutput } },
{ ELECTRICAL_PINTYPE::PT_OPENCOLLECTOR, { _( "Open collector" ), BITMAPS::pintype_opencoll } },
{ ELECTRICAL_PINTYPE::PT_OPENEMITTER, { _( "Open emitter" ), BITMAPS::pintype_openemit } },
{ ELECTRICAL_PINTYPE::PT_NC, { _( "Unconnected" ), BITMAPS::pintype_noconnect } },
};
g_pinShapes = {
{ GRAPHIC_PINSHAPE::LINE, { _( "Line" ), BITMAPS::pinshape_normal } },
{ GRAPHIC_PINSHAPE::INVERTED, { _( "Inverted" ), BITMAPS::pinshape_invert } },
{ GRAPHIC_PINSHAPE::CLOCK, { _( "Clock" ), BITMAPS::pinshape_clock_normal } },
{ GRAPHIC_PINSHAPE::INVERTED_CLOCK, { _( "Inverted clock" ),
BITMAPS::pinshape_clock_invert } },
{ GRAPHIC_PINSHAPE::INPUT_LOW, { _( "Input low" ), BITMAPS::pinshape_active_low_input } },
{ GRAPHIC_PINSHAPE::CLOCK_LOW, { _( "Clock low" ), BITMAPS::pinshape_clock_active_low } },
{ GRAPHIC_PINSHAPE::OUTPUT_LOW, { _( "Output low" ),
BITMAPS::pinshape_active_low_output } },
{ GRAPHIC_PINSHAPE::FALLING_EDGE_CLOCK, { _( "Falling edge clock" ),
BITMAPS::pinshape_clock_fall } },
{ GRAPHIC_PINSHAPE::NONLOGIC, { _( "NonLogic" ),
BITMAPS::pinshape_nonlogic } },
{ GRAPHIC_PINSHAPE::LINE, { _( "Line" ), BITMAPS::pinshape_normal } },
{ GRAPHIC_PINSHAPE::INVERTED, { _( "Inverted" ), BITMAPS::pinshape_invert } },
{ GRAPHIC_PINSHAPE::CLOCK, { _( "Clock" ), BITMAPS::pinshape_clock_normal } },
{ GRAPHIC_PINSHAPE::INVERTED_CLOCK, { _( "Inverted clock" ), BITMAPS::pinshape_clock_invert } },
{ GRAPHIC_PINSHAPE::INPUT_LOW, { _( "Input low" ), BITMAPS::pinshape_active_low_input } },
{ GRAPHIC_PINSHAPE::CLOCK_LOW, { _( "Clock low" ), BITMAPS::pinshape_clock_active_low } },
{ GRAPHIC_PINSHAPE::OUTPUT_LOW, { _( "Output low" ), BITMAPS::pinshape_active_low_output } },
{ GRAPHIC_PINSHAPE::FALLING_EDGE_CLOCK, { _( "Falling edge clock" ), BITMAPS::pinshape_clock_fall } },
{ GRAPHIC_PINSHAPE::NONLOGIC, { _( "NonLogic" ), BITMAPS::pinshape_nonlogic } },
};
g_pinOrientations = {
{ PIN_ORIENTATION::PIN_RIGHT, { _( "Right" ), BITMAPS::pinorient_right } },
{ PIN_ORIENTATION::PIN_LEFT, { _( "Left" ), BITMAPS::pinorient_left } },
{ PIN_ORIENTATION::PIN_UP, { _( "Up" ), BITMAPS::pinorient_up } },
{ PIN_ORIENTATION::PIN_DOWN, { _( "Down" ), BITMAPS::pinorient_down } },
{ PIN_ORIENTATION::PIN_RIGHT, { _( "Right" ), BITMAPS::pinorient_right } },
{ PIN_ORIENTATION::PIN_LEFT, { _( "Left" ), BITMAPS::pinorient_left } },
{ PIN_ORIENTATION::PIN_UP, { _( "Up" ), BITMAPS::pinorient_up } },
{ PIN_ORIENTATION::PIN_DOWN, { _( "Down" ), BITMAPS::pinorient_down } },
};
// clang-format on
+3 -1
View File
@@ -1614,7 +1614,9 @@ void SCH_EDIT_FRAME::RefreshOperatingPointDisplay()
{
std::vector<EMBEDDED_FILES*> embeddedFilesStack;
embeddedFilesStack.push_back( m_schematic->GetEmbeddedFiles() );
embeddedFilesStack.push_back( symbol->GetEmbeddedFiles() );
if( EMBEDDED_FILES* symbolEmbeddedFiles = symbol->GetEmbeddedFiles() )
embeddedFilesStack.push_back( symbolEmbeddedFiles );
simLibMgr.SetFilesStack( embeddedFilesStack );

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