Compare commits

...

1126 Commits

Author SHA1 Message Date
Jon Evans eec5b07179 Add 10.99 qa config dir 2026-03-19 22:05:21 -04:00
Jon Evans ac8f0096ce Lazy-allocate a few pad and padstack things 2026-03-19 21:32:07 -04:00
Jon Evans 755280dec1 Defer initialization of PIN_LAYOUT_CACHE until it is needed 2026-03-19 21:32:07 -04:00
Jon Evans 067533928b Reduce memory usage of EDA_SHAPE pt 2 2026-03-19 21:32:06 -04:00
Jon Evans 5353982a4a Reduce memory usage of EDA_SHAPE 2026-03-19 21:32:02 -04:00
Jon Evans 683bb74b7f Reduce memory usage of FOOTPRINT caches
These aren't needed until a footprint is materialized
2026-03-19 21:25:34 -04:00
Jon Evans 082ec945fc Reduce memory usage of text/fields
Lazy construction of caches that are only needed
for some of these reduces their footprint significantly.
2026-03-19 21:25:34 -04:00
Seth Hillbrand 8f6d321fb5 Zone fill: DAG scheduling and batching
Replace the polling loop in ZONE_FILLER::Fill with a DAG-based wave
scheduler. Each zone-layer pair's fill dependencies are computed
upfront as a directed acyclic graph, and zones are processed in waves
instead of resubmitting each time.

Batch multiple BooleanSubtract calls into single operations in
subtractHigherPriorityZones, fillNonCopperZone, and
refillZoneFromCache by collecting all knockouts into one SHAPE_POLY_SET
before subtracting.
2026-03-19 16:55:53 -07:00
Wayne Stambaugh 10554d4812 Begin version 11 development. 2026-03-19 17:32:42 -04:00
Wayne Stambaugh 0feeca2a80 Tag stable release 10.0.0 2026-03-19 17:29:56 -04:00
Seth Hillbrand 72ea57d861 Allow local labels without pins if they connect
Local labels on a sheet need to be able to connect just to other labels
for intersheet routing.  This was mistakenly disallowed to check to for
dangling local labels
2026-03-19 14:21:31 -07:00
Seth Hillbrand d342761fa0 Fix one more use after free vector 2026-03-19 13:28:34 -07:00
ZbeeGin b9b7cec920 Translated using Weblate (Polish)
Currently translated at 95.5% (10873 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/pl/
2026-03-19 21:26:17 +01:00
Seth Hillbrand 2a9e28c87c Translated using Weblate (Slovak)
Currently translated at 100.0% (11384 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/sk/
2026-03-19 21:26:16 +01:00
dsa-t 2045d3b019 Translated using Weblate (Russian)
Currently translated at 89.1% (10144 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ru/
2026-03-19 21:26:08 +01:00
Seth Hillbrand a4214a3989 Translated using Weblate (Arabic)
Currently translated at 100.0% (11384 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ar/
2026-03-19 21:26:01 +01:00
Seth Hillbrand e34c2d5037 Translated using Weblate (Hebrew)
Currently translated at 100.0% (11384 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/he/
2026-03-19 21:25:45 +01:00
Damjan Prerad 4149bee32b Local history: reuse existing dialog strings 2026-03-19 20:45:45 +01:00
Alex Shvartzkop 182f99abcb Fix MSW build error. 2026-03-19 21:48:45 +03:00
ZbeeGin 67bfd24675 Translated using Weblate (Polish)
Currently translated at 95.4% (10864 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/pl/
2026-03-19 18:36:12 +01:00
ZbeeGin 80b84af23e Translated using Weblate (Polish)
Currently translated at 95.3% (10858 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/pl/
2026-03-19 18:36:12 +01:00
dsa-t 0452493071 Translated using Weblate (Russian)
Currently translated at 87.3% (9939 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ru/
2026-03-19 18:36:12 +01:00
Hildo Guillardi Júnior eeebadac23 Translated using Weblate (Portuguese (Brazil))
Currently translated at 99.2% (11301 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/pt_BR/
2026-03-19 18:36:12 +01:00
dsa-t f2eda2524c Translated using Weblate (Russian)
Currently translated at 82.8% (9434 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ru/
2026-03-19 18:36:11 +01:00
ZbeeGin f75398a86c Translated using Weblate (Polish)
Currently translated at 94.9% (10813 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/pl/
2026-03-19 18:36:11 +01:00
Damjan Prerad f28df85b76 Translated using Weblate (Serbian)
Currently translated at 15.9% (1815 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/sr/
2026-03-19 18:36:11 +01:00
Mitja Nemec e40656b334 Translated using Weblate (Slovenian)
Currently translated at 1.2% (142 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/sl/
2026-03-19 18:36:11 +01:00
Damjan Prerad d23c34aff3 Local history: fix Win64 enum macro collision 2026-03-19 17:57:53 +01:00
Damjan Prerad 77140167a6 QA: fix single-member group save 2026-03-19 17:38:48 +01:00
Damjan Prerad b80ee13595 Local history: add restore dialog
The old restore dialog only showed a simple list of snapshots
so it was hard to see what each entry contained before
restoring. It also had a bug where pressing Restore could
close the dialog but not restore anything, because the
pre-restore backup step treated no changes to save as a faliure.

This change adds a dedicated restore dialog that shows the
snapshot time, summary, hash, and changed files. It also
updates the restore code to load snapshot details for the
dialog and to continue with the restore when the backup
step finds no new changes.
2026-03-19 17:04:02 +01:00
Damjan Prerad 1aa2d1494e DRC Rule Editor: add courtyard clearance bitmap 2026-03-19 17:04:02 +01:00
Alex Shvartzkop 969dbe196f Don't translate strings that shouldn't be translated. 2026-03-19 18:46:37 +03:00
Seth Hillbrand 2439de47b7 Provide lazy loading of webview panel
Avoid instantiating the panel prior to it being shown (if at all)
2026-03-18 21:36:14 -07:00
John Beard ea34bcad4b Docset: disable the reserved index space
Doxygen-Awesome's adaptive top/sidebar CSS doesn't work well
when there is no index, as in a docset.
2026-03-19 10:06:39 +08:00
Seth Hillbrand 9fbb0378c5 Move webview pointer to wxweakref
Uses wx reference counting infrastructure to ensure we have a valid
pointer and adds proper null checking for the webview not being
instantiated yet
2026-03-18 18:00:57 -07:00
Seth Hillbrand 60a9e2ff72 Translated using Weblate (Spanish (Mexico))
Currently translated at 99.1% (11288 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/es_MX/
2026-03-19 01:30:38 +01:00
Seth Hillbrand c831c3940e Translated using Weblate (Greek)
Currently translated at 100.0% (11384 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/el/
2026-03-19 01:30:38 +01:00
Seth Hillbrand 6a5d5f1bff Translated using Weblate (Polish)
Currently translated at 92.4% (10528 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/pl/
2026-03-19 01:30:38 +01:00
Seth Hillbrand 59d2649f2a Translated using Weblate (Romanian)
Currently translated at 100.0% (11384 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ro/
2026-03-19 01:30:38 +01:00
Seth Hillbrand 10bd45093a Translated using Weblate (Ukrainian)
Currently translated at 97.9% (11153 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/uk/
2026-03-19 01:30:38 +01:00
Seth Hillbrand 4c40fffe3a Translated using Weblate (Tamil)
Currently translated at 93.4% (10639 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ta/
2026-03-19 01:30:38 +01:00
Seth Hillbrand a72422648c Translated using Weblate (Spanish)
Currently translated at 99.1% (11288 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/es/
2026-03-19 01:30:38 +01:00
Seth Hillbrand 3bfa435662 Translated using Weblate (Portuguese (Brazil))
Currently translated at 99.1% (11289 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/pt_BR/
2026-03-19 01:30:38 +01:00
Seth Hillbrand 89ed6e7a65 Translated using Weblate (Portuguese)
Currently translated at 100.0% (11384 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/pt/
2026-03-19 01:30:38 +01:00
Seth Hillbrand 98f9a60ccb Translated using Weblate (Danish)
Currently translated at 99.9% (11379 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/da/
2026-03-19 01:30:38 +01:00
Seth Hillbrand f83e5c275a Translated using Weblate (Vietnamese)
Currently translated at 100.0% (11384 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/vi/
2026-03-19 01:30:38 +01:00
Seth Hillbrand 183298a837 Translated using Weblate (Telugu)
Currently translated at 100.0% (11384 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/te/
2026-03-19 01:30:37 +01:00
Seth Hillbrand f24fd95795 Translated using Weblate (Italian)
Currently translated at 98.7% (11239 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/it/
2026-03-19 01:30:37 +01:00
Seth Hillbrand ba48cd21b8 Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 87.8% (10006 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/zh_Hant/
2026-03-19 01:30:37 +01:00
Seth Hillbrand 5396092dce Translated using Weblate (Norwegian Bokmål)
Currently translated at 100.0% (11384 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/nb_NO/
2026-03-19 01:30:37 +01:00
Seth Hillbrand e2e6fed59a Translated using Weblate (Catalan)
Currently translated at 100.0% (11384 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ca/
2026-03-19 01:30:37 +01:00
Seth Hillbrand 16ada50fad Translated using Weblate (Arabic)
Currently translated at 100.0% (11384 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ar/
2026-03-19 01:30:37 +01:00
Seth Hillbrand c2d820510c Translated using Weblate (Finnish)
Currently translated at 82.7% (9418 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/fi/
2026-03-19 01:30:37 +01:00
Seth Hillbrand 01605e186d Translated using Weblate (Turkish)
Currently translated at 100.0% (11384 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/tr/
2026-03-19 01:30:37 +01:00
Damjan Prerad 06a248c2a3 Translated using Weblate (Serbian)
Currently translated at 15.9% (1815 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/sr/
2026-03-19 01:30:37 +01:00
Seth Hillbrand 0c4c94be9e Translated using Weblate (Dutch)
Currently translated at 76.0% (8663 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/nl/
2026-03-19 01:30:37 +01:00
Seth Hillbrand f53786c463 Translated using Weblate (Japanese)
Currently translated at 100.0% (11384 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ja/
2026-03-19 01:30:37 +01:00
dsa-t 5f6384fd27 Translated using Weblate (Russian)
Currently translated at 82.8% (9434 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ru/
2026-03-19 01:30:36 +01:00
Seth Hillbrand 6d25921e3b Translated using Weblate (Bulgarian)
Currently translated at 99.8% (11368 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/bg/
2026-03-19 01:30:36 +01:00
Seth Hillbrand 65fdc4ea00 One more swing at Wayne's webview crash
The teardown order between C++ DTOR and wx may get mis-aligned, so don't
try stopping the timer if it might already be freed
2026-03-18 17:21:36 -07:00
Seth Hillbrand 0acdd4a936 Allow saving single item groups
Fixes https://gitlab.com/kicad/code/kicad/-/issues/23479
2026-03-18 15:45:08 -07:00
Tomasz Wlostowski fb8b01c30e router: don't forget to copy the DP's layers property in its DIFF_PAIR::operator= 2026-03-18 23:06:36 +01:00
Damjan Prerad 246a1344a9 DRC Rule Editor: make graphics consistent and use proper colors 2026-03-18 22:34:26 +01:00
Seth Hillbrand 5f6877002f webview: guard against destroyed browser in deferred init
The wxWebView child can be destroyed before the
WEBVIEW_PANEL when WebKit's GTK widget is torn down
asynchronously (e.g., WebKit process crash or init
failure). The retry timer keeps firing on the
still-alive panel but m_browser is now a dangling
pointer, causing SIGSEGV at the virtual dispatch in
AddScriptMessageHandler.

Bind wxEVT_DESTROY on the wxWebView to null out
m_browser and stop the timer when the browser is
destroyed. Add null guards in DoInitHandlers,
AddMessageHandler, and ClearMessageHandlers.
2026-03-18 13:52:03 -07:00
Seth Hillbrand 803124be11 Translated using Weblate (Czech)
Currently translated at 99.9% (11380 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/cs/
2026-03-18 21:48:58 +01:00
Seth Hillbrand 289ddc34b8 Translated using Weblate (Estonian)
Currently translated at 99.1% (11292 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/et/
2026-03-18 21:48:58 +01:00
Seth Hillbrand e94a2ee0a2 Translated using Weblate (Spanish (Mexico))
Currently translated at 99.1% (11288 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/es_MX/
2026-03-18 21:48:58 +01:00
Seth Hillbrand f8b20d5b2e Translated using Weblate (Portuguese (Brazil))
Currently translated at 99.1% (11289 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/pt_BR/
2026-03-18 21:48:58 +01:00
Seth Hillbrand e06d555a39 Translated using Weblate (Bulgarian)
Currently translated at 99.8% (11368 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/bg/
2026-03-18 21:48:57 +01:00
Seth Hillbrand 0efb213ca6 Translated using Weblate (Swedish)
Currently translated at 98.7% (11243 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/sv/
2026-03-18 21:48:57 +01:00
Seth Hillbrand a645702ad7 Translated using Weblate (Polish)
Currently translated at 92.4% (10528 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/pl/
2026-03-18 21:48:57 +01:00
Seth Hillbrand 9348f43058 Translated using Weblate (Portuguese)
Currently translated at 100.0% (11384 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/pt/
2026-03-18 21:48:57 +01:00
Seth Hillbrand cfa3eff2bf Translated using Weblate (Greek)
Currently translated at 100.0% (11384 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/el/
2026-03-18 21:48:57 +01:00
Seth Hillbrand 6b8625be84 Translated using Weblate (Lithuanian)
Currently translated at 99.9% (11381 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/lt/
2026-03-18 21:48:57 +01:00
Seth Hillbrand 9fe6bc9f71 Translated using Weblate (Norwegian Bokmål)
Currently translated at 100.0% (11384 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/nb_NO/
2026-03-18 21:48:57 +01:00
Seth Hillbrand aafc276e0a Translated using Weblate (Georgian)
Currently translated at 100.0% (11384 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ka/
2026-03-18 21:48:57 +01:00
Seth Hillbrand 114d24d4a5 Translated using Weblate (Arabic)
Currently translated at 100.0% (11384 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ar/
2026-03-18 21:48:57 +01:00
dsa-t 3fb25280df Translated using Weblate (Russian)
Currently translated at 82.8% (9433 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ru/
2026-03-18 21:48:57 +01:00
Seth Hillbrand 5bea71ea0e Translated using Weblate (Slovak)
Currently translated at 100.0% (11384 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/sk/
2026-03-18 21:48:57 +01:00
Seth Hillbrand 2423e703c5 Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 87.8% (10006 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/zh_Hant/
2026-03-18 21:48:56 +01:00
Seth Hillbrand ffb6971dd1 Translated using Weblate (Danish)
Currently translated at 99.9% (11379 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/da/
2026-03-18 21:48:56 +01:00
Seth Hillbrand 5f7db7e344 Translated using Weblate (Romanian)
Currently translated at 100.0% (11384 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ro/
2026-03-18 21:48:56 +01:00
Seth Hillbrand e29d2d0ebe Translated using Weblate (Catalan)
Currently translated at 100.0% (11384 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ca/
2026-03-18 21:48:56 +01:00
Seth Hillbrand 107344a30e Translated using Weblate (Korean)
Currently translated at 99.1% (11288 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ko/
2026-03-18 21:48:56 +01:00
Seth Hillbrand eed471a220 Translated using Weblate (Indonesian)
Currently translated at 100.0% (11384 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/id/
2026-03-18 21:48:56 +01:00
Seth Hillbrand 4fc1e3773c Translated using Weblate (Ukrainian)
Currently translated at 97.9% (11153 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/uk/
2026-03-18 21:48:56 +01:00
Seth Hillbrand 59a17fc45c Translated using Weblate (Hebrew)
Currently translated at 100.0% (11384 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/he/
2026-03-18 21:48:56 +01:00
Seth Hillbrand ecbbe67641 Translated using Weblate (Telugu)
Currently translated at 100.0% (11384 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/te/
2026-03-18 21:48:56 +01:00
Seth Hillbrand d0080455e7 Translated using Weblate (Latvian)
Currently translated at 99.9% (11380 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/lv/
2026-03-18 21:48:56 +01:00
Seth Hillbrand f21cb72d2b Translated using Weblate (Spanish)
Currently translated at 99.1% (11288 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/es/
2026-03-18 21:48:56 +01:00
Seth Hillbrand 7e42f841cc Translated using Weblate (Thai)
Currently translated at 100.0% (11384 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/th/
2026-03-18 21:48:56 +01:00
Seth Hillbrand 8802ac0041 Translated using Weblate (Vietnamese)
Currently translated at 100.0% (11384 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/vi/
2026-03-18 21:48:56 +01:00
Seth Hillbrand 26f52bc57d Translated using Weblate (Hindi)
Currently translated at 100.0% (11384 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/hi/
2026-03-18 21:48:55 +01:00
Seth Hillbrand 2edc8864ad Translated using Weblate (Hungarian)
Currently translated at 99.1% (11285 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/hu/
2026-03-18 21:48:55 +01:00
Seth Hillbrand e25cb1354d webview: defer handler init when main loop is mid-yield
AddScriptMessageHandler internally calls RunScript, which
yields the event loop. When this fires from a timer during
a wxProgressDialog yield (e.g., schematic loading checkpoint),
the reentrant yield crashes WebKit's JSC in sanitizeStackForVM.

The existing guard only checked for non-main event loops but
missed the case where the main loop itself is yielding. Add
IsYielding() to both DoInitHandlers and AddMessageHandler guards
so the timer re-defers until the loop is idle.
2026-03-18 13:26:58 -07:00
Seth Hillbrand 20908ce39b kicad: fix crash on project close in webview
Replace CallAfter with m_initRetryTimer.StartOnce(0)
which gives the same deferred execution but is
automatically cancelled by ~wxTimer when the panel
is destroyed.
2026-03-18 13:22:42 -07:00
Damjan Prerad 235972b035 DRC rule tree: flatten single-child groups 2026-03-18 21:16:22 +01:00
Damjan Prerad dc277bf26a DRC Rule Editor: make graphics consistent and use proper colors 2026-03-18 20:41:35 +01:00
Seth Hillbrand 36f0da1556 eeschema: abort async loads before destroying library tables
Background async library loading workers hold raw LIBRARY_TABLE_ROW
pointers into the LIBRARY_TABLE::m_rows vector. When ProjectChanged()
calls LoadProjectTables(), it destroys the old LIBRARY_TABLE objects
via unique_ptr replacement.

The workers were not aborted until after the tables were destroyed,
creating a window where workers could access freed memory.

Fixes https://gitlab.com/kicad/code/kicad/-/issues/23480
2026-03-18 12:18:23 -07:00
CloverGit 97c4cf6497 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 95.1% (10834 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/zh_Hans/
2026-03-18 19:47:27 +01:00
Seth Hillbrand 5d0485c85f qa: fix remote provider test failures 2026-03-18 08:00:12 -07:00
Mike Williams 557d492384 design blocks: don't apply nested groups
This could be an improvement in the future, but for now it has too many
issues, e.g. what happens if the user has already grouped those items?

Fixes: https://gitlab.com/kicad/code/kicad/-/work_items/23471
2026-03-18 10:12:43 -04:00
Mike Williams 08349b8d8a design blocks: don't crash on missing preview widget
Copied from footprint preview widget, which has the same issue
2026-03-18 10:12:43 -04:00
Damjan Prerad 7c06e9ba12 pcbnew: fix tuning pattern copy in multichannel repeat
Multi-channel repeat did not handle length tuning correctly.
When repeating a layout a tuning pattern was coppied partly.
It got clipped. The copied tuning pattern kept its
source channel genearator.

Fix this by treating tuning patterns as generators during
routing collection in repeat layout. If a tuning pattern
intersects the rule area copy the whole generated structure
instead of only individually enclosed items.

Fixes https://gitlab.com/kicad/code/kicad/-/work_items/23463
2026-03-18 14:07:43 +01:00
Alex Shvartzkop 2f18ec973d Don't raise KICAD_MANAGER_FRAME in ctor.
There's no point trying to raise a window before showing.

This triggered the wx issue https://github.com/wxWidgets/wxWidgets/issues/25348
2026-03-18 15:25:33 +03:00
Damjan Prerad 8b2cb94cb1 pcbnew: fix Flip Board View from custom toolbars
Flip Board View did not work correctly when it was added to a
custom toolbar. The board flip worked from the view menu or
appearance panel.

This change stores the board flip state in PCB_DISPLAY_OPTIONS
and applies it through SetDisplayOptions(), the same way other
display toggles are handled. The toolbar, menu, and appearance
panel now use the same state, so Flip Board View works correctly
from custom toolbars.
2026-03-18 12:41:51 +01:00
Jon Evans 4889bf913c Reset new table positions after Autosize call
Fixes https://gitlab.com/kicad/code/kicad/-/work_items/23278
2026-03-17 19:02:18 -04:00
Tomas0015 f492b347ee Translated using Weblate (Czech)
Currently translated at 99.9% (11380 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/cs/
2026-03-17 23:13:45 +01:00
Seth Hillbrand 8a3e2ed06e Translated using Weblate (Hebrew)
Currently translated at 100.0% (11384 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/he/
2026-03-17 23:13:45 +01:00
Seth Hillbrand 8c75607cef Translated using Weblate (Czech)
Currently translated at 99.9% (11374 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/cs/
2026-03-17 23:13:45 +01:00
Pferd O. 54de853c9c Translated using Weblate (German)
Currently translated at 100.0% (11384 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/de/
2026-03-17 23:13:45 +01:00
Frank Sonnenberg 08ac744b56 Translated using Weblate (German)
Currently translated at 100.0% (11384 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/de/
2026-03-17 23:13:45 +01:00
Seth Hillbrand 173e66c628 Translated using Weblate (Slovak)
Currently translated at 100.0% (11384 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/sk/
2026-03-17 23:13:45 +01:00
Tomas0015 667c746757 Translated using Weblate (Czech)
Currently translated at 67.4% (7681 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/cs/
2026-03-17 23:13:45 +01:00
ZbeeGin dc32646be7 Translated using Weblate (Polish)
Currently translated at 92.4% (10528 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/pl/
2026-03-17 23:13:45 +01:00
Tomasz Wlostowski 83cabf960e router: fix use-after-free issue when dragging multiple tracks in walkaround mode
Also clean up and improve the walkaround order logic.

Fixes: https://gitlab.com/kicad/code/kicad/-/work_items/23462
2026-03-17 21:35:14 +01:00
Bernhard Kirchen 1cece2de21 use expected color for DNP marker on sheets when plotting
Fixes https://gitlab.com/kicad/code/kicad/-/issues/23465
2026-03-17 17:11:36 +01:00
Bernhard Kirchen e3f049f4d9 ADDED: expand VARIANT and VARIANT_DESC in drawing sheets
* add VARIANT and VARIANT_DESC to the list of known vars in the drawing
  sheet editor.
* cache variant and variant description in respective objects.
* expand the respective text variables when building the drawing sheet.
* keep the cached variant and its description up-to-date when selecting
  a variant in the GUI.
* pass variant and its description to the plotters.

Fixes https://gitlab.com/kicad/code/kicad/-/issues/23430
2026-03-17 15:39:34 +00:00
Jeff Young a9f1b41dc2 Attempt to fix non-Mac includes. 2026-03-17 14:41:36 +00:00
Jeff Young 71b48eabd7 Allow compiler to enforce char vs wxUniChar. 2026-03-17 14:25:32 +00:00
Damjan Prerad d1f7bf6e83 DRC Rule Editor: flatten high-speed rule categories in DRC rule editor
Remove the extra nested categories under Highspeed design in the
DRC rule editor

The existing hierarchy added an extra layer for only a small number
of items and did not provide much additional structure. Flattening
the tree makes the high-speed rules easier to navigate.
2026-03-17 15:13:11 +01:00
Jeff Young dbc5e021ed Repair hatching knockouts post-optimization.
The knockout algo was a post-processing step, but it
only knew about the poly representation, and not the
new line segment optimization.  Since the post-process
step proved to be fragile, knockouts are now fetched
from a callback from EDA_SHAPE::UpdateHatching().
2026-03-17 13:16:06 +00:00
Jeff Young 49b819ef81 Don't set dirty flag unnecessarily.
Fixes https://gitlab.com/kicad/code/kicad/-/issues/23292
2026-03-17 13:16:06 +00:00
Jeff Young e4b8fde25b PANEL_PREVIEW_3D_MODEL does its own pretty-printing.
Fixes https://gitlab.com/kicad/code/kicad/-/issues/23401
2026-03-17 13:16:06 +00:00
Damjan Prerad db404d9906 DRC Rule Editor: mark custom rule editor changes as modified
The custom rule text editor did not mark the DRC rule editor dialog as
modified when its contents changed.

Bind the custom rule text control change event to the dialog modified
so custom rule edits behave like the other rule editor panels.
2026-03-17 14:14:19 +01:00
Jon Evans 0f0b3452ac Use locale toggle in ODB++ dialog
Fixes https://gitlab.com/kicad/code/kicad/-/work_items/23447
2026-03-17 08:46:24 -04:00
Jon Evans c866cd4c0c Prevent dangling pointers when removing grouped items from SWIG
Fixes https://gitlab.com/kicad/code/kicad/-/work_items/23249
2026-03-17 08:46:24 -04:00
Damjan Prerad 4d9ad2304a DRC Rule Editor: keep asymmetric DRC constraints as custom rules
The graphical DRC rule editor shows numeric constraints as a
nominal value plus or minus one tolerance. The rule system
supports separate min, opt, and max values. When a rule
used an asymmetric range, loading it into the editor could
change it on save.

Fix this by checking loaded min/opt/max constraints before
mapping them to the graphical editor model. If the range is not
symmetric around the opt value, load the rule as a custom rule
instead of forcing it into the nominal plus/minus tolerance
format.

Fixes https://gitlab.com/kicad/code/kicad/-/work_items/23439
2026-03-17 13:33:46 +01:00
Damjan Prerad 0e8c7d92a3 eeschema: add sheet custom fields to Properties panel
Extend the schematic Properties panel dynamic field handling to cover
SCH_SHEET items in addition to SCH_SYMBOL items.

This allows custom subsheet attributes added in Sheet Properties to
appear in the Properties panel.
2026-03-17 12:51:26 +01:00
Seth Hillbrand 13a09e2f2f Improve zone fill parallelism and indexing
Remove the per-zone mutex that serialized all layer fills of the
same zone. fillSingleZone() is read-only on zone state, so
concurrent fills of different layers are safe. Make m_needRefill
atomic and narrow the CacheTriangulation lock to the map lookup.

Also add an R-tree index to reduce queries over large zones.

Fixes https://gitlab.com/kicad/code/kicad/-/issues/23450
2026-03-16 21:04:56 -07:00
Damjan Prerad b156372d59 Narrow tuning pattern area selection
Use generated child items for box and polygon hit testing so tuning
patterns select more tightly. Fall back to the generator outline only
when the pattern has no child board items.

Fixes https://gitlab.com/kicad/code/kicad/-/work_items/23384
2026-03-17 01:16:51 +01:00
Seth Hillbrand 216ad00bea Fix test_remote_provider_metadata schema path for PPA builds
The schemaPath() helper used __FILE__ to navigate from the test source
file up to the repository root, then down to resources/schemas/. This
breaks when dpkg-buildflags injects -ffile-prefix-map which remaps the
absolute source path to a relative one.  The Normalize() call then
resolves the relative path against the test working directory (inside
the build tree), producing a bogus path that cannot reach the source
tree's schema files.

Replace the __FILE__ navigation with QA_SRC_ROOT compile definition
2026-03-16 16:42:22 -07:00
Damjan Prerad 4d14471ef6 Refresh symbol chooser description caches after library parse
Fixes https://gitlab.com/kicad/code/kicad/-/work_items/23456
2026-03-16 23:50:08 +01:00
Tomasz Wlostowski 1909f3a8b3 router: fix use-after-free error when dragging a single (no tracks attached via) in shove mode
Fixes: https://gitlab.com/kicad/code/kicad/-/work_items/23449
2026-03-16 21:39:36 +01:00
Tomasz Wlostowski 731d46cc8c router: correctly sanitize router layer to BOARD layer translation 2026-03-16 21:39:25 +01:00
Seth Hillbrand 0c10366e84 Fix symbol chooser flicker with missing libraries
Libraries with permanent load errors (LOAD_ERROR) were re-added to
m_pending_load_libraries on every timer tick, creating an infinite
retry loop. Each iteration called m_lazyLoadHandler() which triggered
Regenerate(), rebuilding the tree and resetting scroll position every
second.

Skip LOAD_ERROR libraries instead of retrying them, and only call the
lazy load handler when at least one library was actually loaded in the
current iteration.

Fixes https://gitlab.com/kicad/code/kicad/-/issues/23455
2026-03-16 12:16:45 -07:00
Seth Hillbrand 902048a172 Move history autosave Prettify, file I/O, and git ops to background thread
Savers now serialize to in-memory HISTORY_FILE_DATA on the UI thread,
then Prettify + file writes + git stage/diff/commit run on a background
thread via GetKiCadThreadPool(). An atomic skip-if-busy flag prevents
overlapping saves; WaitForPendingSave() ensures clean shutdown.

Extracted FormatBoardToFormatter and FormatSchematicToFormatter so
SaveToHistory can serialize without touching disk. PROJECT savers use
sourcePath for file-copy semantics since project files are small.
2026-03-16 12:16:45 -07:00
Jeff Young 9ecc6fe838 Numeric evaluator only supports 8-bit chars.
(Worse, wxWidgets' auto-converter can crash on certain input.)
2026-03-16 19:06:08 +00:00
Jeff Young 4241db8488 Formatting. 2026-03-16 19:06:07 +00:00
Seth Hillbrand 6ed8fa0fae Fix crash when realizing instance of OpenGL
The FOOTPRINT_PREVIEW_PANEL may instantiate prior to any other checks,
we need to ensure that this widget is realized on Linux prior to getting
the OpenGL calls otherwise GTKGetDrawingWindow may return NULL
incorrectly
2026-03-16 10:46:08 -07:00
Seth Hillbrand 7e9891c856 Translated using Weblate (Romanian)
Currently translated at 100.0% (11384 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ro/
2026-03-16 10:30:13 -07:00
Seth Hillbrand b23dfbb39b Translated using Weblate (Greek)
Currently translated at 100.0% (11384 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/el/
2026-03-16 10:30:13 -07:00
EdizonTN 5762587fec Translated using Weblate (Slovak)
Currently translated at 69.7% (7941 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/sk/
2026-03-16 10:30:13 -07:00
Seth Hillbrand 5bfdc78b8b Translated using Weblate (Indonesian)
Currently translated at 100.0% (11384 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/id/
2026-03-16 10:30:13 -07:00
Anonymous a09e350ce4 Translated using Weblate (Bulgarian)
Currently translated at 99.8% (11368 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/bg/
2026-03-16 10:30:13 -07:00
Seth Hillbrand 6e96890bbe Translated using Weblate (Lithuanian)
Currently translated at 99.9% (11381 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/lt/
2026-03-16 10:30:13 -07:00
Seth Hillbrand 63a28cade3 Translated using Weblate (Catalan)
Currently translated at 100.0% (11384 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ca/
2026-03-16 10:30:13 -07:00
EdizonTN 8cc108ff10 Translated using Weblate (Slovak)
Currently translated at 69.1% (7875 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/sk/
2026-03-16 10:30:13 -07:00
aris-kimi 4ea1d5f25b Translated using Weblate (Greek)
Currently translated at 71.2% (8116 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/el/
2026-03-16 10:30:13 -07:00
Annonmus 7acb920842 Translated using Weblate (Polish)
Currently translated at 92.4% (10528 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/pl/
2026-03-16 10:30:13 -07:00
ZbeeGin e60a9e0a91 Translated using Weblate (Polish)
Currently translated at 92.4% (10528 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/pl/
2026-03-16 10:30:13 -07:00
EdizonTN 932af067ff Translated using Weblate (Slovak)
Currently translated at 68.0% (7749 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/sk/
2026-03-16 10:30:13 -07:00
Seth Hillbrand 5790543636 Translated using Weblate (Latvian)
Currently translated at 99.9% (11380 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/lv/
2026-03-15 10:30:13 -07:00
Seth Hillbrand 9ff212f19c Translated using Weblate (Finnish)
Currently translated at 82.7% (9418 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/fi/
2026-03-15 10:30:12 -07:00
Seth Hillbrand ff9d15d39c Translated using Weblate (Arabic)
Currently translated at 100.0% (11384 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ar/
2026-03-15 10:30:12 -07:00
Seth Hillbrand f1cb5af21f Translated using Weblate (Turkish)
Currently translated at 100.0% (11384 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/tr/
2026-03-15 10:30:12 -07:00
Seth Hillbrand 89e8229e75 Translated using Weblate (Swedish)
Currently translated at 98.7% (11243 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/sv/
2026-03-15 10:30:12 -07:00
Seth Hillbrand a4a37134a0 Translated using Weblate (Hungarian)
Currently translated at 99.1% (11285 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/hu/
2026-03-15 17:23:34 +01:00
Seth Hillbrand 4a69954026 Translated using Weblate (Georgian)
Currently translated at 100.0% (11384 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ka/
2026-03-15 17:23:34 +01:00
Seth Hillbrand ab0049f0d1 Translated using Weblate (Lithuanian)
Currently translated at 98.7% (11237 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/lt/
2026-03-15 17:23:33 +01:00
Seth Hillbrand 2e6bb8102d Translated using Weblate (Thai)
Currently translated at 100.0% (11384 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/th/
2026-03-15 17:23:33 +01:00
Seth Hillbrand a8d5798aac Translated using Weblate (Hebrew)
Currently translated at 99.1% (11287 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/he/
2026-03-15 17:23:33 +01:00
Seth Hillbrand d2f5ffb5cb Translated using Weblate (Tamil)
Currently translated at 90.9% (10353 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ta/
2026-03-15 17:23:33 +01:00
Seth Hillbrand 9d816985a5 Translated using Weblate (Portuguese)
Currently translated at 100.0% (11384 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/pt/
2026-03-15 17:23:33 +01:00
Seth Hillbrand 357e2e9bd6 Translated using Weblate (Telugu)
Currently translated at 0.0% (0 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/te/
2026-03-15 17:23:33 +01:00
Seth Hillbrand d394584398 Translated using Weblate (Bulgarian)
Currently translated at 6.9% (796 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/bg/
2026-03-15 17:23:33 +01:00
Seth Hillbrand cd3d19f721 Translated using Weblate (Hindi)
Currently translated at 0.0% (0 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/hi/
2026-03-15 17:23:33 +01:00
Seth Hillbrand 37ef308ef3 Avoid calling OpenGL if we fail init
If we can't initialized OpenGL, then glFlush will be null, so calling is
a guaranteed crash
2026-03-16 08:37:33 -07:00
Jon Evans 1637a124ff API: always serialize with UTF-8 2026-03-15 22:02:55 -04:00
Jon Evans 24778647ab API: fix netclass filtering for multiple membership
Fixes https://gitlab.com/kicad/code/kicad/-/work_items/23435
2026-03-15 09:19:52 -04:00
Damjan Prerad 034af9d217 Fix overlapping Edge.Cuts cutouts in DRC and 3D viewer
Overlapping closed cutouts on Edge.Cuts were not reported in DRC
and 3D view of these overlapped coutouts was not renderd correctly.

This change adds explicit DRC detection for overlapping closed Edge.Cuts
contours and footprint Edge.Cuts contours.

Fixes https://gitlab.com/kicad/code/kicad/-/work_items/21829
2026-03-15 13:46:15 +01:00
John Beard 47294a0727 Allegro: parse 0x0C drill mark correctly in V180
The coordinates start one u32 later in v180. Take one off the end
in that case because the group pointer can also be matches between
versions.
2026-03-15 01:51:08 +08:00
John Beard 8da9149da2 Allegro: adjust sometimes-untrue test for FP consistency
The old FP backside logic was to flip anything on the back layer.
However this doesn't work for FPs with things on both sides, which
are rare but do exist (BB-AI-64 power socket for example has silk
on both sides).

In particular, there are some parts that have courtyards on the bottom
for top-side SMD fps:

 - MainBoard - the U1 courtyard is on the back - A mistake I think,
   but the layer class is indeed 0x09/0xfa - PLACE_BOUND_BOTTOM.
 - VCU118 - U1 has front and back courtyards too.
 - BeagleBone Black has a back CY for a thernal pad

So this test is not universally true. Restrict to a board (EVK
BaseBoard) that hs back SMD parts, but no violations of the
principle.
2026-03-15 01:50:07 +08:00
John Beard 6881bd29a5 Allegro: figure out back-side footprint transforms
This wasn't quite correct all backside footprint graphics
were flipped L-R from the gerber outputs on, say, BeagleBone AI.

Wwhat we need to do for back-side FPs:

- Apply a negative rotation if the FP is on the back side.
- For all non-pad items, do a pre-Flip to put the objects in
  front-side canonical form
- Pad padstacks (so the pad layers) are already in this form,
  but the positions are not, so apply a pre-rotation to pad
  positions.
- Apply a final L-R Flip() which puts everything on the correct
  side and position in the final board, while the FP objects are
  stored front-side form.

This now seems to put everything in place. It also correctly handles
the two-sides sikscreen on the BB-AI-64 power input connector which
has the body outline on the bottom (where the part is) but the power
polarity indicator on the other (top) side.
2026-03-14 21:21:26 +08:00
John Beard ed9776967f Allegro: Handle pastemask layers in BB-AI-64 holes
This is a guess at the layer mappings, but those circles in the
BeagleBone AI-64 MH pads must be solder paste, and we are missing
the PasteMask enum values.

Also assume non-courtyard, non-zone areas in FPs are filled shapes
though it would be better to find a flag for this if there is one.

This seems to also fix the BB-AI-64 filled silkscreen shapes
(e.g. the diode arrow in in the bottom left area) and the BB-AI
ESD warning logo on the back side. However back silkscreen items are
still all misplaced - missing a rotation or a flip presumably.
2026-03-14 19:49:51 +08:00
John Beard 874215e5af Allegro: fix versioned field in 0x22 blocks.
0x22 is a rare field wedon't see much. BB-AI is a V172 file, but
the 0x22 field has this element, so it must be at least V172, not
V174.

Add a block test to really nail this down (at least for V172!)

This allows BB-AI-64 to load successfully.
2026-03-14 14:48:35 +08:00
John Beard cfb3da773b Allegro: minor logging tweaks
Correct an index, and also we don't need to protect this trace,
since trace doesn't execute the format if it's not enabled (I think
the block used to have local variables, but not any more)
2026-03-14 13:57:44 +08:00
Seth Hillbrand 3b557a8c21 Translated using Weblate (Persian)
Currently translated at 7.3% (837 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/fa/
2026-03-13 23:43:53 +01:00
Mahdi Ahmadzadeh a7c30b03e6 Translated using Weblate (Persian)
Currently translated at 7.3% (837 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/fa/
2026-03-13 23:43:53 +01:00
Anonymous d4edcdfaeb Translated using Weblate (Persian)
Currently translated at 7.3% (837 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/fa/
2026-03-13 23:43:53 +01:00
j.Kolod f0f69f3fd4 Translated using Weblate (Polish)
Currently translated at 92.2% (10497 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/pl/
2026-03-13 23:43:52 +01:00
szumsky 02482ee258 Translated using Weblate (Polish)
Currently translated at 92.2% (10497 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/pl/
2026-03-13 23:43:52 +01:00
Pomian ae1ffb2f52 Translated using Weblate (Polish)
Currently translated at 92.2% (10497 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/pl/
2026-03-13 23:43:52 +01:00
Krzysztof Kawa e346f4b5fa Translated using Weblate (Polish)
Currently translated at 92.2% (10497 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/pl/
2026-03-13 23:43:52 +01:00
Jan Sobków a5bb267c18 Translated using Weblate (Polish)
Currently translated at 92.2% (10497 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/pl/
2026-03-13 23:43:52 +01:00
maksz42 bf500091a3 Translated using Weblate (Polish)
Currently translated at 92.2% (10497 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/pl/
2026-03-13 23:43:52 +01:00
Marek daf1b864c4 Translated using Weblate (Polish)
Currently translated at 92.2% (10497 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/pl/
2026-03-13 23:43:52 +01:00
Eryk Michalak 53abeaaa59 Translated using Weblate (Polish)
Currently translated at 92.2% (10497 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/pl/
2026-03-13 23:43:52 +01:00
Ivan Chuba c7577e5e2c Translated using Weblate (Polish)
Currently translated at 92.2% (10497 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/pl/
2026-03-13 23:43:52 +01:00
Grzegorz Szymaszek fc12b8a1ba Translated using Weblate (Polish)
Currently translated at 92.2% (10497 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/pl/
2026-03-13 23:43:52 +01:00
dsa-t 7c27c44443 Translated using Weblate (Polish)
Currently translated at 92.2% (10497 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/pl/
2026-03-13 23:43:52 +01:00
Henrik Kauhanen e4eb15038b Translated using Weblate (Polish)
Currently translated at 92.2% (10497 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/pl/
2026-03-13 23:43:52 +01:00
Seth Hillbrand f7b66bd458 Translated using Weblate (Polish)
Currently translated at 92.2% (10497 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/pl/
2026-03-13 23:43:52 +01:00
Mark Roszko 9dbeaf000c Translated using Weblate (Polish)
Currently translated at 92.2% (10497 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/pl/
2026-03-13 23:43:52 +01:00
Czam Ciał 6a3eea8fea Translated using Weblate (Polish)
Currently translated at 92.2% (10497 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/pl/
2026-03-13 23:43:52 +01:00
Anonymous bbfc98ff76 Translated using Weblate (Polish)
Currently translated at 92.2% (10497 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/pl/
2026-03-13 23:43:52 +01:00
ZbeeGin 68fb95d0d5 Translated using Weblate (Polish)
Currently translated at 92.2% (10497 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/pl/
2026-03-13 23:43:51 +01:00
Ahmed Elswah 4412c882ef Translated using Weblate (Arabic)
Currently translated at 1.0% (115 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ar/
2026-03-13 23:43:51 +01:00
Hesham Eina Abdalla 6d61575ff3 Translated using Weblate (Arabic)
Currently translated at 1.0% (115 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ar/
2026-03-13 23:43:51 +01:00
Morad Tamer ba180ab62d Translated using Weblate (Arabic)
Currently translated at 1.0% (115 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ar/
2026-03-13 23:43:51 +01:00
HADJAISSA 9806b74a4f Translated using Weblate (Arabic)
Currently translated at 1.0% (115 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ar/
2026-03-13 23:43:51 +01:00
Seth Hillbrand f9a70b422b Translated using Weblate (Arabic)
Currently translated at 1.0% (115 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ar/
2026-03-13 23:43:51 +01:00
Djamel Dellaa fc24a498bb Translated using Weblate (Arabic)
Currently translated at 1.0% (115 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ar/
2026-03-13 23:43:51 +01:00
Anonymous c82b4ac6f7 Translated using Weblate (Arabic)
Currently translated at 1.0% (115 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ar/
2026-03-13 23:43:51 +01:00
Echedey 58c90fe432 Translated using Weblate (Spanish)
Currently translated at 99.1% (11288 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/es/
2026-03-13 23:43:51 +01:00
dsa-t fbc34ca7d9 Translated using Weblate (Spanish)
Currently translated at 99.1% (11288 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/es/
2026-03-13 23:43:51 +01:00
Tomás Mora 4acf803791 Translated using Weblate (Spanish)
Currently translated at 99.1% (11288 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/es/
2026-03-13 23:43:51 +01:00
uLe f7a7181000 Translated using Weblate (Spanish)
Currently translated at 99.1% (11288 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/es/
2026-03-13 23:43:51 +01:00
Jose Perez ddbe7ed3a1 Translated using Weblate (Spanish)
Currently translated at 99.1% (11288 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/es/
2026-03-13 23:43:51 +01:00
ZbeeGin ccc1c7f4ff Translated using Weblate (Spanish)
Currently translated at 99.1% (11288 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/es/
2026-03-13 23:43:50 +01:00
Gaston Schelotto 13dbe3f6ec Translated using Weblate (Spanish)
Currently translated at 99.1% (11288 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/es/
2026-03-13 23:43:50 +01:00
Gabriel Martinez c7774384c5 Translated using Weblate (Spanish)
Currently translated at 99.1% (11288 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/es/
2026-03-13 23:43:50 +01:00
Pablo Bianchi 72c187c099 Translated using Weblate (Spanish)
Currently translated at 99.1% (11288 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/es/
2026-03-13 23:43:50 +01:00
Francisco Jose Rey 79ca2bc19d Translated using Weblate (Spanish)
Currently translated at 99.1% (11288 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/es/
2026-03-13 23:43:50 +01:00
Deleted User eb36bee65c Translated using Weblate (Spanish)
Currently translated at 99.1% (11288 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/es/
2026-03-13 23:43:50 +01:00
Ulices 37dc915c83 Translated using Weblate (Spanish)
Currently translated at 99.1% (11288 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/es/
2026-03-13 23:43:50 +01:00
Iñigo 52fd72c307 Translated using Weblate (Spanish)
Currently translated at 99.1% (11288 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/es/
2026-03-13 23:43:50 +01:00
Roberto Fernandez Bautista 54ce1d98cd Translated using Weblate (Spanish)
Currently translated at 99.1% (11288 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/es/
2026-03-13 23:43:50 +01:00
VicSanRoPe 1b29265660 Translated using Weblate (Spanish)
Currently translated at 99.1% (11288 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/es/
2026-03-13 23:43:50 +01:00
Anonymous 0d284fd186 Translated using Weblate (Spanish)
Currently translated at 99.1% (11288 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/es/
2026-03-13 23:43:50 +01:00
Iñigo Figuero Sanz 5c7caeb0bc Translated using Weblate (Spanish)
Currently translated at 99.1% (11288 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/es/
2026-03-13 23:43:50 +01:00
Adolfo Jayme Barrientos 947a1bd5dd Translated using Weblate (Spanish)
Currently translated at 99.1% (11288 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/es/
2026-03-13 23:43:50 +01:00
Seth Hillbrand b0858d79db Translated using Weblate (Spanish)
Currently translated at 99.1% (11288 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/es/
2026-03-13 23:43:50 +01:00
Nicoara Alex 7a2917ecef Translated using Weblate (Romanian)
Currently translated at 26.9% (3063 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ro/
2026-03-13 23:43:50 +01:00
Adrian Scripcă 620901002d Translated using Weblate (Romanian)
Currently translated at 26.9% (3063 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ro/
2026-03-13 23:43:49 +01:00
Henrik Kauhanen 50d001f7b2 Translated using Weblate (Romanian)
Currently translated at 26.9% (3063 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ro/
2026-03-13 23:43:49 +01:00
Seth Hillbrand 13db9ecf35 Translated using Weblate (Romanian)
Currently translated at 26.9% (3063 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ro/
2026-03-13 23:43:49 +01:00
Tatu Bogdan 57d3d9d8ce Translated using Weblate (Romanian)
Currently translated at 26.9% (3063 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ro/
2026-03-13 23:43:49 +01:00
Peter B 4cd9a2c6d9 Translated using Weblate (Romanian)
Currently translated at 26.9% (3063 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ro/
2026-03-13 23:43:49 +01:00
Alex Gellen fce14b97a8 Translated using Weblate (Romanian)
Currently translated at 26.9% (3063 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ro/
2026-03-13 23:43:49 +01:00
Anonymous ac03c44095 Translated using Weblate (Romanian)
Currently translated at 26.9% (3063 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ro/
2026-03-13 23:43:49 +01:00
Seth Hillbrand 68be738355 Translated using Weblate (Thai)
Currently translated at 49.9% (5686 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/th/
2026-03-13 23:43:49 +01:00
boonchai k. 770a84062d Translated using Weblate (Thai)
Currently translated at 49.9% (5686 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/th/
2026-03-13 23:43:49 +01:00
Anonymous 7786e7ed42 Translated using Weblate (Thai)
Currently translated at 49.9% (5686 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/th/
2026-03-13 23:43:49 +01:00
Jarl Gjessing 8e37dbd158 Translated using Weblate (Norwegian Bokmål)
Currently translated at 100.0% (11384 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/nb_NO/
2026-03-13 23:43:49 +01:00
Petter Reinholdtsen 6ea53f664b Translated using Weblate (Norwegian Bokmål)
Currently translated at 100.0% (11384 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/nb_NO/
2026-03-13 23:43:49 +01:00
Håvard Syslak 0d87a24032 Translated using Weblate (Norwegian Bokmål)
Currently translated at 100.0% (11384 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/nb_NO/
2026-03-13 23:43:49 +01:00
Henrik Kauhanen 7be0b3c095 Translated using Weblate (Norwegian Bokmål)
Currently translated at 100.0% (11384 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/nb_NO/
2026-03-13 23:43:49 +01:00
Stian Kristensen 6aa2112136 Translated using Weblate (Norwegian Bokmål)
Currently translated at 100.0% (11384 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/nb_NO/
2026-03-13 23:43:49 +01:00
Anonymous 508925486d Translated using Weblate (Norwegian Bokmål)
Currently translated at 100.0% (11384 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/nb_NO/
2026-03-13 23:43:48 +01:00
Allan Nordhøy 588b8006eb Translated using Weblate (Norwegian Bokmål)
Currently translated at 100.0% (11384 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/nb_NO/
2026-03-13 23:43:48 +01:00
Seth Hillbrand c0231a17f0 Translated using Weblate (Norwegian Bokmål)
Currently translated at 100.0% (11384 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/nb_NO/
2026-03-13 23:43:48 +01:00
Anonymous 763ac5af4d Translated using Weblate (Hindi)
Currently translated at 0.0% (0 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/hi/
2026-03-13 23:43:48 +01:00
dsa-t 997e9ae8c4 Translated using Weblate (Serbian)
Currently translated at 15.9% (1813 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/sr/
2026-03-13 23:43:48 +01:00
Seth Hillbrand 479bcad484 Translated using Weblate (Serbian)
Currently translated at 15.9% (1813 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/sr/
2026-03-13 23:43:48 +01:00
___davidpr 2103dc116e Translated using Weblate (Serbian)
Currently translated at 15.9% (1813 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/sr/
2026-03-13 23:43:48 +01:00
Luka Borkovic 9476725db5 Translated using Weblate (Serbian)
Currently translated at 15.9% (1813 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/sr/
2026-03-13 23:43:48 +01:00
Anonymous 0df7ccada1 Translated using Weblate (Serbian)
Currently translated at 15.9% (1813 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/sr/
2026-03-13 23:43:48 +01:00
boromyr 03892a9d4d Translated using Weblate (Italian)
Currently translated at 98.7% (11239 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/it/
2026-03-13 23:43:48 +01:00
Luca Mattii a3fef9465c Translated using Weblate (Italian)
Currently translated at 98.7% (11239 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/it/
2026-03-13 23:43:48 +01:00
Seth Hillbrand 889dd905ab Translated using Weblate (Italian)
Currently translated at 98.7% (11239 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/it/
2026-03-13 23:43:48 +01:00
Anonymous c82677ba50 Translated using Weblate (Italian)
Currently translated at 98.7% (11239 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/it/
2026-03-13 23:43:48 +01:00
Marco Ciampa dd36178913 Translated using Weblate (Italian)
Currently translated at 98.7% (11239 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/it/
2026-03-13 23:43:47 +01:00
Johan Heikkilä fe58ddd990 Translated using Weblate (Swedish)
Currently translated at 98.7% (11243 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/sv/
2026-03-13 23:43:47 +01:00
dsa-t 5f11bce844 Translated using Weblate (Swedish)
Currently translated at 98.7% (11243 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/sv/
2026-03-13 23:43:47 +01:00
Stefan Bjornelund the Gnome ec12368915 Translated using Weblate (Swedish)
Currently translated at 98.7% (11243 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/sv/
2026-03-13 23:43:47 +01:00
Joakim Lundborg 418e611c99 Translated using Weblate (Swedish)
Currently translated at 98.7% (11243 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/sv/
2026-03-13 23:43:47 +01:00
Hanna Breisand 35b958d18d Translated using Weblate (Swedish)
Currently translated at 98.7% (11243 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/sv/
2026-03-13 23:43:47 +01:00
Richard Jonsson 60ad18a92c Translated using Weblate (Swedish)
Currently translated at 98.7% (11243 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/sv/
2026-03-13 23:43:47 +01:00
ZbeeGin d72c45d8ab Translated using Weblate (Swedish)
Currently translated at 98.7% (11243 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/sv/
2026-03-13 23:43:47 +01:00
Axel Henriksson 08f061c70d Translated using Weblate (Swedish)
Currently translated at 98.7% (11243 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/sv/
2026-03-13 23:43:47 +01:00
Anonymous 3d387ad9a1 Translated using Weblate (Swedish)
Currently translated at 98.7% (11243 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/sv/
2026-03-13 23:43:47 +01:00
Seth Hillbrand 0a54ae55fd Translated using Weblate (Swedish)
Currently translated at 98.7% (11243 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/sv/
2026-03-13 23:43:47 +01:00
Henrik Kauhanen 77b0db6ab2 Translated using Weblate (Swedish)
Currently translated at 98.7% (11243 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/sv/
2026-03-13 23:43:47 +01:00
Artem e87a25e2a7 Translated using Weblate (Ukrainian)
Currently translated at 97.9% (11153 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/uk/
2026-03-13 23:43:47 +01:00
dsa-t 7ccb343990 Translated using Weblate (Ukrainian)
Currently translated at 97.9% (11153 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/uk/
2026-03-13 23:43:47 +01:00
Andrii Shelestov d2a4f51078 Translated using Weblate (Ukrainian)
Currently translated at 97.9% (11153 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/uk/
2026-03-13 23:43:47 +01:00
Seth Hillbrand 81421e1b32 Translated using Weblate (Ukrainian)
Currently translated at 97.9% (11153 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/uk/
2026-03-13 23:43:47 +01:00
Stanislav Kaliuk bf70ac8a3a Translated using Weblate (Ukrainian)
Currently translated at 97.9% (11153 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/uk/
2026-03-13 23:43:46 +01:00
Anonymous 8eb9a4bd4a Translated using Weblate (Ukrainian)
Currently translated at 97.9% (11153 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/uk/
2026-03-13 23:43:46 +01:00
Kuzemko Alexsandr 3b8b5bfbba Translated using Weblate (Ukrainian)
Currently translated at 97.9% (11153 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/uk/
2026-03-13 23:43:46 +01:00
Ivan Chuba 3922a796e2 Translated using Weblate (Ukrainian)
Currently translated at 97.9% (11153 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/uk/
2026-03-13 23:43:46 +01:00
Максим Горпиніч 64d0e5dd5b Translated using Weblate (Ukrainian)
Currently translated at 97.9% (11153 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/uk/
2026-03-13 23:43:46 +01:00
dsa-t 70d274449d Translated using Weblate (Bulgarian)
Currently translated at 6.9% (796 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/bg/
2026-03-13 23:43:46 +01:00
Seth Hillbrand 82821818cd Translated using Weblate (Bulgarian)
Currently translated at 6.9% (796 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/bg/
2026-03-13 23:43:46 +01:00
109247019824 053610d162 Translated using Weblate (Bulgarian)
Currently translated at 6.9% (796 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/bg/
2026-03-13 23:43:46 +01:00
Anonymous 71686da44e Translated using Weblate (Bulgarian)
Currently translated at 6.9% (796 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/bg/
2026-03-13 23:43:46 +01:00
김인수 7857b97581 Translated using Weblate (Korean)
Currently translated at 99.1% (11288 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ko/
2026-03-13 23:43:46 +01:00
jeongsuAn f95ab61f8a Translated using Weblate (Korean)
Currently translated at 99.1% (11288 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ko/
2026-03-13 23:43:46 +01:00
김용재 7feef0c7ed Translated using Weblate (Korean)
Currently translated at 99.1% (11288 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ko/
2026-03-13 23:43:46 +01:00
이윤성 159ae82f5f Translated using Weblate (Korean)
Currently translated at 99.1% (11288 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ko/
2026-03-13 23:43:46 +01:00
김낙환 fbc7b1dcfc Translated using Weblate (Korean)
Currently translated at 99.1% (11288 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ko/
2026-03-13 23:43:46 +01:00
김유진 9eb8b405e1 Translated using Weblate (Korean)
Currently translated at 99.1% (11288 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ko/
2026-03-13 23:43:45 +01:00
박세훈 ea88d72c41 Translated using Weblate (Korean)
Currently translated at 99.1% (11288 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ko/
2026-03-13 23:43:45 +01:00
이기형 b3808e3bf0 Translated using Weblate (Korean)
Currently translated at 99.1% (11288 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ko/
2026-03-13 23:43:45 +01:00
Pedro Moreira 400578a0a7 Translated using Weblate (Korean)
Currently translated at 99.1% (11288 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ko/
2026-03-13 23:43:45 +01:00
김호진 e5584449c1 Translated using Weblate (Korean)
Currently translated at 99.1% (11288 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ko/
2026-03-13 23:43:45 +01:00
Jason Son 12bb531704 Translated using Weblate (Korean)
Currently translated at 99.1% (11288 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ko/
2026-03-13 23:43:45 +01:00
이상수 e4975933a7 Translated using Weblate (Korean)
Currently translated at 99.1% (11288 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ko/
2026-03-13 23:43:45 +01:00
minsu kim (0xGabriel) d0fda8347f Translated using Weblate (Korean)
Currently translated at 99.1% (11288 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ko/
2026-03-13 23:43:45 +01:00
YunJiSang 206344b381 Translated using Weblate (Korean)
Currently translated at 99.1% (11288 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ko/
2026-03-13 23:43:45 +01:00
dsa-t fc3aa97ebd Translated using Weblate (Korean)
Currently translated at 99.1% (11288 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ko/
2026-03-13 23:43:45 +01:00
KwonHyeokbeom 1b82a64d3c Translated using Weblate (Korean)
Currently translated at 99.1% (11288 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ko/
2026-03-13 23:43:45 +01:00
kmn4555 ad871e4c84 Translated using Weblate (Korean)
Currently translated at 99.1% (11288 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ko/
2026-03-13 23:43:45 +01:00
jeong-sangwon 84a7a0fd62 Translated using Weblate (Korean)
Currently translated at 99.1% (11288 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ko/
2026-03-13 23:43:45 +01:00
김세영 c4e1927f66 Translated using Weblate (Korean)
Currently translated at 99.1% (11288 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ko/
2026-03-13 23:43:45 +01:00
DevAny 2f85e3ed49 Translated using Weblate (Korean)
Currently translated at 99.1% (11288 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ko/
2026-03-13 23:43:45 +01:00
Anonymous 945603f7f4 Translated using Weblate (Korean)
Currently translated at 99.1% (11288 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ko/
2026-03-13 23:43:45 +01:00
김랑기 401e06831c Translated using Weblate (Korean)
Currently translated at 99.1% (11288 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ko/
2026-03-13 23:43:44 +01:00
Seth Hillbrand 8cc3d58503 Translated using Weblate (Korean)
Currently translated at 99.1% (11288 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ko/
2026-03-13 23:43:44 +01:00
Anonymous 1ead8d4725 Translated using Weblate (Estonian)
Currently translated at 99.1% (11292 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/et/
2026-03-13 23:43:44 +01:00
Ivan Chuba b3b1f3ccdb Translated using Weblate (Estonian)
Currently translated at 99.1% (11292 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/et/
2026-03-13 23:43:44 +01:00
Seth Hillbrand 168bcecbfb Translated using Weblate (Estonian)
Currently translated at 99.1% (11292 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/et/
2026-03-13 23:43:44 +01:00
Roman Ondráček b95ea8516e Translated using Weblate (Czech)
Currently translated at 67.4% (7678 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/cs/
2026-03-13 23:43:44 +01:00
EdizonTN e6d6c6eb47 Translated using Weblate (Czech)
Currently translated at 67.4% (7678 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/cs/
2026-03-13 23:43:44 +01:00
Hynek Štětina ec99640f07 Translated using Weblate (Czech)
Currently translated at 67.4% (7678 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/cs/
2026-03-13 23:43:44 +01:00
Michal Kundrát c3e60bc184 Translated using Weblate (Czech)
Currently translated at 67.4% (7678 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/cs/
2026-03-13 23:43:44 +01:00
René Široký 48bd3c2cf3 Translated using Weblate (Czech)
Currently translated at 67.4% (7678 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/cs/
2026-03-13 23:43:44 +01:00
Ondřej Čertík c54e27e3cb Translated using Weblate (Czech)
Currently translated at 67.4% (7678 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/cs/
2026-03-13 23:43:44 +01:00
dsa-t 992d8fd710 Translated using Weblate (Czech)
Currently translated at 67.4% (7678 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/cs/
2026-03-13 23:43:44 +01:00
Andrej Valek 8e0964235b Translated using Weblate (Czech)
Currently translated at 67.4% (7678 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/cs/
2026-03-13 23:43:44 +01:00
Jan Vykydal 1c3f937eac Translated using Weblate (Czech)
Currently translated at 67.4% (7678 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/cs/
2026-03-13 23:43:44 +01:00
Radovan Blažek ba12735c59 Translated using Weblate (Czech)
Currently translated at 67.4% (7678 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/cs/
2026-03-13 23:43:43 +01:00
Radek K e7eb8306e2 Translated using Weblate (Czech)
Currently translated at 67.4% (7678 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/cs/
2026-03-13 23:43:43 +01:00
ivit VT 9d91f67bfc Translated using Weblate (Czech)
Currently translated at 67.4% (7678 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/cs/
2026-03-13 23:43:43 +01:00
Tomas0015 173d3adfb8 Translated using Weblate (Czech)
Currently translated at 67.4% (7678 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/cs/
2026-03-13 23:43:43 +01:00
Petr Pazourek 85cd9a911a Translated using Weblate (Czech)
Currently translated at 67.4% (7678 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/cs/
2026-03-13 23:43:43 +01:00
Seth Hillbrand 615abf0ba7 Translated using Weblate (Czech)
Currently translated at 67.4% (7678 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/cs/
2026-03-13 23:43:43 +01:00
Jan Straka 2dd05bc728 Translated using Weblate (Czech)
Currently translated at 67.4% (7678 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/cs/
2026-03-13 23:43:43 +01:00
Anonymous ce4f81fa68 Translated using Weblate (Czech)
Currently translated at 67.4% (7678 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/cs/
2026-03-13 23:43:43 +01:00
МАН69К 02d8843683 Translated using Weblate (Russian)
Currently translated at 82.8% (9433 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ru/
2026-03-13 23:43:43 +01:00
Дмитрий Дёмин 7a7ab404df Translated using Weblate (Russian)
Currently translated at 82.8% (9433 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ru/
2026-03-13 23:43:43 +01:00
sergio bb488ed571 Translated using Weblate (Russian)
Currently translated at 82.8% (9433 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ru/
2026-03-13 23:43:43 +01:00
xXx 6fb7516576 Translated using Weblate (Russian)
Currently translated at 82.8% (9433 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ru/
2026-03-13 23:43:43 +01:00
ZbeeGin 8d0a2b18fe Translated using Weblate (Russian)
Currently translated at 82.8% (9433 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ru/
2026-03-13 23:43:43 +01:00
Free_squire 2ae6fccd92 Translated using Weblate (Russian)
Currently translated at 82.8% (9433 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ru/
2026-03-13 23:43:43 +01:00
Dmitry Mikhirev e2ccb4277a Translated using Weblate (Russian)
Currently translated at 82.8% (9433 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ru/
2026-03-13 23:43:43 +01:00
Seth Hillbrand e763de4ba7 Translated using Weblate (Russian)
Currently translated at 82.8% (9433 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ru/
2026-03-13 23:43:42 +01:00
Дмитрий Михирев 8e92aae655 Translated using Weblate (Russian)
Currently translated at 82.8% (9433 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ru/
2026-03-13 23:43:42 +01:00
gfbdrgng dd713ac82c Translated using Weblate (Russian)
Currently translated at 82.8% (9433 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ru/
2026-03-13 23:43:42 +01:00
Andrey Fedorushkov 123830785b Translated using Weblate (Russian)
Currently translated at 82.8% (9433 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ru/
2026-03-13 23:43:42 +01:00
Ivan Chuba e7339ce897 Translated using Weblate (Russian)
Currently translated at 82.8% (9433 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ru/
2026-03-13 23:43:42 +01:00
alevtina-karashokova 5534358950 Translated using Weblate (Russian)
Currently translated at 82.8% (9433 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ru/
2026-03-13 23:43:42 +01:00
dsa-t 6b0c8b6f19 Translated using Weblate (Russian)
Currently translated at 82.8% (9433 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ru/
2026-03-13 23:43:42 +01:00
Konstantin Baranovskiy 55841d282b Translated using Weblate (Russian)
Currently translated at 82.8% (9433 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ru/
2026-03-13 23:43:42 +01:00
Anonymous bd7c9ff8ab Translated using Weblate (Russian)
Currently translated at 82.8% (9433 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ru/
2026-03-13 23:43:42 +01:00
dsa-t 24eb675815 Translated using Weblate (Tamil)
Currently translated at 90.9% (10353 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ta/
2026-03-13 23:43:42 +01:00
Seth Hillbrand b704ccff63 Translated using Weblate (Tamil)
Currently translated at 90.9% (10353 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ta/
2026-03-13 23:43:42 +01:00
Anonymous c333485787 Translated using Weblate (Tamil)
Currently translated at 90.9% (10353 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ta/
2026-03-13 23:43:42 +01:00
தமிழ்நேரம் db1d7f1497 Translated using Weblate (Tamil)
Currently translated at 90.9% (10353 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ta/
2026-03-13 23:43:42 +01:00
ZbeeGin ca7e881d21 Translated using Weblate (Lithuanian)
Currently translated at 35.3% (4025 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/lt/
2026-03-13 23:43:42 +01:00
Ignas Brašiškis 4bc8401569 Translated using Weblate (Lithuanian)
Currently translated at 35.3% (4025 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/lt/
2026-03-13 23:43:41 +01:00
Henrik Kauhanen 2fc4c97c7f Translated using Weblate (Lithuanian)
Currently translated at 35.3% (4025 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/lt/
2026-03-13 23:43:41 +01:00
WhiteChairFromIkea 4705db3bbf Translated using Weblate (Lithuanian)
Currently translated at 35.3% (4025 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/lt/
2026-03-13 23:43:41 +01:00
Seth Hillbrand f87be9c682 Translated using Weblate (Lithuanian)
Currently translated at 35.3% (4025 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/lt/
2026-03-13 23:43:41 +01:00
Anonymous ec89f66715 Translated using Weblate (Lithuanian)
Currently translated at 35.3% (4025 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/lt/
2026-03-13 23:43:41 +01:00
Sašo Domadenik 3bbe988fa2 Translated using Weblate (Slovenian)
Currently translated at 1.2% (141 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/sl/
2026-03-13 23:43:41 +01:00
Mitja Nemec dd1efdfc49 Translated using Weblate (Slovenian)
Currently translated at 1.2% (141 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/sl/
2026-03-13 23:43:41 +01:00
Seth Hillbrand fa139c5088 Translated using Weblate (Slovenian)
Currently translated at 1.2% (141 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/sl/
2026-03-13 23:43:41 +01:00
Vitan Košpenda 4f18162eff Translated using Weblate (Slovenian)
Currently translated at 1.2% (141 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/sl/
2026-03-13 23:43:41 +01:00
Anonymous d47a94423f Translated using Weblate (Slovenian)
Currently translated at 1.2% (141 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/sl/
2026-03-13 23:43:41 +01:00
yangyangdaji 3407a13f88 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 95.1% (10830 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/zh_Hans/
2026-03-13 23:43:41 +01:00
Pinpang Liao dad9ffb6e3 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 95.1% (10830 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/zh_Hans/
2026-03-13 23:43:41 +01:00
JasonTan e03563738c Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 95.1% (10830 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/zh_Hans/
2026-03-13 23:43:40 +01:00
aisuneko icecat b63241de0b Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 95.1% (10830 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/zh_Hans/
2026-03-13 23:43:40 +01:00
Li Yidong f5f2acec8a Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 95.1% (10830 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/zh_Hans/
2026-03-13 23:43:40 +01:00
Liu Guang 7f0b5b59f8 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 95.1% (10830 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/zh_Hans/
2026-03-13 23:43:40 +01:00
CharlieYu 89fc1e8998 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 95.1% (10830 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/zh_Hans/
2026-03-13 23:43:40 +01:00
Dingzhong Chen b4571437cf Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 95.1% (10830 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/zh_Hans/
2026-03-13 23:43:40 +01:00
Zhen Sun 1325b48ecd Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 95.1% (10830 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/zh_Hans/
2026-03-13 23:43:40 +01:00
HalfSweet 13afbe6143 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 95.1% (10830 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/zh_Hans/
2026-03-13 23:43:40 +01:00
dsa-t 3cd1d97e07 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 95.1% (10830 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/zh_Hans/
2026-03-13 23:43:40 +01:00
Rigo Ligo 778f7a6127 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 95.1% (10830 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/zh_Hans/
2026-03-13 23:43:40 +01:00
欠陥電気 33d58675f1 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 95.1% (10830 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/zh_Hans/
2026-03-13 23:43:40 +01:00
Tian Yunhao f2c57ee4d4 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 95.1% (10830 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/zh_Hans/
2026-03-13 23:43:40 +01:00
Seth Hillbrand f5bc48d7ee Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 95.1% (10830 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/zh_Hans/
2026-03-13 23:43:40 +01:00
向阳阳 75dd222b35 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 95.1% (10830 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/zh_Hans/
2026-03-13 23:43:40 +01:00
taotieren 46881e3754 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 95.1% (10830 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/zh_Hans/
2026-03-13 23:43:40 +01:00
Ian McInerney 7887ec0fbd Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 95.1% (10830 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/zh_Hans/
2026-03-13 23:43:40 +01:00
Deleted User 4e332654f9 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 95.1% (10830 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/zh_Hans/
2026-03-13 23:43:39 +01:00
Hubert Hu ed5c78732f Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 95.1% (10830 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/zh_Hans/
2026-03-13 23:43:39 +01:00
CloverGit 90e80237cc Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 95.1% (10830 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/zh_Hans/
2026-03-13 23:43:39 +01:00
Anonymous 790a3ba875 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 95.1% (10830 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/zh_Hans/
2026-03-13 23:43:39 +01:00
John Beard 8fe156607e Translated using Weblate (German)
Currently translated at 100.0% (11384 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/de/
2026-03-13 23:43:39 +01:00
Ken Ovo ecd21af74b Translated using Weblate (German)
Currently translated at 100.0% (11384 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/de/
2026-03-13 23:43:39 +01:00
Ivan Chuba d96d10c20b Translated using Weblate (German)
Currently translated at 100.0% (11384 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/de/
2026-03-13 23:43:39 +01:00
jonathan haas 52ce5eed02 Translated using Weblate (German)
Currently translated at 100.0% (11384 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/de/
2026-03-13 23:43:39 +01:00
Flo082002 5d5fbe4d3c Translated using Weblate (German)
Currently translated at 100.0% (11384 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/de/
2026-03-13 23:43:39 +01:00
Christian Schlüter 018131de5d Translated using Weblate (German)
Currently translated at 100.0% (11384 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/de/
2026-03-13 23:43:39 +01:00
Sven 198bd7e53f Translated using Weblate (German)
Currently translated at 100.0% (11384 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/de/
2026-03-13 23:43:39 +01:00
magical-obama e29a57d455 Translated using Weblate (German)
Currently translated at 100.0% (11384 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/de/
2026-03-13 23:43:39 +01:00
Julian Daube fe4fc23d5f Translated using Weblate (German)
Currently translated at 100.0% (11384 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/de/
2026-03-13 23:43:39 +01:00
dsa-t 09c1ab4c45 Translated using Weblate (German)
Currently translated at 100.0% (11384 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/de/
2026-03-13 23:43:39 +01:00
Mathias Neumann 02feb8c804 Translated using Weblate (German)
Currently translated at 100.0% (11384 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/de/
2026-03-13 23:43:39 +01:00
ulikoehler a14db4730f Translated using Weblate (German)
Currently translated at 100.0% (11384 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/de/
2026-03-13 23:43:39 +01:00
Karl SCHUH 2e09845f14 Translated using Weblate (German)
Currently translated at 100.0% (11384 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/de/
2026-03-13 23:43:39 +01:00
Markus 9d8d92be0f Translated using Weblate (German)
Currently translated at 100.0% (11384 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/de/
2026-03-13 23:43:38 +01:00
Lauritz Tieste 26a4a2f71f Translated using Weblate (German)
Currently translated at 100.0% (11384 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/de/
2026-03-13 23:43:38 +01:00
Kliment 782ff33ad9 Translated using Weblate (German)
Currently translated at 100.0% (11384 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/de/
2026-03-13 23:43:38 +01:00
Dominik Wernberger 7377c4cd67 Translated using Weblate (German)
Currently translated at 100.0% (11384 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/de/
2026-03-13 23:43:38 +01:00
Henrik Kauhanen 2852ff94f1 Translated using Weblate (German)
Currently translated at 100.0% (11384 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/de/
2026-03-13 23:43:38 +01:00
weblateuser 4fa87527c5 Translated using Weblate (German)
Currently translated at 100.0% (11384 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/de/
2026-03-13 23:43:38 +01:00
Johannes Maibaum 4449dda900 Translated using Weblate (German)
Currently translated at 100.0% (11384 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/de/
2026-03-13 23:43:38 +01:00
Benedikt Freisen f0a7a13b19 Translated using Weblate (German)
Currently translated at 100.0% (11384 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/de/
2026-03-13 23:43:38 +01:00
Luc 5e78880863 Translated using Weblate (German)
Currently translated at 100.0% (11384 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/de/
2026-03-13 23:43:38 +01:00
Frank Sonnenberg 940991efb7 Translated using Weblate (German)
Currently translated at 100.0% (11384 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/de/
2026-03-13 23:43:38 +01:00
Ettore Atalan f0b3508ac5 Translated using Weblate (German)
Currently translated at 100.0% (11384 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/de/
2026-03-13 23:43:38 +01:00
Mark Hämmerling ba11705b30 Translated using Weblate (German)
Currently translated at 100.0% (11384 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/de/
2026-03-13 23:43:38 +01:00
Jonathan Haas be394f3f3f Translated using Weblate (German)
Currently translated at 100.0% (11384 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/de/
2026-03-13 23:43:38 +01:00
Anonymous e4b5c2d577 Translated using Weblate (German)
Currently translated at 100.0% (11384 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/de/
2026-03-13 23:43:38 +01:00
Pferd O. bf1b793f65 Translated using Weblate (German)
Currently translated at 100.0% (11384 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/de/
2026-03-13 23:43:38 +01:00
Seth Hillbrand 53a3b5de31 Translated using Weblate (German)
Currently translated at 100.0% (11384 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/de/
2026-03-13 23:43:37 +01:00
SubaruArai e53afe5f7e Translated using Weblate (Japanese)
Currently translated at 100.0% (11384 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ja/
2026-03-13 23:43:37 +01:00
dsa-t d34b4cceca Translated using Weblate (Japanese)
Currently translated at 100.0% (11384 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ja/
2026-03-13 23:43:37 +01:00
Keisuke Nakao 857183d524 Translated using Weblate (Japanese)
Currently translated at 100.0% (11384 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ja/
2026-03-13 23:43:37 +01:00
Yutaro Urata2 439b42aaec Translated using Weblate (Japanese)
Currently translated at 100.0% (11384 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ja/
2026-03-13 23:43:37 +01:00
Ji Yoon Choi 05ac14de15 Translated using Weblate (Japanese)
Currently translated at 100.0% (11384 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ja/
2026-03-13 23:43:37 +01:00
Seth Hillbrand ea27a4cccc Translated using Weblate (Japanese)
Currently translated at 100.0% (11384 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ja/
2026-03-13 23:43:37 +01:00
Anonymous 1690a1012b Translated using Weblate (Japanese)
Currently translated at 100.0% (11384 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ja/
2026-03-13 23:43:37 +01:00
co8 j 1e4d0ef80b Translated using Weblate (Japanese)
Currently translated at 100.0% (11384 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ja/
2026-03-13 23:43:37 +01:00
Tokita, Hiroshi d713e78b58 Translated using Weblate (Japanese)
Currently translated at 100.0% (11384 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ja/
2026-03-13 23:43:37 +01:00
2tama3 bb8fb64668 Translated using Weblate (Japanese)
Currently translated at 100.0% (11384 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ja/
2026-03-13 23:43:37 +01:00
Flórián Fuszkó a4b5e0a401 Translated using Weblate (Hungarian)
Currently translated at 49.7% (5666 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/hu/
2026-03-13 23:43:37 +01:00
iamPeter 0cc859460b Translated using Weblate (Hungarian)
Currently translated at 49.7% (5666 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/hu/
2026-03-13 23:43:37 +01:00
Elek Zoltán d4f38c13a7 Translated using Weblate (Hungarian)
Currently translated at 49.7% (5666 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/hu/
2026-03-13 23:43:37 +01:00
dsa-t a68e7de31a Translated using Weblate (Hungarian)
Currently translated at 49.7% (5666 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/hu/
2026-03-13 23:43:37 +01:00
Seth Hillbrand e3d3b7ecf3 Translated using Weblate (Hungarian)
Currently translated at 49.7% (5666 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/hu/
2026-03-13 23:43:36 +01:00
KB 6bbcb41019 Translated using Weblate (Hungarian)
Currently translated at 49.7% (5666 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/hu/
2026-03-13 23:43:36 +01:00
Miklós Márton 3a7b885c4c Translated using Weblate (Hungarian)
Currently translated at 49.7% (5666 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/hu/
2026-03-13 23:43:36 +01:00
Balázs Meskó 7fef884190 Translated using Weblate (Hungarian)
Currently translated at 49.7% (5666 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/hu/
2026-03-13 23:43:36 +01:00
Hajdu Norbert fe23d245e5 Translated using Weblate (Hungarian)
Currently translated at 49.7% (5666 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/hu/
2026-03-13 23:43:36 +01:00
István Farkas 1ff434ba12 Translated using Weblate (Hungarian)
Currently translated at 49.7% (5666 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/hu/
2026-03-13 23:43:36 +01:00
Sárkány Lőrinc 2051f3626c Translated using Weblate (Hungarian)
Currently translated at 49.7% (5666 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/hu/
2026-03-13 23:43:36 +01:00
Anonymous 9d1428a50f Translated using Weblate (Hungarian)
Currently translated at 49.7% (5666 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/hu/
2026-03-13 23:43:36 +01:00
brunofaus 3da31e1328 Translated using Weblate (Portuguese (Brazil))
Currently translated at 99.1% (11289 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/pt_BR/
2026-03-13 23:43:36 +01:00
soldado-do-wolfenstein cea46f2153 Translated using Weblate (Portuguese (Brazil))
Currently translated at 99.1% (11289 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/pt_BR/
2026-03-13 23:43:36 +01:00
dsa-t 8da02f1733 Translated using Weblate (Portuguese (Brazil))
Currently translated at 99.1% (11289 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/pt_BR/
2026-03-13 23:43:36 +01:00
Hildo Guillardi Júnior c378da0c8e Translated using Weblate (Portuguese (Brazil))
Currently translated at 99.1% (11289 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/pt_BR/
2026-03-13 23:43:36 +01:00
John Beard 72d4bae477 Translated using Weblate (Portuguese (Brazil))
Currently translated at 99.1% (11289 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/pt_BR/
2026-03-13 23:43:36 +01:00
Pedro Moreira 3db624e682 Translated using Weblate (Portuguese (Brazil))
Currently translated at 99.1% (11289 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/pt_BR/
2026-03-13 23:43:36 +01:00
Augusto Fraga Giachero ab2a14d0ef Translated using Weblate (Portuguese (Brazil))
Currently translated at 99.1% (11289 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/pt_BR/
2026-03-13 23:43:36 +01:00
Seth Hillbrand 2ea4261c09 Translated using Weblate (Portuguese (Brazil))
Currently translated at 99.1% (11289 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/pt_BR/
2026-03-13 23:43:36 +01:00
Anonymous df9b6e0c24 Translated using Weblate (Portuguese (Brazil))
Currently translated at 99.1% (11289 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/pt_BR/
2026-03-13 23:43:36 +01:00
Wellington Terumi Uemura 04bc4d4a7a Translated using Weblate (Portuguese (Brazil))
Currently translated at 99.1% (11289 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/pt_BR/
2026-03-13 23:43:35 +01:00
whenwesober 4e7f70b203 Translated using Weblate (Indonesian)
Currently translated at 11.8% (1354 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/id/
2026-03-13 23:43:35 +01:00
Jacque Fresco 4ef3bfc409 Translated using Weblate (Indonesian)
Currently translated at 11.8% (1354 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/id/
2026-03-13 23:43:35 +01:00
Seth Hillbrand 1e42e7b767 Translated using Weblate (Indonesian)
Currently translated at 11.8% (1354 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/id/
2026-03-13 23:43:35 +01:00
Reza Almanda 2f0964ff77 Translated using Weblate (Indonesian)
Currently translated at 11.8% (1354 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/id/
2026-03-13 23:43:35 +01:00
Neko Nekowazarashi 43870428b4 Translated using Weblate (Indonesian)
Currently translated at 11.8% (1354 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/id/
2026-03-13 23:43:35 +01:00
Triyan W. Nugroho 6d48e42452 Translated using Weblate (Indonesian)
Currently translated at 11.8% (1354 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/id/
2026-03-13 23:43:35 +01:00
Anonymous dc87fb1d83 Translated using Weblate (Indonesian)
Currently translated at 11.8% (1354 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/id/
2026-03-13 23:43:35 +01:00
Deleted User 5e25aa508d Translated using Weblate (Spanish (Mexico))
Currently translated at 99.1% (11288 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/es_MX/
2026-03-13 23:43:35 +01:00
uLe 37e18f0c91 Translated using Weblate (Spanish (Mexico))
Currently translated at 99.1% (11288 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/es_MX/
2026-03-13 23:43:35 +01:00
Ulices 5c94020116 Translated using Weblate (Spanish (Mexico))
Currently translated at 99.1% (11288 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/es_MX/
2026-03-13 23:43:35 +01:00
Anonymous b86891cc1e Translated using Weblate (Spanish (Mexico))
Currently translated at 99.1% (11288 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/es_MX/
2026-03-13 23:43:35 +01:00
Seth Hillbrand ab64d09810 Translated using Weblate (Spanish (Mexico))
Currently translated at 99.1% (11288 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/es_MX/
2026-03-13 23:43:35 +01:00
Anonymous 2a4f4f4dfc Translated using Weblate (Hebrew)
Currently translated at 99.1% (11287 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/he/
2026-03-13 23:43:35 +01:00
G.B 22edba47af Translated using Weblate (Hebrew)
Currently translated at 99.1% (11287 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/he/
2026-03-13 23:43:34 +01:00
Seth Hillbrand 425f9bdd2d Translated using Weblate (Hebrew)
Currently translated at 99.1% (11287 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/he/
2026-03-13 23:43:34 +01:00
Herman van der Vaart 1ced930a3d Translated using Weblate (Dutch)
Currently translated at 76.0% (8663 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/nl/
2026-03-13 23:43:34 +01:00
Christiaan Nieuwlaat 656d3d74a3 Translated using Weblate (Dutch)
Currently translated at 76.0% (8663 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/nl/
2026-03-13 23:43:34 +01:00
johanneswilkens 58b87cd7e1 Translated using Weblate (Dutch)
Currently translated at 76.0% (8663 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/nl/
2026-03-13 23:43:34 +01:00
ZbeeGin 6c4b37c1fa Translated using Weblate (Dutch)
Currently translated at 76.0% (8663 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/nl/
2026-03-13 23:43:34 +01:00
Ranforingus 1a40c18d4a Translated using Weblate (Dutch)
Currently translated at 76.0% (8663 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/nl/
2026-03-13 23:43:34 +01:00
Arend-Jan van Hilten 4275d91fee Translated using Weblate (Dutch)
Currently translated at 76.0% (8663 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/nl/
2026-03-13 23:43:34 +01:00
Robin Janssens fffb8b05b4 Translated using Weblate (Dutch)
Currently translated at 76.0% (8663 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/nl/
2026-03-13 23:43:34 +01:00
pimjansen98 1c811be53e Translated using Weblate (Dutch)
Currently translated at 76.0% (8663 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/nl/
2026-03-13 23:43:34 +01:00
Stefan De Raedemaeker e3b257a0cc Translated using Weblate (Dutch)
Currently translated at 76.0% (8663 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/nl/
2026-03-13 23:43:34 +01:00
Bas Wijnen d29ecd2a8a Translated using Weblate (Dutch)
Currently translated at 76.0% (8663 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/nl/
2026-03-13 23:43:34 +01:00
Seth Hillbrand 1da4e53c4d Translated using Weblate (Dutch)
Currently translated at 76.0% (8663 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/nl/
2026-03-13 23:43:34 +01:00
CJ van der Hoeven f3a42304ae Translated using Weblate (Dutch)
Currently translated at 76.0% (8663 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/nl/
2026-03-13 23:43:34 +01:00
Laurens Holst b26bf30bba Translated using Weblate (Dutch)
Currently translated at 76.0% (8663 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/nl/
2026-03-13 23:43:33 +01:00
Anonymous 2bfd690bc5 Translated using Weblate (Dutch)
Currently translated at 76.0% (8663 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/nl/
2026-03-13 23:43:33 +01:00
Anonymous 417498cc5c Translated using Weblate (Telugu)
Currently translated at 0.0% (0 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/te/
2026-03-13 23:43:33 +01:00
Rafael Serrano a8d15c0555 Translated using Weblate (Catalan)
Currently translated at 34.5% (3931 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ca/
2026-03-13 23:43:33 +01:00
rsr.private 054fc410cb Translated using Weblate (Catalan)
Currently translated at 34.5% (3931 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ca/
2026-03-13 23:43:33 +01:00
Marc de Miguel aceb179048 Translated using Weblate (Catalan)
Currently translated at 34.5% (3931 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ca/
2026-03-13 23:43:33 +01:00
Seth Hillbrand 2ee6c08010 Translated using Weblate (Catalan)
Currently translated at 34.5% (3931 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ca/
2026-03-13 23:43:33 +01:00
Adolfo Jayme Barrientos 590a52a534 Translated using Weblate (Catalan)
Currently translated at 34.5% (3931 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ca/
2026-03-13 23:43:33 +01:00
Arnau Llovet Vidal acdfe9f06d Translated using Weblate (Catalan)
Currently translated at 34.5% (3931 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ca/
2026-03-13 23:43:33 +01:00
Anonymous ad9c4111ee Translated using Weblate (Catalan)
Currently translated at 34.5% (3931 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ca/
2026-03-13 23:43:33 +01:00
Axel Henriksson 4c2408e4b0 Translated using Weblate (Greek)
Currently translated at 71.2% (8116 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/el/
2026-03-13 23:43:33 +01:00
Theodoros Asimakopoulos 1bf7a9b408 Translated using Weblate (Greek)
Currently translated at 71.2% (8116 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/el/
2026-03-13 23:43:33 +01:00
Seth Hillbrand c61aac077b Translated using Weblate (Greek)
Currently translated at 71.2% (8116 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/el/
2026-03-13 23:43:33 +01:00
fresh 09b00391a8 Translated using Weblate (Greek)
Currently translated at 71.2% (8116 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/el/
2026-03-13 23:43:33 +01:00
Michalis e65de1ae9e Translated using Weblate (Greek)
Currently translated at 71.2% (8116 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/el/
2026-03-13 23:43:32 +01:00
Michael Misirlis b19c292013 Translated using Weblate (Greek)
Currently translated at 71.2% (8116 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/el/
2026-03-13 23:43:32 +01:00
aris-kimi 6b7f61b983 Translated using Weblate (Greek)
Currently translated at 71.2% (8116 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/el/
2026-03-13 23:43:32 +01:00
Anonymous a94a5847d2 Translated using Weblate (Greek)
Currently translated at 71.2% (8116 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/el/
2026-03-13 23:43:32 +01:00
ℂ𝕠𝕠𝕠𝕝 (𝕘𝕚𝕥𝕙𝕦𝕓.𝕔𝕠𝕞/ℂ𝕠𝕠𝕠𝕝) 1630b236f9 Translated using Weblate (Latvian)
Currently translated at 0.6% (71 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/lv/
2026-03-13 23:43:32 +01:00
Henrik Kauhanen 40ff55e644 Translated using Weblate (Latvian)
Currently translated at 0.6% (71 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/lv/
2026-03-13 23:43:32 +01:00
Rihards Skuja 61d99ded6b Translated using Weblate (Latvian)
Currently translated at 0.6% (71 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/lv/
2026-03-13 23:43:32 +01:00
Seth Hillbrand 9e90121458 Translated using Weblate (Latvian)
Currently translated at 0.6% (71 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/lv/
2026-03-13 23:43:32 +01:00
Anonymous e3221ff359 Translated using Weblate (Latvian)
Currently translated at 0.6% (71 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/lv/
2026-03-13 23:43:32 +01:00
David Chorváth 8c09d1ea46 Translated using Weblate (Slovak)
Currently translated at 67.3% (7670 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/sk/
2026-03-13 23:43:32 +01:00
Jakub Janek 45a2ff0f2b Translated using Weblate (Slovak)
Currently translated at 67.3% (7670 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/sk/
2026-03-13 23:43:32 +01:00
Marcel Hecko 5213730761 Translated using Weblate (Slovak)
Currently translated at 67.3% (7670 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/sk/
2026-03-13 23:43:32 +01:00
Marcel Hecko c38524989e Translated using Weblate (Slovak)
Currently translated at 67.3% (7670 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/sk/
2026-03-13 23:43:32 +01:00
Seth Hillbrand ec89b9d5c3 Translated using Weblate (Slovak)
Currently translated at 67.3% (7670 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/sk/
2026-03-13 23:43:32 +01:00
EdizonTN 19cd96b52e Translated using Weblate (Slovak)
Currently translated at 67.3% (7670 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/sk/
2026-03-13 23:43:32 +01:00
Andrej Valek 6425e01344 Translated using Weblate (Slovak)
Currently translated at 67.3% (7670 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/sk/
2026-03-13 23:43:32 +01:00
Anonymous e44b4e699c Translated using Weblate (Slovak)
Currently translated at 67.3% (7670 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/sk/
2026-03-13 23:43:31 +01:00
撒景賢 54e0d80860 Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 84.4% (9619 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/zh_Hant/
2026-03-13 23:43:31 +01:00
willliam 0d317fbf25 Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 84.4% (9619 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/zh_Hant/
2026-03-13 23:43:31 +01:00
Andrew 457acf99b3 Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 84.4% (9619 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/zh_Hant/
2026-03-13 23:43:31 +01:00
David Chen 31b4f2ac2a Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 84.4% (9619 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/zh_Hant/
2026-03-13 23:43:31 +01:00
William Lin 26bbbff8f1 Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 84.4% (9619 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/zh_Hant/
2026-03-13 23:43:31 +01:00
CloverGit f11ec36fd4 Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 84.4% (9619 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/zh_Hant/
2026-03-13 23:43:31 +01:00
Che-Hsien Su a265c33e88 Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 84.4% (9619 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/zh_Hant/
2026-03-13 23:43:31 +01:00
John Beard d0743e96ab Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 84.4% (9619 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/zh_Hant/
2026-03-13 23:43:31 +01:00
Seth Hillbrand ff81f54da3 Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 84.4% (9619 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/zh_Hant/
2026-03-13 23:43:31 +01:00
Oliver0804 307131c684 Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 84.4% (9619 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/zh_Hant/
2026-03-13 23:43:31 +01:00
pondahai 5df4547dc8 Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 84.4% (9619 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/zh_Hant/
2026-03-13 23:43:31 +01:00
reimu105 3beb1b640b Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 84.4% (9619 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/zh_Hant/
2026-03-13 23:43:31 +01:00
Shuwn Hsu d770e0f93f Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 84.4% (9619 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/zh_Hant/
2026-03-13 23:43:31 +01:00
Vic ea71a530ea Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 84.4% (9619 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/zh_Hant/
2026-03-13 23:43:31 +01:00
Anonymous 95660f56d7 Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 84.4% (9619 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/zh_Hant/
2026-03-13 23:43:31 +01:00
taotieren bf9cde8feb Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 84.4% (9619 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/zh_Hant/
2026-03-13 23:43:30 +01:00
pominglee 6716b0f697 Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 84.4% (9619 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/zh_Hant/
2026-03-13 23:43:30 +01:00
Seth Hillbrand de6909c1a1 Translated using Weblate (Georgian)
Currently translated at 36.0% (4101 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ka/
2026-03-13 23:43:30 +01:00
Temuri Doghonadze a8f3f3d881 Translated using Weblate (Georgian)
Currently translated at 36.0% (4101 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ka/
2026-03-13 23:43:30 +01:00
Anonymous 00d3caeaed Translated using Weblate (Georgian)
Currently translated at 36.0% (4101 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ka/
2026-03-13 23:43:30 +01:00
Seth Hillbrand c8209b3406 Translated using Weblate (Croatian)
Currently translated at 0.0% (0 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/hr/
2026-03-13 23:43:30 +01:00
Anonymous 03c42faf04 Translated using Weblate (Croatian)
Currently translated at 0.0% (0 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/hr/
2026-03-13 23:43:30 +01:00
dsa-t 394037889a Translated using Weblate (Portuguese)
Currently translated at 99.1% (11287 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/pt/
2026-03-13 23:43:30 +01:00
Augusto Fraga Giachero 9a8419c0c7 Translated using Weblate (Portuguese)
Currently translated at 99.1% (11287 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/pt/
2026-03-13 23:43:30 +01:00
leonardokr cf31b363ad Translated using Weblate (Portuguese)
Currently translated at 99.1% (11287 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/pt/
2026-03-13 23:43:30 +01:00
Manuela Silva b2a813c4d8 Translated using Weblate (Portuguese)
Currently translated at 99.1% (11287 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/pt/
2026-03-13 23:43:30 +01:00
Julio Dias e39807946b Translated using Weblate (Portuguese)
Currently translated at 99.1% (11287 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/pt/
2026-03-13 23:43:30 +01:00
Hildo Guillardi Júnior 33074908ad Translated using Weblate (Portuguese)
Currently translated at 99.1% (11287 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/pt/
2026-03-13 23:43:30 +01:00
Rafael Silva 457a3bb428 Translated using Weblate (Portuguese)
Currently translated at 99.1% (11287 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/pt/
2026-03-13 23:43:30 +01:00
Seth Hillbrand 873e620c59 Translated using Weblate (Portuguese)
Currently translated at 99.1% (11287 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/pt/
2026-03-13 23:43:30 +01:00
Anonymous 9c960a9c7e Translated using Weblate (Portuguese)
Currently translated at 99.1% (11287 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/pt/
2026-03-13 23:43:30 +01:00
ssantos 4fd011408d Translated using Weblate (Portuguese)
Currently translated at 99.1% (11287 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/pt/
2026-03-13 23:43:29 +01:00
Nguyen Van Dien 84eb907172 Translated using Weblate (Vietnamese)
Currently translated at 100.0% (11384 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/vi/
2026-03-13 23:43:29 +01:00
Bế Trọng Nghĩa 11f82a8db1 Translated using Weblate (Vietnamese)
Currently translated at 100.0% (11384 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/vi/
2026-03-13 23:43:29 +01:00
Phạm Minh Tấn 0739153758 Translated using Weblate (Vietnamese)
Currently translated at 100.0% (11384 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/vi/
2026-03-13 23:43:29 +01:00
rtyuionoop 890d8ada42 Translated using Weblate (Vietnamese)
Currently translated at 100.0% (11384 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/vi/
2026-03-13 23:43:29 +01:00
Trần Phi Hải 9559b90dd9 Translated using Weblate (Vietnamese)
Currently translated at 100.0% (11384 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/vi/
2026-03-13 23:43:29 +01:00
Anonymous 046e439b0c Translated using Weblate (Vietnamese)
Currently translated at 100.0% (11384 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/vi/
2026-03-13 23:43:29 +01:00
Nguyễn Ngọc Khánh 8f7bc6bcc0 Translated using Weblate (Vietnamese)
Currently translated at 100.0% (11384 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/vi/
2026-03-13 23:43:29 +01:00
lê văn lập 00cd3316a7 Translated using Weblate (Vietnamese)
Currently translated at 100.0% (11384 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/vi/
2026-03-13 23:43:29 +01:00
Seth Hillbrand 2da4716a64 Translated using Weblate (Vietnamese)
Currently translated at 100.0% (11384 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/vi/
2026-03-13 23:43:29 +01:00
dsa-t 920eb87a5f Translated using Weblate (Turkish)
Currently translated at 100.0% (11384 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/tr/
2026-03-13 23:43:29 +01:00
Mahsum Aslan e9519669cd Translated using Weblate (Turkish)
Currently translated at 100.0% (11384 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/tr/
2026-03-13 23:43:29 +01:00
Marine Biologist 6027a6db02 Translated using Weblate (Turkish)
Currently translated at 100.0% (11384 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/tr/
2026-03-13 23:43:29 +01:00
temizinsan f79e1441fa Translated using Weblate (Turkish)
Currently translated at 100.0% (11384 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/tr/
2026-03-13 23:43:28 +01:00
Deleted User 01f4813891 Translated using Weblate (Turkish)
Currently translated at 100.0% (11384 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/tr/
2026-03-13 23:43:28 +01:00
Mert Gülsoy 6c89d38233 Translated using Weblate (Turkish)
Currently translated at 100.0% (11384 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/tr/
2026-03-13 23:43:28 +01:00
dogukansahil a98571b223 Translated using Weblate (Turkish)
Currently translated at 100.0% (11384 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/tr/
2026-03-13 23:43:28 +01:00
NAXSISFLYBY 7b7603da40 Translated using Weblate (Turkish)
Currently translated at 100.0% (11384 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/tr/
2026-03-13 23:43:28 +01:00
Erkan 741f9598d4 Translated using Weblate (Turkish)
Currently translated at 100.0% (11384 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/tr/
2026-03-13 23:43:28 +01:00
metin kiruc d941d918d0 Translated using Weblate (Turkish)
Currently translated at 100.0% (11384 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/tr/
2026-03-13 23:43:28 +01:00
Tevfik Bagcivan 0ba22d2798 Translated using Weblate (Turkish)
Currently translated at 100.0% (11384 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/tr/
2026-03-13 23:43:28 +01:00
prometheus ebba1f597b Translated using Weblate (Turkish)
Currently translated at 100.0% (11384 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/tr/
2026-03-13 23:43:28 +01:00
Mert Kalkancı 0748438916 Translated using Weblate (Turkish)
Currently translated at 100.0% (11384 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/tr/
2026-03-13 23:43:28 +01:00
Murat Ursavaş 0349ec24ce Translated using Weblate (Turkish)
Currently translated at 100.0% (11384 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/tr/
2026-03-13 23:43:28 +01:00
Argeolog 9a9401b46c Translated using Weblate (Turkish)
Currently translated at 100.0% (11384 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/tr/
2026-03-13 23:43:28 +01:00
Niyazi 1348add20c Translated using Weblate (Turkish)
Currently translated at 100.0% (11384 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/tr/
2026-03-13 23:43:28 +01:00
Gökhan Koçmarlı c6cba95930 Translated using Weblate (Turkish)
Currently translated at 100.0% (11384 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/tr/
2026-03-13 23:43:28 +01:00
Bahtiyar Bayram 65c19e69df Translated using Weblate (Turkish)
Currently translated at 100.0% (11384 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/tr/
2026-03-13 23:43:28 +01:00
Ahmet Saygın ÖĞÜLMÜŞ a9bde2f8e1 Translated using Weblate (Turkish)
Currently translated at 100.0% (11384 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/tr/
2026-03-13 23:43:28 +01:00
Oğuz Ersen 651231d620 Translated using Weblate (Turkish)
Currently translated at 100.0% (11384 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/tr/
2026-03-13 23:43:27 +01:00
VEDAT YAMAN af761e9c0f Translated using Weblate (Turkish)
Currently translated at 100.0% (11384 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/tr/
2026-03-13 23:43:27 +01:00
Seth Hillbrand 455d50f312 Translated using Weblate (Turkish)
Currently translated at 100.0% (11384 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/tr/
2026-03-13 23:43:27 +01:00
Anonymous 10aa189a72 Translated using Weblate (Turkish)
Currently translated at 100.0% (11384 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/tr/
2026-03-13 23:43:27 +01:00
turkce 576d7f4278 Translated using Weblate (Turkish)
Currently translated at 100.0% (11384 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/tr/
2026-03-13 23:43:27 +01:00
İclal Gör e451e71ab0 Translated using Weblate (Turkish)
Currently translated at 100.0% (11384 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/tr/
2026-03-13 23:43:27 +01:00
Mustafa Selçuk ÇAVDAR 423147f433 Translated using Weblate (Turkish)
Currently translated at 100.0% (11384 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/tr/
2026-03-13 23:43:27 +01:00
YÜKSEL AÇIKGÖZ da1b5e5ee9 Translated using Weblate (Turkish)
Currently translated at 100.0% (11384 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/tr/
2026-03-13 23:43:27 +01:00
Petri Niemelä e1cda80571 Translated using Weblate (Finnish)
Currently translated at 82.7% (9418 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/fi/
2026-03-13 23:43:27 +01:00
J. Lavoie 7a4b5847ad Translated using Weblate (Finnish)
Currently translated at 82.7% (9418 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/fi/
2026-03-13 23:43:27 +01:00
Riku Viitanen 57586eab8b Translated using Weblate (Finnish)
Currently translated at 82.7% (9418 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/fi/
2026-03-13 23:43:27 +01:00
Ricky Tigg e90de2ea56 Translated using Weblate (Finnish)
Currently translated at 82.7% (9418 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/fi/
2026-03-13 23:43:27 +01:00
dsa-t b87daddeea Translated using Weblate (Finnish)
Currently translated at 82.7% (9418 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/fi/
2026-03-13 23:43:27 +01:00
ZbeeGin 2fbdbb9dce Translated using Weblate (Finnish)
Currently translated at 82.7% (9418 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/fi/
2026-03-13 23:43:27 +01:00
Vesa Solonen cb3fa4aff3 Translated using Weblate (Finnish)
Currently translated at 82.7% (9418 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/fi/
2026-03-13 23:43:27 +01:00
PurkkaKoodari ccec4569da Translated using Weblate (Finnish)
Currently translated at 82.7% (9418 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/fi/
2026-03-13 23:43:27 +01:00
Henrik Kauhanen 1307b7081d Translated using Weblate (Finnish)
Currently translated at 82.7% (9418 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/fi/
2026-03-13 23:43:27 +01:00
Kliment 795fdf336a Translated using Weblate (Finnish)
Currently translated at 82.7% (9418 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/fi/
2026-03-13 23:43:26 +01:00
Ola Rinta-Koski b99969d62e Translated using Weblate (Finnish)
Currently translated at 82.7% (9418 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/fi/
2026-03-13 23:43:26 +01:00
Simo Mattila 38859977c5 Translated using Weblate (Finnish)
Currently translated at 82.7% (9418 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/fi/
2026-03-13 23:43:26 +01:00
Toni Laiho d1c4b70344 Translated using Weblate (Finnish)
Currently translated at 82.7% (9418 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/fi/
2026-03-13 23:43:26 +01:00
Seth Hillbrand 6fb2db39b9 Translated using Weblate (Finnish)
Currently translated at 82.7% (9418 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/fi/
2026-03-13 23:43:26 +01:00
Anonymous 8f58dc87b1 Translated using Weblate (Finnish)
Currently translated at 82.7% (9418 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/fi/
2026-03-13 23:43:26 +01:00
Mads Dyrmann 1cdb1296a3 Translated using Weblate (Danish)
Currently translated at 99.9% (11379 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/da/
2026-03-13 23:43:26 +01:00
ZbeeGin 30dad6691b Translated using Weblate (Danish)
Currently translated at 99.9% (11379 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/da/
2026-03-13 23:43:26 +01:00
nickoe 2e36ff1c97 Translated using Weblate (Danish)
Currently translated at 99.9% (11379 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/da/
2026-03-13 23:43:26 +01:00
dsa-t 88d99b3d72 Translated using Weblate (Danish)
Currently translated at 99.9% (11379 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/da/
2026-03-13 23:43:26 +01:00
Henrik Kauhanen 8feb302964 Translated using Weblate (Danish)
Currently translated at 99.9% (11379 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/da/
2026-03-13 23:43:26 +01:00
Jarl Gjessing ec1f28364b Translated using Weblate (Danish)
Currently translated at 99.9% (11379 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/da/
2026-03-13 23:43:26 +01:00
Anonymous 64a6c70902 Translated using Weblate (Danish)
Currently translated at 99.9% (11379 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/da/
2026-03-13 23:43:26 +01:00
Seth Hillbrand a19468fb2c Translated using Weblate (Danish)
Currently translated at 99.9% (11379 of 11384 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/da/
2026-03-13 23:43:25 +01:00
Seth Hillbrand 20cd448d6d Allegro: initialize DB_REF::m_EndKey to zero
m_EndKey had no default initializer, but Resolve() reads it
unconditionally.  Only one of 20+ DB_REF instances ever sets it,
so most comparisons were against indeterminate memory.
2026-03-13 14:27:44 -07:00
Seth Hillbrand 0e0c54767e Allegro: use wxLogTrace instead of wxLogWarning in zone shape walker
Avoid spamming dialogs
2026-03-13 14:27:44 -07:00
Seth Hillbrand 305301600b Fix broken group membership when saving design blocks
saveSelectionToDesignBlock() used Clone() for groups, which creates a
shallow copy where m_items still references original board items. The
code then separately cloned children via RunOnChildren(cloneAndAdd) on
the original group, but never updated the cloned group's m_items to
reference the new clones. This resulted in design blocks with groups
whose member UUIDs referenced nonexistent items. On reload, the group
would have no children.

Additionally, addNetIfNeeded was called on the original group's children
rather than the clones, corrupting net assignments on the real board.

Replace the shallow Clone()+manual child cloning with DeepClone(), which
recursively clones all children with correct group ownership. The deep
clone and its children are then added to the temporary board for
serialization.

Related https://gitlab.com/kicad/code/kicad/-/issues/23356
2026-03-13 14:27:44 -07:00
Bernhard Kirchen 911231f3ad add support for rule areas in edit -> attributes menu
Fixes https://gitlab.com/kicad/code/kicad/-/issues/23400
2026-03-13 20:27:02 +00:00
Damjan Prerad e25c5a9848 Fix Symbol Editor crash from stale search-term span
Fixes https://gitlab.com/kicad/code/kicad/-/work_items/23429
2026-03-13 21:07:56 +01:00
Seth Hillbrand 57ea841427 Don't re-prune min-width for same-net zone knockouts
The postKnockoutMinWidthPrune() deflate/inflate cycle needs the
same-net zone apron protection as the initial min-width pass.

Fixes https://gitlab.com/kicad/code/kicad/-/issues/23418
2026-03-13 12:44:14 -07:00
Andrew James Miller 27c033a465 Fix "Open file after plot" to use preferred PDF viewer rather than always using system default. 2026-03-13 19:02:46 +00:00
Bernhard Kirchen c040d62dec constrict cell props to table cells in properties panel
shapes like rectangles, arcs, circles, etc. must not show cell
properties in the properties panel.

closes #23398.
2026-03-13 18:57:03 +00:00
Bernhard Kirchen e81dae62ef honor rule area "exclude from BOM" in BOM
choose ResolveExcludedFromBOM() over GetExcludedFromBOM() to test refs
for exclusion from BOM in order to honor a rule area's "exclude from
BOM" flag for all refs inside that area.

closes #23411.
2026-03-13 18:53:49 +00:00
Seth Hillbrand 1920400200 Update translations 2026-03-13 11:19:24 -07:00
Seth Hillbrand c2749d3b49 Fix WebView freeze during modal dialogs
WebKit's AddScriptMessageHandler calls RunScript internally,
which yields the event loop via DoYieldFor. When this runs
inside a nested event loop (e.g., Update PCB from Schematic's
modal dialog), JSC crashes in sanitizeStackForVM.

The previous fix used CallAfter to defer handler registration,
but CallAfter events fire immediately in the modal dialog's
event loop, creating a tight busy-wait that freezes the UI.

Replace CallAfter re-deferral with a wxTimer that retries
every 200ms until the main event loop is active. Also guard
AddMessageHandler's late-registration path with the same
nested loop check so handlers added after init are safe too.

Fixes https://gitlab.com/kicad/code/kicad/-/issues/23423
2026-03-13 11:01:45 -07:00
Damjan 88ffcdf6f4 Fix Unroute Selected/Segment not handling meanders (PCB_GENERATOR) 2026-03-13 15:06:53 +01:00
John Beard b5bcd5b0bf Allegro: fix autoformatted // format:allow 2026-03-13 20:43:52 +08:00
John Beard c91671c211 Allegro: figure out NPTHs
There's a 'plated' flag in the pad info struct in 01c PADSTACK.
Or at least it seems to correlate well with NPTHs on boards like
EVK BaseBoard.

There's another flag 0x01 which seems to be sometimes present, but
it's not immediately clear what that could be.
2026-03-13 17:34:23 +08:00
John Beard e36d741dd6 Allegro: decode some more text properties
From screenshots of the text setup dialogs online, we see there
are three fields in the font defs we haven't handled: line
spacing, char spacing and 'photo width'. The latter makes sense
as the stoke width, and assign the first two based on the relative
sizes (not that we have a good way to use them right now).
2026-03-13 15:00:19 +08:00
John Beard 056878d756 Allegro: apply text fudge factor to compensate for different baseline
A bit of experimentation seems to get things to match up against the
BeagleBone-AI gerbers visually.

We can't get it perfect, because the font is fundamentally not the same
in terms of letter shapes, but it should at least mostly not overlap
things now where it shouldn't.
2026-03-13 14:59:33 +08:00
John Beard 6de090f3f4 Allegro: break out millidegrees function 2026-03-13 14:35:53 +08:00
John Beard 6eee2d239d Allegro: Handle more zones as zones rather than shapes
Several little bits:

* Some keepouts are in the "shape" linked list
* Handle keepouts in footprints
* Handle (at least in theory) merging of same geometry rule areas
* Handle keepout/in with indexed copper layers (0-FCu etc), rather
  than ALL/TOP/etc subclass
* Rectangular outline rotation

This substantially improves import of boards with keepouts, as they
no longer come in as conductive items on copper layers.
2026-03-13 13:37:21 +08:00
John Beard 453cc5fd04 Allegro: tidy up 0x28->0x2C pointer field 2026-03-13 07:59:06 +08:00
Seth Hillbrand 1ef76f798d Cap background library loading threads
AsyncLoad() previously submitted one thread pool task per
library, which could saturate all available cores during
startup. This starved the GUI and blocked other thread pool
work like DRC.

Restructure to use a work-stealing pattern where a limited
number of worker tasks each pull from a shared queue. The
worker count is capped at pool_size - 2 (minimum 1), leaving
threads free for the UI and other operations. Tasks are still
submitted at lowest priority so any higher-priority work
takes precedence in the queue.
2026-03-12 13:07:46 -07:00
Seth Hillbrand 1c68440a17 Mark schematic modified when editing variants
Variant add, delete, rename, and copy operations in the Bulk Edit
Symbol Fields dialog (and toolbar variant selector) modify the
schematic data model but did not call OnModify(), so closing eeschema
afterward would not prompt to save changes.

Fixes https://gitlab.com/kicad/code/kicad/-/issues/23410
2026-03-12 12:10:24 -07:00
Seth Hillbrand 9662b1ae3e Try to address DRC rule editor per-click slowness
Freeze the scrolled content window around panel creation
and data population in RuleTreeItemSelectionChanged so the
entire sequence happens off-screen as a single

Move the 14 wxRegEx autocomplete patterns from per-instance
member variables to function-local statics so they compile
once rather than on every panel creation.
2026-03-12 11:26:22 -07:00
Seth Hillbrand 265b00d994 Try to fix DRC rule editor slow load on Windows
During LoadExistingRules, each call to AppendNewRuleTreeItem
triggered SelectItem, which fired the selection-changed handler.
That handler created a full PANEL_DRC_RULE_EDITOR per rule,
compiling 14 regex patterns, instantiating Scintilla, running
layout, then immediately destroying it when the next rule was
appended.  Also fix other potential slow downs
2026-03-12 09:56:49 -07:00
Seth Hillbrand f3441c00a3 Import Altium project variants
Parse variant data from Altium .PrjPcb project files and
apply it to both schematic symbols and board footprints
during import. Each ProjectVariant section is read as an
INI group, and per-component variation entries are mapped
to KiCad variant structures on the matching designators.
2026-03-12 09:33:59 -07:00
Seth Hillbrand b16cead02a Accept all Altium PCB extensions on import
When importing an Altium project, the handler only recognized
PcbDoc files. Projects that reference Circuit Studio, Circuit
Maker, or SolidWorks PCB files (CSPcbDoc, CMPcbDoc, SWPcbDoc)
had their board silently skipped. Map each extension to its
correct PCB_IO plugin type so the right parser is used.
2026-03-12 08:15:26 -07:00
Wayne Stambaugh f7e9c7a11d Use cached hierarchy when resolving schematic items. 2026-03-12 08:35:45 -04:00
Seth Hillbrand 5c59527278 Add 6 missing languages to LanguagesList[]
Add Estonian, Farsi, Hindi, Croatian, Georgian, and
Telugu
2026-03-11 15:58:02 -07:00
Seth Hillbrand eb62257333 Update contributor lists 2026-03-11 15:36:33 -07:00
Seth Hillbrand 9ffce113c8 Update translations 2026-03-11 13:58:00 -07:00
YÜKSEL AÇIKGÖZ ecf279661c Translated using Weblate (Turkish)
Currently translated at 100.0% (11313 of 11313 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/tr/
2026-03-11 21:56:43 +01:00
brunofaus f3c2eee63f Translated using Weblate (Portuguese (Brazil))
Currently translated at 99.9% (11310 of 11313 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/pt_BR/
2026-03-11 21:56:43 +01:00
EdizonTN 3f6aef9dd3 Translated using Weblate (Slovak)
Currently translated at 66.3% (7510 of 11313 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/sk/
2026-03-11 21:56:43 +01:00
CloverGit 2fc65bdeec Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 95.8% (10839 of 11313 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/zh_Hans/
2026-03-11 21:56:43 +01:00
Seth Hillbrand e6700e85bb Translated using Weblate (Estonian)
Currently translated at 100.0% (11313 of 11313 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/et/
2026-03-11 21:56:43 +01:00
2tama3 2d7bba589f Translated using Weblate (Japanese)
Currently translated at 100.0% (11313 of 11313 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ja/
2026-03-11 21:56:42 +01:00
Pferd O. 18afb514ea Translated using Weblate (German)
Currently translated at 100.0% (11313 of 11313 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/de/
2026-03-11 21:56:42 +01:00
Seth Hillbrand 184eb24474 Translated using Weblate (Hebrew)
Currently translated at 99.9% (11308 of 11313 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/he/
2026-03-11 21:56:42 +01:00
Frank Sonnenberg 32eb6d7479 Translated using Weblate (German)
Currently translated at 99.9% (11312 of 11313 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/de/
2026-03-11 21:56:42 +01:00
Seth Hillbrand 6b0db6977b Translated using Weblate (Spanish)
Currently translated at 99.9% (11309 of 11313 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/es/
2026-03-11 21:56:42 +01:00
Seth Hillbrand 71d347b540 Remote Symbol: cap ZSTD decompressed size before allocation
A malicious or corrupt ZSTD frame content-size header could cause an
unbounded allocation.  Clamp the expected size against the provider's
max_download_bytes (if available) or a 64 MB fallback before calling
resize().
2026-03-11 13:43:26 -07:00
Seth Hillbrand 001c196e7f UrlEncode: percent-encode UTF-8 bytes, not Unicode code points
RFC 3986 requires percent-encoding individual UTF-8 bytes.  The
previous implementation iterated wxUniChar code points, producing
incorrect output for non-ASCII characters (e.g. é became %E9 instead
of %C3%A9, and multi-byte characters like emoji produced invalid
percent-encoding with more than two hex digits).
2026-03-11 13:42:54 -07:00
Seth Hillbrand f3bc64c430 Creepage DRC: fix over-broad endpoint exclusion in segmentIntersectsArc
The early return rejected the entire intersection test whenever a
segment endpoint coincided with an arc endpoint.  This masked genuine
crossings where the segment also intersected the arc body at a
different point.

Compute all intersections first, then filter out only those points
that are both a segment endpoint and an arc endpoint.
2026-03-11 13:42:26 -07:00
Seth Hillbrand a0afa942a9 Creepage DRC: fix memory leak of synthesized NPTH PCB_SHAPE objects
CollectBoardEdges() creates PCB_SHAPE circles for NPTH pads via bare
new, but nothing ever deletes them.  Give CREEPAGE_GRAPH an owning
container (m_ownedBoardEdges) for these synthesized shapes so they are
freed when the graph is destroyed.
2026-03-11 13:40:50 -07:00
Seth Hillbrand 8dd6a096f1 Creepage DRC: rebuild m_nodeset between net-pair iterations
The outer testCreepage() loop reuses a single CREEPAGE_GRAPH across
all net-pair/layer combinations to avoid reconstructing the static
board-edge structure.  Between iterations, m_nodes and m_connections
are truncated back to the board-edge prefix, but m_nodeset (the
unordered_set used for O(1) deduplication in FindNode/AddNode) was
never trimmed.

Stale shared_ptr<GRAPH_NODE> entries from prior iterations remained
in m_nodeset, causing FindNode() to return nodes whose connection
slots had already been cleaned up — corrupting the graph topology
for subsequent net-pair tests.

After truncating m_nodes, rebuild m_nodeset from the surviving
board-edge prefix to restore the 1:1 invariant between the two
containers.
2026-03-11 13:38:14 -07:00
Seth Hillbrand eeb640a4da Fix Windows MSVC link error in qa_common test executable.
Replace direct nlohmann/json.hpp includes with json_common.h in the
remote provider test files
2026-03-11 13:30:57 -07:00
Wayne Stambaugh 1b9f7eef51 Fix Linux build errors. 2026-03-11 15:27:29 -04:00
Seth Hillbrand be2c612dc3 DRC rule editor: fix Windows paint artifacts
The bitmap overlay panels never cleared their background before
drawing. With wxBG_STYLE_PAINT the system skips auto-erase, so
stale pixels from previous panels bled through on Windows during
scrolling and rule switching.

Switch OnPaint from wxPaintDC to wxAutoBufferedPaintDC and clear
the full client area before drawing the bitmap. Wrap the panel
swap in SetContentPanel with Freeze/Thaw to suppress intermediate
repaints between destroy and layout.

Widen overlay text fields on Windows by 15px via a new platform
constant DRC_RE_OVERLAY_WE to allow for Windows wxTextCtrl border
padding
2026-03-11 12:12:12 -07:00
Damjan Prerad dedd545254 Wrap ShowEeschema and UpdatePCBFromSchematic in RunMainStack for macOS WebKit
When opening the schematic editor from pcbnew, the code runs inside
a coroutine with a privately allocated stack. RunMainStack switches
execution to the real thread stack before creating thr schematic
editor frame.
2026-03-11 20:08:39 +01:00
Seth Hillbrand 9482730559 Eeschema: share SCH_SCREEN across top-level sheets referencing same file
When multiple top-level sheets in a multi-root schematic reference the
same sub-sheet file, each sub-sheet must share a single SCH_SCREEN
object.  Previously, loadHierarchy() only searched the current root
sheet's hierarchy for an existing screen, so screens loaded by earlier
top-level sheets were never found.  This caused each top-level sheet to
create its own copy of the shared sub-sheet's screen, leading to data
loss on save as later writes would overwrite earlier ones.

Add m_loadedRootSheets to SCH_IO_KICAD_SEXPR to track root sheets from
prior LoadSchematicFile() calls within the same IO instance.  During
loadHierarchy(), after the existing search fails, also search through
previously loaded root sheets.  The cache is cleared when the SCHEMATIC
pointer changes, preventing stale references when the IO object is
reused for unrelated loads.

Fixes https://gitlab.com/kicad/code/kicad/-/issues/23403
2026-03-11 11:23:02 -07:00
Seth Hillbrand 2dbba4a60a Remote Symbol: consolidate, update and harden
Extract duplicated helpers from remote provider files into shared
utilities.  Split sendRpcMessage into purpose-specific functions.
Implement standard nonce-based exchange for re-auth.  Provide
additional models for more efficient model/symbol/fp/etc using
external URLs.  This allows us to better handle connection errors,
retries and large data packets.

Fixes https://gitlab.com/kicad/code/kicad/-/issues/23381
2026-03-11 06:41:44 -07:00
Seth Hillbrand 42928c8b2f Fix Move command grabbing from grid point instead of anchor
The Move command grabbed footprints from the nearest grid point rather
than the footprint anchor. This was caused by the reference point being
grid-aligned at drag start (commit 89be3fd390), which was a workaround
for fractional-nanometer positioning errors with non-page display origin.

Fix the root cause instead: AlignGrid(VECTOR2I, VECTOR2D, VECTOR2D)
relied on implicit VECTOR2D->VECTOR2I truncation to pass grid parameters
to computeNearest. For grid sizes that aren't exact in IEEE 754 double
(e.g., 0.254mm = 10 mil becomes 253999.999... instead of 254000), the
truncation produces incorrect grid sizes. Use KiROUND for the conversion
so all grid operations produce exact grid multiples.

With AlignGrid returning correct positions, the move tool no longer needs
to grid-align its reference point. Restore the anchor-based grab and the
GetMoveWarpsCursor() preference that 89be3fd390 removed.

Fixes https://gitlab.com/kicad/code/kicad/-/issues/23308
2026-03-10 11:07:39 -07:00
John Beard 0b0387f647 Pcbnew: add some more KICAD_SNAP debug, for BestDragOrigin
Sometimes it's good to know where the BestDragOrigin calls happen
2026-03-10 23:48:19 +08:00
John Beard 8aaea1fc94 Settings manager: explain the assert 2026-03-10 22:32:20 +08:00
John Beard 7b5cc357cb QA: Add an Lsan leak suppression file
Actually haven't tested with lsan, but this works great with heaptrack
which declares to use the same format.
2026-03-10 22:32:20 +08:00
John Beard 6cd04bde02 Allegro: multithread zone fill handler for 70% loading speedup (VCU118)
Intersecting and fracturing zone fills takes forever for complex
fills (VCU118 has some fills severa with hundreds of thousands of
points).

However, they are trivially parallelisable - so do that and cut VCU
board load times by 70% - YMMV depending on CPU.

Further save 10% by sorting the heaviest zones first which is nice,
but the real thing to avoid is accidentally scheduling the biggest
zones consecutively on the same thread, which could be a substantial
penalty.

This has the happy effect of reducing the Allegro test suite to under
a minute (VCU118 dominates)
2026-03-10 22:32:20 +08:00
John Beard 53c2094764 QA Pcbnew: add auto plugin mode to pcbnew tools
This means it can read all supported file types from the command line as
filename. Stream input (for fuzzing) still requires the plugin to be
specified and for the plugin to support a stream interface.

This is useful for putting profilers onto importers without confusing it
with GUI init, libraries, etc.
2026-03-10 22:32:20 +08:00
John Beard e6b80fe966 .gitignore: stop noticing .history in QA data
And the rest the autocruft.
2026-03-10 22:32:20 +08:00
Wayne Stambaugh f982bd02cb Fix build warning.
The wxWidgets wxPATH_NORM_ALL definition throws a deprecated warning.
KiCad defines FN_NORMALIZE_FLAGS as a substitute to prevent the warning.
2026-03-10 09:18:55 -04:00
Wayne Stambaugh 585b79c369 Improve readability of variant exclude from BOM change.
The XOR of the variant exclude from BOM while technically correct gets
performed on every load which makes the intent of the change less clear.
The inversion of the state only needs to be performed when the file format
is older than the version defined in MR2485.  Also add a comment to let
developers know why this change was made.

MR https://gitlab.com/kicad/code/kicad/-/merge_requests/2485
2026-03-10 09:02:42 -04:00
Jon Evans 270a6830b0 Fix a few issues with library start wizard
- Improve text layout / responsiveness
- Fix missing stock tables warning not showing up in the right cases

Fixes https://gitlab.com/kicad/code/kicad/-/issues/22923
2026-03-10 08:48:04 -04:00
Jon Evans 10592c242d Fix status bar progress layout issues
Alignment and padding were off, and layout was
not getting done properly on draw frames until
the window was resized.
2026-03-09 23:55:35 -04:00
Damjan Prerad 837d1c11a9 DRC: Set track-not-centered-on-via DRC default severity to ignore 2026-03-10 02:33:08 +01:00
Jon Evans e468788aa8 Fix up kicad-cli DRC project and library handling
Fixes https://gitlab.com/kicad/code/kicad/-/issues/23379
2026-03-09 20:42:29 -04:00
Seth Hillbrand e47e3cc166 Fix creepage DRC skipping slot edges with multiple Edge.Cuts rectangles
When generating paths between board edge nodes from different Edge.Cuts
shapes (e.g., corners of two rectangular slots), both parents were added
to the IgnoreForTest list.

For POINT shapes (rectangle/polygon corners), the segments_intersect
function already excludes shared-endpoint intersections, so skipping
the parent shape is unnecessary. Only circle board edge shapes need
their parent in IgnoreForTest because segmentIntersectsCircle has no
endpoint exclusion.

Fixes https://gitlab.com/kicad/code/kicad/-/issues/23364
2026-03-09 16:21:05 -07:00
Seth Hillbrand c06d6b9d5a Fix broken hi.po and te.po translations
The degree symbol msgid was corrupted to an empty
string in both files, creating a duplicate of the
PO header entry and causing msgfmt to fail with a
fatal error
2026-03-09 15:16:31 -07:00
Seth Hillbrand a5445df107 Cycle through options on single-click for non-tool flyout groups
Setting flyout groups (units, crosshair, line modes) now cycle to the
next option on single-click instead of requiring a long-press to open
the palette. Tool flyout groups (route track, tune, dimensions, origins)
continue to activate the displayed tool on click.

Fixes https://gitlab.com/kicad/code/kicad/-/issues/23349
2026-03-09 15:06:25 -07:00
Bernhard Kirchen b49c6e1362 resolve trivial compiler warnings
introduced in 0f343a0abc and 92bb000ce6.
2026-03-09 20:48:33 +00:00
Seth Hillbrand 7c4229c066 Re-prune minimum-width violations after zone knockouts
Zone-to-zone clearance knockouts and higher-priority zone subtraction
happen after the initial deflate/inflate minimum-width enforcement
cycle.  These knockouts can carve out material and leave thin copper
strips that violate the zone's minimum width constraint.

Add a second deflate/inflate pass that runs only when knockouts were
actually applied.  The result is intersected with the pre-deflate
boundary to prevent re-inflation into cleared areas (keepouts, pad
clearances, etc.).

Fixes https://gitlab.com/kicad/code/kicad/-/issues/23332
2026-03-09 12:40:37 -07:00
Seth Hillbrand 2a8f3ea5cd Update translation parts
- Add scripting translation strings
- Unify LINGUAS/LINGUAS_INSTALL
- Add hindi
- Add telugu
2026-03-09 12:40:29 -07:00
Seth Hillbrand c552a6292d Update translations 2026-03-09 11:13:55 -07:00
Henrik Kauhanen 1300c31f2c Translated using Weblate (Swedish)
Currently translated at 99.3% (11241 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/sv/
2026-03-09 19:08:14 +01:00
szumsky aed0a82473 Translated using Weblate (Polish)
Currently translated at 92.7% (10488 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/pl/
2026-03-09 19:08:14 +01:00
EdizonTN 16d1b23b4c Translated using Weblate (Slovak)
Currently translated at 66.1% (7478 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/sk/
2026-03-09 19:08:14 +01:00
Tomas0015 0b88f5b7b8 Translated using Weblate (Czech)
Currently translated at 67.8% (7680 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/cs/
2026-03-09 19:08:13 +01:00
Ettore Atalan 8fd0e412a5 Translated using Weblate (German)
Currently translated at 100.0% (11312 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/de/
2026-03-09 19:08:13 +01:00
ZbeeGin 3513b2704f Translated using Weblate (Polish)
Currently translated at 92.7% (10488 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/pl/
2026-03-09 19:08:13 +01:00
Seth Hillbrand c0c9d4ee30 Translated using Weblate (Portuguese)
Currently translated at 99.9% (11308 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/pt/
2026-03-09 19:08:13 +01:00
Hildo Guillardi Júnior 44cedb6c81 Translated using Weblate (Portuguese (Brazil))
Currently translated at 99.9% (11310 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/pt_BR/
2026-03-09 19:08:13 +01:00
Frank Sonnenberg 6d199f4152 Translated using Weblate (German)
Currently translated at 100.0% (11312 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/de/
2026-03-09 19:08:13 +01:00
Ahmed Elswah 5f78432308 Translated using Weblate (Arabic)
Currently translated at 1.0% (115 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ar/
2026-03-09 19:08:13 +01:00
Hesham Eina Abdalla 0546d36bf3 Translated using Weblate (Arabic)
Currently translated at 1.0% (115 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ar/
2026-03-09 19:08:13 +01:00
Morad Tamer 3488c37290 Translated using Weblate (Arabic)
Currently translated at 1.0% (115 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ar/
2026-03-09 19:08:13 +01:00
HADJAISSA 7593a276ec Translated using Weblate (Arabic)
Currently translated at 1.0% (115 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ar/
2026-03-09 19:08:13 +01:00
Seth Hillbrand 47cdac8703 Translated using Weblate (Arabic)
Currently translated at 1.0% (115 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ar/
2026-03-09 19:08:13 +01:00
Djamel Dellaa f109a8c743 Translated using Weblate (Arabic)
Currently translated at 1.0% (115 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ar/
2026-03-09 19:08:13 +01:00
Anonymous 3a1963a76f Translated using Weblate (Arabic)
Currently translated at 1.0% (115 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ar/
2026-03-09 19:08:13 +01:00
Petri Niemelä 4302d53e30 Translated using Weblate (Finnish)
Currently translated at 83.2% (9418 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/fi/
2026-03-09 19:08:12 +01:00
J. Lavoie 7a3d5ef4d9 Translated using Weblate (Finnish)
Currently translated at 83.2% (9418 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/fi/
2026-03-09 19:08:12 +01:00
Riku Viitanen 141d7a7afa Translated using Weblate (Finnish)
Currently translated at 83.2% (9418 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/fi/
2026-03-09 19:08:12 +01:00
Ricky Tigg 2c703c7579 Translated using Weblate (Finnish)
Currently translated at 83.2% (9418 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/fi/
2026-03-09 19:08:12 +01:00
dsa-t 345c998bc5 Translated using Weblate (Finnish)
Currently translated at 83.2% (9418 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/fi/
2026-03-09 19:08:12 +01:00
ZbeeGin b7ddd0cb39 Translated using Weblate (Finnish)
Currently translated at 83.2% (9418 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/fi/
2026-03-09 19:08:12 +01:00
Vesa Solonen 7eea964072 Translated using Weblate (Finnish)
Currently translated at 83.2% (9418 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/fi/
2026-03-09 19:08:12 +01:00
PurkkaKoodari 1f45698670 Translated using Weblate (Finnish)
Currently translated at 83.2% (9418 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/fi/
2026-03-09 19:08:12 +01:00
Henrik Kauhanen dd9525c7a9 Translated using Weblate (Finnish)
Currently translated at 83.2% (9418 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/fi/
2026-03-09 19:08:12 +01:00
Kliment adf4340c3d Translated using Weblate (Finnish)
Currently translated at 83.2% (9418 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/fi/
2026-03-09 19:08:12 +01:00
Ola Rinta-Koski 838cb904ad Translated using Weblate (Finnish)
Currently translated at 83.2% (9418 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/fi/
2026-03-09 19:08:12 +01:00
Simo Mattila 36b4fad93e Translated using Weblate (Finnish)
Currently translated at 83.2% (9418 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/fi/
2026-03-09 19:08:12 +01:00
Toni Laiho 4f40701ce3 Translated using Weblate (Finnish)
Currently translated at 83.2% (9418 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/fi/
2026-03-09 19:08:12 +01:00
Seth Hillbrand 595df5d1f8 Translated using Weblate (Finnish)
Currently translated at 83.2% (9418 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/fi/
2026-03-09 19:08:12 +01:00
Anonymous 62988e295a Translated using Weblate (Finnish)
Currently translated at 83.2% (9418 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/fi/
2026-03-09 19:08:11 +01:00
撒景賢 51e3109991 Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 85.0% (9619 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/zh_Hant/
2026-03-09 19:08:11 +01:00
willliam 13df6f4c65 Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 85.0% (9619 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/zh_Hant/
2026-03-09 19:08:11 +01:00
Andrew 51f13dda01 Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 85.0% (9619 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/zh_Hant/
2026-03-09 19:08:11 +01:00
David Chen 1d9e2fdd48 Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 85.0% (9619 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/zh_Hant/
2026-03-09 19:08:11 +01:00
William Lin f7b9a83d04 Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 85.0% (9619 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/zh_Hant/
2026-03-09 19:08:11 +01:00
CloverGit 374a449091 Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 85.0% (9619 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/zh_Hant/
2026-03-09 19:08:11 +01:00
Che-Hsien Su a1f13e4121 Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 85.0% (9619 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/zh_Hant/
2026-03-09 19:08:11 +01:00
John Beard 11a782c836 Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 85.0% (9619 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/zh_Hant/
2026-03-09 19:08:11 +01:00
Seth Hillbrand 999593a1bb Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 85.0% (9619 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/zh_Hant/
2026-03-09 19:08:11 +01:00
Oliver0804 c3157b0fd1 Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 85.0% (9619 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/zh_Hant/
2026-03-09 19:08:11 +01:00
pondahai 893bca91c5 Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 85.0% (9619 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/zh_Hant/
2026-03-09 19:08:11 +01:00
reimu105 cd816cf310 Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 85.0% (9619 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/zh_Hant/
2026-03-09 19:08:10 +01:00
Shuwn Hsu b170982c35 Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 85.0% (9619 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/zh_Hant/
2026-03-09 19:08:10 +01:00
Vic d093d80129 Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 85.0% (9619 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/zh_Hant/
2026-03-09 19:08:10 +01:00
Anonymous ad6cc50d9a Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 85.0% (9619 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/zh_Hant/
2026-03-09 19:08:10 +01:00
taotieren 979c7ddc7d Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 85.0% (9619 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/zh_Hant/
2026-03-09 19:08:10 +01:00
pominglee 5ae688cf1b Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 85.0% (9619 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/zh_Hant/
2026-03-09 19:08:10 +01:00
Rafael Serrano ac02bf3097 Translated using Weblate (Catalan)
Currently translated at 34.7% (3931 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ca/
2026-03-09 19:08:10 +01:00
rsr.private 3efa3c1fb3 Translated using Weblate (Catalan)
Currently translated at 34.7% (3931 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ca/
2026-03-09 19:08:10 +01:00
Marc de Miguel 3d4c216224 Translated using Weblate (Catalan)
Currently translated at 34.7% (3931 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ca/
2026-03-09 19:08:10 +01:00
Seth Hillbrand c1dbbe7e06 Translated using Weblate (Catalan)
Currently translated at 34.7% (3931 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ca/
2026-03-09 19:08:10 +01:00
Adolfo Jayme Barrientos 74c441ccd7 Translated using Weblate (Catalan)
Currently translated at 34.7% (3931 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ca/
2026-03-09 19:08:09 +01:00
Arnau Llovet Vidal af2944c597 Translated using Weblate (Catalan)
Currently translated at 34.7% (3931 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ca/
2026-03-09 19:08:09 +01:00
Anonymous 0d0719f354 Translated using Weblate (Catalan)
Currently translated at 34.7% (3931 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ca/
2026-03-09 19:08:09 +01:00
yangyangdaji 38ecffcbd0 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 95.7% (10829 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/zh_Hans/
2026-03-09 19:08:09 +01:00
Pinpang Liao 33da3e9047 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 95.7% (10829 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/zh_Hans/
2026-03-09 19:08:09 +01:00
JasonTan ded4e1751a Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 95.7% (10829 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/zh_Hans/
2026-03-09 19:08:09 +01:00
aisuneko icecat 04929cb480 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 95.7% (10829 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/zh_Hans/
2026-03-09 19:08:09 +01:00
Li Yidong 4bc45a0e26 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 95.7% (10829 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/zh_Hans/
2026-03-09 19:08:09 +01:00
Liu Guang 84fa4a3f13 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 95.7% (10829 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/zh_Hans/
2026-03-09 19:08:09 +01:00
CharlieYu 6bdb766360 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 95.7% (10829 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/zh_Hans/
2026-03-09 19:08:08 +01:00
Dingzhong Chen 2155b9e2e1 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 95.7% (10829 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/zh_Hans/
2026-03-09 19:08:08 +01:00
Zhen Sun 86009c5366 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 95.7% (10829 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/zh_Hans/
2026-03-09 19:08:08 +01:00
HalfSweet 06b1b68c1a Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 95.7% (10829 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/zh_Hans/
2026-03-09 19:08:08 +01:00
dsa-t 434129f00a Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 95.7% (10829 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/zh_Hans/
2026-03-09 19:08:08 +01:00
Rigo Ligo e3a128f114 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 95.7% (10829 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/zh_Hans/
2026-03-09 19:08:08 +01:00
欠陥電気 77c5852424 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 95.7% (10829 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/zh_Hans/
2026-03-09 19:08:08 +01:00
Tian Yunhao 736967a9e9 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 95.7% (10829 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/zh_Hans/
2026-03-09 19:08:08 +01:00
Seth Hillbrand 781bfb8b70 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 95.7% (10829 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/zh_Hans/
2026-03-09 19:08:08 +01:00
向阳阳 4eb7219559 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 95.7% (10829 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/zh_Hans/
2026-03-09 19:08:08 +01:00
taotieren 99862d418a Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 95.7% (10829 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/zh_Hans/
2026-03-09 19:08:08 +01:00
Ian McInerney 4aee781c00 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 95.7% (10829 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/zh_Hans/
2026-03-09 19:08:08 +01:00
Deleted User 2483a2c419 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 95.7% (10829 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/zh_Hans/
2026-03-09 19:08:08 +01:00
Hubert Hu 69cb5f462a Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 95.7% (10829 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/zh_Hans/
2026-03-09 19:08:07 +01:00
CloverGit 92b27133d1 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 95.7% (10829 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/zh_Hans/
2026-03-09 19:08:07 +01:00
Anonymous 93daeab8c4 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 95.7% (10829 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/zh_Hans/
2026-03-09 19:08:07 +01:00
dsa-t 5bc5bccc92 Translated using Weblate (Tamil)
Currently translated at 91.5% (10353 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ta/
2026-03-09 19:08:07 +01:00
Seth Hillbrand 762098e017 Translated using Weblate (Tamil)
Currently translated at 91.5% (10353 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ta/
2026-03-09 19:08:07 +01:00
Anonymous 8f7951adb8 Translated using Weblate (Tamil)
Currently translated at 91.5% (10353 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ta/
2026-03-09 19:08:07 +01:00
தமிழ்நேரம் bdab71cf21 Translated using Weblate (Tamil)
Currently translated at 91.5% (10353 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ta/
2026-03-09 19:08:07 +01:00
Seth Hillbrand c8fbe9b03c Translated using Weblate (Croatian)
Currently translated at 0.0% (0 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/hr/
2026-03-09 19:08:07 +01:00
Anonymous 16a4b737a4 Translated using Weblate (Croatian)
Currently translated at 0.0% (0 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/hr/
2026-03-09 19:08:07 +01:00
Jarl Gjessing a387ff02db Translated using Weblate (Norwegian Bokmål)
Currently translated at 35.3% (3998 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/nb_NO/
2026-03-09 19:08:07 +01:00
Petter Reinholdtsen 3c5695394d Translated using Weblate (Norwegian Bokmål)
Currently translated at 35.3% (3998 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/nb_NO/
2026-03-09 19:08:07 +01:00
Håvard Syslak f225c4b0b8 Translated using Weblate (Norwegian Bokmål)
Currently translated at 35.3% (3998 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/nb_NO/
2026-03-09 19:08:07 +01:00
Henrik Kauhanen 0fb0c3686e Translated using Weblate (Norwegian Bokmål)
Currently translated at 35.3% (3998 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/nb_NO/
2026-03-09 19:08:07 +01:00
Stian Kristensen 16eb670dc0 Translated using Weblate (Norwegian Bokmål)
Currently translated at 35.3% (3998 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/nb_NO/
2026-03-09 19:08:06 +01:00
Allan Nordhøy f25e7e3d02 Translated using Weblate (Norwegian Bokmål)
Currently translated at 35.3% (3998 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/nb_NO/
2026-03-09 19:08:06 +01:00
Seth Hillbrand 731dd565d3 Translated using Weblate (Norwegian Bokmål)
Currently translated at 35.3% (3998 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/nb_NO/
2026-03-09 19:08:06 +01:00
Anonymous 2ad2968e4e Translated using Weblate (Norwegian Bokmål)
Currently translated at 35.3% (3998 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/nb_NO/
2026-03-09 19:08:06 +01:00
Echedey d27e935ba5 Translated using Weblate (Spanish)
Currently translated at 99.9% (11309 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/es/
2026-03-09 19:08:06 +01:00
dsa-t 285e4bb481 Translated using Weblate (Spanish)
Currently translated at 99.9% (11309 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/es/
2026-03-09 19:08:06 +01:00
Tomás Mora 80915de947 Translated using Weblate (Spanish)
Currently translated at 99.9% (11309 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/es/
2026-03-09 19:08:06 +01:00
uLe 8e46630977 Translated using Weblate (Spanish)
Currently translated at 99.9% (11309 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/es/
2026-03-09 19:08:06 +01:00
Jose Perez 5a676a10f3 Translated using Weblate (Spanish)
Currently translated at 99.9% (11309 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/es/
2026-03-09 19:08:06 +01:00
ZbeeGin fd06762194 Translated using Weblate (Spanish)
Currently translated at 99.9% (11309 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/es/
2026-03-09 19:08:06 +01:00
Gaston Schelotto cd8d76a91e Translated using Weblate (Spanish)
Currently translated at 99.9% (11309 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/es/
2026-03-09 19:08:05 +01:00
Gabriel Martinez d600e6273d Translated using Weblate (Spanish)
Currently translated at 99.9% (11309 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/es/
2026-03-09 19:08:05 +01:00
Pablo Bianchi 1693b9e524 Translated using Weblate (Spanish)
Currently translated at 99.9% (11309 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/es/
2026-03-09 19:08:05 +01:00
Francisco Jose Rey 83cc1df330 Translated using Weblate (Spanish)
Currently translated at 99.9% (11309 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/es/
2026-03-09 19:08:05 +01:00
Deleted User 8bcd0eef5d Translated using Weblate (Spanish)
Currently translated at 99.9% (11309 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/es/
2026-03-09 19:08:05 +01:00
Ulices 104354167b Translated using Weblate (Spanish)
Currently translated at 99.9% (11309 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/es/
2026-03-09 19:08:05 +01:00
Iñigo e8e1dd231c Translated using Weblate (Spanish)
Currently translated at 99.9% (11309 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/es/
2026-03-09 19:08:05 +01:00
Roberto Fernandez Bautista 0432223544 Translated using Weblate (Spanish)
Currently translated at 99.9% (11309 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/es/
2026-03-09 19:08:05 +01:00
VicSanRoPe 8a87c4ea5f Translated using Weblate (Spanish)
Currently translated at 99.9% (11309 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/es/
2026-03-09 19:08:05 +01:00
Anonymous a178c9f518 Translated using Weblate (Spanish)
Currently translated at 99.9% (11309 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/es/
2026-03-09 19:08:05 +01:00
Iñigo Figuero Sanz 7721d228d3 Translated using Weblate (Spanish)
Currently translated at 99.9% (11309 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/es/
2026-03-09 19:08:05 +01:00
Adolfo Jayme Barrientos 1ef8c151f0 Translated using Weblate (Spanish)
Currently translated at 99.9% (11309 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/es/
2026-03-09 19:08:04 +01:00
Seth Hillbrand 26f4e262fb Translated using Weblate (Spanish)
Currently translated at 99.9% (11309 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/es/
2026-03-09 19:08:04 +01:00
j.Kolod 24614352ec Translated using Weblate (Polish)
Currently translated at 92.3% (10451 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/pl/
2026-03-09 19:08:04 +01:00
Pomian 3bbcb2de2c Translated using Weblate (Polish)
Currently translated at 92.3% (10451 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/pl/
2026-03-09 19:08:04 +01:00
Krzysztof Kawa c7f90f4b7c Translated using Weblate (Polish)
Currently translated at 92.3% (10451 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/pl/
2026-03-09 19:08:04 +01:00
Jan Sobków 80c47400f1 Translated using Weblate (Polish)
Currently translated at 92.3% (10451 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/pl/
2026-03-09 19:08:04 +01:00
maksz42 3b2ac3ffd8 Translated using Weblate (Polish)
Currently translated at 92.3% (10451 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/pl/
2026-03-09 19:08:04 +01:00
Marek f1912cdbea Translated using Weblate (Polish)
Currently translated at 92.3% (10451 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/pl/
2026-03-09 19:08:04 +01:00
Eryk Michalak 34a393001c Translated using Weblate (Polish)
Currently translated at 92.3% (10451 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/pl/
2026-03-09 19:08:04 +01:00
Ivan Chuba fd5e5b0c93 Translated using Weblate (Polish)
Currently translated at 92.3% (10451 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/pl/
2026-03-09 19:08:04 +01:00
Grzegorz Szymaszek 1f26c55bf1 Translated using Weblate (Polish)
Currently translated at 92.3% (10451 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/pl/
2026-03-09 19:08:03 +01:00
dsa-t 01796a221f Translated using Weblate (Polish)
Currently translated at 92.3% (10451 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/pl/
2026-03-09 19:08:03 +01:00
Henrik Kauhanen 9f2f59d1ba Translated using Weblate (Polish)
Currently translated at 92.3% (10451 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/pl/
2026-03-09 19:08:03 +01:00
Seth Hillbrand e7ebee9bf0 Translated using Weblate (Polish)
Currently translated at 92.3% (10451 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/pl/
2026-03-09 19:08:03 +01:00
Mark Roszko 9c2b026bac Translated using Weblate (Polish)
Currently translated at 92.3% (10451 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/pl/
2026-03-09 19:08:03 +01:00
Czam Ciał 48080d2fd7 Translated using Weblate (Polish)
Currently translated at 92.3% (10451 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/pl/
2026-03-09 19:08:03 +01:00
Anonymous 2c1c533a18 Translated using Weblate (Polish)
Currently translated at 92.3% (10451 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/pl/
2026-03-09 19:08:03 +01:00
ZbeeGin f9fd7bc7eb Translated using Weblate (Polish)
Currently translated at 92.3% (10451 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/pl/
2026-03-09 19:08:03 +01:00
Deleted User 0284b4ad32 Translated using Weblate (Spanish (Mexico))
Currently translated at 99.9% (11309 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/es_MX/
2026-03-09 19:08:03 +01:00
uLe 3fb642dc94 Translated using Weblate (Spanish (Mexico))
Currently translated at 99.9% (11309 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/es_MX/
2026-03-09 19:08:03 +01:00
Ulices d624f453bc Translated using Weblate (Spanish (Mexico))
Currently translated at 99.9% (11309 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/es_MX/
2026-03-09 19:08:03 +01:00
Anonymous 3e03dd5757 Translated using Weblate (Spanish (Mexico))
Currently translated at 99.9% (11309 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/es_MX/
2026-03-09 19:08:03 +01:00
Seth Hillbrand 65a92d7f30 Translated using Weblate (Spanish (Mexico))
Currently translated at 99.9% (11309 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/es_MX/
2026-03-09 19:08:02 +01:00
John Beard d2a2d49d20 Translated using Weblate (German)
Currently translated at 100.0% (11312 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/de/
2026-03-09 19:08:02 +01:00
Ken Ovo ea696ffdcb Translated using Weblate (German)
Currently translated at 100.0% (11312 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/de/
2026-03-09 19:08:02 +01:00
Ivan Chuba e58ab38743 Translated using Weblate (German)
Currently translated at 100.0% (11312 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/de/
2026-03-09 19:08:02 +01:00
jonathan haas 79f9229ec5 Translated using Weblate (German)
Currently translated at 100.0% (11312 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/de/
2026-03-09 19:08:02 +01:00
Flo082002 3365b44832 Translated using Weblate (German)
Currently translated at 100.0% (11312 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/de/
2026-03-09 19:08:02 +01:00
Christian Schlüter 6e79b74f35 Translated using Weblate (German)
Currently translated at 100.0% (11312 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/de/
2026-03-09 19:08:02 +01:00
Sven 2cd3ce8d43 Translated using Weblate (German)
Currently translated at 100.0% (11312 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/de/
2026-03-09 19:08:02 +01:00
magical-obama 46b1d8b949 Translated using Weblate (German)
Currently translated at 100.0% (11312 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/de/
2026-03-09 19:08:02 +01:00
Julian Daube 53f75f58ac Translated using Weblate (German)
Currently translated at 100.0% (11312 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/de/
2026-03-09 19:08:02 +01:00
dsa-t 877e2dc944 Translated using Weblate (German)
Currently translated at 100.0% (11312 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/de/
2026-03-09 19:08:02 +01:00
Mathias Neumann 2d2630ac2d Translated using Weblate (German)
Currently translated at 100.0% (11312 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/de/
2026-03-09 19:08:02 +01:00
ulikoehler f71de6f1ce Translated using Weblate (German)
Currently translated at 100.0% (11312 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/de/
2026-03-09 19:08:02 +01:00
Karl SCHUH e5d62ffe9d Translated using Weblate (German)
Currently translated at 100.0% (11312 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/de/
2026-03-09 19:08:02 +01:00
Markus 3623052835 Translated using Weblate (German)
Currently translated at 100.0% (11312 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/de/
2026-03-09 19:08:02 +01:00
Lauritz Tieste 013edf241c Translated using Weblate (German)
Currently translated at 100.0% (11312 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/de/
2026-03-09 19:08:01 +01:00
Kliment 752d341d2f Translated using Weblate (German)
Currently translated at 100.0% (11312 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/de/
2026-03-09 19:08:01 +01:00
Dominik Wernberger e81f93bc07 Translated using Weblate (German)
Currently translated at 100.0% (11312 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/de/
2026-03-09 19:08:01 +01:00
Henrik Kauhanen 3ee1fa53f3 Translated using Weblate (German)
Currently translated at 100.0% (11312 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/de/
2026-03-09 19:08:01 +01:00
Seth Hillbrand 75e32414f0 Translated using Weblate (German)
Currently translated at 100.0% (11312 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/de/
2026-03-09 19:08:01 +01:00
weblateuser 6d64c406cf Translated using Weblate (German)
Currently translated at 100.0% (11312 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/de/
2026-03-09 19:08:01 +01:00
Johannes Maibaum 035ee47581 Translated using Weblate (German)
Currently translated at 100.0% (11312 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/de/
2026-03-09 19:08:01 +01:00
Benedikt Freisen 8fd760da6a Translated using Weblate (German)
Currently translated at 100.0% (11312 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/de/
2026-03-09 19:08:01 +01:00
Luc cfdec3410b Translated using Weblate (German)
Currently translated at 100.0% (11312 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/de/
2026-03-09 19:08:01 +01:00
Frank Sonnenberg 4b588ad3e7 Translated using Weblate (German)
Currently translated at 100.0% (11312 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/de/
2026-03-09 19:08:01 +01:00
Ettore Atalan fde6876984 Translated using Weblate (German)
Currently translated at 100.0% (11312 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/de/
2026-03-09 19:08:01 +01:00
Mark Hämmerling 2fe9565a4d Translated using Weblate (German)
Currently translated at 100.0% (11312 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/de/
2026-03-09 19:08:01 +01:00
Jonathan Haas f848190b5a Translated using Weblate (German)
Currently translated at 100.0% (11312 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/de/
2026-03-09 19:08:01 +01:00
Pferd O. d1f779155f Translated using Weblate (German)
Currently translated at 100.0% (11312 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/de/
2026-03-09 19:08:00 +01:00
Anonymous 521ec6227d Translated using Weblate (German)
Currently translated at 100.0% (11312 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/de/
2026-03-09 19:08:00 +01:00
Johan Heikkilä bd4c1a33ff Translated using Weblate (Swedish)
Currently translated at 99.1% (11212 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/sv/
2026-03-09 19:08:00 +01:00
dsa-t 1d9a906cd2 Translated using Weblate (Swedish)
Currently translated at 99.1% (11212 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/sv/
2026-03-09 19:08:00 +01:00
Stefan Bjornelund the Gnome 1738e21973 Translated using Weblate (Swedish)
Currently translated at 99.1% (11212 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/sv/
2026-03-09 19:08:00 +01:00
Joakim Lundborg 6b5ec5e847 Translated using Weblate (Swedish)
Currently translated at 99.1% (11212 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/sv/
2026-03-09 19:08:00 +01:00
Hanna Breisand 2bbfba76f9 Translated using Weblate (Swedish)
Currently translated at 99.1% (11212 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/sv/
2026-03-09 19:08:00 +01:00
Richard Jonsson 54fabed4da Translated using Weblate (Swedish)
Currently translated at 99.1% (11212 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/sv/
2026-03-09 19:08:00 +01:00
ZbeeGin 9288b8633f Translated using Weblate (Swedish)
Currently translated at 99.1% (11212 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/sv/
2026-03-09 19:08:00 +01:00
Axel Henriksson ff82f078b0 Translated using Weblate (Swedish)
Currently translated at 99.1% (11212 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/sv/
2026-03-09 19:08:00 +01:00
Anonymous 4a27cbe8c3 Translated using Weblate (Swedish)
Currently translated at 99.1% (11212 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/sv/
2026-03-09 19:08:00 +01:00
Seth Hillbrand 7162c158b5 Translated using Weblate (Swedish)
Currently translated at 99.1% (11212 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/sv/
2026-03-09 19:08:00 +01:00
Henrik Kauhanen daf0777dc7 Translated using Weblate (Swedish)
Currently translated at 99.1% (11212 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/sv/
2026-03-09 19:07:59 +01:00
Seth Hillbrand 3639c02392 Translated using Weblate (Estonian)
Currently translated at 3.1% (357 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/et/
2026-03-09 19:07:59 +01:00
Ivan Chuba 44a9af2f0e Translated using Weblate (Estonian)
Currently translated at 3.1% (357 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/et/
2026-03-09 19:07:59 +01:00
Anonymous 8075517527 Translated using Weblate (Estonian)
Currently translated at 3.1% (357 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/et/
2026-03-09 19:07:59 +01:00
김인수 e6e098f58d Translated using Weblate (Korean)
Currently translated at 99.9% (11309 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ko/
2026-03-09 19:07:59 +01:00
jeongsuAn 24f9c7a954 Translated using Weblate (Korean)
Currently translated at 99.9% (11309 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ko/
2026-03-09 19:07:59 +01:00
김용재 e323722870 Translated using Weblate (Korean)
Currently translated at 99.9% (11309 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ko/
2026-03-09 19:07:59 +01:00
이윤성 f76c60f11d Translated using Weblate (Korean)
Currently translated at 99.9% (11309 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ko/
2026-03-09 19:07:59 +01:00
김낙환 cf4ddcf96f Translated using Weblate (Korean)
Currently translated at 99.9% (11309 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ko/
2026-03-09 19:07:59 +01:00
김유진 55ec72c650 Translated using Weblate (Korean)
Currently translated at 99.9% (11309 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ko/
2026-03-09 19:07:58 +01:00
박세훈 8dd955fb6f Translated using Weblate (Korean)
Currently translated at 99.9% (11309 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ko/
2026-03-09 19:07:58 +01:00
이기형 e18c5fce48 Translated using Weblate (Korean)
Currently translated at 99.9% (11309 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ko/
2026-03-09 19:07:58 +01:00
Pedro Moreira 5cb89b0bc4 Translated using Weblate (Korean)
Currently translated at 99.9% (11309 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ko/
2026-03-09 19:07:58 +01:00
김호진 79229b38b3 Translated using Weblate (Korean)
Currently translated at 99.9% (11309 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ko/
2026-03-09 19:07:58 +01:00
Jason Son 9ff4c4db60 Translated using Weblate (Korean)
Currently translated at 99.9% (11309 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ko/
2026-03-09 19:07:58 +01:00
이상수 265e03757f Translated using Weblate (Korean)
Currently translated at 99.9% (11309 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ko/
2026-03-09 19:07:58 +01:00
minsu kim (0xGabriel) 0303872c99 Translated using Weblate (Korean)
Currently translated at 99.9% (11309 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ko/
2026-03-09 19:07:58 +01:00
YunJiSang ae24f2ddbc Translated using Weblate (Korean)
Currently translated at 99.9% (11309 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ko/
2026-03-09 19:07:58 +01:00
dsa-t 79ce411ef8 Translated using Weblate (Korean)
Currently translated at 99.9% (11309 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ko/
2026-03-09 19:07:58 +01:00
KwonHyeokbeom a8d897e682 Translated using Weblate (Korean)
Currently translated at 99.9% (11309 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ko/
2026-03-09 19:07:58 +01:00
kmn4555 5afc0e9289 Translated using Weblate (Korean)
Currently translated at 99.9% (11309 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ko/
2026-03-09 19:07:58 +01:00
jeong-sangwon cfa6e9f940 Translated using Weblate (Korean)
Currently translated at 99.9% (11309 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ko/
2026-03-09 19:07:57 +01:00
김세영 de3ea9f7d1 Translated using Weblate (Korean)
Currently translated at 99.9% (11309 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ko/
2026-03-09 19:07:57 +01:00
DevAny 0e4b10bb3c Translated using Weblate (Korean)
Currently translated at 99.9% (11309 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ko/
2026-03-09 19:07:57 +01:00
Anonymous c844a8e6e6 Translated using Weblate (Korean)
Currently translated at 99.9% (11309 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ko/
2026-03-09 19:07:57 +01:00
김랑기 c582b12e19 Translated using Weblate (Korean)
Currently translated at 99.9% (11309 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ko/
2026-03-09 19:07:57 +01:00
Seth Hillbrand f8e8b8cc14 Translated using Weblate (Korean)
Currently translated at 99.9% (11309 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ko/
2026-03-09 19:07:57 +01:00
Flórián Fuszkó 284be5f508 Translated using Weblate (Hungarian)
Currently translated at 50.0% (5666 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/hu/
2026-03-09 19:07:57 +01:00
iamPeter bb8b4e7a3a Translated using Weblate (Hungarian)
Currently translated at 50.0% (5666 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/hu/
2026-03-09 19:07:57 +01:00
Elek Zoltán 7972a00c30 Translated using Weblate (Hungarian)
Currently translated at 50.0% (5666 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/hu/
2026-03-09 19:07:57 +01:00
dsa-t 4f9a2ba086 Translated using Weblate (Hungarian)
Currently translated at 50.0% (5666 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/hu/
2026-03-09 19:07:57 +01:00
Seth Hillbrand d6e2436539 Translated using Weblate (Hungarian)
Currently translated at 50.0% (5666 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/hu/
2026-03-09 19:07:57 +01:00
KB d8dd6ebf1b Translated using Weblate (Hungarian)
Currently translated at 50.0% (5666 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/hu/
2026-03-09 19:07:57 +01:00
Miklós Márton ec5fe06b12 Translated using Weblate (Hungarian)
Currently translated at 50.0% (5666 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/hu/
2026-03-09 19:07:57 +01:00
Balázs Meskó 42034fc799 Translated using Weblate (Hungarian)
Currently translated at 50.0% (5666 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/hu/
2026-03-09 19:07:57 +01:00
Hajdu Norbert 70e9bec4e4 Translated using Weblate (Hungarian)
Currently translated at 50.0% (5666 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/hu/
2026-03-09 19:07:56 +01:00
István Farkas a35673f098 Translated using Weblate (Hungarian)
Currently translated at 50.0% (5666 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/hu/
2026-03-09 19:07:56 +01:00
Sárkány Lőrinc c7e5cbdcb9 Translated using Weblate (Hungarian)
Currently translated at 50.0% (5666 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/hu/
2026-03-09 19:07:56 +01:00
Anonymous f32678a012 Translated using Weblate (Hungarian)
Currently translated at 50.0% (5666 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/hu/
2026-03-09 19:07:56 +01:00
dsa-t 13b1c6589a Translated using Weblate (Serbian)
Currently translated at 16.0% (1813 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/sr/
2026-03-09 19:07:56 +01:00
Seth Hillbrand 3f7dabb3c2 Translated using Weblate (Serbian)
Currently translated at 16.0% (1813 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/sr/
2026-03-09 19:07:56 +01:00
___davidpr b3a6d9174b Translated using Weblate (Serbian)
Currently translated at 16.0% (1813 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/sr/
2026-03-09 19:07:56 +01:00
Luka Borkovic f9b5a48675 Translated using Weblate (Serbian)
Currently translated at 16.0% (1813 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/sr/
2026-03-09 19:07:56 +01:00
Anonymous 6d5072ed9e Translated using Weblate (Serbian)
Currently translated at 16.0% (1813 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/sr/
2026-03-09 19:07:56 +01:00
soldado-do-wolfenstein c7bdd19388 Translated using Weblate (Portuguese (Brazil))
Currently translated at 99.9% (11310 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/pt_BR/
2026-03-09 19:07:56 +01:00
dsa-t 95ad7ff4cb Translated using Weblate (Portuguese (Brazil))
Currently translated at 99.9% (11310 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/pt_BR/
2026-03-09 19:07:56 +01:00
Hildo Guillardi Júnior 9e1a031227 Translated using Weblate (Portuguese (Brazil))
Currently translated at 99.9% (11310 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/pt_BR/
2026-03-09 19:07:56 +01:00
John Beard b02d45f1c9 Translated using Weblate (Portuguese (Brazil))
Currently translated at 99.9% (11310 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/pt_BR/
2026-03-09 19:07:56 +01:00
Pedro Moreira c97b348700 Translated using Weblate (Portuguese (Brazil))
Currently translated at 99.9% (11310 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/pt_BR/
2026-03-09 19:07:56 +01:00
Augusto Fraga Giachero 3134dab167 Translated using Weblate (Portuguese (Brazil))
Currently translated at 99.9% (11310 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/pt_BR/
2026-03-09 19:07:55 +01:00
Seth Hillbrand cb3169a56e Translated using Weblate (Portuguese (Brazil))
Currently translated at 99.9% (11310 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/pt_BR/
2026-03-09 19:07:55 +01:00
Anonymous 7a40f2e81d Translated using Weblate (Portuguese (Brazil))
Currently translated at 99.9% (11310 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/pt_BR/
2026-03-09 19:07:55 +01:00
Wellington Terumi Uemura 2abdfec5a0 Translated using Weblate (Portuguese (Brazil))
Currently translated at 99.9% (11310 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/pt_BR/
2026-03-09 19:07:55 +01:00
Nguyen Van Dien a5eb41e48f Translated using Weblate (Vietnamese)
Currently translated at 19.1% (2162 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/vi/
2026-03-09 19:07:55 +01:00
John Beard 67e4bc5646 Translated using Weblate (Vietnamese)
Currently translated at 19.1% (2162 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/vi/
2026-03-09 19:07:55 +01:00
Bế Trọng Nghĩa 502eda77ad Translated using Weblate (Vietnamese)
Currently translated at 19.1% (2162 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/vi/
2026-03-09 19:07:55 +01:00
Phạm Minh Tấn c04bed6768 Translated using Weblate (Vietnamese)
Currently translated at 19.1% (2162 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/vi/
2026-03-09 19:07:55 +01:00
Seth Hillbrand 03cc4c8933 Translated using Weblate (Vietnamese)
Currently translated at 19.1% (2162 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/vi/
2026-03-09 19:07:55 +01:00
rtyuionoop 5e40a10433 Translated using Weblate (Vietnamese)
Currently translated at 19.1% (2162 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/vi/
2026-03-09 19:07:55 +01:00
Trần Phi Hải 1d337743e1 Translated using Weblate (Vietnamese)
Currently translated at 19.1% (2162 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/vi/
2026-03-09 19:07:55 +01:00
Nguyễn Ngọc Khánh e357c21aea Translated using Weblate (Vietnamese)
Currently translated at 19.1% (2162 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/vi/
2026-03-09 19:07:55 +01:00
lê văn lập fb1ab094fe Translated using Weblate (Vietnamese)
Currently translated at 19.1% (2162 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/vi/
2026-03-09 19:07:55 +01:00
Anonymous 89bdff17cc Translated using Weblate (Vietnamese)
Currently translated at 19.1% (2162 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/vi/
2026-03-09 19:07:55 +01:00
YÜKSEL AÇIKGÖZ a44bd872ff Translated using Weblate (Turkish)
Currently translated at 100.0% (11312 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/tr/
2026-03-09 19:07:54 +01:00
ZbeeGin faf09c2fe6 Translated using Weblate (Lithuanian)
Currently translated at 35.5% (4025 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/lt/
2026-03-09 19:07:54 +01:00
Ignas Brašiškis 3890e47fed Translated using Weblate (Lithuanian)
Currently translated at 35.5% (4025 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/lt/
2026-03-09 19:07:54 +01:00
Henrik Kauhanen 26133f30e0 Translated using Weblate (Lithuanian)
Currently translated at 35.5% (4025 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/lt/
2026-03-09 19:07:54 +01:00
WhiteChairFromIkea 7c6c1f48e2 Translated using Weblate (Lithuanian)
Currently translated at 35.5% (4025 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/lt/
2026-03-09 19:07:54 +01:00
Seth Hillbrand 4be78114fe Translated using Weblate (Lithuanian)
Currently translated at 35.5% (4025 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/lt/
2026-03-09 19:07:54 +01:00
Anonymous 4528a1f579 Translated using Weblate (Lithuanian)
Currently translated at 35.5% (4025 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/lt/
2026-03-09 19:07:54 +01:00
boromyr faa5bfefc3 Translated using Weblate (Italian)
Currently translated at 99.5% (11257 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/it/
2026-03-09 19:07:54 +01:00
Luca Mattii 2a8e1fef16 Translated using Weblate (Italian)
Currently translated at 99.5% (11257 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/it/
2026-03-09 19:07:54 +01:00
Seth Hillbrand f4e627fda2 Translated using Weblate (Italian)
Currently translated at 99.5% (11257 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/it/
2026-03-09 19:07:54 +01:00
Anonymous c417d6ad0a Translated using Weblate (Italian)
Currently translated at 99.5% (11257 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/it/
2026-03-09 19:07:54 +01:00
Marco Ciampa b4b291da10 Translated using Weblate (Italian)
Currently translated at 99.5% (11257 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/it/
2026-03-09 19:07:54 +01:00
Roman Ondráček f6ed489cd0 Translated using Weblate (Czech)
Currently translated at 67.8% (7679 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/cs/
2026-03-09 19:07:53 +01:00
EdizonTN 091b302b9c Translated using Weblate (Czech)
Currently translated at 67.8% (7679 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/cs/
2026-03-09 19:07:53 +01:00
Hynek Štětina f298be1d50 Translated using Weblate (Czech)
Currently translated at 67.8% (7679 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/cs/
2026-03-09 19:07:53 +01:00
Michal Kundrát 76bcef63c3 Translated using Weblate (Czech)
Currently translated at 67.8% (7679 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/cs/
2026-03-09 19:07:53 +01:00
René Široký 2012182ef6 Translated using Weblate (Czech)
Currently translated at 67.8% (7679 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/cs/
2026-03-09 19:07:53 +01:00
Ondřej Čertík 8746fba7b7 Translated using Weblate (Czech)
Currently translated at 67.8% (7679 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/cs/
2026-03-09 19:07:52 +01:00
dsa-t 094289523d Translated using Weblate (Czech)
Currently translated at 67.8% (7679 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/cs/
2026-03-09 19:07:52 +01:00
Andrej Valek e6cb2556ad Translated using Weblate (Czech)
Currently translated at 67.8% (7679 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/cs/
2026-03-09 19:07:52 +01:00
Jan Vykydal fa93c846e4 Translated using Weblate (Czech)
Currently translated at 67.8% (7679 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/cs/
2026-03-09 19:07:52 +01:00
Radovan Blažek 26d57926c4 Translated using Weblate (Czech)
Currently translated at 67.8% (7679 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/cs/
2026-03-09 19:07:52 +01:00
Radek K 80efb27221 Translated using Weblate (Czech)
Currently translated at 67.8% (7679 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/cs/
2026-03-09 19:07:52 +01:00
ivit VT 7783ed97fb Translated using Weblate (Czech)
Currently translated at 67.8% (7679 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/cs/
2026-03-09 19:07:52 +01:00
Tomas0015 a27a8a3d95 Translated using Weblate (Czech)
Currently translated at 67.8% (7679 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/cs/
2026-03-09 19:07:52 +01:00
Petr Pazourek 3b637763e8 Translated using Weblate (Czech)
Currently translated at 67.8% (7679 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/cs/
2026-03-09 19:07:52 +01:00
Seth Hillbrand cdc723e36e Translated using Weblate (Czech)
Currently translated at 67.8% (7679 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/cs/
2026-03-09 19:07:52 +01:00
Jan Straka 6a56b435e0 Translated using Weblate (Czech)
Currently translated at 67.8% (7679 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/cs/
2026-03-09 19:07:52 +01:00
Anonymous 967900a9dd Translated using Weblate (Czech)
Currently translated at 67.8% (7679 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/cs/
2026-03-09 19:07:51 +01:00
МАН69К f05584f90a Translated using Weblate (Russian)
Currently translated at 83.3% (9433 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ru/
2026-03-09 19:07:51 +01:00
Дмитрий Дёмин 3957aa7aa1 Translated using Weblate (Russian)
Currently translated at 83.3% (9433 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ru/
2026-03-09 19:07:51 +01:00
sergio 1a7b21ee38 Translated using Weblate (Russian)
Currently translated at 83.3% (9433 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ru/
2026-03-09 19:07:51 +01:00
xXx 4ed8d7f20a Translated using Weblate (Russian)
Currently translated at 83.3% (9433 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ru/
2026-03-09 19:07:51 +01:00
ZbeeGin 4acf50bb13 Translated using Weblate (Russian)
Currently translated at 83.3% (9433 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ru/
2026-03-09 19:07:51 +01:00
Free_squire 82e3b28cf7 Translated using Weblate (Russian)
Currently translated at 83.3% (9433 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ru/
2026-03-09 19:07:51 +01:00
Dmitry Mikhirev f241794f82 Translated using Weblate (Russian)
Currently translated at 83.3% (9433 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ru/
2026-03-09 19:07:51 +01:00
Seth Hillbrand 6d67ce74b1 Translated using Weblate (Russian)
Currently translated at 83.3% (9433 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ru/
2026-03-09 19:07:51 +01:00
Дмитрий Михирев e4d116affc Translated using Weblate (Russian)
Currently translated at 83.3% (9433 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ru/
2026-03-09 19:07:51 +01:00
gfbdrgng 9e65c96899 Translated using Weblate (Russian)
Currently translated at 83.3% (9433 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ru/
2026-03-09 19:07:51 +01:00
Andrey Fedorushkov 38852cf329 Translated using Weblate (Russian)
Currently translated at 83.3% (9433 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ru/
2026-03-09 19:07:51 +01:00
Ivan Chuba 9f7f6266df Translated using Weblate (Russian)
Currently translated at 83.3% (9433 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ru/
2026-03-09 19:07:51 +01:00
alevtina-karashokova 74ab85dd41 Translated using Weblate (Russian)
Currently translated at 83.3% (9433 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ru/
2026-03-09 19:07:51 +01:00
dsa-t 6ac3d4eb11 Translated using Weblate (Russian)
Currently translated at 83.3% (9433 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ru/
2026-03-09 19:07:51 +01:00
Konstantin Baranovskiy 413b600479 Translated using Weblate (Russian)
Currently translated at 83.3% (9433 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ru/
2026-03-09 19:07:50 +01:00
Anonymous 91e2e6ee55 Translated using Weblate (Russian)
Currently translated at 83.3% (9433 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ru/
2026-03-09 19:07:50 +01:00
Sašo Domadenik 37114e3718 Translated using Weblate (Slovenian)
Currently translated at 1.2% (141 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/sl/
2026-03-09 19:07:50 +01:00
Mitja Nemec 69e6fb941e Translated using Weblate (Slovenian)
Currently translated at 1.2% (141 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/sl/
2026-03-09 19:07:50 +01:00
Seth Hillbrand 7139f21a8d Translated using Weblate (Slovenian)
Currently translated at 1.2% (141 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/sl/
2026-03-09 19:07:50 +01:00
Vitan Košpenda 15383e613c Translated using Weblate (Slovenian)
Currently translated at 1.2% (141 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/sl/
2026-03-09 19:07:50 +01:00
Anonymous 7a368cd58b Translated using Weblate (Slovenian)
Currently translated at 1.2% (141 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/sl/
2026-03-09 19:07:50 +01:00
Mads Dyrmann 848659e4aa Translated using Weblate (Danish)
Currently translated at 34.8% (3940 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/da/
2026-03-09 19:07:50 +01:00
ZbeeGin fdc27b17da Translated using Weblate (Danish)
Currently translated at 34.8% (3940 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/da/
2026-03-09 19:07:50 +01:00
nickoe c7d9d5f210 Translated using Weblate (Danish)
Currently translated at 34.8% (3940 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/da/
2026-03-09 19:07:50 +01:00
dsa-t 0aa7e17347 Translated using Weblate (Danish)
Currently translated at 34.8% (3940 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/da/
2026-03-09 19:07:50 +01:00
Henrik Kauhanen 6288f57ff6 Translated using Weblate (Danish)
Currently translated at 34.8% (3940 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/da/
2026-03-09 19:07:50 +01:00
Jarl Gjessing 570724eebc Translated using Weblate (Danish)
Currently translated at 34.8% (3940 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/da/
2026-03-09 19:07:50 +01:00
Seth Hillbrand 0dc07634f8 Translated using Weblate (Danish)
Currently translated at 34.8% (3940 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/da/
2026-03-09 19:07:50 +01:00
Anonymous 6fa6c66553 Translated using Weblate (Danish)
Currently translated at 34.8% (3940 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/da/
2026-03-09 19:07:50 +01:00
Seth Hillbrand b9cb51be2b Translated using Weblate (Persian)
Currently translated at 7.3% (837 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/fa/
2026-03-09 19:07:49 +01:00
Mahdi Ahmadzadeh 6159ad3777 Translated using Weblate (Persian)
Currently translated at 7.3% (837 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/fa/
2026-03-09 19:07:49 +01:00
Anonymous dcd43a7328 Translated using Weblate (Persian)
Currently translated at 7.3% (837 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/fa/
2026-03-09 19:07:49 +01:00
Seth Hillbrand ca471e1b03 Translated using Weblate (Thai)
Currently translated at 50.2% (5686 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/th/
2026-03-09 19:07:49 +01:00
boonchai k. bd175cd5ac Translated using Weblate (Thai)
Currently translated at 50.2% (5686 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/th/
2026-03-09 19:07:49 +01:00
Anonymous f41498e894 Translated using Weblate (Thai)
Currently translated at 50.2% (5686 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/th/
2026-03-09 19:07:49 +01:00
Anonymous 779bfe84d8 Translated using Weblate (Hebrew)
Currently translated at 99.9% (11307 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/he/
2026-03-09 19:07:49 +01:00
G.B 8ceb51335c Translated using Weblate (Hebrew)
Currently translated at 99.9% (11307 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/he/
2026-03-09 19:07:49 +01:00
Seth Hillbrand 0f26f4331a Translated using Weblate (Hebrew)
Currently translated at 99.9% (11307 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/he/
2026-03-09 19:07:49 +01:00
Herman van der Vaart a71d657b0f Translated using Weblate (Dutch)
Currently translated at 76.5% (8663 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/nl/
2026-03-09 19:07:49 +01:00
Christiaan Nieuwlaat e5cbd56f7e Translated using Weblate (Dutch)
Currently translated at 76.5% (8663 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/nl/
2026-03-09 19:07:49 +01:00
johanneswilkens 5b068fe2ec Translated using Weblate (Dutch)
Currently translated at 76.5% (8663 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/nl/
2026-03-09 19:07:48 +01:00
ZbeeGin 44d6af1d88 Translated using Weblate (Dutch)
Currently translated at 76.5% (8663 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/nl/
2026-03-09 19:07:48 +01:00
Ranforingus 5f4a81b850 Translated using Weblate (Dutch)
Currently translated at 76.5% (8663 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/nl/
2026-03-09 19:07:48 +01:00
Arend-Jan van Hilten 73733f6f6c Translated using Weblate (Dutch)
Currently translated at 76.5% (8663 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/nl/
2026-03-09 19:07:48 +01:00
Robin Janssens c433af7f7b Translated using Weblate (Dutch)
Currently translated at 76.5% (8663 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/nl/
2026-03-09 19:07:48 +01:00
pimjansen98 4a42825530 Translated using Weblate (Dutch)
Currently translated at 76.5% (8663 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/nl/
2026-03-09 19:07:48 +01:00
Stefan De Raedemaeker 9032472ce7 Translated using Weblate (Dutch)
Currently translated at 76.5% (8663 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/nl/
2026-03-09 19:07:48 +01:00
Bas Wijnen bfbc3a8dc7 Translated using Weblate (Dutch)
Currently translated at 76.5% (8663 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/nl/
2026-03-09 19:07:48 +01:00
Seth Hillbrand 97b6125ff1 Translated using Weblate (Dutch)
Currently translated at 76.5% (8663 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/nl/
2026-03-09 19:07:48 +01:00
CJ van der Hoeven 5724727c0d Translated using Weblate (Dutch)
Currently translated at 76.5% (8663 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/nl/
2026-03-09 19:07:48 +01:00
Laurens Holst 978bd2af08 Translated using Weblate (Dutch)
Currently translated at 76.5% (8663 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/nl/
2026-03-09 19:07:48 +01:00
Anonymous 3f3971772d Translated using Weblate (Dutch)
Currently translated at 76.5% (8663 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/nl/
2026-03-09 19:07:47 +01:00
Axel Henriksson 2eed4bcac1 Translated using Weblate (Greek)
Currently translated at 71.7% (8116 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/el/
2026-03-09 19:07:47 +01:00
Theodoros Asimakopoulos 1f6995bb04 Translated using Weblate (Greek)
Currently translated at 71.7% (8116 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/el/
2026-03-09 19:07:47 +01:00
Seth Hillbrand f9bcd1e029 Translated using Weblate (Greek)
Currently translated at 71.7% (8116 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/el/
2026-03-09 19:07:47 +01:00
fresh 6cdc777428 Translated using Weblate (Greek)
Currently translated at 71.7% (8116 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/el/
2026-03-09 19:07:47 +01:00
Michalis b3a835cc41 Translated using Weblate (Greek)
Currently translated at 71.7% (8116 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/el/
2026-03-09 19:07:47 +01:00
Michael Misirlis b91c48b52c Translated using Weblate (Greek)
Currently translated at 71.7% (8116 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/el/
2026-03-09 19:07:47 +01:00
aris-kimi 5f0f9f17ba Translated using Weblate (Greek)
Currently translated at 71.7% (8116 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/el/
2026-03-09 19:07:47 +01:00
Anonymous 728896ae46 Translated using Weblate (Greek)
Currently translated at 71.7% (8116 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/el/
2026-03-09 19:07:47 +01:00
dsa-t b88a5fa735 Translated using Weblate (Portuguese)
Currently translated at 99.9% (11309 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/pt/
2026-03-09 19:07:47 +01:00
Augusto Fraga Giachero 25a46800d7 Translated using Weblate (Portuguese)
Currently translated at 99.9% (11309 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/pt/
2026-03-09 19:07:47 +01:00
leonardokr 11b7681e3a Translated using Weblate (Portuguese)
Currently translated at 99.9% (11309 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/pt/
2026-03-09 19:07:47 +01:00
Manuela Silva 06a3bd7fd4 Translated using Weblate (Portuguese)
Currently translated at 99.9% (11309 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/pt/
2026-03-09 19:07:47 +01:00
Julio Dias 64ec3ea249 Translated using Weblate (Portuguese)
Currently translated at 99.9% (11309 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/pt/
2026-03-09 19:07:46 +01:00
Hildo Guillardi Júnior 9be1a353a4 Translated using Weblate (Portuguese)
Currently translated at 99.9% (11309 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/pt/
2026-03-09 19:07:46 +01:00
Rafael Silva 3cbb9562c5 Translated using Weblate (Portuguese)
Currently translated at 99.9% (11309 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/pt/
2026-03-09 19:07:46 +01:00
Seth Hillbrand 36eae5507e Translated using Weblate (Portuguese)
Currently translated at 99.9% (11309 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/pt/
2026-03-09 19:07:46 +01:00
Anonymous 857db6e44e Translated using Weblate (Portuguese)
Currently translated at 99.9% (11309 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/pt/
2026-03-09 19:07:46 +01:00
ssantos 6736d19224 Translated using Weblate (Portuguese)
Currently translated at 99.9% (11309 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/pt/
2026-03-09 19:07:46 +01:00
SubaruArai fbf3bef184 Translated using Weblate (Japanese)
Currently translated at 100.0% (11312 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ja/
2026-03-09 19:07:46 +01:00
dsa-t 8f7b447382 Translated using Weblate (Japanese)
Currently translated at 100.0% (11312 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ja/
2026-03-09 19:07:46 +01:00
Keisuke Nakao f155bb29b2 Translated using Weblate (Japanese)
Currently translated at 100.0% (11312 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ja/
2026-03-09 19:07:46 +01:00
Yutaro Urata2 07b40f6a57 Translated using Weblate (Japanese)
Currently translated at 100.0% (11312 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ja/
2026-03-09 19:07:46 +01:00
Ji Yoon Choi 341d2f5fdb Translated using Weblate (Japanese)
Currently translated at 100.0% (11312 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ja/
2026-03-09 19:07:46 +01:00
Seth Hillbrand 8870ee2fc3 Translated using Weblate (Japanese)
Currently translated at 100.0% (11312 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ja/
2026-03-09 19:07:46 +01:00
co8 j 6402de7e89 Translated using Weblate (Japanese)
Currently translated at 100.0% (11312 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ja/
2026-03-09 19:07:46 +01:00
2tama3 4e8e267574 Translated using Weblate (Japanese)
Currently translated at 100.0% (11312 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ja/
2026-03-09 19:07:46 +01:00
Tokita, Hiroshi 836993b088 Translated using Weblate (Japanese)
Currently translated at 100.0% (11312 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ja/
2026-03-09 19:07:45 +01:00
Anonymous 5c7d6c3931 Translated using Weblate (Japanese)
Currently translated at 100.0% (11312 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ja/
2026-03-09 19:07:45 +01:00
David Chorváth 4945718bd4 Translated using Weblate (Slovak)
Currently translated at 64.0% (7249 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/sk/
2026-03-09 19:07:45 +01:00
Jakub Janek ac12e69714 Translated using Weblate (Slovak)
Currently translated at 64.0% (7249 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/sk/
2026-03-09 19:07:45 +01:00
Marcel Hecko 1f99936392 Translated using Weblate (Slovak)
Currently translated at 64.0% (7249 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/sk/
2026-03-09 19:07:45 +01:00
Marcel Hecko 6e204b5d04 Translated using Weblate (Slovak)
Currently translated at 64.0% (7249 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/sk/
2026-03-09 19:07:45 +01:00
Seth Hillbrand 69aca57bbb Translated using Weblate (Slovak)
Currently translated at 64.0% (7249 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/sk/
2026-03-09 19:07:45 +01:00
EdizonTN 78fd479daf Translated using Weblate (Slovak)
Currently translated at 64.0% (7249 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/sk/
2026-03-09 19:07:45 +01:00
Anonymous 16fdf4ece3 Translated using Weblate (Slovak)
Currently translated at 64.0% (7249 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/sk/
2026-03-09 19:07:45 +01:00
Andrej Valek 9c10642e0c Translated using Weblate (Slovak)
Currently translated at 64.0% (7249 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/sk/
2026-03-09 19:07:45 +01:00
Anonymous a55d06e3f8 Translated using Weblate (Slovak)
Currently translated at 64.0% (7249 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/sk/
2026-03-09 19:07:45 +01:00
Nicoara Alex 3a6158abe7 Translated using Weblate (Romanian)
Currently translated at 27.0% (3064 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ro/
2026-03-09 19:07:45 +01:00
Adrian Scripcă a265c7a86d Translated using Weblate (Romanian)
Currently translated at 27.0% (3064 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ro/
2026-03-09 19:07:45 +01:00
Henrik Kauhanen 887734eaa4 Translated using Weblate (Romanian)
Currently translated at 27.0% (3064 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ro/
2026-03-09 19:07:44 +01:00
Seth Hillbrand ca848c6e69 Translated using Weblate (Romanian)
Currently translated at 27.0% (3064 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ro/
2026-03-09 19:07:44 +01:00
Tatu Bogdan 750f420a30 Translated using Weblate (Romanian)
Currently translated at 27.0% (3064 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ro/
2026-03-09 19:07:44 +01:00
Peter B 61c193bf0b Translated using Weblate (Romanian)
Currently translated at 27.0% (3064 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ro/
2026-03-09 19:07:44 +01:00
Alex Gellen 41d477d271 Translated using Weblate (Romanian)
Currently translated at 27.0% (3064 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ro/
2026-03-09 19:07:44 +01:00
Anonymous 67b1c187ed Translated using Weblate (Romanian)
Currently translated at 27.0% (3064 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ro/
2026-03-09 19:07:44 +01:00
whenwesober d3d5381f40 Translated using Weblate (Indonesian)
Currently translated at 11.9% (1354 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/id/
2026-03-09 19:07:44 +01:00
Jacque Fresco be28232462 Translated using Weblate (Indonesian)
Currently translated at 11.9% (1354 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/id/
2026-03-09 19:07:44 +01:00
Seth Hillbrand f963aa53b4 Translated using Weblate (Indonesian)
Currently translated at 11.9% (1354 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/id/
2026-03-09 19:07:44 +01:00
Reza Almanda 781bf7dee1 Translated using Weblate (Indonesian)
Currently translated at 11.9% (1354 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/id/
2026-03-09 19:07:44 +01:00
Neko Nekowazarashi 24f930f894 Translated using Weblate (Indonesian)
Currently translated at 11.9% (1354 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/id/
2026-03-09 19:07:43 +01:00
Triyan W. Nugroho 77b8f0b155 Translated using Weblate (Indonesian)
Currently translated at 11.9% (1354 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/id/
2026-03-09 19:07:43 +01:00
Anonymous 1c878253c0 Translated using Weblate (Indonesian)
Currently translated at 11.9% (1354 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/id/
2026-03-09 19:07:43 +01:00
dsa-t 2194294160 Translated using Weblate (Bulgarian)
Currently translated at 7.0% (796 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/bg/
2026-03-09 19:07:43 +01:00
Seth Hillbrand 5a56d051a0 Translated using Weblate (Bulgarian)
Currently translated at 7.0% (796 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/bg/
2026-03-09 19:07:43 +01:00
109247019824 aa5facd673 Translated using Weblate (Bulgarian)
Currently translated at 7.0% (796 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/bg/
2026-03-09 19:07:43 +01:00
Anonymous 490c36694b Translated using Weblate (Bulgarian)
Currently translated at 7.0% (796 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/bg/
2026-03-09 19:07:43 +01:00
Artem ceddf79cad Translated using Weblate (Ukrainian)
Currently translated at 98.7% (11171 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/uk/
2026-03-09 19:07:43 +01:00
dsa-t 7c46d8c28a Translated using Weblate (Ukrainian)
Currently translated at 98.7% (11171 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/uk/
2026-03-09 19:07:43 +01:00
Andrii Shelestov 11f0960137 Translated using Weblate (Ukrainian)
Currently translated at 98.7% (11171 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/uk/
2026-03-09 19:07:43 +01:00
Seth Hillbrand f7da521c1b Translated using Weblate (Ukrainian)
Currently translated at 98.7% (11171 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/uk/
2026-03-09 19:07:43 +01:00
Stanislav Kaliuk 28afd1991c Translated using Weblate (Ukrainian)
Currently translated at 98.7% (11171 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/uk/
2026-03-09 19:07:43 +01:00
Anonymous a2e904f7df Translated using Weblate (Ukrainian)
Currently translated at 98.7% (11171 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/uk/
2026-03-09 19:07:43 +01:00
Kuzemko Alexsandr 077227397a Translated using Weblate (Ukrainian)
Currently translated at 98.7% (11171 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/uk/
2026-03-09 19:07:42 +01:00
Ivan Chuba 44793a3ba5 Translated using Weblate (Ukrainian)
Currently translated at 98.7% (11171 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/uk/
2026-03-09 19:07:42 +01:00
Максим Горпиніч ce139eec75 Translated using Weblate (Ukrainian)
Currently translated at 98.7% (11171 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/uk/
2026-03-09 19:07:42 +01:00
dsa-t d68fb96985 Translated using Weblate (Turkish)
Currently translated at 100.0% (11312 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/tr/
2026-03-09 19:07:42 +01:00
Mahsum Aslan 97aab1b018 Translated using Weblate (Turkish)
Currently translated at 100.0% (11312 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/tr/
2026-03-09 19:07:42 +01:00
Marine Biologist 965fbaaf7d Translated using Weblate (Turkish)
Currently translated at 100.0% (11312 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/tr/
2026-03-09 19:07:42 +01:00
temizinsan ab4fa7fdbb Translated using Weblate (Turkish)
Currently translated at 100.0% (11312 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/tr/
2026-03-09 19:07:42 +01:00
Deleted User 84c265ab2d Translated using Weblate (Turkish)
Currently translated at 100.0% (11312 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/tr/
2026-03-09 19:07:42 +01:00
Mert Gülsoy d0e98c0ed4 Translated using Weblate (Turkish)
Currently translated at 100.0% (11312 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/tr/
2026-03-09 19:07:42 +01:00
dogukansahil 8989d49d0e Translated using Weblate (Turkish)
Currently translated at 100.0% (11312 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/tr/
2026-03-09 19:07:42 +01:00
NAXSISFLYBY e5d956b078 Translated using Weblate (Turkish)
Currently translated at 100.0% (11312 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/tr/
2026-03-09 19:07:42 +01:00
Erkan 71d217792f Translated using Weblate (Turkish)
Currently translated at 100.0% (11312 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/tr/
2026-03-09 19:07:42 +01:00
metin kiruc 28e804e18a Translated using Weblate (Turkish)
Currently translated at 100.0% (11312 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/tr/
2026-03-09 19:07:42 +01:00
Tevfik Bagcivan 4ac3f7a29b Translated using Weblate (Turkish)
Currently translated at 100.0% (11312 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/tr/
2026-03-09 19:07:41 +01:00
prometheus 761f94f669 Translated using Weblate (Turkish)
Currently translated at 100.0% (11312 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/tr/
2026-03-09 19:07:41 +01:00
Mert Kalkancı 3ac103523a Translated using Weblate (Turkish)
Currently translated at 100.0% (11312 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/tr/
2026-03-09 19:07:41 +01:00
Murat Ursavaş bd66e77dfd Translated using Weblate (Turkish)
Currently translated at 100.0% (11312 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/tr/
2026-03-09 19:07:41 +01:00
Argeolog 20da216b17 Translated using Weblate (Turkish)
Currently translated at 100.0% (11312 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/tr/
2026-03-09 19:07:41 +01:00
Niyazi 49f9f877a3 Translated using Weblate (Turkish)
Currently translated at 100.0% (11312 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/tr/
2026-03-09 19:07:41 +01:00
Gökhan Koçmarlı 96c1c2206b Translated using Weblate (Turkish)
Currently translated at 100.0% (11312 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/tr/
2026-03-09 19:07:41 +01:00
Bahtiyar Bayram f1ba0c934a Translated using Weblate (Turkish)
Currently translated at 100.0% (11312 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/tr/
2026-03-09 19:07:41 +01:00
Ahmet Saygın ÖĞÜLMÜŞ 36575870f5 Translated using Weblate (Turkish)
Currently translated at 100.0% (11312 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/tr/
2026-03-09 19:07:41 +01:00
Oğuz Ersen 500fbd862f Translated using Weblate (Turkish)
Currently translated at 100.0% (11312 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/tr/
2026-03-09 19:07:41 +01:00
VEDAT YAMAN 373f2ee12e Translated using Weblate (Turkish)
Currently translated at 100.0% (11312 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/tr/
2026-03-09 19:07:41 +01:00
Anonymous 88d622d615 Translated using Weblate (Turkish)
Currently translated at 100.0% (11312 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/tr/
2026-03-09 19:07:41 +01:00
YÜKSEL AÇIKGÖZ 496bec8827 Translated using Weblate (Turkish)
Currently translated at 100.0% (11312 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/tr/
2026-03-09 19:07:41 +01:00
Mustafa Selçuk ÇAVDAR a77c6bdc8f Translated using Weblate (Turkish)
Currently translated at 100.0% (11312 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/tr/
2026-03-09 19:07:40 +01:00
Seth Hillbrand a5fe48d27a Translated using Weblate (Turkish)
Currently translated at 100.0% (11312 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/tr/
2026-03-09 19:07:40 +01:00
İclal Gör 581b193231 Translated using Weblate (Turkish)
Currently translated at 100.0% (11312 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/tr/
2026-03-09 19:07:40 +01:00
turkce 4400c886e6 Translated using Weblate (Turkish)
Currently translated at 100.0% (11312 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/tr/
2026-03-09 19:07:40 +01:00
ℂ𝕠𝕠𝕠𝕝 (𝕘𝕚𝕥𝕙𝕦𝕓.𝕔𝕠𝕞/ℂ𝕠𝕠𝕠𝕝) f4ff697852 Translated using Weblate (Latvian)
Currently translated at 0.6% (71 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/lv/
2026-03-09 19:07:40 +01:00
Henrik Kauhanen 8e0a755123 Translated using Weblate (Latvian)
Currently translated at 0.6% (71 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/lv/
2026-03-09 19:07:40 +01:00
Rihards Skuja c265f7df1e Translated using Weblate (Latvian)
Currently translated at 0.6% (71 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/lv/
2026-03-09 19:07:40 +01:00
Seth Hillbrand faf8cb5275 Translated using Weblate (Latvian)
Currently translated at 0.6% (71 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/lv/
2026-03-09 19:07:40 +01:00
Anonymous bcef42db26 Translated using Weblate (Latvian)
Currently translated at 0.6% (71 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/lv/
2026-03-09 19:07:40 +01:00
Seth Hillbrand 8f03c38465 Translated using Weblate (Georgian)
Currently translated at 36.3% (4112 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ka/
2026-03-09 19:07:40 +01:00
Temuri Doghonadze ab47380a52 Translated using Weblate (Georgian)
Currently translated at 36.3% (4112 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ka/
2026-03-09 19:07:40 +01:00
Anonymous b3e40f2ff9 Translated using Weblate (Georgian)
Currently translated at 36.3% (4112 of 11312 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ka/
2026-03-09 19:07:39 +01:00
Bernhard Kirchen f4e0bd846f variants: fix boolean value for in_bom in serialzed schematic file 2026-03-09 11:58:41 -04:00
Damjan Prerad 2da7acffb2 DRC: Skip off-center violation when another track on the same layer reaches VIA center
A track bending inside a VIA pad before connecting to the center via
another segment is not a real violation. Check per-layer whether any
connected track reaches the VIA center before flagging.
2026-03-09 13:11:33 +01:00
Ian McInerney 783480d2a6 Always force toolbars to be visible when restoring settings
There seem to be some cases where the AUI perspectives are getting saved
with false visibility. This means they aren't getting shown when
settings are restored. We don't support hiding toolbars, so just always
force them to be shown because otherwise there is no other way to get
them back.
2026-03-08 23:22:32 +00:00
Damjan Prerad 0baff2c0b2 DRC: Default track-not-centered-on-via to warning, fix tests 2026-03-08 18:20:00 +01:00
Jeff Young 81e6cfda17 Use correct instance path when climbing up the sheet hierarchy.
Fixes https://gitlab.com/kicad/code/kicad/-/issues/23360
2026-03-08 16:49:24 +00:00
Damjan Prerad 33f4982c84 Add DRC check for track endpoints not centered on via
When a track endpoint lies within a via pad but is not at the exact
via center, the PNS router fails to connect through the via.
As a result length tuning tool to reports shorter
paths than Net Inspector.
2026-03-08 17:26:01 +01:00
John Beard a4021c9816 Pcbnew: don't crash if rotation anchor drop down is uninitialised
This seems to be able to happen when the dialog persistence store
is missing.

Not entirely sure WHY it's uninitialised in that case, since the wxFB
project sets it to 0, but since GetSelection can return -1, we should be
probably ready for it to do so anyway.

Fixes: https://gitlab.com/kicad/code/kicad/-/issues/21811
Fixes: https://gitlab.com/kicad/code/kicad/-/issues/23361
2026-03-08 23:54:26 +08:00
John Beard d5e129a3a0 Pcbnew/Allegro: Break out zone merge function.
This is a tricky function that really needs a test around it.

Also it has several assumptions and traps:

 - It will not work if the zones have multiple polygons in the poly sets
 - It will not work if any polygon has line chains in a different order
 - It is quadratic in number of zones and the compare itself is
   superlinear (Simplify is called, evilly in a const function, which is
   quadratic) and in a cyclic comparison, sort, which is presumably nlog-n
   ish.

However, at least for the quadratic nature, profiling shows this to be
absolutely insignificant even for the VCU118 board.
2026-03-08 22:17:43 +08:00
Jon Evans 6098e745be Fix crash in AutoDecodeCSV when nothing is found in the input 2026-03-08 10:10:11 -04:00
Jon Evans e761038f16 Remove parallel-path schematic CLI settings manager
This is not necessary, and since 10.0 causes invalid ERC
for several reasons:

1) Library loading now relies on grabbing the project path
   via Pgm().GetSettingsManager()

2) Bus alias definitions now live in the project file, also
   loaded through Pgm()

Also fix an issue where the LoadSchematic helper would wipe
out the bus aliases because `SCHEMATIC::Reset` could never
be called after the initial creation, but was via
`CreateDefaultScreens`.

Fixes https://gitlab.com/kicad/code/kicad/-/issues/23326
2026-03-08 10:10:11 -04:00
Jeff Young 92bb000ce6 Implement variant processing for text var resolution.
Fixes https://gitlab.com/kicad/code/kicad/-/issues/23355
2026-03-08 12:26:28 +00:00
Jeff Young 3f7b8baff5 Reduce line-breaking. 2026-03-08 12:09:21 +00:00
Jeff Young 0f343a0abc Repair loss of earlier commit likely caused by auto-formatter.
Also fixes missing instance/variant logic when fetching
ExcludeFromSim, ExcludeFromBOM and ExcludeFromBoard.

Fixes https://gitlab.com/kicad/code/kicad/-/issues/22319
2026-03-08 12:09:21 +00:00
Damjan Prerad 20d28da85f DRC Rule Editor: Use TokenName() instead of hardcoded strings
Replace hardcoded constraint code strings with DRC_RULES_LEXER::TokenName()
calls in GetConstraintCodeFromType().
2026-03-08 09:59:52 +01:00
Jon Evans c62b9aad23 API: Avoid redundant serialization of polyline arcs
Fixes https://gitlab.com/kicad/code/kicad-python/-/issues/79

(cherry picked from commit 0aeb33f94f)
2026-03-08 00:22:23 -05:00
JamesJCode 3538e456d7 DRC rule editor: Improve inner / outer plausibility checks
Fixes #23290
2026-03-07 20:47:36 +00:00
Jeff Young 4da7c180c2 Apply KiCad look & feel to DRC Rules Editor. 2026-03-07 19:28:46 +00:00
Jeff Young b19f3d6bab Formatting. 2026-03-07 19:28:46 +00:00
John Beard f8c62b3b36 QA: Standardise on the modern Boost test printer style
boost_test_print_type was introduced in 1.64 and we can tidy
up/standardise the old style printers in boost::test_tools::tt_detail
and "normal" stream operators which risk conflicts if one appears in
a header in future.
2026-03-08 01:45:27 +08:00
John Beard c8b2bef4f5 Pcbnew: preserve courtyard cache on Flip and Rotate
This isn't a major hotspot, but Flip does show up a little on
a profile of board loading, so it not nothing, and it's quite
easy to maintain the existing geometry here.

Also maintains the hull on rotation.

And add some tests around the courtyard and hull class invariants.
2026-03-08 00:53:34 +08:00
JamesJCode 69f218f8ff Auto-increment directive label fields on repeat item action
Fixes #23331
2026-03-06 21:47:15 +00:00
Ian McKernan 8acdf8d3ea Fix incorrect SVG export offset for symbols reference and value fields 2026-03-06 15:48:08 -05:00
Seth Hillbrand 30f4e962e7 Update translations 2026-03-06 12:40:10 -08:00
YÜKSEL AÇIKGÖZ db897a1ee7 Translated using Weblate (Turkish)
Currently translated at 100.0% (11308 of 11308 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/tr/
2026-03-06 21:35:31 +01:00
EdizonTN e0576fcfc1 Translated using Weblate (Slovak)
Currently translated at 63.3% (7167 of 11308 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/sk/
2026-03-06 21:35:31 +01:00
Seth Hillbrand 377ce1cab3 Translated using Weblate (Portuguese)
Currently translated at 100.0% (11308 of 11308 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/pt/
2026-03-06 21:35:31 +01:00
Seth Hillbrand 89d3b93323 Translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (11308 of 11308 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/pt_BR/
2026-03-06 21:35:31 +01:00
EdizonTN 8094a18abe Translated using Weblate (Slovak)
Currently translated at 63.3% (7166 of 11308 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/sk/
2026-03-06 21:35:31 +01:00
Seth Hillbrand 01b2e449bb Translated using Weblate (Hebrew)
Currently translated at 99.9% (11307 of 11308 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/he/
2026-03-06 21:35:31 +01:00
YÜKSEL AÇIKGÖZ 744b6420ac Translated using Weblate (Turkish)
Currently translated at 100.0% (11308 of 11308 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/tr/
2026-03-06 21:35:30 +01:00
Seth Hillbrand 42083ee21c Translated using Weblate (Spanish (Mexico))
Currently translated at 100.0% (11308 of 11308 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/es_MX/
2026-03-06 21:35:30 +01:00
Seth Hillbrand fd756ffbb9 Translated using Weblate (Korean)
Currently translated at 100.0% (11308 of 11308 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ko/
2026-03-06 21:35:30 +01:00
2tama3 69ee0e2fef Translated using Weblate (Japanese)
Currently translated at 100.0% (11308 of 11308 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ja/
2026-03-06 21:35:30 +01:00
Pferd O. 7bee0705a9 Translated using Weblate (German)
Currently translated at 100.0% (11308 of 11308 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/de/
2026-03-06 21:35:30 +01:00
Ettore Atalan d10a804613 Translated using Weblate (German)
Currently translated at 100.0% (11308 of 11308 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/de/
2026-03-06 21:35:30 +01:00
Seth Hillbrand 0736d3571c Translated using Weblate (Spanish)
Currently translated at 100.0% (11308 of 11308 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/es/
2026-03-06 21:35:30 +01:00
Seth Hillbrand 2dbaa8d025 Initialize variant attributes from symbol/sheet defaults during parse
The S-expression serializer only writes variant attributes that differ
from the symbol/sheet default values.  When deserializing, the parser
created variants with all-false attribute defaults from the VARIANT
constructor.  This meant any variant attribute matching the owner's
default was silently lost on save/reload.

Call InitializeAttributes() on each variant immediately after
construction in the parser so that unparsed attributes inherit the
correct default values from the owning symbol or sheet.

Fixes https://gitlab.com/kicad/code/kicad/-/issues/23347
2026-03-06 12:31:34 -08:00
Seth Hillbrand dd22dbbc43 Allow negative silk screen clearance values to be saved
The PARAM_SCALED lower bound for min_silk_clearance was 0.0mm, which
caused negative values to be reset to the default on project reload.
Users set negative silk clearance to suppress DRC violations for
footprints that intentionally overlap their silkscreen.

Changed the lower bound from 0.0mm to -10.0mm so negative values
survive the JSON round-trip through the project file.

Fixes https://gitlab.com/kicad/code/kicad/-/issues/23327
2026-03-06 12:05:57 -08:00
Seth Hillbrand ad591d0a5a Fix DNP cross-out size for rotated footprints
The cross-out was drawn using the axis-aligned bounding box of the
effective shape. Fix by computing an oriented bounding box

Fixes https://gitlab.com/kicad/code/kicad/-/issues/23351
2026-03-06 12:02:40 -08:00
Seth Hillbrand e541232848 ERC: flag local labels with no local component pin connections
A local label that only connects to other labels or hierarchical sheet
pins without any component pin on the same sheet serves no local purpose
and is likely mislabeled. Extend the existing bus-member check to all
local labels so that ercCheckLabels() flags these cases as
ERCE_LABEL_NOT_CONNECTED.

The allPins > 1 guard prevents double-reporting with
ERCE_LABEL_SINGLE_PIN which already covers the allPins == 1 case.

Fixes https://gitlab.com/kicad/code/kicad/-/issues/23346
2026-03-06 11:53:09 -08:00
Seth Hillbrand b79862e7b8 Reset git cancel flag when opening new project
EmptyTreePrj() sets the KIGIT_COMMON cancel flag to true during
project close to stop in-flight git operations. However, when
ReCreateTreePrj() opens a new git repository for the next project,
the cancel flag was never reset to false. Since the KIGIT_COMMON
object persists across project switches (owned by PROJECT_TREE),
all git operations (status icons, sync, fetch) were permanently
disabled after the first project close.

Fixes https://gitlab.com/kicad/code/kicad/-/issues/23344
2026-03-06 11:44:56 -08:00
Seth Hillbrand 17d53bd77f Cycle through options on single-click for toggle flyout groups
When clicking flyout buttons for non-tool groups (crosshair style,
units, line modes), advance to the next option in the group instead
of re-dispatching the already-active action. Tool-type flyout groups
retain existing behavior of selecting the displayed tool.

Fixes https://gitlab.com/kicad/code/kicad/-/issues/23349
2026-03-06 11:28:28 -08:00
Seth Hillbrand fb1cab3e07 Fix "Save Library As" writing empty symbol library files
cacheLib() was unconditionally calling Load() for new caches even when
buffering was enabled, introduced by e013691d02 to fix issue #22191.
This broke "Save Library As" because the target file doesn't exist yet,
causing Load() to throw IO_ERROR. The exception was caught but no
symbols were added to the cache, resulting in an empty file

Additionally, the unbuffered library save path was passing the library
nickname instead of the target file path to the plugin's LoadSymbol/
SaveSymbol calls. While this was always wrong, it was masked before
e013691d02 because buffering mode skipped Load() entirely.

Fix cacheLib() to only call Load() for new caches when the library file
actually exists on disk, and fix the unbuffered save path to use the
target file path.

Fixes https://gitlab.com/kicad/code/kicad/-/issues/23337
2026-03-06 11:26:39 -08:00
Seth Hillbrand 31d1c09f24 PADS importer: fix pad shapes, zones, netclasses
PADSTACK in NORMAL mode stores one shape for all layers. When front
and back copper have different shapes, the second convertPadShape()
call overwrites the first. Pre-scanning copper layers and switching
to FRONT_INNER_BACK mode when shapes differ fixes this.

PADS stores connection style per-pin, not per-zone. The zone default
was THERMAL; it is now FULL (solid). Per-pad THERMAL overrides are
set from RT/ST thermal relief entries in the pad stack, carrying
over spoke width and angle.

The parser read NET_CLASS names and memberships but skipped per-class
RULE_SET entries for clearance and track width. RULE_SET parsing now
handles non-default rule sets and matches them to netclasses via the
FOR/NET_CLASS declaration.

Fixes https://gitlab.com/kicad/code/kicad/-/issues/23352
2026-03-06 11:25:54 -08:00
Seth Hillbrand 1cf4284930 IPC-2581: use schematic revision for BOM
The BOM revision in IPC-2581 export was hardcoded to "1.0"
instead of reflecting the actual design revision.

The project file stores two separate fields: bomRev for
explicit user overrides set in the PCBnew export dialog or
via --bom-rev on the CLI, and schRevision for the value
auto-propagated from eeschema.
2026-03-06 09:13:56 -08:00
Damjan Prerad 4c536dcf2b DRC Rule Editor: Update constraint diagrams
Update SVG sources and rendered PNGs for routing width,
silk-to-silk clearance, and silk-to-soldermask clearance
diagrams in the DRC Rule Editor.
2026-03-06 15:59:40 +01:00
Damjan Prerad a097c67466 DRC Rule Editor: allow independent constraints in matched length and diff pair panels
Make length and skew constraints independently optional in the matched
length diff pair panel.
Allow standalone uncoupled length in the routing diff pair panel.
2026-03-06 10:53:18 +01:00
Seth Hillbrand 45b5765af0 IPC-2581: infer pinOneOrientation from pin 1 position
Instead of always emitting "OTHER", compute the pin 1 orientation
relative to the package bounding box center. Look for pad "1" or
"A1" and map to UPPER_LEFT/UPPER_RIGHT/LOWER_LEFT/LOWER_RIGHT
based on quadrant. Fall back to OTHER with a comment attribute
when pin 1 cannot be found (per IPC-2581C 8.2.3.6).
2026-03-05 19:49:21 -08:00
Seth Hillbrand ecd9338158 IPC-2581: remove spurious Xform from footprint-owned graphic features
Footprint graphic features were emitted with both absolute board-space
coordinates and a footprint rotation Xform, mixing coordinate frames.
Consumers applying the Xform would double-rotate the geometry. Remove
the Xform since the absolute coordinates are self-contained.
2026-03-05 19:49:21 -08:00
Seth Hillbrand 3d6886ef12 IPC-2581: add Content/BomRef and Content/AvlRef elements
The Bom and Avl top-level sections were emitted without corresponding
BomRef/AvlRef elements in the Content section, which IPC-2581C 4.1.1.2
requires as cross-references. Insert them in schema order after
LayerRef and before Dictionary elements.
2026-03-05 19:49:21 -08:00
Seth Hillbrand d2f603f54d IPC-2581: merge multi-outline geometry instead of collapsing to bbox
When a shape had multiple outlines, the exporter replaced them with a
bounding box rectangle, corrupting the actual geometry. Use Simplify()
to merge overlapping outlines into a single valid contour.
2026-03-05 19:49:21 -08:00
Seth Hillbrand 5704ec821d IPC-2581: emit board profile cutouts
The Profile element only exported the outer board contour, ignoring
internal cutouts/voids. Emit cutout polygons from the board outline
polygon after the main contour.
2026-03-05 19:49:21 -08:00
Seth Hillbrand 03f2b6ee5a IPC-2581: fix OtherSideView element ordering and missing Package Outline
OtherSideView was appended to Package during courtyard processing,
before Pin elements, violating the IPC-2581C schema sequence. Build
it off-tree and attach after all Pin elements.

Also fix packages without a primary courtyard missing the required
Outline element by always emitting a bounding hull fallback when the
primary courtyard is empty.
2026-03-05 19:49:21 -08:00
Seth Hillbrand 724200a6fd IPC-2581: normalize slot cavity rotation to 0..360 range
Slot cavity rotation used raw GetOrientation() without normalization,
which could emit negative rotation values in the XML. Align with pad
and component code paths that normalize to 0..360.
2026-03-05 19:49:21 -08:00
Seth Hillbrand 612c882a7a IPC-2581: fix auxiliary via-finish layer element names and side enums
Use schema-valid PascalCase element names (Layer, Span) instead of
all-caps (LAYER, SPAN). Use IPC-2581C sideType enum values (TOP,
BOTTOM) instead of non-existent FRONT/BACK.
2026-03-05 19:49:21 -08:00
Seth Hillbrand 7e4c55bd6f IPC-2581: synthesize stable refdes for footprints with empty references
Footprints with blank references produced schema-invalid XML with empty
refDes, RefDes/@name, and PinRef/@componentRef attributes. Generate a
stable UUID-based identifier when GetReference() is empty.
2026-03-05 19:49:21 -08:00
Seth Hillbrand b91019973e Altium PCB: fix full-stack via padstack import on F.Cu.
Iterate only over the board's enabled copper layers instead of all 32
possible layers. Non-present inner layers were mapped back to F.Cu by
EffectiveLayerFor(), overwriting the front copper size.

Fixes https://gitlab.com/kicad/code/kicad/-/issues/23328
2026-03-05 18:56:23 -08:00
Seth Hillbrand ee346e1cf3 Fix rule editor handling of layer-scoped DRC rules
The text-based rule editor incorrectly warned about "duplicate conditions"
when two rules shared the same condition expression but had different layer
scopes (e.g., "(layer outer)" vs "(layer inner)"). Include the layer source
in the deduplication key so layer-differentiated rules are not flagged.

The graphical rule editor's save path had three related issues:
generateLayerClause() emitted multi-token "(layer "F.Cu" "B.Cu")" format
that the parser cannot handle (it expects a single token). Now detects
ExternalCuMask/InternalCuMask and emits "(layer outer)"/"(layer inner)".
The merge grouping key only used (ruleName, condition), causing rules with
different layer scopes to be incorrectly merged. Now includes layerSource.
The same-name validation in the graphical editor also excluded layer scope.

Add regression test verifying EvalRules returns correct per-layer clearances
for layer-scoped custom rules and zone fill produces no DRC violations.
2026-03-05 16:20:50 -08:00
Seth Hillbrand 4a3899d30d Add PCM v2 schema and content negotiation
Load both v1 and v2 JSON schemas at startup and select the
validator based on the repository's schema_version field. Send
an Accept header with the v2 vendor media type so the server
can respond with the appropriate schema version.

Defuse the v1 schema by removing forward-looking type enum
values and opening the category field to free strings. Add a
v2 schema that uses pattern-validated open strings for type,
category, and license.

Skip packages with unrecognized types in the dialog rather
than displaying broken entries.
2026-03-05 15:08:20 -08:00
508 changed files with 461802 additions and 307819 deletions
+7
View File
@@ -63,6 +63,13 @@ demos/**/fp-info-cache
demos/**/~*.lck
demos/**/.history
# QA data aux files
qa/data**/*-bak
qa/data/**/_autosave-*
qa/data/**/fp-info-cache
qa/data/**/~*.lck
qa/data/**/.history
# MacOS package info created by CMake
bitmap2component/Info.plist
cvpcb/Info.plist
+113 -114
View File
@@ -56,8 +56,51 @@
#include <3d_navlib/nl_footprint_properties_plugin.h>
#endif
PANEL_PREVIEW_3D_MODEL::PANEL_PREVIEW_3D_MODEL( wxWindow* aParent, PCB_BASE_FRAME* aFrame,
FOOTPRINT* aFootprint,
static wxString evaluateTextCtrl( const wxString& aValue )
{
// NUMERIC_EVALUATOR doesn't handle UTF-8 multi-byte characters properly,
// so skip evaluation if the string contains non-ASCII characters (e.g., degree symbols)
for( wxUniChar c : aValue )
{
if( !c.IsAscii() )
return aValue;
}
// Attempt to evaluate formula; if successful return result, otherwise return original
NUMERIC_EVALUATOR eval( EDA_UNITS::UNSCALED );
if( eval.Process( aValue ) )
return eval.Result();
return aValue;
}
/**
* Ensure -MAX_ROTATION <= rotation <= MAX_ROTATION.
*
* @param \a aRotation will be normalized between -MAX_ROTATION and MAX_ROTATION.
*/
static double rotationFromString( const wxString& aValue )
{
double rotation = EDA_UNIT_UTILS::UI::DoubleValueFromString( unityScale, EDA_UNITS::DEGREES, aValue );
if( rotation > MAX_ROTATION )
{
int n = KiROUND( rotation / MAX_ROTATION );
rotation -= MAX_ROTATION * n;
}
else if( rotation < -MAX_ROTATION )
{
int n = KiROUND( -rotation / MAX_ROTATION );
rotation += MAX_ROTATION * n;
}
return rotation;
}
PANEL_PREVIEW_3D_MODEL::PANEL_PREVIEW_3D_MODEL( wxWindow* aParent, PCB_BASE_FRAME* aFrame, FOOTPRINT* aFootprint,
std::vector<FP_3DMODEL>* aParentModelList ) :
PANEL_PREVIEW_3D_MODEL_BASE( aParent, PANEL_PREVIEW_3D_MODEL_ID ),
m_parentFrame( aFrame ),
@@ -116,6 +159,27 @@ PANEL_PREVIEW_3D_MODEL::PANEL_PREVIEW_3D_MODEL( wxWindow* aParent, PCB_BASE_FRAM
for( wxSpinButton* button : spinButtonList )
button->SetRange(INT_MIN, INT_MAX );
for( TEXT_CTRL_EVAL* rotCtrl : { xrot, yrot, zrot } )
{
rotCtrl->SetCustomEval(
[&]( TEXT_CTRL_EVAL* aCtrl )
{
double value = rotationFromString( evaluateTextCtrl( aCtrl->GetValue() ) );
aCtrl->SetValue( formatRotationValue( value ) );
} );
}
for( TEXT_CTRL_EVAL* scaleCtrl : { xscale, yscale, zscale } )
{
scaleCtrl->SetCustomEval(
[&]( TEXT_CTRL_EVAL* aCtrl )
{
double value = EDA_UNIT_UTILS::UI::DoubleValueFromString( unityScale, EDA_UNITS::UNSCALED,
evaluateTextCtrl( aCtrl->GetValue() ) );
aCtrl->SetValue( formatScaleValue( value ) );
} );
}
m_parentModelList = aParentModelList;
m_dummyFootprint = new FOOTPRINT( *aFootprint );
@@ -128,12 +192,10 @@ PANEL_PREVIEW_3D_MODEL::PANEL_PREVIEW_3D_MODEL( wxWindow* aParent, PCB_BASE_FRAM
m_dummyFootprint->SetOrientation( ANGLE_0 );
m_dummyBoard->Add( m_dummyFootprint );
// Create the 3D canvas
m_previewPane = new EDA_3D_CANVAS( this,
OGL_ATT_LIST::GetAttributesList( ANTIALIASING_MODE::AA_8X ),
m_previewPane = new EDA_3D_CANVAS( this, OGL_ATT_LIST::GetAttributesList( ANTIALIASING_MODE::AA_8X ),
m_boardAdapter, m_currentCamera,
PROJECT_PCB::Get3DCacheManager( &aFrame->Prj() ) );
@@ -181,13 +243,9 @@ PANEL_PREVIEW_3D_MODEL::PANEL_PREVIEW_3D_MODEL( wxWindow* aParent, PCB_BASE_FRAM
m_SizerPanelView->Add( m_previewPane, 1, wxEXPAND, 5 );
for( wxEventType eventType : { wxEVT_MENU_OPEN, wxEVT_MENU_CLOSE, wxEVT_MENU_HIGHLIGHT } )
{
Connect( eventType, wxMenuEventHandler( PANEL_PREVIEW_3D_MODEL::OnMenuEvent ), nullptr,
this );
}
Connect( eventType, wxMenuEventHandler( PANEL_PREVIEW_3D_MODEL::OnMenuEvent ), nullptr, this );
aFrame->Connect( EDA_EVT_UNITS_CHANGED,
wxCommandEventHandler( PANEL_PREVIEW_3D_MODEL::onUnitsChanged ),
aFrame->Connect( EDA_EVT_UNITS_CHANGED, wxCommandEventHandler( PANEL_PREVIEW_3D_MODEL::onUnitsChanged ),
nullptr, this );
Bind( wxCUSTOM_PANEL_SHOWN_EVENT, &PANEL_PREVIEW_3D_MODEL::onPanelShownEvent, this );
@@ -241,31 +299,6 @@ void PANEL_PREVIEW_3D_MODEL::loadSettings()
}
/**
* Ensure -MAX_ROTATION <= rotation <= MAX_ROTATION.
*
* @param \a aRotation will be normalized between -MAX_ROTATION and MAX_ROTATION.
*/
static double rotationFromString( const wxString& aValue )
{
double rotation = EDA_UNIT_UTILS::UI::DoubleValueFromString( unityScale, EDA_UNITS::DEGREES,
aValue );
if( rotation > MAX_ROTATION )
{
int n = KiROUND( rotation / MAX_ROTATION );
rotation -= MAX_ROTATION * n;
}
else if( rotation < -MAX_ROTATION )
{
int n = KiROUND( -rotation / MAX_ROTATION );
rotation += MAX_ROTATION * n;
}
return rotation;
}
wxString PANEL_PREVIEW_3D_MODEL::formatScaleValue( double aValue )
{
return wxString::Format( wxT( "%.4f" ),
@@ -345,26 +378,6 @@ void PANEL_PREVIEW_3D_MODEL::SetSelectedModel( int idx )
}
static wxString evaluateTextCtrlFormula( const wxString& aValue )
{
// NUMERIC_EVALUATOR doesn't handle UTF-8 multi-byte characters properly,
// so skip evaluation if the string contains non-ASCII characters (e.g., degree symbols)
for( wxUniChar c : aValue )
{
if( !c.IsAscii() )
return aValue;
}
// Attempt to evaluate formula; if successful return result, otherwise return original
NUMERIC_EVALUATOR eval( EDA_UNITS::UNSCALED );
if( eval.Process( aValue ) )
return eval.Result();
return aValue;
}
void PANEL_PREVIEW_3D_MODEL::updateOrientation( wxCommandEvent &event )
{
if( m_parentModelList && m_selected >= 0 && m_selected < (int) m_parentModelList->size() )
@@ -372,27 +385,27 @@ void PANEL_PREVIEW_3D_MODEL::updateOrientation( wxCommandEvent &event )
// Write settings back to the parent
FP_3DMODEL* modelInfo = &m_parentModelList->at( (unsigned) m_selected );
modelInfo->m_Scale.x = EDA_UNIT_UTILS::UI::DoubleValueFromString(
pcbIUScale, EDA_UNITS::UNSCALED, evaluateTextCtrlFormula( xscale->GetValue() ) );
modelInfo->m_Scale.y = EDA_UNIT_UTILS::UI::DoubleValueFromString(
pcbIUScale, EDA_UNITS::UNSCALED, evaluateTextCtrlFormula( yscale->GetValue() ) );
modelInfo->m_Scale.z = EDA_UNIT_UTILS::UI::DoubleValueFromString(
pcbIUScale, EDA_UNITS::UNSCALED, evaluateTextCtrlFormula( zscale->GetValue() ) );
modelInfo->m_Scale.x = EDA_UNIT_UTILS::UI::DoubleValueFromString( unityScale, EDA_UNITS::UNSCALED,
evaluateTextCtrl( xscale->GetValue() ) );
modelInfo->m_Scale.y = EDA_UNIT_UTILS::UI::DoubleValueFromString( unityScale, EDA_UNITS::UNSCALED,
evaluateTextCtrl( yscale->GetValue() ) );
modelInfo->m_Scale.z = EDA_UNIT_UTILS::UI::DoubleValueFromString( unityScale, EDA_UNITS::UNSCALED,
evaluateTextCtrl( zscale->GetValue() ) );
// Rotation is stored in the file as positive-is-CW, but we use positive-is-CCW in the GUI
// to match the rest of KiCad
modelInfo->m_Rotation.x = -rotationFromString( evaluateTextCtrlFormula( xrot->GetValue() ) );
modelInfo->m_Rotation.y = -rotationFromString( evaluateTextCtrlFormula( yrot->GetValue() ) );
modelInfo->m_Rotation.z = -rotationFromString( evaluateTextCtrlFormula( zrot->GetValue() ) );
modelInfo->m_Rotation.x = -rotationFromString( evaluateTextCtrl( xrot->GetValue() ) );
modelInfo->m_Rotation.y = -rotationFromString( evaluateTextCtrl( yrot->GetValue() ) );
modelInfo->m_Rotation.z = -rotationFromString( evaluateTextCtrl( zrot->GetValue() ) );
modelInfo->m_Offset.x = EDA_UNIT_UTILS::UI::DoubleValueFromString( pcbIUScale, m_userUnits,
evaluateTextCtrlFormula( xoff->GetValue() ) )
evaluateTextCtrl( xoff->GetValue() ) )
/ pcbIUScale.IU_PER_MM;
modelInfo->m_Offset.y = EDA_UNIT_UTILS::UI::DoubleValueFromString( pcbIUScale, m_userUnits,
evaluateTextCtrlFormula( yoff->GetValue() ) )
evaluateTextCtrl( yoff->GetValue() ) )
/ pcbIUScale.IU_PER_MM;
modelInfo->m_Offset.z = EDA_UNIT_UTILS::UI::DoubleValueFromString( pcbIUScale, m_userUnits,
evaluateTextCtrlFormula( zoff->GetValue() ) )
evaluateTextCtrl( zoff->GetValue() ) )
/ pcbIUScale.IU_PER_MM;
// Update the dummy footprint for the preview
@@ -439,8 +452,7 @@ void PANEL_PREVIEW_3D_MODEL::View3DSettings( wxCommandEvent& event )
BOARD_DESIGN_SETTINGS bds = m_dummyBoard->GetDesignSettings();
int thickness = bds.GetBoardThickness();
WX_UNIT_ENTRY_DIALOG dlg( m_parentFrame, _( "3D Preview Options" ), _( "Board thickness:" ),
thickness );
WX_UNIT_ENTRY_DIALOG dlg( m_parentFrame, _( "3D Preview Options" ), _( "Board thickness:" ), thickness );
if( dlg.ShowModal() != wxID_OK )
return;
@@ -476,14 +488,13 @@ void PANEL_PREVIEW_3D_MODEL::doIncrementScale( wxSpinEvent& event, double aSign
if( wxGetMouseState().ShiftDown( ) )
step = SCALE_INCREMENT_FINE;
double curr_value = EDA_UNIT_UTILS::UI::DoubleValueFromString( pcbIUScale, EDA_UNITS::UNSCALED,
textCtrl->GetValue() );
double value = EDA_UNIT_UTILS::UI::DoubleValueFromString( unityScale, EDA_UNITS::UNSCALED, textCtrl->GetValue() );
curr_value += ( step * aSign );
curr_value = std::max( 1/MAX_SCALE, curr_value );
curr_value = std::min( curr_value, MAX_SCALE );
value += ( step * aSign );
value = std::max( 1/MAX_SCALE, value );
value = std::min( value, MAX_SCALE );
textCtrl->SetValue( formatScaleValue( curr_value ) );
textCtrl->SetValue( formatScaleValue( value ) );
}
@@ -505,14 +516,11 @@ void PANEL_PREVIEW_3D_MODEL::doIncrementRotation( wxSpinEvent& aEvent, double aS
if( wxGetMouseState().ShiftDown( ) )
step = ROTATION_INCREMENT_FINE;
double curr_value = EDA_UNIT_UTILS::UI::DoubleValueFromString( unityScale, EDA_UNITS::DEGREES,
textCtrl->GetValue() );
double value = rotationFromString( textCtrl->GetValue() );
curr_value += ( step * aSign );
curr_value = std::max( -MAX_ROTATION, curr_value );
curr_value = std::min( curr_value, MAX_ROTATION );
value += ( step * aSign );
textCtrl->SetValue( formatRotationValue( curr_value ) );
textCtrl->SetValue( formatRotationValue( value ) );
}
@@ -542,15 +550,14 @@ void PANEL_PREVIEW_3D_MODEL::doIncrementOffset( wxSpinEvent& event, double aSign
step_mm = 25.4*OFFSET_INCREMENT_MIL_FINE/1000;;
}
double curr_value_mm = EDA_UNIT_UTILS::UI::DoubleValueFromString( pcbIUScale, m_userUnits,
textCtrl->GetValue() )
/ pcbIUScale.IU_PER_MM;
double value_mm = EDA_UNIT_UTILS::UI::DoubleValueFromString( pcbIUScale, m_userUnits, textCtrl->GetValue() )
/ pcbIUScale.IU_PER_MM;
curr_value_mm += ( step_mm * aSign );
curr_value_mm = std::max( -MAX_OFFSET, curr_value_mm );
curr_value_mm = std::min( curr_value_mm, MAX_OFFSET );
value_mm += ( step_mm * aSign );
value_mm = std::max( -MAX_OFFSET, value_mm );
value_mm = std::min( value_mm, MAX_OFFSET );
textCtrl->SetValue( formatOffsetValue( curr_value_mm ) );
textCtrl->SetValue( formatOffsetValue( value_mm ) );
}
@@ -568,14 +575,13 @@ void PANEL_PREVIEW_3D_MODEL::onMouseWheelScale( wxMouseEvent& event )
if( event.GetWheelRotation() >= 0 )
step = -step;
double curr_value = EDA_UNIT_UTILS::UI::DoubleValueFromString( pcbIUScale, EDA_UNITS::UNSCALED,
textCtrl->GetValue() );
double value = EDA_UNIT_UTILS::UI::DoubleValueFromString( unityScale, EDA_UNITS::UNSCALED, textCtrl->GetValue() );
curr_value += step;
curr_value = std::max( 1/MAX_SCALE, curr_value );
curr_value = std::min( curr_value, MAX_SCALE );
value += step;
value = std::max( 1/MAX_SCALE, value );
value = std::min( value, MAX_SCALE );
textCtrl->SetValue( formatScaleValue( curr_value ) );
textCtrl->SetValue( formatScaleValue( value ) );
}
@@ -593,14 +599,11 @@ void PANEL_PREVIEW_3D_MODEL::onMouseWheelRot( wxMouseEvent& event )
if( event.GetWheelRotation() >= 0 )
step = -step;
double curr_value = EDA_UNIT_UTILS::UI::DoubleValueFromString( unityScale, EDA_UNITS::DEGREES,
textCtrl->GetValue() );
double value = rotationFromString( textCtrl->GetValue() );
curr_value += step;
curr_value = std::max( -MAX_ROTATION, curr_value );
curr_value = std::min( curr_value, MAX_ROTATION );
value += step;
textCtrl->SetValue( formatRotationValue( curr_value ) );
textCtrl->SetValue( formatRotationValue( value ) );
}
@@ -626,28 +629,24 @@ void PANEL_PREVIEW_3D_MODEL::onMouseWheelOffset( wxMouseEvent& event )
if( event.GetWheelRotation() >= 0 )
step_mm = -step_mm;
double curr_value_mm = EDA_UNIT_UTILS::UI::DoubleValueFromString( pcbIUScale, m_userUnits,
textCtrl->GetValue() )
/ pcbIUScale.IU_PER_MM;
double value_mm = EDA_UNIT_UTILS::UI::DoubleValueFromString( pcbIUScale, m_userUnits, textCtrl->GetValue() )
/ pcbIUScale.IU_PER_MM;
curr_value_mm += step_mm;
curr_value_mm = std::max( -MAX_OFFSET, curr_value_mm );
curr_value_mm = std::min( curr_value_mm, MAX_OFFSET );
value_mm += step_mm;
value_mm = std::max( -MAX_OFFSET, value_mm );
value_mm = std::min( value_mm, MAX_OFFSET );
textCtrl->SetValue( formatOffsetValue( curr_value_mm ) );
textCtrl->SetValue( formatOffsetValue( value_mm ) );
}
void PANEL_PREVIEW_3D_MODEL::onUnitsChanged( wxCommandEvent& aEvent )
{
double xoff_mm = EDA_UNIT_UTILS::UI::DoubleValueFromString( pcbIUScale, m_userUnits,
xoff->GetValue() )
double xoff_mm = EDA_UNIT_UTILS::UI::DoubleValueFromString( pcbIUScale, m_userUnits, xoff->GetValue() )
/ pcbIUScale.IU_PER_MM;
double yoff_mm = EDA_UNIT_UTILS::UI::DoubleValueFromString( pcbIUScale, m_userUnits,
yoff->GetValue() )
double yoff_mm = EDA_UNIT_UTILS::UI::DoubleValueFromString( pcbIUScale, m_userUnits, yoff->GetValue() )
/ pcbIUScale.IU_PER_MM;
double zoff_mm = EDA_UNIT_UTILS::UI::DoubleValueFromString( pcbIUScale, m_userUnits,
zoff->GetValue() )
double zoff_mm = EDA_UNIT_UTILS::UI::DoubleValueFromString( pcbIUScale, m_userUnits, zoff->GetValue() )
/ pcbIUScale.IU_PER_MM;
PCB_BASE_FRAME* frame = static_cast<PCB_BASE_FRAME*>( aEvent.GetClientData() );
@@ -163,6 +163,8 @@ private:
wxString formatRotationValue( double aValue );
wxString formatOffsetValue( double aValue );
void evalRotationValue( TEXT_CTRL_EVAL* aRotationControl );
void View3DISO( wxCommandEvent& event ) override
{
m_currentCamera.ToggleProjection();
+3 -1
View File
@@ -51,5 +51,7 @@ DOCSET_BUNDLE_ID = ${DOCSET_BUNDLE_ID}
DISABLE_INDEX = YES
GENERATE_TREEVIEW = NO
SEARCHENGINE = NO
GENERATE_TAGFILE = ${DOXY_TAG_FILE}"
GENERATE_TAGFILE = ${DOXY_TAG_FILE}
# Doxygen-awesome doesn't look great without the index
HTML_EXTRA_STYLESHEET = "
)
+1 -1
View File
@@ -37,7 +37,7 @@
# KiCad.
#
# Note: This version string should follow the semantic versioning system
set( KICAD_SEMANTIC_VERSION "10.0.0-rc2" )
set( KICAD_SEMANTIC_VERSION "10.99.0-unknown" )
# Default the version to the semantic version.
# This is overridden by the git repository tag though (if using git)
+37 -2
View File
@@ -59,6 +59,22 @@ add_custom_target(
-DBANNED_DIRS="${PROJECT_SOURCE_DIR}/common/io;${PROJECT_SOURCE_DIR}/pcbnew/pcb_io;${PROJECT_SOURCE_DIR}/eeschema/sch_io"
-P ${KICAD_CMAKE_MODULE_PATH}/CheckBannedFunctions.cmake
)
if( NOT (${CMAKE_CURRENT_SOURCE_DIR} STREQUAL ${CMAKE_CURRENT_BINARY_DIR} ) )
file( GLOB REMOTE_PROVIDER_SCHEMA_FILES
${CMAKE_SOURCE_DIR}/resources/schemas/kicad-remote-*.json
)
add_custom_target( remote_provider_schema_build_copy
COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_BINARY_DIR}/schemas
COMMAND ${CMAKE_COMMAND} -E copy_if_different
${REMOTE_PROVIDER_SCHEMA_FILES}
${CMAKE_BINARY_DIR}/schemas
DEPENDS ${REMOTE_PROVIDER_SCHEMA_FILES}
COMMENT "Copying remote provider schema files into build directory"
)
endif()
# A shared library used by multiple *.kiface files and one or two program
# launchers. Object files can migrate into here over time, but only if they are
# surely needed and certainly used from more than one place without recompilation.
@@ -182,6 +198,7 @@ set( KICOMMON_SRCS
dialogs/dialog_rc_job.cpp
dialogs/dialog_rc_job_base.cpp
dialogs/dialog_restore_local_history.cpp
dialogs/dialog_HTML_reporter_base.cpp
dialogs/panel_startwizard_libraries_base.cpp
dialogs/panel_startwizard_privacy_base.cpp
@@ -258,8 +275,17 @@ set( KICOMMON_SRCS
netclass.cpp
notifications_manager.cpp
page_info.cpp
oauth/oauth_loopback_server.cpp
oauth/oauth_pkce.cpp
oauth/oauth_session.cpp
oauth/secure_token_store.cpp
paths.cpp
project.cpp
remote_provider_client.cpp
remote_provider_metadata.cpp
remote_provider_models.cpp
remote_provider_settings.cpp
remote_provider_utils.cpp
reporter.cpp
richio.cpp
scintilla_tricks.cpp
@@ -430,6 +456,10 @@ target_include_directories( kicommon
add_dependencies( kicommon pegtl version_header )
if( TARGET remote_provider_schema_build_copy )
add_dependencies( kicommon remote_provider_schema_build_copy )
endif()
if( MSVC )
target_sources( kicommon PRIVATE ${CMAKE_SOURCE_DIR}/resources/msw/kicommon-dll.rc )
endif()
@@ -646,6 +676,7 @@ set( COMMON_IO_SRCS
io/altium/altium_binary_parser.cpp
io/altium/altium_ascii_parser.cpp
io/altium/altium_parser_utils.cpp
io/altium/altium_project_variants.cpp
io/altium/altium_props_utils.cpp
# Cadstar
@@ -738,7 +769,6 @@ set( COMMON_SRCS
refdes_utils.cpp
reference_image.cpp
render_settings.cpp
remote_login_server.cpp
status_popup.cpp
stroke_params.cpp
template_fieldnames.cpp
@@ -840,12 +870,16 @@ if( KICAD_USE_PCH )
<clipper2/clipper.h>
<eda_draw_frame.h>
<kiid.h>
<pgm_base.h>
<pgm_base.h>
<wx/wx.h>
)
endif()
add_dependencies( common version_header )
if( TARGET remote_provider_schema_build_copy )
add_dependencies( common remote_provider_schema_build_copy )
endif()
add_dependencies( common compoundfilereader ) # used by altium_parser.cpp
target_link_libraries( common
@@ -949,6 +983,7 @@ set( PCB_COMMON_SRCS
${CMAKE_SOURCE_DIR}/pcbnew/pcb_track.cpp
${CMAKE_SOURCE_DIR}/pcbnew/pcb_generator.cpp
${CMAKE_SOURCE_DIR}/pcbnew/zone.cpp
${CMAKE_SOURCE_DIR}/pcbnew/zone_utils.cpp
${CMAKE_SOURCE_DIR}/pcbnew/collectors.cpp
${CMAKE_SOURCE_DIR}/pcbnew/connectivity/connectivity_algo.cpp
${CMAKE_SOURCE_DIR}/pcbnew/connectivity/connectivity_items.cpp
+4 -4
View File
@@ -123,10 +123,9 @@ KICOMMON_API void PackPolyLine( types::PolyLine& aOutput, const SHAPE_LINE_CHAIN
if( vertex < 0 )
break;
types::PolyLineNode* node = aOutput.mutable_nodes()->Add();
if( aSlc.IsPtOnArc( vertex ) )
if( aSlc.IsArcStart( vertex ) )
{
types::PolyLineNode* node = aOutput.mutable_nodes()->Add();
const SHAPE_ARC& arc = aSlc.Arc( aSlc.ArcIndex( vertex ) );
node->mutable_arc()->mutable_start()->set_x_nm( arc.GetP0().x );
node->mutable_arc()->mutable_start()->set_y_nm( arc.GetP0().y );
@@ -135,8 +134,9 @@ KICOMMON_API void PackPolyLine( types::PolyLine& aOutput, const SHAPE_LINE_CHAIN
node->mutable_arc()->mutable_end()->set_x_nm( arc.GetP1().x );
node->mutable_arc()->mutable_end()->set_y_nm( arc.GetP1().y );
}
else
else if( !aSlc.IsPtOnArc( vertex ) )
{
types::PolyLineNode* node = aOutput.mutable_nodes()->Add();
node->mutable_point()->set_x_nm( aSlc.CPoint( vertex ).x );
node->mutable_point()->set_y_nm( aSlc.CPoint( vertex ).y );
}
+4 -6
View File
@@ -5036,6 +5036,7 @@ void BuildBitmapInfo( std::unordered_map<BITMAPS, std::vector<BITMAP_INFO>>& aBi
aBitmapInfoCache[BITMAPS::constraint_basic_clearance].emplace_back( BITMAPS::constraint_basic_clearance, wxT( "constraint_basic_clearance.png" ), -1, wxT( "light" ) );
aBitmapInfoCache[BITMAPS::constraint_board_outline_clearance].emplace_back( BITMAPS::constraint_board_outline_clearance, wxT( "constraint_board_outline_clearance.png" ), -1, wxT( "light" ) );
aBitmapInfoCache[BITMAPS::constraint_clearance].emplace_back( BITMAPS::constraint_clearance, wxT( "constraint_clearance.png" ), -1, wxT( "light" ) );
aBitmapInfoCache[BITMAPS::constraint_courtyard_clearance].emplace_back( BITMAPS::constraint_courtyard_clearance, wxT( "constraint_courtyard_clearance.png" ), -1, wxT( "light" ) );
aBitmapInfoCache[BITMAPS::constraint_copper_to_edge_clearance].emplace_back( BITMAPS::constraint_copper_to_edge_clearance, wxT( "constraint_copper_to_edge_clearance.png" ), -1, wxT( "light" ) );
aBitmapInfoCache[BITMAPS::constraint_copper_to_hole_clearance].emplace_back( BITMAPS::constraint_copper_to_hole_clearance, wxT( "constraint_copper_to_hole_clearance.png" ), -1, wxT( "light" ) );
aBitmapInfoCache[BITMAPS::constraint_creepage_distance].emplace_back( BITMAPS::constraint_creepage_distance, wxT( "constraint_creepage_distance.png" ), -1, wxT( "light" ) );
@@ -5044,9 +5045,7 @@ void BuildBitmapInfo( std::unordered_map<BITMAPS, std::vector<BITMAP_INFO>>& aBi
aBitmapInfoCache[BITMAPS::constraint_hole_to_hole_distance].emplace_back( BITMAPS::constraint_hole_to_hole_distance, wxT( "constraint_hole_to_hole_distance.png" ), -1, wxT( "light" ) );
aBitmapInfoCache[BITMAPS::constraint_length].emplace_back( BITMAPS::constraint_length, wxT( "constraint_length.png" ), -1, wxT( "light" ) );
aBitmapInfoCache[BITMAPS::constraint_matched_length_diff_pair].emplace_back( BITMAPS::constraint_matched_length_diff_pair, wxT( "constraint_matched_length_diff_pair.png" ), -1, wxT( "light" ) );
aBitmapInfoCache[BITMAPS::constraint_matched_length_diff_pair_v2].emplace_back(
BITMAPS::constraint_matched_length_diff_pair_v2, wxT( "constraint_matched_length_diff_pair_v2.png" ), -1,
wxT( "light" ) );
aBitmapInfoCache[BITMAPS::constraint_matched_length_diff_pair_v2].emplace_back( BITMAPS::constraint_matched_length_diff_pair_v2, wxT( "constraint_matched_length_diff_pair_v2.png" ), -1, wxT( "light" ) );
aBitmapInfoCache[BITMAPS::constraint_maximum_allowed_deviation].emplace_back( BITMAPS::constraint_maximum_allowed_deviation, wxT( "constraint_maximum_allowed_deviation.png" ), -1, wxT( "light" ) );
aBitmapInfoCache[BITMAPS::constraint_maximum_via_count].emplace_back( BITMAPS::constraint_maximum_via_count, wxT( "constraint_maximum_via_count.png" ), -1, wxT( "light" ) );
aBitmapInfoCache[BITMAPS::constraint_minimum_angular_ring].emplace_back( BITMAPS::constraint_minimum_angular_ring, wxT( "constraint_minimum_angular_ring.png" ), -1, wxT( "light" ) );
@@ -5074,6 +5073,7 @@ void BuildBitmapInfo( std::unordered_map<BITMAPS, std::vector<BITMAP_INFO>>& aBi
aBitmapInfoCache[BITMAPS::constraint_basic_clearance].emplace_back( BITMAPS::constraint_basic_clearance, wxT( "constraint_basic_clearance_dark.png" ), -1, wxT( "dark" ) );
aBitmapInfoCache[BITMAPS::constraint_board_outline_clearance].emplace_back( BITMAPS::constraint_board_outline_clearance, wxT( "constraint_board_outline_clearance_dark.png" ), -1, wxT( "dark" ) );
aBitmapInfoCache[BITMAPS::constraint_clearance].emplace_back( BITMAPS::constraint_clearance, wxT( "constraint_clearance_dark.png" ), -1, wxT( "dark" ) );
aBitmapInfoCache[BITMAPS::constraint_courtyard_clearance].emplace_back( BITMAPS::constraint_courtyard_clearance, wxT( "constraint_courtyard_clearance_dark.png" ), -1, wxT( "dark" ) );
aBitmapInfoCache[BITMAPS::constraint_copper_to_edge_clearance].emplace_back( BITMAPS::constraint_copper_to_edge_clearance, wxT( "constraint_copper_to_edge_clearance_dark.png" ), -1, wxT( "dark" ) );
aBitmapInfoCache[BITMAPS::constraint_copper_to_hole_clearance].emplace_back( BITMAPS::constraint_copper_to_hole_clearance, wxT( "constraint_copper_to_hole_clearance_dark.png" ), -1, wxT( "dark" ) );
aBitmapInfoCache[BITMAPS::constraint_creepage_distance].emplace_back( BITMAPS::constraint_creepage_distance, wxT( "constraint_creepage_distance_dark.png" ), -1, wxT( "dark" ) );
@@ -5082,9 +5082,7 @@ void BuildBitmapInfo( std::unordered_map<BITMAPS, std::vector<BITMAP_INFO>>& aBi
aBitmapInfoCache[BITMAPS::constraint_hole_to_hole_distance].emplace_back( BITMAPS::constraint_hole_to_hole_distance, wxT( "constraint_hole_to_hole_distance_dark.png" ), -1, wxT( "dark" ) );
aBitmapInfoCache[BITMAPS::constraint_length].emplace_back( BITMAPS::constraint_length, wxT( "constraint_length_dark.png" ), -1, wxT( "dark" ) );
aBitmapInfoCache[BITMAPS::constraint_matched_length_diff_pair].emplace_back( BITMAPS::constraint_matched_length_diff_pair, wxT( "constraint_matched_length_diff_pair_dark.png" ), -1, wxT( "dark" ) );
aBitmapInfoCache[BITMAPS::constraint_matched_length_diff_pair_v2].emplace_back(
BITMAPS::constraint_matched_length_diff_pair_v2, wxT( "constraint_matched_length_diff_pair_v2_dark.png" ),
-1, wxT( "dark" ) );
aBitmapInfoCache[BITMAPS::constraint_matched_length_diff_pair_v2].emplace_back( BITMAPS::constraint_matched_length_diff_pair_v2, wxT( "constraint_matched_length_diff_pair_v2_dark.png" ), -1, wxT( "dark" ) );
aBitmapInfoCache[BITMAPS::constraint_maximum_allowed_deviation].emplace_back( BITMAPS::constraint_maximum_allowed_deviation, wxT( "constraint_maximum_allowed_deviation_dark.png" ), -1, wxT( "dark" ) );
aBitmapInfoCache[BITMAPS::constraint_maximum_via_count].emplace_back( BITMAPS::constraint_maximum_via_count, wxT( "constraint_maximum_via_count_dark.png" ), -1, wxT( "dark" ) );
aBitmapInfoCache[BITMAPS::constraint_minimum_angular_ring].emplace_back( BITMAPS::constraint_minimum_angular_ring, wxT( "constraint_minimum_angular_ring_dark.png" ), -1, wxT( "dark" ) );
+253 -77
View File
@@ -231,6 +231,7 @@ static void buildKicadAboutBanner( EDA_BASE_FRAME* aParent, ABOUT_APP_INFO& aInf
ADD_DEV( wxT( "Johannes Agricola" ), CONTRIB_DEV );
ADD_DEV( wxT( "Erik Agsjö" ), CONTRIB_DEV );
ADD_DEV( wxT( "Nabeel Ahmad" ), CONTRIB_DEV );
ADD_DEV( wxT( "Christopher Alexander" ), CONTRIB_DEV );
ADD_DEV( wxT( "Werner Almesberger" ), CONTRIB_DEV );
ADD_DEV( wxT( "Shawn Anastasio" ), CONTRIB_DEV );
ADD_DEV( wxT( "Collin Anderson" ), CONTRIB_DEV );
@@ -244,8 +245,8 @@ static void buildKicadAboutBanner( EDA_BASE_FRAME* aParent, ABOUT_APP_INFO& aInf
ADD_DEV( wxT( "Konstantin Baranovskiy" ), CONTRIB_DEV );
ADD_DEV( wxT( "Roman Bashkov" ), CONTRIB_DEV );
ADD_DEV( wxT( "Michael Beardsworth" ), CONTRIB_DEV );
ADD_DEV( wxT( "Matthew Beckler" ), CONTRIB_DEV );
ADD_DEV( wxT( "Markus Becker" ), CONTRIB_DEV );
ADD_DEV( wxT( "Matthew Beckler" ), CONTRIB_DEV );
ADD_DEV( wxT( "Konrad Beckmann" ), CONTRIB_DEV );
ADD_DEV( wxT( "Eduardo Behr" ), CONTRIB_DEV );
ADD_DEV( wxT( "David Beinder" ), CONTRIB_DEV );
@@ -260,10 +261,12 @@ static void buildKicadAboutBanner( EDA_BASE_FRAME* aParent, ABOUT_APP_INFO& aInf
ADD_DEV( wxT( "Andreas Beutling" ), CONTRIB_DEV );
ADD_DEV( wxT( "Brian F. G. Bidulock" ), CONTRIB_DEV );
ADD_DEV( wxT( "Anton Blanchard" ), CONTRIB_DEV );
ADD_DEV( wxT( "Alexander Boehm" ), CONTRIB_DEV );
ADD_DEV( wxT( "Steve Bollinger" ), CONTRIB_DEV );
ADD_DEV( wxT( "Blair Bonnett" ), CONTRIB_DEV );
ADD_DEV( wxT( "Markus Bonk" ), CONTRIB_DEV );
ADD_DEV( wxT( "Blair Bonnett" ), CONTRIB_DEV );
ADD_DEV( wxT( "Franck Bourdonnec" ), CONTRIB_DEV );
ADD_DEV( wxT( "Kevin Bralten" ), CONTRIB_DEV );
ADD_DEV( wxT( "Carlo Bramini" ), CONTRIB_DEV );
ADD_DEV( wxT( "Matthias Breithaupt" ), CONTRIB_DEV );
ADD_DEV( wxT( "Stefan Brüns" ), CONTRIB_DEV );
@@ -271,10 +274,10 @@ static void buildKicadAboutBanner( EDA_BASE_FRAME* aParent, ABOUT_APP_INFO& aInf
ADD_DEV( wxT( "Ryan Bunch" ), CONTRIB_DEV );
ADD_DEV( wxT( "Emery Burhan" ), CONTRIB_DEV );
ADD_DEV( wxT( "Matt Campbell" ), CONTRIB_DEV );
ADD_DEV( wxT( "Scott Candey" ), CONTRIB_DEV );
ADD_DEV( wxT( "Phinitnan Chanasabaeng" ), CONTRIB_DEV );
ADD_DEV( wxT( "Shivpratap Chauhan" ), CONTRIB_DEV );
ADD_DEV( wxT( "Kevin Cozens" ), CONTRIB_DEV );
ADD_DEV( wxT( "Joseph Y. Chen" ), CONTRIB_DEV );
ADD_DEV( wxT( "Alexey Chernov" ), CONTRIB_DEV );
ADD_DEV( wxT( "Marco Ciampa" ), CONTRIB_DEV );
@@ -291,17 +294,18 @@ static void buildKicadAboutBanner( EDA_BASE_FRAME* aParent, ABOUT_APP_INFO& aInf
ADD_DEV( wxT( "Martin d'Allens" ), CONTRIB_DEV );
ADD_DEV( wxT( "Greg Davill" ), CONTRIB_DEV );
ADD_DEV( wxT( "Camille Delbegue" ), CONTRIB_DEV );
ADD_DEV( wxT( "Albin Dennevi" ), CONTRIB_DEV );
ADD_DEV( wxT( "Ruben De Smet" ), CONTRIB_DEV );
ADD_DEV( wxT( "Alexander Dewing" ), CONTRIB_DEV );
ADD_DEV( wxT( "Okan Demir" ), CONTRIB_DEV );
ADD_DEV( wxT( "Albin Dennevi" ), CONTRIB_DEV );
ADD_DEV( wxT( "Troy Denton" ), CONTRIB_DEV );
ADD_DEV( wxT( "Alexander Dewing" ), CONTRIB_DEV );
ADD_DEV( wxT( "Jonas Diemer" ), CONTRIB_DEV );
ADD_DEV( wxT( "Ben Dooks" ), CONTRIB_DEV );
ADD_DEV( wxT( "Jan Dorniak" ), CONTRIB_DEV );
ADD_DEV( wxT( "Pavel Dovgalyuk" ), CONTRIB_DEV );
ADD_DEV( wxT( "Andrew Downing" ), CONTRIB_DEV );
ADD_DEV( wxT( "Jan Dubiec" ), CONTRIB_DEV );
ADD_DEV( wxT( "Lucas Dumont" ), CONTRIB_DEV );
ADD_DEV( wxT( "Ruben De Smet" ), CONTRIB_DEV );
ADD_DEV( wxT( "Gerd Egidy" ), CONTRIB_DEV );
ADD_DEV( wxT( "Jean Philippe Eimer" ), CONTRIB_DEV );
@@ -310,6 +314,7 @@ static void buildKicadAboutBanner( EDA_BASE_FRAME* aParent, ABOUT_APP_INFO& aInf
ADD_DEV( wxT( "Damien Espitallier" ), CONTRIB_DEV );
ADD_DEV( wxT( "Paul Ewing" ), CONTRIB_DEV );
ADD_DEV( wxT( "Steven A. Falco" ), CONTRIB_DEV );
ADD_DEV( wxT( "Andrey Fedorushkov" ), CONTRIB_DEV );
ADD_DEV( wxT( "Julian Fellinger" ), CONTRIB_DEV );
ADD_DEV( wxT( "Joe Ferner" ), CONTRIB_DEV );
@@ -317,15 +322,19 @@ static void buildKicadAboutBanner( EDA_BASE_FRAME* aParent, ABOUT_APP_INFO& aInf
ADD_DEV( wxT( "Thomas Figueroa" ), CONTRIB_DEV );
ADD_DEV( wxT( "Gilbert J.M. Forkel" ), CONTRIB_DEV );
ADD_DEV( wxT( "Vincenzo Fortunato" ), CONTRIB_DEV );
ADD_DEV( wxT( "Quentin Freimanis" ), CONTRIB_DEV );
ADD_DEV( wxT( "Dominique Fuchs" ), CONTRIB_DEV );
ADD_DEV( wxT( "Drew Fustini" ), CONTRIB_DEV );
ADD_DEV( wxT( "Ronnie Gaensli" ), CONTRIB_DEV );
ADD_DEV( wxT( "Christian Gagneraud" ), CONTRIB_DEV );
ADD_DEV( wxT( "Ben Gamari" ), CONTRIB_DEV );
ADD_DEV( wxT( "Ashutosh Gangwar" ), CONTRIB_DEV );
ADD_DEV( wxT( "Kamil Galik" ), CONTRIB_DEV );
ADD_DEV( wxT( "Alessandro Gatti" ), CONTRIB_DEV );
ADD_DEV( wxT( "Ben Gamari" ), CONTRIB_DEV );
ADD_DEV( wxT( "Thomas Gambier" ), CONTRIB_DEV );
ADD_DEV( wxT( "Ashutosh Gangwar" ), CONTRIB_DEV );
ADD_DEV( wxT( "Adrián García" ), CONTRIB_DEV );
ADD_DEV( wxT( "Alessandro Gatti" ), CONTRIB_DEV );
ADD_DEV( wxT( "Zenn Geeraerts" ), CONTRIB_DEV );
ADD_DEV( wxT( "Hal Gentz" ), CONTRIB_DEV );
ADD_DEV( wxT( "Lucas Gerads" ), CONTRIB_DEV );
ADD_DEV( wxT( "Davide Gerhard" ), CONTRIB_DEV );
@@ -333,17 +342,19 @@ static void buildKicadAboutBanner( EDA_BASE_FRAME* aParent, ABOUT_APP_INFO& aInf
ADD_DEV( wxT( "Giulio Girardi" ), CONTRIB_DEV );
ADD_DEV( wxT( "Jeff Glass" ), CONTRIB_DEV );
ADD_DEV( wxT( "Alexander Golubev" ), CONTRIB_DEV );
ADD_DEV( wxT( "Paweł Gorgoń" ), CONTRIB_DEV );
ADD_DEV( wxT( "Connor Goss" ), CONTRIB_DEV );
ADD_DEV( wxT( "Angus Gratton" ), CONTRIB_DEV );
ADD_DEV( wxT( "Andrea Greco" ), CONTRIB_DEV );
ADD_DEV( wxT( "Element Green" ), CONTRIB_DEV );
ADD_DEV( wxT( "Mathias Grimmberger" ), CONTRIB_DEV );
ADD_DEV( wxT( "Johan Grip" ), CONTRIB_DEV );
ADD_DEV( wxT( "Michal Grzegorzek" ), CONTRIB_DEV );
ADD_DEV( wxT( "Hildo Guillardi Júnior" ), CONTRIB_DEV );
ADD_DEV( wxT( "Niki Guldbrand" ), CONTRIB_DEV );
ADD_DEV( wxT( "Tanay Gupta" ), CONTRIB_DEV );
ADD_DEV( wxT( "Alexander Guy" ), CONTRIB_DEV );
ADD_DEV( wxT( "Zoltan Gyarmati" ), CONTRIB_DEV );
ADD_DEV( wxT( "Hildo Guillardi Júnior" ), CONTRIB_DEV );
ADD_DEV( wxT( "Jonathan Haas" ), CONTRIB_DEV );
ADD_DEV( wxT( "Mark Hämmerling" ), CONTRIB_DEV );
@@ -357,26 +368,29 @@ static void buildKicadAboutBanner( EDA_BASE_FRAME* aParent, ABOUT_APP_INFO& aInf
ADD_DEV( wxT( "Stefan Helmert" ), CONTRIB_DEV );
ADD_DEV( wxT( "Hartmut Henkel" ), CONTRIB_DEV );
ADD_DEV( wxT( "Brian Henning" ), CONTRIB_DEV );
ADD_DEV( wxT( "Paulo Henrique Silva" ), CONTRIB_DEV );
ADD_DEV( wxT( "Hans Henry von Tresckow" ), CONTRIB_DEV );
ADD_DEV( wxT( "Diego Herranz" ), CONTRIB_DEV );
ADD_DEV( wxT( "Marco Hess" ), CONTRIB_DEV );
ADD_DEV( wxT( "Brendan Hickey" ), CONTRIB_DEV );
ADD_DEV( wxT( "Petri Hodju" ), CONTRIB_DEV );
ADD_DEV( wxT( "David Holdeman" ), CONTRIB_DEV );
ADD_DEV( wxT( "Laurens Holst" ), CONTRIB_DEV );
ADD_DEV( wxT( "Yang Hongbo" ), CONTRIB_DEV );
ADD_DEV( wxT( "Mario Hros" ), CONTRIB_DEV );
ADD_DEV( wxT( "Josue Huaroto" ), CONTRIB_DEV );
ADD_DEV( wxT( "Eli Hughes" ), CONTRIB_DEV );
ADD_DEV( wxT( "Matt Huszagh" ), CONTRIB_DEV );
ADD_DEV( wxT( "Torsten Hüter" ), CONTRIB_DEV );
ADD_DEV( wxT( "Paulo Henrique Silva" ), CONTRIB_DEV );
ADD_DEV( wxT( "Hans Henry von Tresckow" ), CONTRIB_DEV );
ADD_DEV( wxT( "José Ignacio Romero" ), CONTRIB_DEV );
ADD_DEV( wxT( "Marco Inacio" ), CONTRIB_DEV );
ADD_DEV( wxT( "Kinichiro Inoguchi" ), CONTRIB_DEV );
ADD_DEV( wxT( "Fabián Inostroza" ), CONTRIB_DEV );
ADD_DEV( wxT( "Vlad Ivanov" ), CONTRIB_DEV );
ADD_DEV( wxT( "Andre Iwers" ), CONTRIB_DEV );
ADD_DEV( wxT( "José Ignacio Romero" ), CONTRIB_DEV );
ADD_DEV( wxT( "José Jorge Enríquez" ), CONTRIB_DEV );
ADD_DEV( wxT( "Hasan Jaafar" ), CONTRIB_DEV );
ADD_DEV( wxT( "Jerry Jacobs" ), CONTRIB_DEV );
ADD_DEV( wxT( "Christian Jacobsen" ), CONTRIB_DEV );
@@ -384,7 +398,6 @@ static void buildKicadAboutBanner( EDA_BASE_FRAME* aParent, ABOUT_APP_INFO& aInf
ADD_DEV( wxT( "Martin Janitschke" ), CONTRIB_DEV );
ADD_DEV( wxT( "Jonathan Jara-Almonte" ), CONTRIB_DEV );
ADD_DEV( wxT( "Zhuang Jiezhi" ), CONTRIB_DEV );
ADD_DEV( wxT( "José Jorge Enríquez" ), CONTRIB_DEV );
ADD_DEV( wxT( "Franck Jullien" ), CONTRIB_DEV );
ADD_DEV( wxT( "Eeli Kaikkonen" ), CONTRIB_DEV );
@@ -397,42 +410,49 @@ static void buildKicadAboutBanner( EDA_BASE_FRAME* aParent, ABOUT_APP_INFO& aInf
ADD_DEV( wxT( "Graham Keeth" ), CONTRIB_DEV );
ADD_DEV( wxT( "Yury Khalyavin" ), CONTRIB_DEV );
ADD_DEV( wxT( "Eldar Khayrullin" ), CONTRIB_DEV );
ADD_DEV( wxT( "Lenny Khazan" ), CONTRIB_DEV );
ADD_DEV( wxT( "Georges Khaznadar" ), CONTRIB_DEV );
ADD_DEV( wxT( "Gary Kim" ), CONTRIB_DEV );
ADD_DEV( wxT( "Aristeidis Kimirtzis" ), CONTRIB_DEV );
ADD_DEV( wxT( "Bernhard Kirchen" ), CONTRIB_DEV );
ADD_DEV( wxT( "Ingo Kletti" ), CONTRIB_DEV );
ADD_DEV( wxT( "Kliment" ), CONTRIB_DEV );
ADD_DEV( wxT( "Sylwester Kocjan" ), CONTRIB_DEV );
ADD_DEV( wxT( "Uli Köhler" ), CONTRIB_DEV );
ADD_DEV( wxT( "Clemens Koller" ), CONTRIB_DEV );
ADD_DEV( wxT( "Asuki Kono" ), CONTRIB_DEV );
ADD_DEV( wxT( "Matt Kosman" ), CONTRIB_DEV );
ADD_DEV( wxT( "Jakub Kozdon" ), CONTRIB_DEV );
ADD_DEV( wxT( "Andrej Krpic" ), CONTRIB_DEV );
ADD_DEV( wxT( "Hajo Nils Krabbenhöft" ), CONTRIB_DEV );
ADD_DEV( wxT( "Andrej Krpic" ), CONTRIB_DEV );
ADD_DEV( wxT( "Simon Kueppers" ), CONTRIB_DEV );
ADD_DEV( wxT( "Martijn Kuipers" ), CONTRIB_DEV );
ADD_DEV( wxT( "Dhinesh Kumar" ), CONTRIB_DEV );
ADD_DEV( wxT( "Eric Kuzmenko" ), CONTRIB_DEV );
ADD_DEV( wxT( "Paul LeoNerd Evens" ), CONTRIB_DEV );
ADD_DEV( wxT( "Robbert Lagerweij" ), CONTRIB_DEV );
ADD_DEV( wxT( "Mika Laitio" ), CONTRIB_DEV );
ADD_DEV( wxT( "Floris Lambrechts" ), CONTRIB_DEV );
ADD_DEV( wxT( "Dimitris Lampridis" ), CONTRIB_DEV );
ADD_DEV( wxT( "Marco Langer" ), CONTRIB_DEV );
ADD_DEV( wxT( "Kevin Lannen" ), CONTRIB_DEV );
ADD_DEV( wxT( "Mika Laitio" ), CONTRIB_DEV );
ADD_DEV( wxT( "Floris Lambrechts" ), CONTRIB_DEV );
ADD_DEV( wxT( "lê văn lập" ), CONTRIB_DEV );
ADD_DEV( wxT( "Denis Latyshev" ), CONTRIB_DEV );
ADD_DEV( wxT( "Anton Lazarev" ), CONTRIB_DEV );
ADD_DEV( wxT( "Dag Lem" ), CONTRIB_DEV );
ADD_DEV( wxT( "Ludovic Léau-mercier" ), CONTRIB_DEV );
ADD_DEV( wxT( "Paul LeoNerd Evens" ), CONTRIB_DEV );
ADD_DEV( wxT( "Dag Lem" ), CONTRIB_DEV );
ADD_DEV( wxT( "Jonatan Liljedahl" ), CONTRIB_DEV );
ADD_DEV( wxT( "Huanyin Liu" ), CONTRIB_DEV );
ADD_DEV( wxT( "Brian Lu" ), CONTRIB_DEV );
ADD_DEV( wxT( "Magnus Lundmark" ), CONTRIB_DEV );
ADD_DEV( wxT( "Alexander Lunev" ), CONTRIB_DEV );
ADD_DEV( wxT( "Andrew Lutsenko" ), CONTRIB_DEV );
ADD_DEV( wxT( "Mario Luzeiro" ), CONTRIB_DEV );
ADD_DEV( wxT( "Mojca Miklavec Groenhuis" ), CONTRIB_DEV );
ADD_DEV( wxT( "Johannes Maibaum" ), CONTRIB_DEV );
ADD_DEV( wxT( "Philippe Maire" ), CONTRIB_DEV );
ADD_DEV( wxT( "Mateusz Majchrzycki" ), CONTRIB_DEV );
ADD_DEV( wxT( "Daniel Majewski" ), CONTRIB_DEV );
ADD_DEV( wxT( "Rachel Mant" ), CONTRIB_DEV );
@@ -440,18 +460,20 @@ static void buildKicadAboutBanner( EDA_BASE_FRAME* aParent, ABOUT_APP_INFO& aInf
ADD_DEV( wxT( "Miklós Márton" ), CONTRIB_DEV );
ADD_DEV( wxT( "Marco Mattila" ), CONTRIB_DEV );
ADD_DEV( wxT( "Steffen Mauch" ), CONTRIB_DEV );
ADD_DEV( wxT( "Brian Mayton" ), CONTRIB_DEV );
ADD_DEV( wxT( "Maui" ), CONTRIB_DEV );
ADD_DEV( wxT( "Kirill Mavreshko" ), CONTRIB_DEV );
ADD_DEV( wxT( "Brian Mayton" ), CONTRIB_DEV );
ADD_DEV( wxT( "Miles McCoo" ), CONTRIB_DEV );
ADD_DEV( wxT( "Charles McDowell" ), CONTRIB_DEV );
ADD_DEV( wxT( "Ian McKernan" ), CONTRIB_DEV );
ADD_DEV( wxT( "Moses McKnight" ), CONTRIB_DEV );
ADD_DEV( wxT( "Martin McNamara" ), CONTRIB_DEV );
ADD_DEV( wxT( "Cameron McQuinn" ), CONTRIB_DEV );
ADD_DEV( wxT( "Ievgenii Meshcheriakov" ), CONTRIB_DEV );
ADD_DEV( wxT( "Mojca Miklavec Groenhuis" ), CONTRIB_DEV );
ADD_DEV( wxT( "Yiannis Michael" ), CONTRIB_DEV );
ADD_DEV( wxT( "Ashley Mills" ), CONTRIB_DEV );
ADD_DEV( wxT( "Christoph Moench-Tegeder" ), CONTRIB_DEV );
ADD_DEV( wxT( "Sean Mollet" ), CONTRIB_DEV );
ADD_DEV( wxT( "Peter Montgomery" ), CONTRIB_DEV );
ADD_DEV( wxT( "Alejandro García Montoro" ), CONTRIB_DEV );
ADD_DEV( wxT( "Chris Morgan" ), CONTRIB_DEV );
@@ -462,8 +484,8 @@ static void buildKicadAboutBanner( EDA_BASE_FRAME* aParent, ABOUT_APP_INFO& aInf
ADD_DEV( wxT( "Michael Narigon" ), CONTRIB_DEV );
ADD_DEV( wxT( "Jon Neal" ), CONTRIB_DEV );
ADD_DEV( wxT( "Bastian Neumann" ), CONTRIB_DEV );
ADD_DEV( wxT( "Daniil Nikolaev" ), CONTRIB_DEV );
ADD_DEV( wxT( "Kristian Nielsen" ), CONTRIB_DEV );
ADD_DEV( wxT( "Daniil Nikolaev" ), CONTRIB_DEV );
ADD_DEV( wxT( "Érico Nogueira" ), CONTRIB_DEV );
ADD_DEV( wxT( "Allan Nordhøy" ), CONTRIB_DEV );
ADD_DEV( wxT( "Henrik Nyberg" ), CONTRIB_DEV );
@@ -471,6 +493,7 @@ static void buildKicadAboutBanner( EDA_BASE_FRAME* aParent, ABOUT_APP_INFO& aInf
ADD_DEV( wxT( "Kristoffer Ödmark" ), CONTRIB_DEV );
ADD_DEV( wxT( "Russell Oliver" ), CONTRIB_DEV );
ADD_DEV( wxT( "Jason Oster" ), CONTRIB_DEV );
ADD_DEV( wxT( "Juho Ovaska" ), CONTRIB_DEV );
ADD_DEV( wxT( "Frank Palazzolo" ), CONTRIB_DEV );
ADD_DEV( wxT( "Sven Pauli" ), CONTRIB_DEV );
@@ -486,22 +509,25 @@ static void buildKicadAboutBanner( EDA_BASE_FRAME* aParent, ABOUT_APP_INFO& aInf
ADD_DEV( wxT( "Brian Piccioni" ), CONTRIB_DEV );
ADD_DEV( wxT( "Mathieu Pilato" ), CONTRIB_DEV );
ADD_DEV( wxT( "Nicolas Planel" ), CONTRIB_DEV );
ADD_DEV( wxT( "Paweł Płóciennik" ), CONTRIB_DEV );
ADD_DEV( wxT( "Carl Poirier" ), CONTRIB_DEV );
ADD_DEV( wxT( "Reece Pollack" ), CONTRIB_DEV );
ADD_DEV( wxT( "Alain Portal" ), CONTRIB_DEV );
ADD_DEV( wxT( "Andrei Pozolotin" ), CONTRIB_DEV );
ADD_DEV( wxT( "Damjan Prerad" ), CONTRIB_DEV );
ADD_DEV( wxT( "Antia Puentes" ), CONTRIB_DEV );
ADD_DEV( wxT( "Zoltan Puskas" ), CONTRIB_DEV );
ADD_DEV( wxT( "Heikki Pulkkinen" ), CONTRIB_DEV );
ADD_DEV( wxT( "Zoltan Puskas" ), CONTRIB_DEV );
ADD_DEV( wxT( "Paweł Płóciennik" ), CONTRIB_DEV );
ADD_DEV( wxT( "Morgan Quigley" ), CONTRIB_DEV );
ADD_DEV( wxT( "Zlatan Radovanovic" ), CONTRIB_DEV );
ADD_DEV( wxT( "Barabas Raffai" ), CONTRIB_DEV );
ADD_DEV( wxT( "Urja Rannikko" ), CONTRIB_DEV );
ADD_DEV( wxT( "Alexander Rauth" ), CONTRIB_DEV );
ADD_DEV( wxT( "Hendrik v. Raven" ), CONTRIB_DEV );
ADD_DEV( wxT( "Joshua Redstone" ), CONTRIB_DEV );
ADD_DEV( wxT( "David Rees" ), CONTRIB_DEV );
ADD_DEV( wxT( "Michele Renda" ), CONTRIB_DEV );
ADD_DEV( wxT( "Jean-Samuel Reynaud" ), CONTRIB_DEV );
ADD_DEV( wxT( "Dmitry Rezvanov" ), CONTRIB_DEV );
@@ -522,30 +548,32 @@ static void buildKicadAboutBanner( EDA_BASE_FRAME* aParent, ABOUT_APP_INFO& aInf
ADD_DEV( wxT( "Clément Saccoccio" ), CONTRIB_DEV );
ADD_DEV( wxT( "J. Morio Sakaguchi" ), CONTRIB_DEV );
ADD_DEV( wxT( "Simon Schaak" ), CONTRIB_DEV );
ADD_DEV( wxT( "Olliver Schinagl" ), CONTRIB_DEV );
ADD_DEV( wxT( "Ross Schlaikjer" ), CONTRIB_DEV );
ADD_DEV( wxT( "Julius Schmidt" ), CONTRIB_DEV );
ADD_DEV( wxT( "Felix Schneider" ), CONTRIB_DEV );
ADD_DEV( wxT( "Marvin Schmidt" ), CONTRIB_DEV );
ADD_DEV( wxT( "Felix Schneider" ), CONTRIB_DEV );
ADD_DEV( wxT( "David Schneider" ), CONTRIB_DEV );
ADD_DEV( wxT( "Carsten Schoenert" ), CONTRIB_DEV );
ADD_DEV( wxT( "Armin Schoisswohl" ), CONTRIB_DEV );
ADD_DEV( wxT( "Simon Schubert" ), CONTRIB_DEV );
ADD_DEV( wxT( "Michal Schulz" ), CONTRIB_DEV );
ADD_DEV( wxT( "Adrian Scripca" ), CONTRIB_DEV );
ADD_DEV( wxT( "Pradeepa Senanayake" ), CONTRIB_DEV );
ADD_DEV( wxT( "Alihossein Sepahvand" ), CONTRIB_DEV );
ADD_DEV( wxT( "Marco Serantoni" ), CONTRIB_DEV );
ADD_DEV( wxT( "Julien Serin" ), CONTRIB_DEV );
ADD_DEV( wxT( "Frank Severinsen" ), CONTRIB_DEV );
ADD_DEV( wxT( "Cheng Sheng" ), CONTRIB_DEV );
ADD_DEV( wxT( "Yang Sheng" ), CONTRIB_DEV );
ADD_DEV( wxT( "Chetan Shinde" ), CONTRIB_DEV );
ADD_DEV( wxT( "Alexander Shuklin" ), CONTRIB_DEV );
ADD_DEV( wxT( "Guillaume Simard" ), CONTRIB_DEV );
ADD_DEV( wxT( "Adam Simpkins" ), CONTRIB_DEV );
ADD_DEV( wxT( "Slawomir Siudym" ), CONTRIB_DEV );
ADD_DEV( wxT( "Marco Serantoni" ), CONTRIB_DEV );
ADD_DEV( wxT( "Guillaume Simard" ), CONTRIB_DEV );
ADD_DEV( wxT( "Martin Sivak" ), CONTRIB_DEV );
ADD_DEV( wxT( "Mateusz Skowroński" ), CONTRIB_DEV );
ADD_DEV( wxT( "Dominik Sliwa" ), CONTRIB_DEV );
ADD_DEV( wxT( "Kacper Słomiński" ), CONTRIB_DEV );
ADD_DEV( wxT( "Blake Smith" ), CONTRIB_DEV );
ADD_DEV( wxT( "Ikoma So" ), CONTRIB_DEV );
ADD_DEV( wxT( "Michal Sojka" ), CONTRIB_DEV );
@@ -560,32 +588,39 @@ static void buildKicadAboutBanner( EDA_BASE_FRAME* aParent, ABOUT_APP_INFO& aInf
ADD_DEV( wxT( "Marco Sterbik" ), CONTRIB_DEV );
ADD_DEV( wxT( "Alexander Stock" ), CONTRIB_DEV );
ADD_DEV( wxT( "Martin Stoilov" ), CONTRIB_DEV );
ADD_DEV( wxT( "Michal Suchánek" ), CONTRIB_DEV );
ADD_DEV( wxT( "Hiroki Suenaga" ), CONTRIB_DEV );
ADD_DEV( wxT( "Kuba Sunderland-Ober" ), CONTRIB_DEV );
ADD_DEV( wxT( "Kacper Słomiński" ), CONTRIB_DEV );
ADD_DEV( wxT( "Nimish Telang" ), CONTRIB_DEV );
ADD_DEV( wxT( "Martin Thierer" ), CONTRIB_DEV );
ADD_DEV( wxT( "Karl Thorén" ), CONTRIB_DEV );
ADD_DEV( wxT( "Hiroshi Tokita" ), CONTRIB_DEV );
ADD_DEV( wxT( "Daniel Treffenstädt" ), CONTRIB_DEV );
ADD_DEV( wxT( "Salvador E. Tropea" ), CONTRIB_DEV );
ADD_DEV( wxT( "Vladimir Ur" ), CONTRIB_DEV );
ADD_DEV( wxT( "Yon Uriarte" ), CONTRIB_DEV );
ADD_DEV( wxT( "Matthias Urlichs" ), CONTRIB_DEV );
ADD_DEV( wxT( "Vladimir Uryvaev" ), CONTRIB_DEV );
ADD_DEV( wxT( "Mark van Doesburg" ), CONTRIB_DEV );
ADD_DEV( wxT( "Edwin van den Oetelaar" ), CONTRIB_DEV );
ADD_DEV( wxT( "Julie Vairai" ), CONTRIB_DEV );
ADD_DEV( wxT( "Andrej Valek" ), CONTRIB_DEV );
ADD_DEV( wxT( "Henri Valta" ), CONTRIB_DEV );
ADD_DEV( wxT( "Dave Vandenbout" ), CONTRIB_DEV );
ADD_DEV( wxT( "Edwin van den Oetelaar" ), CONTRIB_DEV );
ADD_DEV( wxT( "Mark van Doesburg" ), CONTRIB_DEV );
ADD_DEV( wxT( "Nils van Zuijlen" ), CONTRIB_DEV );
ADD_DEV( wxT( "Raman Varabets" ), CONTRIB_DEV );
ADD_DEV( wxT( "Fabio Varesano" ), CONTRIB_DEV );
ADD_DEV( wxT( "Akhil Velagapudi" ), CONTRIB_DEV );
ADD_DEV( wxT( "Emmanuel Vera" ), CONTRIB_DEV );
ADD_DEV( wxT( "Benjamin Vernoux" ), CONTRIB_DEV );
ADD_DEV( wxT( "Frank Villaro-Dixon" ), CONTRIB_DEV );
ADD_DEV( wxT( "Mark Visser" ), CONTRIB_DEV );
ADD_DEV( wxT( "Forrest Voight" ), CONTRIB_DEV );
ADD_DEV( wxT( "Tormod Volden" ), CONTRIB_DEV );
ADD_DEV( wxT( "Nils van Zuijlen" ), CONTRIB_DEV );
ADD_DEV( wxT( "Bartek Wacławik" ), CONTRIB_DEV );
ADD_DEV( wxT( "Johannes Wågen" ), CONTRIB_DEV );
@@ -594,17 +629,20 @@ static void buildKicadAboutBanner( EDA_BASE_FRAME* aParent, ABOUT_APP_INFO& aInf
ADD_DEV( wxT( "Dan Weatherill" ), CONTRIB_DEV );
ADD_DEV( wxT( "Stefan Weber" ), CONTRIB_DEV );
ADD_DEV( wxT( "Christian Weickhmann" ), CONTRIB_DEV );
ADD_DEV( wxT( "Bernhard M. Wiedemann" ), CONTRIB_DEV );
ADD_DEV( wxT( "Bevan Weiss" ), CONTRIB_DEV );
ADD_DEV( wxT( "Simon Wells" ), CONTRIB_DEV );
ADD_DEV( wxT( "Dominik Wernberger" ), CONTRIB_DEV );
ADD_DEV( wxT( "Martin Whitaker" ), CONTRIB_DEV );
ADD_DEV( wxT( "Addo White" ), CONTRIB_DEV );
ADD_DEV( wxT( "Jan Wichmann" ), CONTRIB_DEV );
ADD_DEV( wxT( "Bernhard M. Wiedemann" ), CONTRIB_DEV );
ADD_DEV( wxT( "Nick Winters" ), CONTRIB_DEV );
ADD_DEV( wxT( "Adam Wolf" ), CONTRIB_DEV );
ADD_DEV( wxT( "Andrzej Wolski" ), CONTRIB_DEV );
ADD_DEV( wxT( "Céleste Wouters" ), CONTRIB_DEV );
ADD_DEV( wxT( "Damian Wrobel" ), CONTRIB_DEV );
ADD_DEV( wxT( "Andrew Wygle" ), CONTRIB_DEV );
ADD_DEV( wxT( "Adam Wysocki" ), CONTRIB_DEV );
ADD_DEV( wxT( "xx" ), CONTRIB_DEV );
@@ -615,14 +653,16 @@ static void buildKicadAboutBanner( EDA_BASE_FRAME* aParent, ABOUT_APP_INFO& aInf
ADD_DEV( wxT( "Alexander Zakamaldin" ), CONTRIB_DEV );
ADD_DEV( wxT( "Frank Zeeman" ), CONTRIB_DEV );
ADD_DEV( wxT( "Henner Zeller" ), CONTRIB_DEV );
ADD_DEV( wxT( "Andrew Zonenberg" ), CONTRIB_DEV );
ADD_DEV( wxT( "Karl Zeilhofer" ), CONTRIB_DEV );
ADD_DEV( wxT( "Henner Zeller" ), CONTRIB_DEV );
ADD_DEV( wxT( "Kevin Zheng" ), CONTRIB_DEV );
ADD_DEV( wxT( "Andrew Zonenberg" ), CONTRIB_DEV );
ADD_DEV( wxT( "wh201906" ), CONTRIB_DEV );
ADD_DEV( wxT( "Nick Østergaard" ), CONTRIB_DEV );
ADD_DEV( wxT( "木 王" ), CONTRIB_DEV );
ADD_DEV( wxT( "wh201906" ), CONTRIB_DEV );
// The document writers
#define DOC_TEAM _( "Documentation Team" )
@@ -646,10 +686,12 @@ static void buildKicadAboutBanner( EDA_BASE_FRAME* aParent, ABOUT_APP_INFO& aInf
ADD_TRANSLATOR( wxT( "Radovan Blažek" ), wxS( "Czech (CS)" ) );
ADD_TRANSLATOR( wxT( "Ondřej Čertík" ), wxS( "Czech (CS)" ) );
ADD_TRANSLATOR( wxT( "Martin Kratoška" ), wxS( "Czech (CS)" ) );
ADD_TRANSLATOR( wxT( "Michal Kundrát" ), wxS( "Czech (CS)" ) );
ADD_TRANSLATOR( wxT( "Radek Kuznik" ), wxS( "Czech (CS)" ) );
ADD_TRANSLATOR( wxT( "Roman Ondráček" ), wxS( "Czech (CS)" ) );
ADD_TRANSLATOR( wxT( "Petr Pazourek" ), wxS( "Czech (CS)" ) );
ADD_TRANSLATOR( wxT( "René Široký" ), wxS( "Czech (CS)" ) );
ADD_TRANSLATOR( wxT( "Hynek Štětina" ), wxS( "Czech (CS)" ) );
ADD_TRANSLATOR( wxT( "Jan Straka" ), wxS( "Czech (CS)" ) );
ADD_TRANSLATOR( wxT( "Andrej Valek" ), wxS( "Czech (CS)" ) );
ADD_TRANSLATOR( wxT( "Jan Vykydal" ), wxS( "Czech (CS)" ) );
@@ -664,146 +706,189 @@ static void buildKicadAboutBanner( EDA_BASE_FRAME* aParent, ABOUT_APP_INFO& aInf
ADD_TRANSLATOR( wxS( "Benedikt Freisen" ), wxS( "German (DE)" ) );
ADD_TRANSLATOR( wxS( "Jonathan Haas" ), wxS( "German (DE)" ) );
ADD_TRANSLATOR( wxT( "Mark Hämmerling" ), wxS( "German (DE)" ) );
ADD_TRANSLATOR( wxT( "Johannes Maibaum" ), wxS( "German (DE)" ) );
ADD_TRANSLATOR( wxT( "Henrik Kauhanen" ), wxS( "German (DE)" ) );
ADD_TRANSLATOR( wxT( "Johannes Maibaum" ), wxS( "German (DE)" ) );
ADD_TRANSLATOR( wxT( "Mathias Neumann" ), wxS( "German (DE)" ) );
ADD_TRANSLATOR( wxT( "Ken Ovo" ), wxS( "German (DE)" ) );
ADD_TRANSLATOR( wxT( "Christian Schlüter" ), wxS( "German (DE)" ) );
ADD_TRANSLATOR( wxT( "Karl Schuh" ), wxS( "German (DE)" ) );
ADD_TRANSLATOR( wxT( "Frank Sonnenberg" ), wxS( "German (DE)" ) );
ADD_TRANSLATOR( wxT( "Lauritz Tieste" ), wxS( "German (DE)" ) );
ADD_TRANSLATOR( wxT( "Dominik Wernberger" ), wxS( "German (DE)" ) );
ADD_TRANSLATOR( wxS( "Manolis Stefanis" ), wxS( "Greek (el_GR)" ) );
ADD_TRANSLATOR( wxS( "Athanasios Vlastos" ), wxS( "Greek (el_GR)" ) );
ADD_TRANSLATOR( wxT( "Theodoros Asimakopoulos" ), wxS( "Greek (el_GR)" ) );
ADD_TRANSLATOR( wxS( "Aristeidis Kimirtzis" ), wxS( "Greek (el_GR)" ) );
ADD_TRANSLATOR( wxS( "Milonas Kostas" ), wxS( "Greek (el_GR)" ) );
ADD_TRANSLATOR( wxS( "Michail Misirlis" ), wxS( "Greek (el_GR)" ) );
ADD_TRANSLATOR( wxS( "Aristeidis Kimirtzis" ), wxS( "Greek (el_GR)" ) );
ADD_TRANSLATOR( wxS( "Manolis Stefanis" ), wxS( "Greek (el_GR)" ) );
ADD_TRANSLATOR( wxS( "Athanasios Vlastos" ), wxS( "Greek (el_GR)" ) );
ADD_TRANSLATOR( wxT( "Adolfo Jayme Barrientos" ), wxS( "Spanish (ES)" ) );
ADD_TRANSLATOR( wxT( "Roberto Fernandez Bautista" ), wxS( "Spanish (ES)" ) );
ADD_TRANSLATOR( wxT( "Pablo Bianchi" ), wxS( "Spanish (ES)" ) );
ADD_TRANSLATOR( wxT( "Echedey" ), wxS( "Spanish (ES)" ) );
ADD_TRANSLATOR( wxT( "Iñigo Figuero" ), wxS( "Spanish (ES)" ) );
ADD_TRANSLATOR( wxT( "Augusto Fraga Giachero" ), wxS( "Spanish (ES)" ) );
ADD_TRANSLATOR( wxS( "Pedro Martin del Valle" ), wxS( "Spanish (ES)" ) );
ADD_TRANSLATOR( wxT( "Ulices Avila Hernandez" ), wxS( "Spanish (ES)" ) );
ADD_TRANSLATOR( wxS( "Gabriel Martinez" ), wxS( "Spanish (ES)" ) );
ADD_TRANSLATOR( wxT( "Tomás Mora" ), wxS( "Spanish (ES)" ) );
ADD_TRANSLATOR( wxT( "Gallego Novato" ), wxS( "Spanish (ES)" ) );
ADD_TRANSLATOR( wxT( "Jose Perez" ), wxS( "Spanish (ES)" ) );
ADD_TRANSLATOR( wxT( "Iñigo Zuluaga" ), wxS( "Spanish (ES)" ) );
ADD_TRANSLATOR( wxT( "Ulices Avila Hernandez" ), wxS( "Spanish (ES)" ) );
ADD_TRANSLATOR( wxT( "Francisco Jose Rey" ), wxS( "Spanish (ES)" ) );
ADD_TRANSLATOR( wxT( "Gaston Schelotto" ), wxS( "Spanish (ES)" ) );
ADD_TRANSLATOR( wxT( "uLe" ), wxS( "Spanish (ES)" ) );
ADD_TRANSLATOR( wxS( "Pedro Martin del Valle" ), wxS( "Spanish (ES)" ) );
ADD_TRANSLATOR( wxT( "VicSanRoPe" ), wxS( "Spanish (ES)" ) );
ADD_TRANSLATOR( wxT( "Iñigo Zuluaga" ), wxS( "Spanish (ES)" ) );
ADD_TRANSLATOR( wxT( "VicSanRoPe" ), wxS( "Spanish - Latin American (ES)" ) );
ADD_TRANSLATOR( wxT( "Ulices Avila Hernandez" ), wxS( "Spanish - Latin American (ES)" ) );
ADD_TRANSLATOR( wxT( "lylythechosenone" ), wxS( "Spanish - Latin American (ES)" ) );
ADD_TRANSLATOR( wxT( "uLe" ), wxS( "Spanish - Latin American (ES)" ) );
ADD_TRANSLATOR( wxT( "VicSanRoPe" ), wxS( "Spanish - Latin American (ES)" ) );
ADD_TRANSLATOR( wxT( "Vesa Solonen" ), wxS( "Finnish (FI)" ) );
ADD_TRANSLATOR( wxT( "Alex Gellen" ), wxS( "Finnish (FI)" ) );
ADD_TRANSLATOR( wxT( "Toni Laiho" ), wxS( "Finnish (FI)" ) );
ADD_TRANSLATOR( wxT( "Henrik Kauhanen" ), wxS( "Finnish (FI)" ) );
ADD_TRANSLATOR( wxT( "Purkka Koodari" ), wxS( "Finnish (FI)" ) );
ADD_TRANSLATOR( wxT( "Toni Laiho" ), wxS( "Finnish (FI)" ) );
ADD_TRANSLATOR( wxT( "J. Lavoie" ), wxS( "Finnish (FI)" ) );
ADD_TRANSLATOR( wxT( "Purkka Koodari" ), wxS( "Finnish (FI)" ) );
ADD_TRANSLATOR( wxT( "Simo Mattila" ), wxS( "Finnish (FI)" ) );
ADD_TRANSLATOR( wxT( "Petri Niemelä" ), wxS( "Finnish (FI)" ) );
ADD_TRANSLATOR( wxT( "Ola Rinta-Koski" ), wxS( "Finnish (FI)" ) );
ADD_TRANSLATOR( wxT( "Vesa Solonen" ), wxS( "Finnish (FI)" ) );
ADD_TRANSLATOR( wxT( "Ricky Tigg" ), wxS( "Finnish (FI)" ) );
ADD_TRANSLATOR( wxT( "Riku Viitanen" ), wxS( "Finnish (FI)" ) );
ADD_TRANSLATOR( wxT( "Jean-Pierre Charras" ), wxS( "French (FR)" ) );
ADD_TRANSLATOR( wxT( "Boromyr" ), wxS( "Italian (IT)" ) );
ADD_TRANSLATOR( wxT( "Marco Ciampa" ), wxS( "Italian (IT)" ) );
ADD_TRANSLATOR( wxT( "Luca Mattii" ), wxS( "Italian (IT)" ) );
ADD_TRANSLATOR( wxT( "2tama3" ), wxS( "Japanese (JA)" ) );
ADD_TRANSLATOR( wxT( "Subaru Arai" ), wxS( "Japanese (JA)" ) );
ADD_TRANSLATOR( wxT( "Ji Yoon Choi" ), wxS( "Japanese (JA)" ) );
ADD_TRANSLATOR( wxT( "Hidemichi Gotou" ), wxS( "Japanese (JA)" ) );
ADD_TRANSLATOR( wxT( "Kinichiro Inoguchi" ), wxS( "Japanese (JA)" ) );
ADD_TRANSLATOR( wxT( "co8 j" ), wxS( "Japanese (JA)" ) );
ADD_TRANSLATOR( wxT( "Keisuke Nakao" ), wxS( "Japanese (JA)" ) );
ADD_TRANSLATOR( wxT( "Norio Suzuki" ), wxS( "Japanese (JA)" ) );
ADD_TRANSLATOR( wxT( "starfort-jp" ), wxS( "Japanese (JA)" ) );
ADD_TRANSLATOR( wxT( "Norio Suzuki" ), wxS( "Japanese (JA)" ) );
ADD_TRANSLATOR( wxT( "Hiroshi Tokita" ), wxS( "Japanese (JA)" ) );
ADD_TRANSLATOR( wxT( "Yutaro Urata" ), wxS( "Japanese (JA)" ) );
ADD_TRANSLATOR( wxT( "Kenta Yonekura" ), wxS( "Japanese (JA)" ) );
ADD_TRANSLATOR( wxT( "Kaoru Zenyouji" ), wxS( "Japanese (JA)" ) );
ADD_TRANSLATOR( wxT( "킴슨김랑기" ), wxS( "Korean (KO)" ) );
ADD_TRANSLATOR( wxT( "Minsu Kim (0xGabriel)" ), wxS( "Korean (KO)" ) );
ADD_TRANSLATOR( wxT( "Ji Yoon Choi" ), wxS( "Korean (KO)" ) );
ADD_TRANSLATOR( wxT( "jeongsuAn" ), wxS( "Korean (KO)" ) );
ADD_TRANSLATOR( wxT( "이상수" ), wxS( "Korean (KO)" ) );
ADD_TRANSLATOR( wxT( "DevAny" ), wxS( "Korean (KO)" ) );
ADD_TRANSLATOR( wxT( "hokim" ), wxS( "Korean (KO)" ) );
ADD_TRANSLATOR( wxT( "jehunseo" ), wxS( "Korean (KO)" ) );
ADD_TRANSLATOR( wxT( "jeong-sangwon" ), wxS( "Korean (KO)" ) );
ADD_TRANSLATOR( wxT( "jeongsuAn" ), wxS( "Korean (KO)" ) );
ADD_TRANSLATOR( wxT( "Uibeom Jung" ), wxS( "Korean (KO)" ) );
ADD_TRANSLATOR( wxT( "kmn4555" ), wxS( "Korean (KO)" ) );
ADD_TRANSLATOR( wxT( "KwonHyeokbeom" ), wxS( "Korean (KO)" ) );
ADD_TRANSLATOR( wxT( "Pedro Moreira" ), wxS( "Korean (KO)" ) );
ADD_TRANSLATOR( wxT( "Jason Son" ), wxS( "Korean (KO)" ) );
ADD_TRANSLATOR( wxT( "YunJiSang" ), wxS( "Korean (KO)" ) );
ADD_TRANSLATOR( wxT( "강명구" ), wxS( "Korean (KO)" ) );
ADD_TRANSLATOR( wxT( "김낙환" ), wxS( "Korean (KO)" ) );
ADD_TRANSLATOR( wxT( "김랑기" ), wxS( "Korean (KO)" ) );
ADD_TRANSLATOR( wxT( "김세영" ), wxS( "Korean (KO)" ) );
ADD_TRANSLATOR( wxT( "김용재" ), wxS( "Korean (KO)" ) );
ADD_TRANSLATOR( wxT( "김유진" ), wxS( "Korean (KO)" ) );
ADD_TRANSLATOR( wxT( "김인수" ), wxS( "Korean (KO)" ) );
ADD_TRANSLATOR( wxT( "김호진" ), wxS( "Korean (KO)" ) );
ADD_TRANSLATOR( wxT( "남우근" ), wxS( "Korean (KO)" ) );
ADD_TRANSLATOR( wxT( "박기정" ), wxS( "Korean (KO)" ) );
ADD_TRANSLATOR( wxT( "박세훈" ), wxS( "Korean (KO)" ) );
ADD_TRANSLATOR( wxT( "박준언" ), wxS( "Korean (KO)" ) );
ADD_TRANSLATOR( wxT( "방준영" ), wxS( "Korean (KO)" ) );
ADD_TRANSLATOR( wxT( "박기정" ), wxS( "Korean (KO)" ) );
ADD_TRANSLATOR( wxT( "hokim" ), wxS( "Korean (KO)" ) );
ADD_TRANSLATOR( wxT( "김낙환" ), wxS( "Korean (KO)" ) );
ADD_TRANSLATOR( wxT( "이기형" ), wxS( "Korean (KO)" ) );
ADD_TRANSLATOR( wxT( "남우근" ), wxS( "Korean (KO)" ) );
ADD_TRANSLATOR( wxT( "강명구" ), wxS( "Korean (KO)" ) );
ADD_TRANSLATOR( wxT( "김용재" ), wxS( "Korean (KO)" ) );
ADD_TRANSLATOR( wxT( "서범기" ), wxS( "Korean (KO)" ) );
ADD_TRANSLATOR( wxT( "김세영" ), wxS( "Korean (KO)" ) );
ADD_TRANSLATOR( wxT( "이기형" ), wxS( "Korean (KO)" ) );
ADD_TRANSLATOR( wxT( "이상수" ), wxS( "Korean (KO)" ) );
ADD_TRANSLATOR( wxT( "이윤성" ), wxS( "Korean (KO)" ) );
ADD_TRANSLATOR( wxT( "김랑기" ), wxS( "Korean (KO)" ) );
ADD_TRANSLATOR( wxT( "KwonHyeokbeom" ), wxS( "Korean (KO)" ) );
ADD_TRANSLATOR( wxT( "Minsu Kim (0xGabriel)" ), wxS( "Korean (KO)" ) );
ADD_TRANSLATOR( wxT( "Pedro Moreira" ), wxS( "Korean (KO)" ) );
ADD_TRANSLATOR( wxT( "jeong-sangwon" ), wxS( "Korean (KO)" ) );
ADD_TRANSLATOR( wxT( "킴슨김랑기" ), wxS( "Korean (KO)" ) );
ADD_TRANSLATOR( wxT( "Ignas Brašiškis" ), wxS( "Lithuanian (LT)" ) );
ADD_TRANSLATOR( wxT( "Henrik Kauhanen" ), wxS( "Lithuanian (LT)" ) );
ADD_TRANSLATOR( wxT( "Dainius Mazuika" ), wxS( "Lithuanian (LT)" ) );
ADD_TRANSLATOR( wxT( "WhiteChairFromIkea" ), wxS( "Lithuanian (LT)" ) );
ADD_TRANSLATOR( wxT( "Stefan De Raedemaeker" ), wxS( "Dutch (NL)" ) );
ADD_TRANSLATOR( wxT( "Arend-Jan van Hilten" ), wxS( "Dutch (NL)" ) );
ADD_TRANSLATOR( wxT( "CJ van der Hoeven" ), wxS( "Dutch (NL)" ) );
ADD_TRANSLATOR( wxT( "Laurens Holst" ), wxS( "Dutch (NL)" ) );
ADD_TRANSLATOR( wxT( "Pim Jansen" ), wxS( "Dutch (NL)" ) );
ADD_TRANSLATOR( wxT( "Robin Janssens" ), wxS( "Dutch (NL)" ) );
ADD_TRANSLATOR( wxT( "johanneswilkens" ), wxS( "Dutch (NL)" ) );
ADD_TRANSLATOR( wxT( "Henrik Kauhanen" ), wxS( "Dutch (NL)" ) );
ADD_TRANSLATOR( wxT( "Tom Niesse" ), wxS( "Dutch (NL)" ) );
ADD_TRANSLATOR( wxT( "Christiaan Nieuwlaat" ), wxS( "Dutch (NL)" ) );
ADD_TRANSLATOR( wxT( "Stefan De Raedemaeker" ), wxS( "Dutch (NL)" ) );
ADD_TRANSLATOR( wxT( "Ranforingus" ), wxS( "Dutch (NL)" ) );
ADD_TRANSLATOR( wxT( "CJ van der Hoeven" ), wxS( "Dutch (NL)" ) );
ADD_TRANSLATOR( wxT( "Arend-Jan van Hilten" ), wxS( "Dutch (NL)" ) );
ADD_TRANSLATOR( wxT( "Herman van der Vaart" ), wxS( "Dutch (NL)" ) );
ADD_TRANSLATOR( wxT( "Bas Wijnen" ), wxS( "Dutch (NL)" ) );
ADD_TRANSLATOR( wxT( "Jarl Gjessing" ), wxS( "Norwegian (NO)" ) );
ADD_TRANSLATOR( wxT( "Henrik Kauhanen" ), wxS( "Norwegian (NO)" ) );
ADD_TRANSLATOR( wxT( "Stian Kristensen" ), wxS( "Norwegian (NO)" ) );
ADD_TRANSLATOR( wxT( "Allan Nordhøy" ), wxS( "Norwegian (NO)" ) );
ADD_TRANSLATOR( wxT( "Petter Reinholdtsen" ), wxS( "Norwegian (NO)" ) );
ADD_TRANSLATOR( wxT( "Håvard Syslak" ), wxS( "Norwegian (NO)" ) );
ADD_TRANSLATOR( wxT( "Ivan Chuba" ), wxS( "Polish (PL)" ) );
ADD_TRANSLATOR( wxT( "Czam Ciał" ), wxS( "Polish (PL)" ) );
ADD_TRANSLATOR( wxT( "Kerusey Karyu" ), wxS( "Polish (PL)" ) );
ADD_TRANSLATOR( wxT( "Krzysztof Kawa" ), wxS( "Polish (PL)" ) );
ADD_TRANSLATOR( wxT( "J Kolod" ), wxS( "Polish (PL)" ) );
ADD_TRANSLATOR( wxT( "maksz42" ), wxS( "Polish (PL)" ) );
ADD_TRANSLATOR( wxT( "Eryk Michalak" ), wxS( "Polish (PL)" ) );
ADD_TRANSLATOR( wxT( "Filip Piękoś" ), wxS( "Polish (PL)" ) );
ADD_TRANSLATOR( wxT( "Pomian" ), wxS( "Polish (PL)" ) );
ADD_TRANSLATOR( wxT( "Mark Roszko" ), wxS( "Polish (PL)" ) );
ADD_TRANSLATOR( wxT( "Mateusz Skowroński" ), wxS( "Polish (PL)" ) );
ADD_TRANSLATOR( wxT( "Jan Sobków" ), wxS( "Polish (PL)" ) );
ADD_TRANSLATOR( wxT( "szumsky" ), wxS( "Polish (PL)" ) );
ADD_TRANSLATOR( wxT( "Grzegorz Szymaszek" ), wxS( "Polish (PL)" ) );
ADD_TRANSLATOR( wxT( "ZbeeGin" ), wxS( "Polish (PL)" ) );
ADD_TRANSLATOR( wxT( "brunofaus" ), wxS( "Brazilian Portuguese (PT_BR)" ) );
ADD_TRANSLATOR( wxT( "Augusto Fraga Giachero" ), wxS( "Brazilian Portuguese (PT_BR)" ) );
ADD_TRANSLATOR( wxT( "Hildo Guillardi Júnior" ), wxS( "Brazilian Portuguese (PT_BR)" ) );
ADD_TRANSLATOR( wxT( "Pedro Moreira" ), wxS( "Brazilian Portuguese (PT_BR)" ) );
ADD_TRANSLATOR( wxT( "soldado-do-wolfenstein" ), wxS( "Brazilian Portuguese (PT_BR)" ) );
ADD_TRANSLATOR( wxT( "Wellington Terumi Uemura" ), wxS( "Brazilian Portuguese (PT_BR)" ) );
ADD_TRANSLATOR( wxT( "Julio Dias" ), wxS( "Portuguese (PT)" ) );
ADD_TRANSLATOR( wxT( "Augusto Fraga Giachero" ), wxS( "Portuguese (PT)" ) );
ADD_TRANSLATOR( wxT( "Hildo Guillardi Júnior" ), wxS( "Portuguese (PT)" ) );
ADD_TRANSLATOR( wxT( "leonardokr" ), wxS( "Portuguese (PT)" ) );
ADD_TRANSLATOR( wxT( "Renie Marquet" ), wxS( "Portuguese (PT)" ) );
ADD_TRANSLATOR( wxT( "Rafael Silva" ), wxS( "Portuguese (PT)" ) );
ADD_TRANSLATOR( wxT( "Manuela Silva" ), wxS( "Portuguese (PT)" ) );
ADD_TRANSLATOR( wxT( "ssantos" ), wxS( "Portuguese (PT)" ) );
ADD_TRANSLATOR( wxT( "Konstantin Baranovskiy" ), wxS( "Russian (RU)" ) );
ADD_TRANSLATOR( wxT( "Дмитрий Дёмин" ), wxS( "Russian (RU)" ) );
ADD_TRANSLATOR( wxT( "Ivan Chuba" ), wxS( "Russian (RU)" ) );
ADD_TRANSLATOR( wxT( "Andrey Fedorushkov" ), wxS( "Russian (RU)" ) );
ADD_TRANSLATOR( wxT( "Free_squire" ), wxS( "Russian (RU)" ) );
ADD_TRANSLATOR( wxT( "Alevtina Karashokova" ), wxS( "Russian (RU)" ) );
ADD_TRANSLATOR( wxT( "Eldar Khayrullin" ), wxS( "Russian (RU)" ) );
ADD_TRANSLATOR( wxT( "Alex Life" ), wxS( "Russian (RU)" ) );
ADD_TRANSLATOR( wxT( "Dmitry Mikhirev" ), wxS( "Russian (RU)" ) );
ADD_TRANSLATOR( wxT( "Igor Plyatov" ), wxS( "Russian (RU)" ) );
ADD_TRANSLATOR( wxT( "sergio" ), wxS( "Russian (RU)" ) );
ADD_TRANSLATOR( wxT( "xXx" ), wxS( "Russian (RU)" ) );
ADD_TRANSLATOR( wxT( "Дмитрий Дёмин" ), wxS( "Russian (RU)" ) );
ADD_TRANSLATOR( wxT( "МАН69К" ), wxS( "Russian (RU)" ) );
ADD_TRANSLATOR( wxT( "Hanna Breisand" ), wxS( "Swedish (SV)" ) );
ADD_TRANSLATOR( wxT( "Stefan Bjornelund the Gnome" ), wxS( "Swedish (SV)" ) );
ADD_TRANSLATOR( wxT( "Johan Heikkilä" ), wxS( "Swedish (SV)" ) );
ADD_TRANSLATOR( wxT( "Axel Henriksson" ), wxS( "Swedish (SV)" ) );
ADD_TRANSLATOR( wxT( "Richard Jonsson" ), wxS( "Swedish (SV)" ) );
ADD_TRANSLATOR( wxT( "Henrik Kauhanen" ), wxS( "Swedish (SV)" ) );
ADD_TRANSLATOR( wxT( "Joakim Lundborg" ), wxS( "Swedish (SV)" ) );
ADD_TRANSLATOR( wxT( "Allan Nordhøy" ), wxS( "Swedish (SV)" ) );
ADD_TRANSLATOR( wxT( "Elias Sjögreen" ), wxS( "Swedish (SV)" ) );
@@ -814,40 +899,131 @@ static void buildKicadAboutBanner( EDA_BASE_FRAME* aParent, ABOUT_APP_INFO& aInf
ADD_TRANSLATOR( wxT( "Stanislav Kaliuk" ), wxS( "Ukrainian (UK)" ) );
ADD_TRANSLATOR( wxT( "Alexsandr Kuzemko" ), wxS( "Ukrainian (UK)" ) );
ADD_TRANSLATOR( wxT( "Andrii Shelestov" ), wxS( "Ukrainian (UK)" ) );
ADD_TRANSLATOR( wxT( "Максим Горпиніч" ), wxS( "Ukrainian (UK)" ) );
ADD_TRANSLATOR( wxT( "欠陥電気" ), wxS( "Simplified Chinese (zh_CN)" ) );
ADD_TRANSLATOR( wxT( "向阳阳" ), wxS( "Simplified Chinese (zh_CN)" ) );
ADD_TRANSLATOR( wxT( "CharlieYu" ), wxS( "Simplified Chinese (zh_CN)" ) );
ADD_TRANSLATOR( wxT( "David Chen" ), wxS( "Simplified Chinese (zh_CN)" ) );
ADD_TRANSLATOR( wxT( "Dingzhong Chen" ), wxS( "Simplified Chinese (zh_CN)" ) );
ADD_TRANSLATOR( wxT( "CloverGit" ), wxS( "Simplified Chinese (zh_CN)" ) );
ADD_TRANSLATOR( wxT( "Eric" ), wxS( "Simplified Chinese (zh_CN)" ) );
ADD_TRANSLATOR( wxT( "Hubert Hu" ), wxS( "Simplified Chinese (zh_CN)" ) );
ADD_TRANSLATOR( wxT( "Liu Guang" ), wxS( "Simplified Chinese (zh_CN)" ) );
ADD_TRANSLATOR( wxT( "HalfSweet" ), wxS( "Simplified Chinese (zh_CN)" ) );
ADD_TRANSLATOR( wxT( "Huanyin Liu" ), wxS( "Simplified Chinese (zh_CN)" ) );
ADD_TRANSLATOR( wxT( "Hubert Hu" ), wxS( "Simplified Chinese (zh_CN)" ) );
ADD_TRANSLATOR( wxT( "aisuneko icecat" ), wxS( "Simplified Chinese (zh_CN)" ) );
ADD_TRANSLATOR( wxT( "Pinpang Liao" ), wxS( "Simplified Chinese (zh_CN)" ) );
ADD_TRANSLATOR( wxT( "Rigo Ligo" ), wxS( "Simplified Chinese (zh_CN)" ) );
ADD_TRANSLATOR( wxT( "Huanyin Liu" ), wxS( "Simplified Chinese (zh_CN)" ) );
ADD_TRANSLATOR( wxT( "Zhen Sun" ), wxS( "Simplified Chinese (zh_CN)" ) );
ADD_TRANSLATOR( wxT( "Jason Tan" ), wxS( "Simplified Chinese (zh_CN)" ) );
ADD_TRANSLATOR( wxT( "Taotieren" ), wxS( "Simplified Chinese (zh_CN)" ) );
ADD_TRANSLATOR( wxT( "Tian Yunhao" ), wxS( "Simplified Chinese (zh_CN)" ) );
ADD_TRANSLATOR( wxT( "Li Yidong" ), wxS( "Simplified Chinese (zh_CN)" ) );
ADD_TRANSLATOR( wxT( "yangyangdaji" ), wxS( "Simplified Chinese (zh_CN)" ) );
ADD_TRANSLATOR( wxT( "Li Yi" ), wxS( "Simplified Chinese (zh_CN)" ) );
ADD_TRANSLATOR( wxT( "Li Yidong" ), wxS( "Simplified Chinese (zh_CN)" ) );
ADD_TRANSLATOR( wxT( "Tian Yunhao" ), wxS( "Simplified Chinese (zh_CN)" ) );
ADD_TRANSLATOR( wxT( "Lao Zhu" ), wxS( "Simplified Chinese (zh_CN)" ) );
ADD_TRANSLATOR( wxT( "yanzhen zhu" ), wxS( "Simplified Chinese (zh_CN)" ) );
ADD_TRANSLATOR( wxT( "zly20129" ), wxS( "Simplified Chinese (zh_CN)" ) );
ADD_TRANSLATOR( wxT( "向阳阳" ), wxS( "Simplified Chinese (zh_CN)" ) );
ADD_TRANSLATOR( wxT( "欠陥電気" ), wxS( "Simplified Chinese (zh_CN)" ) );
ADD_TRANSLATOR( wxT( "撒景賢" ), wxS( "Traditional Chinese (zh_TW)" ) );
ADD_TRANSLATOR( wxT( "David Chen" ), wxS( "Traditional Chinese (zh_TW)" ) );
ADD_TRANSLATOR( wxT( "pon dahai" ), wxS( "Traditional Chinese (zh_TW)" ) );
ADD_TRANSLATOR( wxT( "kai chiao chuang" ), wxS( "Traditional Chinese (zh_TW)" ) );
ADD_TRANSLATOR( wxT( "pon dahai" ), wxS( "Traditional Chinese (zh_TW)" ) );
ADD_TRANSLATOR( wxT( "Shuwn Hsu" ), wxS( "Traditional Chinese (zh_TW)" ) );
ADD_TRANSLATOR( wxT( "Poming Lee" ), wxS( "Traditional Chinese (zh_TW)" ) );
ADD_TRANSLATOR( wxT( "William Lin" ), wxS( "Traditional Chinese (zh_TW)" ) );
ADD_TRANSLATOR( wxT( "Oliver0804" ), wxS( "Traditional Chinese (zh_TW)" ) );
ADD_TRANSLATOR( wxT( "reimu105" ), wxS( "Traditional Chinese (zh_TW)" ) );
ADD_TRANSLATOR( wxT( "Che-Hsien Su" ), wxS( "Traditional Chinese (zh_TW)" ) );
ADD_TRANSLATOR( wxT( "Taotieren" ), wxS( "Traditional Chinese (zh_TW)" ) );
ADD_TRANSLATOR( wxT( "Li Yidong" ), wxS( "Traditional Chinese (zh_TW)" ) );
ADD_TRANSLATOR( wxT( "撒景賢" ), wxS( "Traditional Chinese (zh_TW)" ) );
ADD_TRANSLATOR( wxT( "Hesham Eina Abdalla" ), wxS( "Arabic (AR)" ) );
ADD_TRANSLATOR( wxT( "Djamel Dellaa" ), wxS( "Arabic (AR)" ) );
ADD_TRANSLATOR( wxT( "Ahmed Elswah" ), wxS( "Arabic (AR)" ) );
ADD_TRANSLATOR( wxT( "HADJAISSA" ), wxS( "Arabic (AR)" ) );
ADD_TRANSLATOR( wxT( "Morad Tamer" ), wxS( "Arabic (AR)" ) );
ADD_TRANSLATOR( wxT( "Adolfo Jayme Barrientos" ), wxS( "Catalan (CA)" ) );
ADD_TRANSLATOR( wxT( "Marc de Miguel" ), wxS( "Catalan (CA)" ) );
ADD_TRANSLATOR( wxT( "Rafael Serrano" ), wxS( "Catalan (CA)" ) );
ADD_TRANSLATOR( wxT( "Arnau Llovet Vidal" ), wxS( "Catalan (CA)" ) );
ADD_TRANSLATOR( wxT( "Ivan Chuba" ), wxS( "Estonian (ET)" ) );
ADD_TRANSLATOR( wxT( "Temuri Doghonadze" ), wxS( "Georgian (KA)" ) );
ADD_TRANSLATOR( wxT( "Viktor Döme" ), wxS( "Hungarian (HU)" ) );
ADD_TRANSLATOR( wxT( "István Farkas" ), wxS( "Hungarian (HU)" ) );
ADD_TRANSLATOR( wxT( "Flórián Fuszkó" ), wxS( "Hungarian (HU)" ) );
ADD_TRANSLATOR( wxT( "Sárkány Lőrinc" ), wxS( "Hungarian (HU)" ) );
ADD_TRANSLATOR( wxT( "Miklós Márton" ), wxS( "Hungarian (HU)" ) );
ADD_TRANSLATOR( wxT( "Balázs Meskó" ), wxS( "Hungarian (HU)" ) );
ADD_TRANSLATOR( wxT( "Hajdu Norbert" ), wxS( "Hungarian (HU)" ) );
ADD_TRANSLATOR( wxT( "Elek Zoltán" ), wxS( "Hungarian (HU)" ) );
ADD_TRANSLATOR( wxT( "Reza Almanda" ), wxS( "Indonesian (ID)" ) );
ADD_TRANSLATOR( wxT( "Jacque Fresco" ), wxS( "Indonesian (ID)" ) );
ADD_TRANSLATOR( wxT( "Neko Nekowazarashi" ), wxS( "Indonesian (ID)" ) );
ADD_TRANSLATOR( wxT( "Triyan W. Nugroho" ), wxS( "Indonesian (ID)" ) );
ADD_TRANSLATOR( wxT( "Rihards Skuja" ), wxS( "Latvian (LV)" ) );
ADD_TRANSLATOR( wxT( "Mahdi Ahmadzadeh" ), wxS( "Persian (FA)" ) );
ADD_TRANSLATOR( wxT( "Nicoara Alex" ), wxS( "Romanian (RO)" ) );
ADD_TRANSLATOR( wxT( "Tatu Bogdan" ), wxS( "Romanian (RO)" ) );
ADD_TRANSLATOR( wxT( "Alex Gellen" ), wxS( "Romanian (RO)" ) );
ADD_TRANSLATOR( wxT( "Adrian Scripcă" ), wxS( "Romanian (RO)" ) );
ADD_TRANSLATOR( wxT( "Luka Borkovic" ), wxS( "Serbian (SR)" ) );
ADD_TRANSLATOR( wxT( "David Chorváth" ), wxS( "Slovak (SK)" ) );
ADD_TRANSLATOR( wxT( "Marcel Hecko" ), wxS( "Slovak (SK)" ) );
ADD_TRANSLATOR( wxT( "Jakub Janek" ), wxS( "Slovak (SK)" ) );
ADD_TRANSLATOR( wxT( "Andrej Valek" ), wxS( "Slovak (SK)" ) );
ADD_TRANSLATOR( wxT( "Sašo Domadenik" ), wxS( "Slovenian (SI)" ) );
ADD_TRANSLATOR( wxT( "Vitan Košpenda" ), wxS( "Slovenian (SI)" ) );
ADD_TRANSLATOR( wxT( "Mitja Nemec" ), wxS( "Slovenian (SI)" ) );
ADD_TRANSLATOR( wxT( "தமிழ்நேரம்" ), wxS( "Tamil (TA)" ) );
ADD_TRANSLATOR( wxT( "YÜKSEL AÇIKGÖZ" ), wxS( "Turkish (TR)" ) );
ADD_TRANSLATOR( wxT( "Argeolog" ), wxS( "Turkish (TR)" ) );
ADD_TRANSLATOR( wxT( "Mahsum Aslan" ), wxS( "Turkish (TR)" ) );
ADD_TRANSLATOR( wxT( "Tevfik Bagcivan" ), wxS( "Turkish (TR)" ) );
ADD_TRANSLATOR( wxT( "Bahtiyar Bayram" ), wxS( "Turkish (TR)" ) );
ADD_TRANSLATOR( wxT( "Marine Biologist" ), wxS( "Turkish (TR)" ) );
ADD_TRANSLATOR( wxT( "Mustafa Selçuk ÇAVDAR" ), wxS( "Turkish (TR)" ) );
ADD_TRANSLATOR( wxT( "dogukansahil" ), wxS( "Turkish (TR)" ) );
ADD_TRANSLATOR( wxT( "Erkan" ), wxS( "Turkish (TR)" ) );
ADD_TRANSLATOR( wxT( "Oğuz Ersen" ), wxS( "Turkish (TR)" ) );
ADD_TRANSLATOR( wxT( "İclal Gör" ), wxS( "Turkish (TR)" ) );
ADD_TRANSLATOR( wxT( "Mert Gülsoy" ), wxS( "Turkish (TR)" ) );
ADD_TRANSLATOR( wxT( "Mert Kalkancı" ), wxS( "Turkish (TR)" ) );
ADD_TRANSLATOR( wxT( "metin kiruc" ), wxS( "Turkish (TR)" ) );
ADD_TRANSLATOR( wxT( "Gökhan Koçmarlı" ), wxS( "Turkish (TR)" ) );
ADD_TRANSLATOR( wxT( "Niyazi" ), wxS( "Turkish (TR)" ) );
ADD_TRANSLATOR( wxT( "Ahmet Saygın ÖĞÜLMÜŞ" ), wxS( "Turkish (TR)" ) );
ADD_TRANSLATOR( wxT( "Ertuğrul Reisoğlu" ), wxS( "Turkish (TR)" ) );
ADD_TRANSLATOR( wxT( "Murat Ursavaş" ), wxS( "Turkish (TR)" ) );
ADD_TRANSLATOR( wxT( "VEDAT YAMAN" ), wxS( "Turkish (TR)" ) );
ADD_TRANSLATOR( wxT( "Nguyen Van Dien" ), wxS( "Vietnamese (VI)" ) );
ADD_TRANSLATOR( wxT( "Trần Phi Hải" ), wxS( "Vietnamese (VI)" ) );
ADD_TRANSLATOR( wxT( "Nguyễn Ngọc Khánh" ), wxS( "Vietnamese (VI)" ) );
ADD_TRANSLATOR( wxT( "lê văn lập" ), wxS( "Vietnamese (VI)" ) );
ADD_TRANSLATOR( wxT( "Bế Trọng Nghĩa" ), wxS( "Vietnamese (VI)" ) );
ADD_TRANSLATOR( wxT( "An Nguyen" ), wxS( "Vietnamese (VI)" ) );
ADD_TRANSLATOR( wxT( "Phạm Minh Tấn" ), wxS( "Vietnamese (VI)" ) );
ADD_TRANSLATOR( wxT( "Remy Halvick" ), wxS( "Other" ) );
ADD_TRANSLATOR( wxS( "David J S Briscoe" ), wxS( "Other" ) );
ADD_TRANSLATOR( wxS( "Dominique Laigle" ), wxS( "Other" ) );
ADD_TRANSLATOR( wxS( "Paul Burke" ), wxS( "Other" ) );
ADD_TRANSLATOR( wxT( "Remy Halvick" ), wxS( "Other" ) );
ADD_TRANSLATOR( wxS( "Dominique Laigle" ), wxS( "Other" ) );
// Program credits for library team
@@ -0,0 +1,197 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright The 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, you may find one here:
* http://www.gnu.org/licenses/gpl-3.0.html
* or you may search the http://www.gnu.org website for the version 3 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include "dialog_restore_local_history.h"
#include <wx/button.h>
#include <wx/listctrl.h>
#include <wx/sizer.h>
#include <wx/textctrl.h>
DIALOG_RESTORE_LOCAL_HISTORY::DIALOG_RESTORE_LOCAL_HISTORY(
wxWindow* aParent, const std::vector<LOCAL_HISTORY_SNAPSHOT_INFO>& aSnapshots ) :
DIALOG_SHIM( aParent, wxID_ANY, _( "Restore Project from Local History..." ) ),
m_snapshots( aSnapshots )
{
BuildUi();
Populate();
Centre();
}
void DIALOG_RESTORE_LOCAL_HISTORY::BuildUi()
{
m_list = new wxListCtrl( this, wxID_ANY, wxDefaultPosition, wxDefaultSize,
wxLC_HRULES | wxLC_REPORT | wxLC_SINGLE_SEL | wxLC_VRULES );
m_list->AppendColumn( _( "Time" ) );
m_list->AppendColumn( _( "Action" ) );
m_list->AppendColumn( _( "Count" ) );
m_details = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize,
wxTE_MULTILINE | wxTE_READONLY );
wxStdDialogButtonSizer* buttons = new wxStdDialogButtonSizer();
m_restoreButton = new wxButton( this, wxID_OK, _( "Restore" ) );
m_restoreButton->Enable( false );
m_restoreButton->Bind( wxEVT_BUTTON, &DIALOG_RESTORE_LOCAL_HISTORY::OnRestoreClicked, this );
buttons->AddButton( m_restoreButton );
buttons->AddButton( new wxButton( this, wxID_CANCEL ) );
buttons->Realize();
wxBoxSizer* topSizer = new wxBoxSizer( wxVERTICAL );
topSizer->Add( m_list, 1, wxEXPAND | wxALL, 5 );
topSizer->Add( m_details, 1, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5 );
topSizer->Add( buttons, 0, wxEXPAND | wxALL, 5 );
SetSizerAndFit( topSizer );
SetMinSize( FromDIP( wxSize( 700, 500 ) ) );
m_list->Bind( wxEVT_LIST_ITEM_SELECTED, &DIALOG_RESTORE_LOCAL_HISTORY::OnSelectionChanged, this );
m_list->Bind( wxEVT_LIST_ITEM_ACTIVATED, &DIALOG_RESTORE_LOCAL_HISTORY::OnItemActivated, this );
}
void DIALOG_RESTORE_LOCAL_HISTORY::Populate()
{
for( size_t i = 0; i < m_snapshots.size(); ++i )
{
const auto& snapshot = m_snapshots[i];
long row = m_list->InsertItem( m_list->GetItemCount(), snapshot.date.FormatISOCombined() );
wxString countText =
snapshot.filesChanged > 0 ? wxString::Format( "%d", snapshot.filesChanged ) : wxString( "-" );
m_list->SetItem( row, 1, snapshot.summary );
m_list->SetItem( row, 2, countText );
}
m_list->SetColumnWidth( 0, FromDIP( 170 ) );
m_list->SetColumnWidth( 1, FromDIP( 380 ) );
m_list->SetColumnWidth( 2, FromDIP( 70 ) );
m_details->Clear();
m_selectedIndex = wxNOT_FOUND;
m_selectedHash.clear();
if( m_restoreButton )
m_restoreButton->Enable( false );
}
void DIALOG_RESTORE_LOCAL_HISTORY::UpdateDetails( long aIndex )
{
if( aIndex < 0 || aIndex >= static_cast<long>( m_snapshots.size() ) )
return;
const auto& snapshot = m_snapshots[aIndex];
wxString text;
text << snapshot.summary << "\n";
text << snapshot.date.FormatISOCombined() << "\n";
text << snapshot.hash;
if( !snapshot.changedFiles.empty() )
text << "\n\n";
for( size_t ii = 0; ii < snapshot.changedFiles.size(); ++ii )
{
if( ii > 0 )
text << "\n";
text << snapshot.changedFiles[ii];
}
m_details->SetValue( text );
}
wxString DIALOG_RESTORE_LOCAL_HISTORY::GetSelectedHash() const
{
if( m_selectedIndex == wxNOT_FOUND || m_selectedIndex >= static_cast<long>( m_snapshots.size() ) )
{
return wxEmptyString;
}
return m_snapshots[m_selectedIndex].hash;
}
void DIALOG_RESTORE_LOCAL_HISTORY::OnSelectionChanged( wxListEvent& aEvent )
{
long selected = m_list->GetNextItem( -1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED );
if( selected == wxNOT_FOUND )
{
m_selectedIndex = wxNOT_FOUND;
m_selectedHash.clear();
m_details->Clear();
if( m_restoreButton )
m_restoreButton->Enable( false );
}
else
{
m_selectedIndex = selected;
m_selectedHash = m_snapshots[selected].hash;
UpdateDetails( selected );
if( m_restoreButton )
m_restoreButton->Enable( true );
}
aEvent.Skip();
}
void DIALOG_RESTORE_LOCAL_HISTORY::OnItemActivated( wxListEvent& aEvent )
{
long index = aEvent.GetIndex();
if( index >= 0 && index < static_cast<long>( m_snapshots.size() ) )
{
m_selectedIndex = index;
m_selectedHash = m_snapshots[index].hash;
UpdateDetails( index );
}
if( !m_selectedHash.IsEmpty() )
EndModal( wxID_OK );
}
void DIALOG_RESTORE_LOCAL_HISTORY::OnRestoreClicked( wxCommandEvent& aEvent )
{
long index = m_list->GetNextItem( -1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED );
if( index == wxNOT_FOUND )
index = m_list->GetNextItem( -1, wxLIST_NEXT_ALL, wxLIST_STATE_FOCUSED );
if( index == wxNOT_FOUND || index >= static_cast<long>( m_snapshots.size() ) )
return;
m_selectedIndex = index;
m_selectedHash = m_snapshots[index].hash;
aEvent.Skip();
}
@@ -0,0 +1,56 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright The 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, you may find one here:
* http://www.gnu.org/licenses/gpl-3.0.html
* or you may search the http://www.gnu.org website for the version 3 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#pragma once
#include <dialog_shim.h>
#include <local_history.h>
class wxButton;
class wxCommandEvent;
class wxListCtrl;
class wxListEvent;
class wxTextCtrl;
class DIALOG_RESTORE_LOCAL_HISTORY : public DIALOG_SHIM
{
public:
DIALOG_RESTORE_LOCAL_HISTORY( wxWindow* aParent, const std::vector<LOCAL_HISTORY_SNAPSHOT_INFO>& aSnapshots );
wxString GetSelectedHash() const;
private:
void BuildUi();
void Populate();
void UpdateDetails( long aIndex );
void OnSelectionChanged( wxListEvent& aEvent );
void OnItemActivated( wxListEvent& aEvent );
void OnRestoreClicked( wxCommandEvent& aEvent );
const std::vector<LOCAL_HISTORY_SNAPSHOT_INFO>& m_snapshots;
wxListCtrl* m_list = nullptr;
wxTextCtrl* m_details = nullptr;
wxButton* m_restoreButton = nullptr;
long m_selectedIndex = wxNOT_FOUND;
wxString m_selectedHash;
};
@@ -18,7 +18,7 @@ PANEL_STARTWIZARD_LIBRARIES_BASE::PANEL_STARTWIZARD_LIBRARIES_BASE( wxWindow* pa
bSizer8 = new wxBoxSizer( wxVERTICAL );
m_stIntro = new wxStaticText( this, wxID_ANY, _("KiCad comes with a large set of symbol and footprint libraries maintained by the KiCad librarian team. You may also create your own libraries, and install third-party ones from the Plugin and Content Manager or other sources.\n\nLibrary tables are the configuration files which list the libraries to be loaded. Global libraries are available in every project, and you may also add project-specific libraries if desired."), wxDefaultPosition, wxDefaultSize, 0 );
m_stIntro->Wrap( 540 );
m_stIntro->Wrap( -1 );
bSizer8->Add( m_stIntro, 0, wxALL|wxEXPAND, 5 );
m_stRequiredTablesLabel = new wxStaticText( this, wxID_ANY, _("<b>The following global library tables need to be created:</b>"), wxDefaultPosition, wxDefaultSize, 0 );
@@ -61,7 +61,7 @@ PANEL_STARTWIZARD_LIBRARIES_BASE::PANEL_STARTWIZARD_LIBRARIES_BASE( wxWindow* pa
m_sizerWarning->Add( m_bmpWarning, 0, wxALL, 4 );
m_stWarning = new wxStaticText( this, wxID_ANY, _("The built-in library tables could not be found in the expected location. This usually means that you have installed the KiCad software without also installing the libraries. You can proceed with setup, but you will need to install the libraries separately in order for them to be available."), wxDefaultPosition, wxDefaultSize, 0 );
m_stWarning->Wrap( 540 );
m_stWarning->Wrap( -1 );
m_sizerWarning->Add( m_stWarning, 0, wxALL, 5 );
@@ -73,8 +73,15 @@ PANEL_STARTWIZARD_LIBRARIES_BASE::PANEL_STARTWIZARD_LIBRARIES_BASE( wxWindow* pa
this->SetSizer( bPanelSizer );
this->Layout();
bPanelSizer->Fit( this );
// Connect Events
this->Connect( wxEVT_SIZE, wxSizeEventHandler( PANEL_STARTWIZARD_LIBRARIES_BASE::OnSize ) );
}
PANEL_STARTWIZARD_LIBRARIES_BASE::~PANEL_STARTWIZARD_LIBRARIES_BASE()
{
// Disconnect Events
this->Disconnect( wxEVT_SIZE, wxSizeEventHandler( PANEL_STARTWIZARD_LIBRARIES_BASE::OnSize ) );
}
@@ -48,13 +48,14 @@
<property name="minimum_size"></property>
<property name="name">PANEL_STARTWIZARD_LIBRARIES_BASE</property>
<property name="pos"></property>
<property name="size">550,-1</property>
<property name="size">-1,-1</property>
<property name="subclass"></property>
<property name="tooltip"></property>
<property name="two_step_creation">0</property>
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style">wxTAB_TRAVERSAL</property>
<event name="OnSize">OnSize</event>
<object class="wxBoxSizer" expanded="true">
<property name="minimum_size"></property>
<property name="name">bPanelSizer</property>
@@ -128,7 +129,7 @@
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style"></property>
<property name="wrap">540</property>
<property name="wrap">-1</property>
</object>
</object>
<object class="sizeritem" expanded="true">
@@ -659,7 +660,7 @@
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style"></property>
<property name="wrap">540</property>
<property name="wrap">-1</property>
</object>
</object>
</object>
@@ -45,9 +45,13 @@ class PANEL_STARTWIZARD_LIBRARIES_BASE : public wxPanel
wxStaticBitmap* m_bmpWarning;
wxStaticText* m_stWarning;
// Virtual event handlers, override them in your derived class
virtual void OnSize( wxSizeEvent& event ) { event.Skip(); }
public:
PANEL_STARTWIZARD_LIBRARIES_BASE( wxWindow* parent, wxWindowID id = wxID_ANY, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( 550,-1 ), long style = wxTAB_TRAVERSAL, const wxString& name = wxEmptyString );
PANEL_STARTWIZARD_LIBRARIES_BASE( wxWindow* parent, wxWindowID id = wxID_ANY, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( -1,-1 ), long style = wxTAB_TRAVERSAL, const wxString& name = wxEmptyString );
~PANEL_STARTWIZARD_LIBRARIES_BASE();
+96 -92
View File
@@ -43,6 +43,7 @@
#include <launch_ext.h>
#include <algorithm>
#include <dialogs/rule_editor_dialog_base.h>
#include <widgets/std_bitmap_button.h>
static wxSearchCtrl* CreateTextFilterBox( wxWindow* aParent, const wxString& aDescriptiveText )
@@ -75,6 +76,7 @@ RULE_EDITOR_DIALOG_BASE::RULE_EDITOR_DIALOG_BASE( wxWindow* aParent, const wxStr
m_enableDuplicateRule( false ),
m_enableDeleteRule( false ),
m_modified( false ),
m_suppressSelectionEvents( false ),
m_defaultSashPosition( 200 ),
m_title( aTitle ),
m_selectedData( nullptr ),
@@ -91,59 +93,50 @@ RULE_EDITOR_DIALOG_BASE::RULE_EDITOR_DIALOG_BASE( wxWindow* aParent, const wxStr
// Add the tree panel to the content sizer
m_splitter = new wxSplitterWindow( this, wxID_ANY, wxDefaultPosition, wxDefaultSize,
wxSP_3D | wxSP_LIVE_UPDATE | wxSP_3DSASH );
wxBORDER_NONE | wxSP_LIVE_UPDATE | wxSP_3DSASH );
m_splitter->SetMinimumPaneSize( 50 ); // Set a minimum pane size
// Create the tree control panel
WX_PANEL* treeCtrlPanel =
new WX_PANEL( m_splitter, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxBORDER_NONE | wxTAB_TRAVERSAL );
treeCtrlPanel->SetBorders( true, true, true, true );
WX_PANEL* treeCtrlPanel = new WX_PANEL( m_splitter, wxID_ANY, wxDefaultPosition, wxDefaultSize,
wxBORDER_NONE | wxTAB_TRAVERSAL );
treeCtrlPanel->SetBorders( false, false, false, true );
wxBoxSizer* treeCtrlSizer = new wxBoxSizer( wxVERTICAL );
treeCtrlPanel->SetSizer( treeCtrlSizer );
// Add a search text box above the tree control
m_filterSearch = CreateTextFilterBox( treeCtrlPanel, _( "Type filter text" ) );
treeCtrlSizer->Add( m_filterSearch, 0, wxEXPAND | wxBOTTOM, 5 );
treeCtrlSizer->Add( m_filterSearch, 0, wxEXPAND, 5 );
// Create the tree control and set its font
m_ruleTreeCtrl = new wxTreeCtrl( treeCtrlPanel, wxID_ANY, wxDefaultPosition, wxDefaultSize,
wxTR_DEFAULT_STYLE | wxTR_HIDE_ROOT | wxTR_HAS_BUTTONS );
wxTR_DEFAULT_STYLE | wxTR_HIDE_ROOT | wxTR_HAS_BUTTONS | wxBORDER_NONE );
m_ruleTreeCtrl->SetFont( KIUI::GetControlFont( this ) );
// Adjust the tree control's window style to remove the border
long treeCtrlFlags = m_ruleTreeCtrl->GetWindowStyleFlag();
treeCtrlFlags = ( treeCtrlFlags & ~wxBORDER_MASK ) | wxBORDER_NONE;
m_ruleTreeCtrl->SetWindowStyleFlag( treeCtrlFlags );
// Add the tree control to its sizer
treeCtrlSizer->Add( m_ruleTreeCtrl, 1, wxEXPAND | wxBOTTOM, 5 );
treeCtrlSizer->Add( m_ruleTreeCtrl, 1, wxEXPAND | wxBOTTOM, 3 );
// Create a sizer for the action buttons
wxBoxSizer* actionButtonsSizer = new wxBoxSizer( wxHORIZONTAL );
// Create the action buttons
m_addRuleButton =
new wxBitmapButton( treeCtrlPanel, wxID_ANY, KiBitmapBundle( BITMAPS::small_plus ),
wxDefaultPosition, wxDefaultSize, 0 );
m_copyRuleButton = new wxBitmapButton( treeCtrlPanel, wxID_ANY, KiBitmapBundle( BITMAPS::copy ),
wxDefaultPosition, wxDefaultSize, 0 );
m_moveTreeItemUpButton =
new wxBitmapButton( treeCtrlPanel, wxID_ANY, KiBitmapBundle( BITMAPS::small_up ),
wxDefaultPosition, wxDefaultSize, 0 );
m_moveTreeItemDownButton =
new wxBitmapButton( treeCtrlPanel, wxID_ANY, KiBitmapBundle( BITMAPS::small_down ),
wxDefaultPosition, wxDefaultSize, 0 );
m_deleteRuleButton =
new wxBitmapButton( treeCtrlPanel, wxID_ANY, KiBitmapBundle( BITMAPS::small_trash ),
wxDefaultPosition, wxDefaultSize, 0 );
m_addRuleButton = new STD_BITMAP_BUTTON( treeCtrlPanel, wxID_ANY, wxNullBitmap, wxDefaultPosition,
wxDefaultSize, wxBU_AUTODRAW );
m_copyRuleButton = new STD_BITMAP_BUTTON( treeCtrlPanel, wxID_ANY, wxNullBitmap, wxDefaultPosition,
wxDefaultSize, wxBU_AUTODRAW );
m_moveTreeItemUpButton = new STD_BITMAP_BUTTON( treeCtrlPanel, wxID_ANY, wxNullBitmap, wxDefaultPosition,
wxDefaultSize, wxBU_AUTODRAW );
m_moveTreeItemDownButton = new STD_BITMAP_BUTTON( treeCtrlPanel, wxID_ANY, wxNullBitmap, wxDefaultPosition,
wxDefaultSize, wxBU_AUTODRAW );
m_deleteRuleButton = new STD_BITMAP_BUTTON( treeCtrlPanel, wxID_ANY, wxNullBitmap, wxDefaultPosition,
wxDefaultSize, wxBU_AUTODRAW );
actionButtonsSizer->Add( m_addRuleButton, 0, wxLEFT | wxRIGHT, 5 );
actionButtonsSizer->Add( m_copyRuleButton, 0, wxLEFT | wxRIGHT, 5 );
actionButtonsSizer->Add( m_moveTreeItemUpButton, 0, wxLEFT | wxRIGHT, 5 );
actionButtonsSizer->Add( m_moveTreeItemDownButton, 0, wxLEFT | wxRIGHT, 5 );
actionButtonsSizer->Add( m_addRuleButton, 0, wxLEFT, 5 );
actionButtonsSizer->Add( m_copyRuleButton, 0, wxLEFT, 5 );
actionButtonsSizer->Add( m_moveTreeItemUpButton, 0, wxLEFT, 5 );
actionButtonsSizer->Add( m_moveTreeItemDownButton, 0, wxLEFT, 5 );
// Add a spacer between the "Move" buttons and the "Delete" button
actionButtonsSizer->AddStretchSpacer( 1 ); // Spacer between the Move and Delete buttons
actionButtonsSizer->AddSpacer( 20 ); // Spacer between the Move and Delete buttons
// Add the "Delete" button at the end
actionButtonsSizer->Add( m_deleteRuleButton, 0, wxRIGHT, 5 );
@@ -153,12 +146,17 @@ RULE_EDITOR_DIALOG_BASE::RULE_EDITOR_DIALOG_BASE( wxWindow* aParent, const wxStr
treeCtrlPanel->Layout();
m_addRuleButton->SetBitmap( KiBitmapBundle( BITMAPS::small_plus ) );
m_copyRuleButton->SetBitmap( KiBitmapBundle( BITMAPS::copy ) );
m_moveTreeItemUpButton->SetBitmap( KiBitmapBundle( BITMAPS::small_up ) );
m_moveTreeItemDownButton->SetBitmap( KiBitmapBundle( BITMAPS::small_down ) );
m_deleteRuleButton->SetBitmap( KiBitmapBundle( BITMAPS::small_trash ) );
// Create a scrolled window for the dynamic content panel
m_scrolledContentWin = new wxScrolledWindow( m_splitter, wxID_ANY, wxDefaultPosition,
wxDefaultSize, wxVSCROLL | wxBORDER_NONE );
m_scrolledContentWin = new wxScrolledWindow( m_splitter, wxID_ANY, wxDefaultPosition, wxDefaultSize,
wxVSCROLL | wxBORDER_NONE );
m_scrolledContentWin->SetScrollRate( 0, 10 );
m_scrolledContentWin->SetBackgroundColour(
wxSystemSettings::GetColour( wxSYS_COLOUR_FRAMEBK ) );
m_scrolledContentWin->SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_FRAMEBK ) );
m_contentPanel = nullptr;
// Add the tree control panel to the splitter.
@@ -167,8 +165,8 @@ RULE_EDITOR_DIALOG_BASE::RULE_EDITOR_DIALOG_BASE( wxWindow* aParent, const wxStr
int minTreeWidth = treeCtrlPanel->GetBestSize().GetWidth();
// Ensure a reasonable minimum width for the tree panel
if( minTreeWidth < 200 )
minTreeWidth = 200;
if( minTreeWidth < 240 )
minTreeWidth = 240;
m_defaultSashPosition = minTreeWidth;
@@ -195,33 +193,26 @@ RULE_EDITOR_DIALOG_BASE::RULE_EDITOR_DIALOG_BASE( wxWindow* aParent, const wxStr
mainSizer->Add( infoBarSizer, 0, wxEXPAND, 0 );
mainSizer->Add( m_splitter, 1, wxEXPAND | wxBOTTOM, 5 );
mainSizer->Add( m_sizerButtons, 0, wxALL | wxEXPAND, 5 );
if( aInitialSize != wxDefaultSize )
SetSize( aInitialSize );
Layout();
// Bind the context menu event
m_filterSearch->Bind( wxEVT_COMMAND_TEXT_UPDATED, &RULE_EDITOR_DIALOG_BASE::onFilterSearch,
this );
m_ruleTreeCtrl->Bind( wxEVT_TREE_ITEM_RIGHT_CLICK,
&RULE_EDITOR_DIALOG_BASE::onRuleTreeItemRightClick, this );
m_ruleTreeCtrl->Bind( wxEVT_TREE_SEL_CHANGED,
&RULE_EDITOR_DIALOG_BASE::onRuleTreeItemSelectionChanged, this );
m_ruleTreeCtrl->Bind( wxEVT_TREE_ITEM_ACTIVATED,
&RULE_EDITOR_DIALOG_BASE::onRuleTreeItemActivated, this );
m_filterSearch->Bind( wxEVT_COMMAND_TEXT_UPDATED, &RULE_EDITOR_DIALOG_BASE::onFilterSearch, this );
m_ruleTreeCtrl->Bind( wxEVT_TREE_ITEM_RIGHT_CLICK, &RULE_EDITOR_DIALOG_BASE::onRuleTreeItemRightClick, this );
m_ruleTreeCtrl->Bind( wxEVT_TREE_SEL_CHANGED, &RULE_EDITOR_DIALOG_BASE::onRuleTreeItemSelectionChanged, this );
m_ruleTreeCtrl->Bind( wxEVT_TREE_ITEM_ACTIVATED, &RULE_EDITOR_DIALOG_BASE::onRuleTreeItemActivated, this );
m_ruleTreeCtrl->Bind( wxEVT_LEFT_DOWN, &RULE_EDITOR_DIALOG_BASE::onRuleTreeItemLeftDown, this );
m_ruleTreeCtrl->Bind( wxEVT_MOTION, &RULE_EDITOR_DIALOG_BASE::onRuleTreeItemMouseMotion, this );
m_ruleTreeCtrl->Bind( wxEVT_LEFT_UP, &RULE_EDITOR_DIALOG_BASE::onRuleTreeItemLeftUp, this );
m_addRuleButton->Bind( wxEVT_BUTTON, &RULE_EDITOR_DIALOG_BASE::onNewRuleOptionClick, this );
m_copyRuleButton->Bind( wxEVT_BUTTON, &RULE_EDITOR_DIALOG_BASE::onDuplicateRuleOptionClick,
this );
m_moveTreeItemUpButton->Bind( wxEVT_BUTTON, &RULE_EDITOR_DIALOG_BASE::onMoveUpRuleOptionClick,
this );
m_moveTreeItemDownButton->Bind( wxEVT_BUTTON,
&RULE_EDITOR_DIALOG_BASE::onMoveDownRuleOptionClick, this );
m_deleteRuleButton->Bind( wxEVT_BUTTON, &RULE_EDITOR_DIALOG_BASE::onDeleteRuleOptionClick,
this );
m_copyRuleButton->Bind( wxEVT_BUTTON, &RULE_EDITOR_DIALOG_BASE::onDuplicateRuleOptionClick, this );
m_moveTreeItemUpButton->Bind( wxEVT_BUTTON, &RULE_EDITOR_DIALOG_BASE::onMoveUpRuleOptionClick, this );
m_moveTreeItemDownButton->Bind( wxEVT_BUTTON, &RULE_EDITOR_DIALOG_BASE::onMoveDownRuleOptionClick, this );
m_deleteRuleButton->Bind( wxEVT_BUTTON, &RULE_EDITOR_DIALOG_BASE::onDeleteRuleOptionClick, this );
m_saveRuleButton->Bind( wxEVT_BUTTON, &RULE_EDITOR_DIALOG_BASE::OnSave, this );
m_cancelRuleButton->Bind( wxEVT_BUTTON, &RULE_EDITOR_DIALOG_BASE::OnCancel, this );
@@ -349,8 +340,7 @@ RULE_EDITOR_DIALOG_BASE* RULE_EDITOR_DIALOG_BASE::GetDialog( wxWindow* aParent )
{
while( aParent )
{
if( RULE_EDITOR_DIALOG_BASE* currentDialog =
dynamic_cast<RULE_EDITOR_DIALOG_BASE*>( aParent ) )
if( RULE_EDITOR_DIALOG_BASE* currentDialog = dynamic_cast<RULE_EDITOR_DIALOG_BASE*>( aParent ) )
return currentDialog;
aParent = aParent->GetParent();
@@ -367,10 +357,12 @@ void RULE_EDITOR_DIALOG_BASE::InitRuleTreeItems( const std::vector<RULE_TREE_NOD
m_defaultTreeItems = aNodes;
m_ruleTreeCtrl->Freeze();
m_suppressSelectionEvents = true;
wxTreeItemId rootId = m_ruleTreeCtrl->AddRoot( aNodes[0].m_nodeName );
RULE_TREE_ITEM_DATA* itemData =
new RULE_TREE_ITEM_DATA( aNodes[0].m_nodeId, nullptr, rootId );
RULE_TREE_ITEM_DATA* itemData = new RULE_TREE_ITEM_DATA( aNodes[0].m_nodeId, nullptr, rootId );
m_ruleTreeCtrl->SetItemData( rootId, itemData );
std::vector<RULE_TREE_NODE> childNodes;
@@ -384,13 +376,19 @@ void RULE_EDITOR_DIALOG_BASE::InitRuleTreeItems( const std::vector<RULE_TREE_NOD
m_treeHistoryData.clear();
saveRuleTreeState( m_ruleTreeCtrl->GetRootItem(), m_defaultTreeItems[0].m_nodeId );
m_ruleTreeCtrl->SelectItem( m_ruleTreeCtrl->GetFirstVisibleItem() );
m_ruleTreeCtrl->CollapseAll();
m_suppressSelectionEvents = false;
m_ruleTreeCtrl->Thaw();
m_ruleTreeCtrl->SelectItem( m_ruleTreeCtrl->GetFirstVisibleItem() );
}
void RULE_EDITOR_DIALOG_BASE::SetContentPanel( wxPanel* aContentPanel )
{
m_scrolledContentWin->Freeze();
if( m_contentPanel )
{
unregisterUnitBinders( m_contentPanel );
@@ -404,8 +402,13 @@ void RULE_EDITOR_DIALOG_BASE::SetContentPanel( wxPanel* aContentPanel )
resetUndoRedoForNewContent( m_contentPanel->GetChildren() );
Layout();
CallAfter( [this]() { RefreshContentScrollArea(); } );
Refresh();
m_scrolledContentWin->Thaw();
CallAfter(
[this]()
{
RefreshContentScrollArea();
} );
}
@@ -439,12 +442,11 @@ void RULE_EDITOR_DIALOG_BASE::AppendNewRuleTreeItem( const RULE_TREE_NODE& aNode
std::vector<int>& existingChildren = std::get<1>( it->second );
existingChildren.push_back( aNode.m_nodeId );
m_treeHistoryData[aNode.m_nodeId] = { aNode.m_nodeName,
{},
currentTreeItemId };
m_treeHistoryData[aNode.m_nodeId] = { aNode.m_nodeName, {}, currentTreeItemId };
}
m_ruleTreeCtrl->SelectItem( currentTreeItemId );
if( !m_suppressSelectionEvents )
m_ruleTreeCtrl->SelectItem( currentTreeItemId );
}
@@ -495,6 +497,7 @@ void RULE_EDITOR_DIALOG_BASE::SetModified()
if( itemId.IsOk() )
{
wxString currentText = m_ruleTreeCtrl->GetItemText( itemId );
if( !currentText.EndsWith( wxS( " *" ) ) )
{
m_ruleTreeCtrl->SetItemText( itemId, currentText + wxS( " *" ) );
@@ -526,9 +529,8 @@ void RULE_EDITOR_DIALOG_BASE::DeleteRuleTreeItem( wxTreeItemId aItemId, const in
}
void RULE_EDITOR_DIALOG_BASE::populateRuleTreeCtrl(
const std::vector<RULE_TREE_NODE>& aNodes, const RULE_TREE_NODE& aNode,
wxTreeItemId aParent )
void RULE_EDITOR_DIALOG_BASE::populateRuleTreeCtrl( const std::vector<RULE_TREE_NODE>& aNodes,
const RULE_TREE_NODE& aNode, wxTreeItemId aParent )
{
wxTreeItemId currentId = appendRuleTreeItem( aNode, aParent );
@@ -553,8 +555,7 @@ void RULE_EDITOR_DIALOG_BASE::onRuleTreeItemRightClick( wxTreeEvent& aEvent )
m_ruleTreeCtrl->SelectItem( item );
RULE_TREE_ITEM_DATA* ruleTreeItemData =
dynamic_cast<RULE_TREE_ITEM_DATA*>( m_ruleTreeCtrl->GetItemData( item ) );
RULE_TREE_ITEM_DATA* ruleTreeItemData = dynamic_cast<RULE_TREE_ITEM_DATA*>( m_ruleTreeCtrl->GetItemData( item ) );
if( !ruleTreeItemData )
return;
@@ -570,17 +571,12 @@ void RULE_EDITOR_DIALOG_BASE::onRuleTreeItemRightClick( wxTreeEvent& aEvent )
KIUI::AddMenuItem( &menu, ID_COPYRULE, _( "Copy Rule" ), KiBitmap( BITMAPS::copy ) );
if( m_enableDeleteRule )
KIUI::AddMenuItem( &menu, ID_DELETERULE, _( "Delete Rule" ),
KiBitmap( BITMAPS::small_trash ) );
KIUI::AddMenuItem( &menu, ID_DELETERULE, _( "Delete Rule" ), KiBitmap( BITMAPS::small_trash ) );
if( isEnabled( ruleTreeItemData,
RULE_EDITOR_TREE_CONTEXT_OPT::MOVE_UP )
&& m_enableMoveUp )
if( isEnabled( ruleTreeItemData, RULE_EDITOR_TREE_CONTEXT_OPT::MOVE_UP ) && m_enableMoveUp )
KIUI::AddMenuItem( &menu, ID_MOVEUP, _( "Move Up" ), KiBitmap( BITMAPS::small_up ) );
if( isEnabled( ruleTreeItemData,
RULE_EDITOR_TREE_CONTEXT_OPT::MOVE_DOWN )
&& m_enableMoveDown )
if( isEnabled( ruleTreeItemData, RULE_EDITOR_TREE_CONTEXT_OPT::MOVE_DOWN ) && m_enableMoveDown )
KIUI::AddMenuItem( &menu, ID_MOVEDOWN, _( "Move Down" ), KiBitmap( BITMAPS::small_down ) );
menu.Bind( wxEVT_COMMAND_MENU_SELECTED,
@@ -607,6 +603,9 @@ void RULE_EDITOR_DIALOG_BASE::onRuleTreeItemRightClick( wxTreeEvent& aEvent )
void RULE_EDITOR_DIALOG_BASE::onRuleTreeItemSelectionChanged( wxTreeEvent& aEvent )
{
if( m_suppressSelectionEvents )
return;
wxTreeItemId selectedItem = aEvent.GetItem();
RULE_TREE_ITEM_DATA* selectedItemData =
@@ -676,6 +675,7 @@ void RULE_EDITOR_DIALOG_BASE::onMoveUpRuleOptionClick( wxCommandEvent& aEvent )
return;
wxTreeItemId selectedItem = m_ruleTreeCtrl->GetSelection();
if( !selectedItem.IsOk() )
return;
@@ -703,8 +703,8 @@ void RULE_EDITOR_DIALOG_BASE::onMoveUpRuleOptionClick( wxCommandEvent& aEvent )
wxTreeItemId insertPosition = beforePrevious.IsOk() ? beforePrevious : wxTreeItemId();
wxTreeItemId newItem = m_ruleTreeCtrl->InsertItem(
parent, insertPosition, m_ruleTreeCtrl->GetItemText( selectedItem ) );
wxTreeItemId newItem = m_ruleTreeCtrl->InsertItem( parent, insertPosition,
m_ruleTreeCtrl->GetItemText( selectedItem ) );
moveRuleTreeItemChildrensTooOnDrag( selectedItem, newItem );
@@ -832,8 +832,8 @@ void RULE_EDITOR_DIALOG_BASE::onRuleTreeItemMouseMotion( wxMouseEvent& aEvent )
if( hitParent == dragParent )
{
m_ruleTreeCtrl->SetItemBackgroundColour(
hitItem, wxSystemSettings::GetColour( wxSYS_COLOUR_HIGHLIGHT ) );
m_ruleTreeCtrl->SetItemBackgroundColour( hitItem,
wxSystemSettings::GetColour( wxSYS_COLOUR_HIGHLIGHT ) );
m_dropTargetItem = hitItem;
}
}
@@ -876,8 +876,8 @@ void RULE_EDITOR_DIALOG_BASE::onRuleTreeItemLeftUp( wxMouseEvent& aEvent )
&& targetItem == m_ruleTreeCtrl->GetFirstChild( targetParent, cookie ) )
{
// Prepend item as the first child of target parent
newItem = m_ruleTreeCtrl->PrependItem(
targetParent, m_ruleTreeCtrl->GetItemText( m_draggedItem ) );
newItem = m_ruleTreeCtrl->PrependItem( targetParent,
m_ruleTreeCtrl->GetItemText( m_draggedItem ) );
}
else
{
@@ -894,8 +894,8 @@ void RULE_EDITOR_DIALOG_BASE::onRuleTreeItemLeftUp( wxMouseEvent& aEvent )
if( !previous.IsOk() )
{
// If no previous item, insert as the first child
newItem = m_ruleTreeCtrl->PrependItem(
targetParent, m_ruleTreeCtrl->GetItemText( m_draggedItem ) );
newItem = m_ruleTreeCtrl->PrependItem( targetParent,
m_ruleTreeCtrl->GetItemText( m_draggedItem ) );
}
else
{
@@ -904,15 +904,14 @@ void RULE_EDITOR_DIALOG_BASE::onRuleTreeItemLeftUp( wxMouseEvent& aEvent )
if( nextSibling.IsOk() )
{
// If there is a next sibling, insert after the previous item
newItem = m_ruleTreeCtrl->InsertItem(
targetParent, previous,
m_ruleTreeCtrl->GetItemText( m_draggedItem ) );
newItem = m_ruleTreeCtrl->InsertItem( targetParent, previous,
m_ruleTreeCtrl->GetItemText( m_draggedItem ) );
}
else
{
// If no next sibling, append the item as the last child
newItem = m_ruleTreeCtrl->AppendItem(
targetParent, m_ruleTreeCtrl->GetItemText( m_draggedItem ) );
newItem = m_ruleTreeCtrl->AppendItem( targetParent,
m_ruleTreeCtrl->GetItemText( m_draggedItem ) );
}
}
}
@@ -952,6 +951,9 @@ void RULE_EDITOR_DIALOG_BASE::onFilterSearch( wxCommandEvent& aEvent )
{
const auto searchStr = aEvent.GetString().Lower();
m_ruleTreeCtrl->Freeze();
m_suppressSelectionEvents = true;
m_ruleTreeCtrl->DeleteAllItems();
restoreRuleTree( nullptr, m_defaultTreeItems[0].m_nodeId );
@@ -962,6 +964,9 @@ void RULE_EDITOR_DIALOG_BASE::onFilterSearch( wxCommandEvent& aEvent )
{
filterRuleTree( root, searchStr );
}
m_suppressSelectionEvents = false;
m_ruleTreeCtrl->Thaw();
}
@@ -1103,8 +1108,7 @@ void RULE_EDITOR_DIALOG_BASE::moveRuleTreeItemChildrensTooOnDrag( wxTreeItemId a
while( child.IsOk() )
{
wxTreeItemId newChild =
m_ruleTreeCtrl->AppendItem( aDest, m_ruleTreeCtrl->GetItemText( child ) );
wxTreeItemId newChild = m_ruleTreeCtrl->AppendItem( aDest, m_ruleTreeCtrl->GetItemText( child ) );
RULE_TREE_ITEM_DATA* ruleTreeItemData =
dynamic_cast<RULE_TREE_ITEM_DATA*>( m_ruleTreeCtrl->GetItemData( child ) );
+12
View File
@@ -107,6 +107,8 @@ void DS_DRAW_ITEM_LIST::GetTextVars( wxArrayString* aVars )
aVars->push_back( wxT( "PROJECTNAME" ) );
aVars->push_back( wxT( "PAPER" ) );
aVars->push_back( wxT( "LAYER" ) );
aVars->push_back( wxT( "VARIANT" ) );
aVars->push_back( wxT( "VARIANT_DESC" ) );
TITLE_BLOCK::GetContextualTextVars( aVars );
}
@@ -165,6 +167,16 @@ wxString DS_DRAW_ITEM_LIST::BuildFullText( const wxString& aTextbase )
*token = m_sheetLayer;
tokenUpdated = true;
}
else if( token->IsSameAs( wxT( "VARIANT" ) ) )
{
*token = m_variantName;
tokenUpdated = true;
}
else if( token->IsSameAs( wxT( "VARIANT_DESC" ) ) )
{
*token = m_variantDesc;
tokenUpdated = true;
}
else if( m_titleBlock )
{
if( m_titleBlock->TextVarResolver( token, m_project, m_flags ) )
@@ -80,6 +80,8 @@ void DS_PROXY_VIEW_ITEM::buildDrawList( VIEW* aView,
wxString fileName( m_fileName.c_str(), wxConvUTF8 );
wxString sheetName( m_sheetName.c_str(), wxConvUTF8 );
wxString sheetPath( m_sheetPath.c_str(), wxConvUTF8 );
wxString variantName( m_variantName.c_str(), wxConvUTF8 );
wxString variantDesc( m_variantDesc.c_str(), wxConvUTF8 );
aDrawList->SetDefaultPenSize( (int) settings->GetDrawingSheetLineWidth() );
aDrawList->SetIsFirstPage( m_isFirstPage );
@@ -89,6 +91,8 @@ void DS_PROXY_VIEW_ITEM::buildDrawList( VIEW* aView,
aDrawList->SetSheetName( sheetName );
aDrawList->SetSheetPath( sheetPath );
aDrawList->SetSheetLayer( settings->GetLayerName() );
aDrawList->SetVariantName( variantName );
aDrawList->SetVariantDesc( variantDesc );
aDrawList->SetProject( m_project );
aDrawList->SetProperties( aProperties );
+11 -10
View File
@@ -1215,19 +1215,20 @@ void EDA_BASE_FRAME::RestoreAuiLayout()
* wx 3.2 or the first settings upgrade when wx 3.3 is used in KiCad (e.g., 9.0->10.0 for Windows and macOS).
*/
if( !restored && !m_perspective.IsEmpty() )
{
m_auimgr.LoadPerspective( m_perspective );
// Workaround for wx 3.2: LoadPerspective() hides all panes first, then shows only
// those in the saved string. If toolbar names changed or new toolbars were added,
// they'd stay hidden. Ensure all toolbars are visible after restore.
wxAuiPaneInfoArray& panes = m_auimgr.GetAllPanes();
// Workaround for two bugs:
// 1) wx 3.2: LoadPerspective() hides all panes first, then shows only
// those in the saved string. If toolbar names changed or new toolbars were added,
// they'd stay hidden. Ensure all toolbars are visible after restore.
// 2) We still saw this even after this fix, so just make the toolbars shown unconditionally
// since we don't actually allow hiding them. The root cause of this part is not known.
wxAuiPaneInfoArray& panes = m_auimgr.GetAllPanes();
for( size_t i = 0; i < panes.GetCount(); ++i )
{
if( panes.Item( i ).IsToolbar() )
panes.Item( i ).Show( true );
}
for( size_t i = 0; i < panes.GetCount(); ++i )
{
if( panes.Item( i ).IsToolbar() )
panes.Item( i ).Show( true );
}
}
+192 -65
View File
@@ -107,8 +107,8 @@ EDA_SHAPE::EDA_SHAPE( const SHAPE& aShape ) :
{
auto line = static_cast<const SHAPE_LINE_CHAIN&>( aShape );
m_shape = SHAPE_T::POLY;
m_poly = SHAPE_POLY_SET();
m_poly.AddOutline( line );
GetPolyShape() = SHAPE_POLY_SET();
GetPolyShape().AddOutline( line );
SetWidth( line.Width() );
break;
}
@@ -135,7 +135,7 @@ EDA_SHAPE::EDA_SHAPE( const SHAPE& aShape ) :
{
auto poly = static_cast<const SHAPE_SIMPLE&>( aShape );
m_shape = SHAPE_T::POLY;
poly.TransformToPolygon( m_poly, 0, ERROR_INSIDE );
poly.TransformToPolygon( GetPolyShape(), 0, ERROR_INSIDE );
break;
}
@@ -151,6 +151,64 @@ EDA_SHAPE::EDA_SHAPE( const SHAPE& aShape ) :
}
EDA_SHAPE::EDA_SHAPE( const EDA_SHAPE& aOther ) :
m_endsSwapped( aOther.m_endsSwapped ),
m_shape( aOther.m_shape ),
m_stroke( aOther.m_stroke ),
m_fill( aOther.m_fill ),
m_fillColor( aOther.m_fillColor ),
m_hatchingDirty( true ),
m_rectangleHeight( aOther.m_rectangleHeight ),
m_rectangleWidth( aOther.m_rectangleWidth ),
m_cornerRadius( aOther.m_cornerRadius ),
m_start( aOther.m_start ),
m_end( aOther.m_end ),
m_arcCenter( aOther.m_arcCenter ),
m_arcMidData( aOther.m_arcMidData ),
m_bezierC1( aOther.m_bezierC1 ),
m_bezierC2( aOther.m_bezierC2 ),
m_bezierPoints( aOther.m_bezierPoints ),
m_editState( aOther.m_editState ),
m_proxyItem( aOther.m_proxyItem )
{
if( aOther.m_poly )
m_poly = std::make_unique<SHAPE_POLY_SET>( *aOther.m_poly );
}
EDA_SHAPE& EDA_SHAPE::operator=( const EDA_SHAPE& aOther )
{
if( this == &aOther )
return *this;
m_endsSwapped = aOther.m_endsSwapped;
m_shape = aOther.m_shape;
m_stroke = aOther.m_stroke;
m_fill = aOther.m_fill;
m_fillColor = aOther.m_fillColor;
m_hatchingCache.reset();
m_hatchingDirty = true;
m_rectangleHeight = aOther.m_rectangleHeight;
m_rectangleWidth = aOther.m_rectangleWidth;
m_cornerRadius = aOther.m_cornerRadius;
m_start = aOther.m_start;
m_end = aOther.m_end;
m_arcCenter = aOther.m_arcCenter;
m_arcMidData = aOther.m_arcMidData;
m_bezierC1 = aOther.m_bezierC1;
m_bezierC2 = aOther.m_bezierC2;
m_bezierPoints = aOther.m_bezierPoints;
if( aOther.m_poly )
m_poly = std::make_unique<SHAPE_POLY_SET>( *aOther.m_poly );
else
m_poly.reset();
m_editState = aOther.m_editState;
m_proxyItem = aOther.m_proxyItem;
return *this;
}
void EDA_SHAPE::Serialize( google::protobuf::Any &aContainer ) const
{
using namespace kiapi::common;
@@ -375,7 +433,7 @@ VECTOR2I EDA_SHAPE::getPosition() const
if( m_shape == SHAPE_T::ARC )
return getCenter();
else if( m_shape == SHAPE_T::POLY )
return m_poly.CVertex( 0 );
return GetPolyShape().CVertex( 0 );
else
return m_start;
}
@@ -397,8 +455,8 @@ double EDA_SHAPE::GetLength() const
return GetStart().Distance( GetEnd() );
case SHAPE_T::POLY:
for( int ii = 0; ii < m_poly.COutline( 0 ).SegmentCount(); ii++ )
length += m_poly.COutline( 0 ).CSegment( ii ).Length();
for( int ii = 0; ii < GetPolyShape().COutline( 0 ).SegmentCount(); ii++ )
length += GetPolyShape().COutline( 0 ).CSegment( ii ).Length();
return length;
@@ -521,10 +579,10 @@ bool EDA_SHAPE::IsClosed() const
return false;
case SHAPE_T::POLY:
if( m_poly.IsEmpty() )
if( GetPolyShape().IsEmpty() )
return false;
else
return m_poly.Outline( 0 ).IsClosed();
return GetPolyShape().Outline( 0 ).IsClosed();
case SHAPE_T::BEZIER:
if( m_bezierPoints.size() < 3 )
@@ -572,6 +630,42 @@ UI_FILL_MODE EDA_SHAPE::GetFillModeProp() const
}
const SHAPE_POLY_SET& EDA_SHAPE::GetHatching() const
{
if( !m_hatchingCache )
m_hatchingCache = std::make_unique<EDA_SHAPE_HATCH_CACHE_DATA>();
return m_hatchingCache->hatching;
}
const std::vector<SEG>& EDA_SHAPE::GetHatchLines() const
{
if( !m_hatchingCache )
m_hatchingCache = std::make_unique<EDA_SHAPE_HATCH_CACHE_DATA>();
return m_hatchingCache->hatchLines;
}
SHAPE_POLY_SET& EDA_SHAPE::hatching() const
{
if( !m_hatchingCache )
m_hatchingCache = std::make_unique<EDA_SHAPE_HATCH_CACHE_DATA>();
return m_hatchingCache->hatching;
}
std::vector<SEG>& EDA_SHAPE::hatchLines() const
{
if( !m_hatchingCache )
m_hatchingCache = std::make_unique<EDA_SHAPE_HATCH_CACHE_DATA>();
return m_hatchingCache->hatchLines;
}
void EDA_SHAPE::UpdateHatching() const
{
if( !m_hatchingDirty )
@@ -607,8 +701,7 @@ void EDA_SHAPE::UpdateHatching() const
case SHAPE_T::RECTANGLE:
{
ROUNDRECT rr( SHAPE_RECT( getPosition(), GetRectangleWidth(), GetRectangleHeight() ),
GetCornerRadius() );
ROUNDRECT rr( SHAPE_RECT( getPosition(), GetRectangleWidth(), GetRectangleHeight() ), GetCornerRadius() );
rr.TransformToPolygon( shapeBuffer, getMaxError() );
}
break;
@@ -621,7 +714,7 @@ void EDA_SHAPE::UpdateHatching() const
if( !IsClosed() )
return;
shapeBuffer = m_poly.CloneDropTriangulation();
shapeBuffer = GetPolyShape().CloneDropTriangulation();
break;
default:
@@ -631,8 +724,8 @@ void EDA_SHAPE::UpdateHatching() const
// Clear cached hatching only after all validation passes.
// This prevents flickering when early returns would otherwise leave empty hatching.
m_hatching.RemoveAllContours();
m_hatchLines.clear();
hatching().RemoveAllContours();
hatchLines().clear();
BOX2I extents = shapeBuffer.BBox();
int majorAxis = std::max( extents.GetWidth(), extents.GetHeight() );
@@ -640,9 +733,17 @@ void EDA_SHAPE::UpdateHatching() const
if( majorAxis / spacing > 100 )
spacing = majorAxis / 100;
SHAPE_POLY_SET knockouts = getHatchingKnockouts();
if( !knockouts.IsEmpty() )
{
shapeBuffer.BooleanSubtract( knockouts );
shapeBuffer.Fracture();
}
// Generate hatch lines for stroke-based rendering. All hatch types use line segments.
std::vector<SEG> hatchSegs = shapeBuffer.GenerateHatchLines( slopes, spacing, -1 );
m_hatchLines = hatchSegs;
hatchLines() = hatchSegs;
// Also generate polygon representation for exports, 3D viewer, and hit testing
if( GetFillMode() == FILL_T::HATCH || GetFillMode() == FILL_T::REVERSE_HATCH )
@@ -652,10 +753,11 @@ void EDA_SHAPE::UpdateHatching() const
// We don't really need the rounded ends at all, so don't spend any extra time on them
int maxError = lineWidth;
TransformOvalToPolygon( m_hatching, seg.A, seg.B, lineWidth, maxError, ERROR_INSIDE );
TransformOvalToPolygon( hatching(), seg.A, seg.B, lineWidth, maxError,
ERROR_INSIDE );
}
m_hatching.Fracture();
hatching().Fracture();
m_hatchingDirty = false;
}
else
@@ -666,8 +768,8 @@ void EDA_SHAPE::UpdateHatching() const
int gridsize = spacing;
int hole_size = gridsize - GetHatchLineWidth();
m_hatching = shapeBuffer.CloneDropTriangulation();
m_hatching.Rotate( -ANGLE_45 );
hatching() = shapeBuffer.CloneDropTriangulation();
hatching().Rotate( -ANGLE_45 );
// Build hole shape
SHAPE_LINE_CHAIN hole_base;
@@ -682,7 +784,7 @@ void EDA_SHAPE::UpdateHatching() const
hole_base.SetClosed( true );
// Build holes
BOX2I bbox = m_hatching.BBox( 0 );
BOX2I bbox = GetHatching().BBox( 0 );
SHAPE_POLY_SET holes;
int x_offset = bbox.GetX() - ( bbox.GetX() ) % gridsize - gridsize;
@@ -698,12 +800,19 @@ void EDA_SHAPE::UpdateHatching() const
}
}
m_hatching.BooleanSubtract( holes );
m_hatching.Fracture();
hatching().BooleanSubtract( holes );
hatching().Fracture();
// Must re-rotate after Fracture(). Clipper struggles mightily with fracturing
// 45-degree holes.
m_hatching.Rotate( ANGLE_45 );
hatching().Rotate( ANGLE_45 );
if( !knockouts.IsEmpty() )
{
hatching().BooleanSubtract( knockouts );
hatching().Fracture();
}
m_hatchingDirty = false;
}
}
@@ -729,7 +838,7 @@ void EDA_SHAPE::move( const VECTOR2I& aMoveVector )
break;
case SHAPE_T::POLY:
m_poly.Move( aMoveVector );
GetPolyShape().Move( aMoveVector );
break;
case SHAPE_T::BEZIER:
@@ -778,9 +887,9 @@ void EDA_SHAPE::scale( double aScale )
{
std::vector<VECTOR2I> pts;
for( int ii = 0; ii < m_poly.OutlineCount(); ++ ii )
for( int ii = 0; ii < GetPolyShape().OutlineCount(); ++ ii )
{
for( const VECTOR2I& pt : m_poly.Outline( ii ).CPoints() )
for( const VECTOR2I& pt : GetPolyShape().Outline( ii ).CPoints() )
{
pts.emplace_back( pt );
scalePt( pts.back() );
@@ -839,14 +948,14 @@ void EDA_SHAPE::rotate( const VECTOR2I& aRotCentre, const EDA_ANGLE& aAngle )
// Convert non-cardinally-rotated rect to a diamond
ROUNDRECT rr( SHAPE_RECT( GetStart(), GetRectangleWidth(), GetRectangleHeight() ), m_cornerRadius );
m_shape = SHAPE_T::POLY;
rr.TransformToPolygon( m_poly, getMaxError() );
m_poly.Rotate( aAngle, aRotCentre );
rr.TransformToPolygon( GetPolyShape(), getMaxError() );
GetPolyShape().Rotate( aAngle, aRotCentre );
}
break;
case SHAPE_T::POLY:
m_poly.Rotate( aAngle, aRotCentre );
GetPolyShape().Rotate( aAngle, aRotCentre );
break;
case SHAPE_T::BEZIER:
@@ -893,7 +1002,7 @@ void EDA_SHAPE::flip( const VECTOR2I& aCentre, FLIP_DIRECTION aFlipDirection )
break;
case SHAPE_T::POLY:
m_poly.Mirror( aCentre, aFlipDirection );
GetPolyShape().Mirror( aCentre, aFlipDirection );
break;
case SHAPE_T::BEZIER:
@@ -1242,10 +1351,10 @@ const BOX2I EDA_SHAPE::getBoundingBox() const
break;
case SHAPE_T::POLY:
if( m_poly.IsEmpty() )
if( GetPolyShape().IsEmpty() )
break;
for( auto iter = m_poly.CIterate(); iter; iter++ )
for( auto iter = GetPolyShape().CIterate(); iter; iter++ )
bbox.Merge( *iter );
break;
@@ -1399,26 +1508,26 @@ bool EDA_SHAPE::hitTest( const VECTOR2I& aPosition, int aAccuracy ) const
return false;
case SHAPE_T::POLY:
if( m_poly.OutlineCount() < 1 ) // empty poly
if( GetPolyShape().OutlineCount() < 1 ) // empty poly
return false;
if( IsFilledForHitTesting() )
{
if( !m_poly.COutline( 0 ).IsClosed() )
if( !GetPolyShape().COutline( 0 ).IsClosed() )
{
// Only one outline is expected
SHAPE_LINE_CHAIN copy( m_poly.COutline( 0 ) );
SHAPE_LINE_CHAIN copy( GetPolyShape().COutline( 0 ) );
copy.SetClosed( true );
return copy.Collide( aPosition, maxdist );
}
else
{
return m_poly.Collide( aPosition, maxdist );
return GetPolyShape().Collide( aPosition, maxdist );
}
}
else
{
if( m_poly.CollideEdge( aPosition, nullptr, maxdist ) )
if( GetPolyShape().CollideEdge( aPosition, nullptr, maxdist ) )
return true;
if( IsHatchedFill() && GetHatching().Collide( aPosition, maxdist ) )
@@ -1572,9 +1681,9 @@ bool EDA_SHAPE::hitTest( const BOX2I& aRect, bool aContained, int aAccuracy ) co
// Account for the width of the line
arect.Inflate( GetWidth() / 2 );
for( int ii = 0; ii < m_poly.OutlineCount(); ++ii )
for( int ii = 0; ii < GetPolyShape().OutlineCount(); ++ii )
{
if( checkOutline( m_poly.Outline( ii ) ) )
if( checkOutline( GetPolyShape().Outline( ii ) ) )
return true;
}
@@ -1820,11 +1929,11 @@ void EDA_SHAPE::computeArcBBox( BOX2I& aBBox ) const
void EDA_SHAPE::SetPolyPoints( const std::vector<VECTOR2I>& aPoints )
{
m_poly.RemoveAllContours();
m_poly.NewOutline();
GetPolyShape().RemoveAllContours();
GetPolyShape().NewOutline();
for( const VECTOR2I& p : aPoints )
m_poly.Append( p.x, p.y );
GetPolyShape().Append( p.x, p.y );
}
@@ -1968,9 +2077,9 @@ std::vector<VECTOR2I> EDA_SHAPE::GetPolyPoints() const
{
std::vector<VECTOR2I> points;
for( int ii = 0; ii < m_poly.OutlineCount(); ++ii )
for( int ii = 0; ii < GetPolyShape().OutlineCount(); ++ii )
{
const SHAPE_LINE_CHAIN& outline = m_poly.COutline( ii );
const SHAPE_LINE_CHAIN& outline = GetPolyShape().COutline( ii );
int pointCount = outline.PointCount();
if( pointCount )
@@ -1986,6 +2095,23 @@ std::vector<VECTOR2I> EDA_SHAPE::GetPolyPoints() const
}
SHAPE_POLY_SET& EDA_SHAPE::GetPolyShape()
{
if( !m_poly )
m_poly = std::make_unique<SHAPE_POLY_SET>();
return *m_poly;
}
const SHAPE_POLY_SET& EDA_SHAPE::GetPolyShape() const
{
if( !m_poly )
m_poly = std::make_unique<SHAPE_POLY_SET>();
return *m_poly;
}
bool EDA_SHAPE::IsPolyShapeValid() const
{
// return true if the polygonal shape is valid (has more than 2 points)
@@ -2028,12 +2154,12 @@ void EDA_SHAPE::beginEdit( const VECTOR2I& aPosition )
break;
case SHAPE_T::POLY:
m_poly.NewOutline();
m_poly.Outline( 0 ).SetClosed( false );
GetPolyShape().NewOutline();
GetPolyShape().Outline( 0 ).SetClosed( false );
// Start and end of the first segment (co-located for now)
m_poly.Outline( 0 ).Append( aPosition );
m_poly.Outline( 0 ).Append( aPosition, true );
GetPolyShape().Outline( 0 ).Append( aPosition );
GetPolyShape().Outline( 0 ).Append( aPosition, true );
break;
default:
@@ -2061,7 +2187,7 @@ bool EDA_SHAPE::continueEdit( const VECTOR2I& aPosition )
case SHAPE_T::POLY:
{
SHAPE_LINE_CHAIN& poly = m_poly.Outline( 0 );
SHAPE_LINE_CHAIN& poly = GetPolyShape().Outline( 0 );
// do not add zero-length segments
if( poly.CPoint( (int) poly.GetPointCount() - 2 ) != poly.CLastPoint() )
@@ -2229,7 +2355,8 @@ void EDA_SHAPE::calcEdit( const VECTOR2I& aPosition )
}
case SHAPE_T::POLY:
m_poly.Outline( 0 ).SetPoint( m_poly.Outline( 0 ).GetPointCount() - 1, aPosition );
GetPolyShape().Outline( 0 ).SetPoint( GetPolyShape().Outline( 0 ).GetPointCount() - 1,
aPosition );
break;
default:
@@ -2251,7 +2378,7 @@ void EDA_SHAPE::endEdit( bool aClosed )
case SHAPE_T::POLY:
{
SHAPE_LINE_CHAIN& poly = m_poly.Outline( 0 );
SHAPE_LINE_CHAIN& poly = GetPolyShape().Outline( 0 );
// do not include last point twice
if( poly.GetPointCount() > 2 )
@@ -2330,14 +2457,14 @@ int EDA_SHAPE::Compare( const EDA_SHAPE* aOther ) const
}
else if( m_shape == SHAPE_T::POLY )
{
TEST( m_poly.TotalVertices(), aOther->m_poly.TotalVertices() );
TEST( GetPolyShape().TotalVertices(), aOther->GetPolyShape().TotalVertices() );
}
for( size_t ii = 0; ii < m_bezierPoints.size(); ++ii )
TEST_PT( m_bezierPoints[ii], aOther->m_bezierPoints[ii] );
for( int ii = 0; ii < m_poly.TotalVertices(); ++ii )
TEST_PT( m_poly.CVertex( ii ), aOther->m_poly.CVertex( ii ) );
for( int ii = 0; ii < GetPolyShape().TotalVertices(); ++ii )
TEST_PT( GetPolyShape().CVertex( ii ), aOther->GetPolyShape().CVertex( ii ) );
TEST_E( m_stroke.GetWidth(), aOther->m_stroke.GetWidth() );
TEST( (int) m_stroke.GetLineStyle(), (int) aOther->m_stroke.GetLineStyle() );
@@ -2438,9 +2565,9 @@ void EDA_SHAPE::TransformShapeToPolygon( SHAPE_POLY_SET& aBuffer, int aClearance
if( solidFill )
{
for( int ii = 0; ii < m_poly.OutlineCount(); ++ii )
for( int ii = 0; ii < GetPolyShape().OutlineCount(); ++ii )
{
const SHAPE_LINE_CHAIN& poly = m_poly.Outline( ii );
const SHAPE_LINE_CHAIN& poly = GetPolyShape().Outline( ii );
SHAPE_POLY_SET tmp;
tmp.NewOutline();
@@ -2462,9 +2589,9 @@ void EDA_SHAPE::TransformShapeToPolygon( SHAPE_POLY_SET& aBuffer, int aClearance
}
else
{
for( int ii = 0; ii < m_poly.OutlineCount(); ++ii )
for( int ii = 0; ii < GetPolyShape().OutlineCount(); ++ii )
{
const SHAPE_LINE_CHAIN& poly = m_poly.Outline( ii );
const SHAPE_LINE_CHAIN& poly = GetPolyShape().Outline( ii );
for( int jj = 0; jj < (int) poly.SegmentCount(); ++jj )
{
@@ -2560,9 +2687,9 @@ bool EDA_SHAPE::operator==( const EDA_SHAPE& aOther ) const
if( m_bezierPoints != aOther.m_bezierPoints )
return false;
for( int ii = 0; ii < m_poly.TotalVertices(); ++ii )
for( int ii = 0; ii < GetPolyShape().TotalVertices(); ++ii )
{
if( m_poly.CVertex( ii ) != aOther.m_poly.CVertex( ii ) )
if( GetPolyShape().CVertex( ii ) != aOther.GetPolyShape().CVertex( ii ) )
return false;
}
@@ -2614,8 +2741,8 @@ double EDA_SHAPE::Similarity( const EDA_SHAPE& aOther ) const
}
{
int m = m_poly.TotalVertices();
int n = aOther.m_poly.TotalVertices();
int m = GetPolyShape().TotalVertices();
int n = aOther.GetPolyShape().TotalVertices();
std::vector<VECTOR2I> poly;
std::vector<VECTOR2I> otherPoly;
VECTOR2I lastPt( 0, 0 );
@@ -2627,16 +2754,16 @@ double EDA_SHAPE::Similarity( const EDA_SHAPE& aOther ) const
// will not be a match but the rest of the sequence will.
for( int ii = 0; ii < m; ++ii )
{
poly.emplace_back( lastPt - m_poly.CVertex( ii ) );
lastPt = m_poly.CVertex( ii );
poly.emplace_back( lastPt - GetPolyShape().CVertex( ii ) );
lastPt = GetPolyShape().CVertex( ii );
}
lastPt = VECTOR2I( 0, 0 );
for( int ii = 0; ii < n; ++ii )
{
otherPoly.emplace_back( lastPt - aOther.m_poly.CVertex( ii ) );
lastPt = aOther.m_poly.CVertex( ii );
otherPoly.emplace_back( lastPt - aOther.GetPolyShape().CVertex( ii ) );
lastPt = aOther.GetPolyShape().CVertex( ii );
}
size_t longest = alg::longest_common_subset( poly, otherPoly );
+46 -62
View File
@@ -100,8 +100,6 @@ GR_TEXT_V_ALIGN_T EDA_TEXT::MapVertJustify( int aVertJustify )
EDA_TEXT::EDA_TEXT( const EDA_IU_SCALE& aIuScale, const wxString& aText ) :
m_text( aText ),
m_IuScale( aIuScale ),
m_render_cache_font( nullptr ),
m_render_cache_mirrored( false ),
m_visible( true )
{
SetTextSize( VECTOR2I( EDA_UNIT_UTILS::Mils2IU( m_IuScale, DEFAULT_SIZE_TEXT ),
@@ -131,21 +129,7 @@ EDA_TEXT::EDA_TEXT( const EDA_TEXT& aText ) :
m_pos = aText.m_pos;
m_visible = aText.m_visible;
m_render_cache_font = aText.m_render_cache_font;
m_render_cache_text = aText.m_render_cache_text;
m_render_cache_angle = aText.m_render_cache_angle;
m_render_cache_offset = aText.m_render_cache_offset;
m_render_cache_mirrored = aText.m_render_cache_mirrored;
m_render_cache.clear();
for( const std::unique_ptr<KIFONT::GLYPH>& glyph : aText.m_render_cache )
{
if( KIFONT::OUTLINE_GLYPH* outline = dynamic_cast<KIFONT::OUTLINE_GLYPH*>( glyph.get() ) )
m_render_cache.emplace_back( std::make_unique<KIFONT::OUTLINE_GLYPH>( *outline ) );
else if( KIFONT::STROKE_GLYPH* stroke = dynamic_cast<KIFONT::STROKE_GLYPH*>( glyph.get() ) )
m_render_cache.emplace_back( std::make_unique<KIFONT::STROKE_GLYPH>( *stroke ) );
}
m_render_cache.reset();
{
std::lock_guard<std::mutex> bboxLock( aText.m_bbox_cacheMutex );
@@ -174,21 +158,7 @@ EDA_TEXT& EDA_TEXT::operator=( const EDA_TEXT& aText )
m_pos = aText.m_pos;
m_visible = aText.m_visible;
m_render_cache_font = aText.m_render_cache_font;
m_render_cache_text = aText.m_render_cache_text;
m_render_cache_angle = aText.m_render_cache_angle;
m_render_cache_offset = aText.m_render_cache_offset;
m_render_cache_mirrored = aText.m_render_cache_mirrored;
m_render_cache.clear();
for( const std::unique_ptr<KIFONT::GLYPH>& glyph : aText.m_render_cache )
{
if( KIFONT::OUTLINE_GLYPH* outline = dynamic_cast<KIFONT::OUTLINE_GLYPH*>( glyph.get() ) )
m_render_cache.emplace_back( std::make_unique<KIFONT::OUTLINE_GLYPH>( *outline ) );
else if( KIFONT::STROKE_GLYPH* stroke = dynamic_cast<KIFONT::STROKE_GLYPH*>( glyph.get() ) )
m_render_cache.emplace_back( std::make_unique<KIFONT::STROKE_GLYPH>( *stroke ) );
}
m_render_cache.reset();
{
std::scoped_lock<std::mutex, std::mutex> bboxLock( m_bbox_cacheMutex, aText.m_bbox_cacheMutex );
@@ -206,14 +176,14 @@ void EDA_TEXT::Serialize( google::protobuf::Any& aContainer ) const
using namespace kiapi::common;
types::Text text;
text.set_text( GetText().ToStdString() );
text.set_hyperlink( GetHyperlink().ToStdString() );
text.set_text( GetText().ToUTF8() );
text.set_hyperlink( GetHyperlink().ToUTF8() );
PackVector2( *text.mutable_position(), GetTextPos() );
types::TextAttributes* attrs = text.mutable_attributes();
if( GetFont() )
attrs->set_font_name( GetFont()->GetName().ToStdString() );
attrs->set_font_name( GetFont()->GetName().ToUTF8() );
attrs->set_horizontal_alignment( ToProtoEnum<GR_TEXT_H_ALIGN_T, types::HorizontalAlignment>( GetHorizJustify() ) );
@@ -524,8 +494,8 @@ bool EDA_TEXT::ResolveFont( const std::vector<wxString>* aEmbeddedFonts )
{
m_attributes.m_Font = KIFONT::FONT::GetFont( m_unresolvedFontName, IsBold(), IsItalic(), aEmbeddedFonts );
if( !m_render_cache.empty() )
m_render_cache_font = m_attributes.m_Font;
if( m_render_cache && !m_render_cache->glyphs.empty() )
m_render_cache->font = m_attributes.m_Font;
m_unresolvedFontName = wxEmptyString;
return true;
@@ -612,12 +582,15 @@ void EDA_TEXT::Offset( const VECTOR2I& aOffset )
m_pos += aOffset;
for( std::unique_ptr<KIFONT::GLYPH>& glyph : m_render_cache )
if( m_render_cache )
{
if( KIFONT::OUTLINE_GLYPH* outline = dynamic_cast<KIFONT::OUTLINE_GLYPH*>( glyph.get() ) )
outline->Move( aOffset );
else if( KIFONT::STROKE_GLYPH* stroke = dynamic_cast<KIFONT::STROKE_GLYPH*>( glyph.get() ) )
glyph = stroke->Transform( { 1.0, 1.0 }, aOffset, 0, ANGLE_0, false, { 0, 0 } );
for( std::unique_ptr<KIFONT::GLYPH>& glyph : m_render_cache->glyphs )
{
if( KIFONT::OUTLINE_GLYPH* outline = dynamic_cast<KIFONT::OUTLINE_GLYPH*>( glyph.get() ) )
outline->Move( aOffset );
else if( KIFONT::STROKE_GLYPH* stroke = dynamic_cast<KIFONT::STROKE_GLYPH*>( glyph.get() ) )
glyph = stroke->Transform( { 1.0, 1.0 }, aOffset, 0, ANGLE_0, false, { 0, 0 } );
}
}
ClearBoundingBoxCache();
@@ -682,7 +655,7 @@ const KIFONT::METRICS& EDA_TEXT::getFontMetrics() const
void EDA_TEXT::ClearRenderCache()
{
m_render_cache.clear();
m_render_cache.reset();
}
@@ -701,26 +674,31 @@ EDA_TEXT::GetRenderCache( const KIFONT::FONT* aFont, const wxString& forResolved
EDA_ANGLE resolvedAngle = GetDrawRotation();
bool mirrored = IsMirrored();
if( m_render_cache.empty() || m_render_cache_font != aFont || m_render_cache_text != forResolvedText
|| m_render_cache_angle != resolvedAngle || m_render_cache_offset != aOffset
|| m_render_cache_mirrored != mirrored )
if( !m_render_cache )
m_render_cache = std::make_unique<EDA_TEXT_RENDER_CACHE_DATA>();
if( m_render_cache->glyphs.empty() || m_render_cache->font != aFont
|| m_render_cache->text != forResolvedText
|| m_render_cache->angle != resolvedAngle || m_render_cache->offset != aOffset
|| m_render_cache->mirrored != mirrored )
{
m_render_cache.clear();
m_render_cache->glyphs.clear();
const KIFONT::OUTLINE_FONT* font = static_cast<const KIFONT::OUTLINE_FONT*>( aFont );
TEXT_ATTRIBUTES attrs = GetAttributes();
attrs.m_Angle = resolvedAngle;
font->GetLinesAsGlyphs( &m_render_cache, forResolvedText, GetDrawPos() + aOffset, attrs, getFontMetrics() );
m_render_cache_font = aFont;
m_render_cache_angle = resolvedAngle;
m_render_cache_text = forResolvedText;
m_render_cache_offset = aOffset;
m_render_cache_mirrored = mirrored;
font->GetLinesAsGlyphs( &m_render_cache->glyphs, forResolvedText, GetDrawPos() + aOffset, attrs,
getFontMetrics() );
m_render_cache->font = aFont;
m_render_cache->angle = resolvedAngle;
m_render_cache->text = forResolvedText;
m_render_cache->offset = aOffset;
m_render_cache->mirrored = mirrored;
}
return &m_render_cache;
return &m_render_cache->glyphs;
}
return nullptr;
@@ -730,19 +708,25 @@ EDA_TEXT::GetRenderCache( const KIFONT::FONT* aFont, const wxString& forResolved
void EDA_TEXT::SetupRenderCache( const wxString& aResolvedText, const KIFONT::FONT* aFont, const EDA_ANGLE& aAngle,
const VECTOR2I& aOffset )
{
m_render_cache_text = aResolvedText;
m_render_cache_font = aFont;
m_render_cache_angle = aAngle;
m_render_cache_offset = aOffset;
m_render_cache_mirrored = IsMirrored();
m_render_cache.clear();
if( !m_render_cache )
m_render_cache = std::make_unique<EDA_TEXT_RENDER_CACHE_DATA>();
m_render_cache->text = aResolvedText;
m_render_cache->font = aFont;
m_render_cache->angle = aAngle;
m_render_cache->offset = aOffset;
m_render_cache->mirrored = IsMirrored();
m_render_cache->glyphs.clear();
}
void EDA_TEXT::AddRenderCacheGlyph( const SHAPE_POLY_SET& aPoly )
{
m_render_cache.emplace_back( std::make_unique<KIFONT::OUTLINE_GLYPH>( aPoly ) );
static_cast<KIFONT::OUTLINE_GLYPH*>( m_render_cache.back().get() )->CacheTriangulation();
if( !m_render_cache )
m_render_cache = std::make_unique<EDA_TEXT_RENDER_CACHE_DATA>();
m_render_cache->glyphs.emplace_back( std::make_unique<KIFONT::OUTLINE_GLYPH>( aPoly ) );
static_cast<KIFONT::OUTLINE_GLYPH*>( m_render_cache->glyphs.back().get() )->CacheTriangulation();
}
+18 -3
View File
@@ -43,6 +43,7 @@
#include <pgm_base.h>
#include <trace_helpers.h>
#include <wx/app.h>
#include <wx/frame.h>
#include <macros.h>
@@ -433,7 +434,8 @@ OPENGL_GAL::~OPENGL_GAL()
gl_mgr->LockCtx( m_glPrivContext, this );
--m_instanceCounter;
glFlush();
if( m_isInitialized )
glFlush();
gluDeleteTess( m_tesselator );
ClearCache();
@@ -497,6 +499,13 @@ wxString OPENGL_GAL::CheckFeatures( GAL_DISPLAY_OPTIONS& aOptions )
testFrame->Raise();
testFrame->Show();
#ifdef __WXGTK__
// On GTK, Show() only queues realization. The GDK drawing window
// needed by SetCurrent() may not exist yet. Yield to let the event
// loop process the realize signal before we try to lock the context.
wxYield();
#endif
GAL_CONTEXT_LOCKER lock( opengl_gal );
opengl_gal->init();
}
@@ -2836,8 +2845,14 @@ void OPENGL_GAL::init()
if( glVersion == 0 )
throw std::runtime_error( "Failed to load OpenGL via loader" );
SetOpenGLInfo( (const char*) glGetString( GL_VENDOR ), (const char*) glGetString( GL_RENDERER ),
(const char*) glGetString( GL_VERSION ) );
const char* vendor = (const char*) glGetString( GL_VENDOR );
const char* renderer = (const char*) glGetString( GL_RENDERER );
const char* version = (const char*) glGetString( GL_VERSION );
if( !version )
throw std::runtime_error( "No GL context is current (glGetString returned NULL)" );
SetOpenGLInfo( vendor, renderer, version );
// Check the OpenGL version (minimum 2.1 is required)
if( !GLAD_GL_VERSION_2_1 )
@@ -0,0 +1,159 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright The 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 2
* 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, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include <io/altium/altium_project_variants.h>
#include <wx/fileconf.h>
#include <wx/log.h>
static ALTIUM_VARIANT_ENTRY ParseVariationString( const wxString& aValue )
{
ALTIUM_VARIANT_ENTRY entry;
for( const wxString& token : wxSplit( aValue, '|' ) )
{
int eqPos = token.Find( '=' );
if( eqPos == wxNOT_FOUND )
continue;
wxString key = token.Left( eqPos ).Trim().Trim( false );
wxString val = token.Mid( eqPos + 1 ).Trim().Trim( false );
if( key.CmpNoCase( wxS( "Designator" ) ) == 0 )
{
entry.designator = val;
}
else if( key.CmpNoCase( wxS( "UniqueId" ) ) == 0 )
{
entry.uniqueId = val;
}
else if( key.CmpNoCase( wxS( "Kind" ) ) == 0 )
{
long k = 0;
val.ToLong( &k );
entry.kind = static_cast<int>( k );
}
else if( key.CmpNoCase( wxS( "AlternatePart" ) ) == 0 )
{
if( val.empty() )
continue;
// AlternatePart contains sub-fields in the same pipe-delimited format, but since
// it appears at the end of the line, the remaining tokens are its sub-fields.
// We've already split on '|', so we just keep accumulating from here.
// However, wxSplit already split everything. The AlternatePart sub-fields are the
// remaining tokens after this one. We handle this below after the loop.
}
}
// Parse AlternatePart sub-fields. In the raw line, AlternatePart= is followed by
// pipe-separated key=value pairs that are part of the alternate part definition.
// Since we already split on '|', find the AlternatePart token and treat everything
// after it as sub-fields.
bool inAlternatePart = false;
for( const wxString& token : wxSplit( aValue, '|' ) )
{
int eqPos = token.Find( '=' );
if( eqPos == wxNOT_FOUND )
continue;
wxString key = token.Left( eqPos ).Trim().Trim( false );
wxString val = token.Mid( eqPos + 1 ).Trim().Trim( false );
if( key.CmpNoCase( wxS( "AlternatePart" ) ) == 0 )
{
inAlternatePart = true;
// The value after AlternatePart= might itself be the first sub-field value
// In practice it's typically empty for Kind=1, or a lib reference for Kind=0
if( !val.empty() )
entry.alternateFields[wxS( "LibReference" )] = val;
continue;
}
if( inAlternatePart && !val.empty() )
entry.alternateFields[key] = val;
}
return entry;
}
std::vector<ALTIUM_PROJECT_VARIANT> ParseAltiumProjectVariants( const wxString& aPrjPcbPath )
{
std::vector<ALTIUM_PROJECT_VARIANT> variants;
wxFileConfig config( wxEmptyString, wxEmptyString, wxEmptyString, aPrjPcbPath,
wxCONFIG_USE_NO_ESCAPE_CHARACTERS );
wxString groupname;
long groupid;
for( bool more = config.GetFirstGroup( groupname, groupid ); more;
more = config.GetNextGroup( groupname, groupid ) )
{
if( !groupname.StartsWith( wxS( "ProjectVariant" ) ) )
continue;
wxString numStr = groupname.Mid( 14 );
long num;
if( !numStr.ToLong( &num ) )
continue;
ALTIUM_PROJECT_VARIANT pv;
pv.description = config.Read( groupname + wxS( "/Description" ), wxEmptyString );
pv.name = pv.description;
if( pv.name.empty() )
pv.name = groupname;
long variationCount = 0;
config.Read( groupname + wxS( "/VariationCount" ), &variationCount, 0 );
for( long vi = 1; vi <= variationCount; ++vi )
{
wxString key = wxString::Format( wxS( "%s/Variation%ld" ), groupname, vi );
wxString value = config.Read( key, wxEmptyString );
if( value.empty() )
continue;
ALTIUM_VARIANT_ENTRY entry = ParseVariationString( value );
if( !entry.designator.empty() )
pv.variations.push_back( std::move( entry ) );
}
if( !pv.variations.empty() )
variants.push_back( std::move( pv ) );
}
return variants;
}
@@ -0,0 +1,68 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright The 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 2
* 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, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#ifndef ALTIUM_PROJECT_VARIANTS_H
#define ALTIUM_PROJECT_VARIANTS_H
#include <map>
#include <vector>
#include <wx/string.h>
/**
* A single component variation within an Altium project variant.
*
* In Altium, each variant can override individual components. Kind=1 means
* "Not Fitted" (DNP), Kind=0 means "Alternate" with optional field overrides
* supplied via the AlternatePart string.
*/
struct ALTIUM_VARIANT_ENTRY
{
wxString designator;
wxString uniqueId;
int kind = 0;
std::map<wxString, wxString> alternateFields;
};
/**
* A project-level assembly variant parsed from an Altium .PrjPcb file.
*
* Each [ProjectVariantN] section in the .PrjPcb becomes one of these.
*/
struct ALTIUM_PROJECT_VARIANT
{
wxString name;
wxString description;
std::vector<ALTIUM_VARIANT_ENTRY> variations;
};
/**
* Parse all [ProjectVariantN] sections from an Altium .PrjPcb project file.
*
* @param aPrjPcbPath Full path to the .PrjPcb file.
* @return Vector of project variants with their per-component entries.
*/
std::vector<ALTIUM_PROJECT_VARIANT> ParseAltiumProjectVariants( const wxString& aPrjPcbPath );
#endif // ALTIUM_PROJECT_VARIANTS_H
+1 -1
View File
@@ -98,5 +98,5 @@ bool AutoDecodeCSV( const wxString& aInput, std::vector<std::vector<wxString>>&
}
// Anything in the first row?
return aData[0].size() > 0;
return !aData.empty() && aData[0].size() > 0;
}
+3 -1
View File
@@ -47,7 +47,8 @@ JOB_EXPORT_PCB_IPC2581::JOB_EXPORT_PCB_IPC2581() :
m_colMfgPn(),
m_colMfg(),
m_colDistPn(),
m_colDist()
m_colDist(),
m_bomRev()
{
m_params.emplace_back( new JOB_PARAM<wxString>( "drawing_sheet", &m_drawingSheet, m_drawingSheet ) );
m_params.emplace_back( new JOB_PARAM<IPC2581_UNITS>( "units", &m_units, m_units ) );
@@ -64,6 +65,7 @@ JOB_EXPORT_PCB_IPC2581::JOB_EXPORT_PCB_IPC2581() :
&m_colDistPn,
m_colDistPn ) );
m_params.emplace_back( new JOB_PARAM<wxString>( "field_bom_map.dist", &m_colDist, m_colDist ) );
m_params.emplace_back( new JOB_PARAM<wxString>( "bom_rev", &m_bomRev, m_bomRev ) );
}
+1
View File
@@ -61,6 +61,7 @@ public:
wxString m_colMfg;
wxString m_colDistPn;
wxString m_colDist;
wxString m_bomRev;
};
#endif
+1 -1
View File
@@ -214,7 +214,7 @@ bool NUMERIC_EVALUATOR::IsOldSchoolDecimalSeparator( wxUniChar ch, double* siSca
// Limited version of above for 8-bit chars
bool NUMERIC_EVALUATOR::isOldSchoolDecimalSeparator( char ch, double* siScaler )
bool NUMERIC_EVALUATOR::IsOldSchoolDecimalSeparator( char ch, double* siScaler )
{
switch( ch )
{
+115 -47
View File
@@ -346,6 +346,17 @@ wxString LIBRARY_MANAGER::DefaultGlobalTablePath( LIBRARY_TABLE_TYPE aType )
}
wxString LIBRARY_MANAGER::StockTablePath( LIBRARY_TABLE_TYPE aType )
{
wxString basePath = PATHS::GetStockTemplatesPath();
wxFileName fn( basePath, tableFileName( aType ) );
fn.Normalize( FN_NORMALIZE_FLAGS | wxPATH_NORM_ENV_VARS );
return fn.GetFullPath();
}
bool LIBRARY_MANAGER::IsTableValid( const wxString& aPath )
{
if( wxFileName fn( aPath ); fn.IsFileReadable() )
@@ -393,7 +404,7 @@ bool LIBRARY_MANAGER::CreateGlobalTable( LIBRARY_TABLE_TYPE aType, bool aPopulat
table.SetType( aType );
table.Rows().clear();
wxFileName defaultLib( PATHS::GetStockTemplatesPath(), tableFileName( aType ) );
wxFileName defaultLib( StockTablePath( aType ) );
if( !defaultLib.IsFileReadable() )
{
@@ -515,6 +526,11 @@ void LIBRARY_MANAGER::LoadProjectTables( std::initializer_list<LIBRARY_TABLE_TYP
void LIBRARY_MANAGER::ProjectChanged()
{
// Abort any running async library loads before reloading project tables.
// Background workers hold raw LIBRARY_TABLE_ROW pointers that become dangling
// when loadTables() destroys and replaces the table objects.
AbortAsyncLoads();
LoadProjectTables( Pgm().GetSettingsManager().Prj().GetProjectDirectory() );
std::scoped_lock lock( m_adaptersMutex );
@@ -751,9 +767,14 @@ void LIBRARY_MANAGER::ReloadTables( LIBRARY_TABLE_SCOPE aScope,
std::initializer_list<LIBRARY_TABLE_TYPE> aTablesToLoad )
{
if( aScope == LIBRARY_TABLE_SCOPE::PROJECT )
{
AbortAsyncLoads();
LoadProjectTables( aTablesToLoad );
}
else
{
LoadGlobalTables( aTablesToLoad );
}
}
@@ -1440,6 +1461,18 @@ void LIBRARY_MANAGER_ADAPTER::AsyncLoad()
return false;
};
// Collect work items with pre-resolved URIs. URI expansion accesses PROJECT data
// (text variables, env vars) that is not thread-safe, so resolve on the calling thread.
struct LOAD_WORK
{
wxString nickname;
LIBRARY_TABLE_SCOPE scope;
wxString uri;
};
auto workQueue = std::make_shared<std::vector<LOAD_WORK>>();
workQueue->reserve( rows.size() );
for( const LIBRARY_TABLE_ROW* row : rows )
{
wxString nickname = row->Nickname();
@@ -1457,67 +1490,102 @@ void LIBRARY_MANAGER_ADAPTER::AsyncLoad()
continue;
}
// Resolve the URI on the main thread. URI expansion accesses PROJECT data
// (text variables, env vars) that is not thread-safe.
wxString uri = getUri( row );
workQueue->emplace_back( LOAD_WORK{ nickname, scope, getUri( row ) } );
}
if( workQueue->empty() )
{
wxLogTrace( traceLibraries, "AsyncLoad: all libraries already loaded; exiting" );
return;
}
// Cap loading threads to leave headroom for the GUI and other thread pool work.
// Each worker pulls libraries from a shared queue, so we submit fewer tasks than
// libraries and avoid flooding the pool.
size_t poolSize = tp.get_thread_count();
size_t maxLoadThreads = std::max<size_t>( 1, poolSize > 2 ? poolSize - 2 : 1 );
size_t numWorkers = std::min( maxLoadThreads, workQueue->size() );
auto workIndex = std::make_shared<std::atomic<size_t>>( 0 );
wxLogTrace( traceLibraries, "AsyncLoad: %zu libraries to load, using %zu worker threads (pool has %zu)",
workQueue->size(), numWorkers, poolSize );
for( size_t w = 0; w < numWorkers; ++w )
{
m_futures.emplace_back( tp.submit_task(
[this, nickname, scope, uri]()
[this, workQueue, workIndex]()
{
if( m_abort.load() )
return;
LIBRARY_RESULT<LIB_DATA*> result = loadIfNeeded( nickname );
if( result.has_value() )
while( true )
{
LIB_DATA* lib = *result;
if( m_abort.load() )
return;
try
size_t idx = workIndex->fetch_add( 1 );
if( idx >= workQueue->size() )
return;
const LOAD_WORK& work = ( *workQueue )[idx];
LIBRARY_RESULT<LIB_DATA*> result = loadIfNeeded( work.nickname );
if( result.has_value() )
{
LIB_DATA* lib = *result;
try
{
std::unique_lock lock( scope == LIBRARY_TABLE_SCOPE::GLOBAL ? globalLibsMutex()
: m_librariesMutex );
lib->status.load_status = LOAD_STATUS::LOADING;
{
std::unique_lock lock(
work.scope == LIBRARY_TABLE_SCOPE::GLOBAL
? globalLibsMutex()
: m_librariesMutex );
lib->status.load_status = LOAD_STATUS::LOADING;
}
enumerateLibrary( lib, work.uri );
{
std::unique_lock lock(
work.scope == LIBRARY_TABLE_SCOPE::GLOBAL
? globalLibsMutex()
: m_librariesMutex );
lib->status.load_status = LOAD_STATUS::LOADED;
}
}
enumerateLibrary( lib, uri );
catch( IO_ERROR& e )
{
std::unique_lock lock( scope == LIBRARY_TABLE_SCOPE::GLOBAL ? globalLibsMutex()
: m_librariesMutex );
lib->status.load_status = LOAD_STATUS::LOADED;
std::unique_lock lock(
work.scope == LIBRARY_TABLE_SCOPE::GLOBAL
? globalLibsMutex()
: m_librariesMutex );
lib->status.load_status = LOAD_STATUS::LOAD_ERROR;
lib->status.error = LIBRARY_ERROR( { e.What() } );
wxLogTrace( traceLibraries, "%s: plugin threw exception: %s",
work.nickname, e.What() );
}
}
catch( IO_ERROR& e )
else
{
std::unique_lock lock( scope == LIBRARY_TABLE_SCOPE::GLOBAL ? globalLibsMutex()
: m_librariesMutex );
lib->status.load_status = LOAD_STATUS::LOAD_ERROR;
lib->status.error = LIBRARY_ERROR( { e.What() } );
wxLogTrace( traceLibraries, "%s: plugin threw exception: %s", nickname, e.What() );
std::unique_lock lock(
work.scope == LIBRARY_TABLE_SCOPE::GLOBAL
? globalLibsMutex()
: m_librariesMutex );
std::map<wxString, LIB_DATA>& target =
( work.scope == LIBRARY_TABLE_SCOPE::GLOBAL ) ? globalLibs()
: m_libraries;
target[work.nickname].status = LIB_STATUS( {
.load_status = LOAD_STATUS::LOAD_ERROR,
.error = result.error()
} );
}
++m_loadCount;
}
else
{
std::unique_lock lock( scope == LIBRARY_TABLE_SCOPE::GLOBAL ? globalLibsMutex()
: m_librariesMutex );
std::map<wxString, LIB_DATA>& target = ( scope == LIBRARY_TABLE_SCOPE::GLOBAL ) ? globalLibs()
: m_libraries;
target[nickname].status = LIB_STATUS( {
.load_status = LOAD_STATUS::LOAD_ERROR,
.error = result.error()
} );
}
++m_loadCount;
}, BS::pr::lowest ) );
}
size_t total = m_loadTotal.load();
if( total )
wxLogTrace( traceLibraries, "Started async load of %zu libraries", total );
wxLogTrace( traceLibraries, "Started async load of %zu libraries", workQueue->size() );
}
+205 -86
View File
@@ -22,10 +22,13 @@
*/
#include <local_history.h>
#include <dialogs/dialog_restore_local_history.h>
#include <history_lock.h>
#include <io/kicad/kicad_io_utils.h>
#include <lockfile.h>
#include <settings/common_settings.h>
#include <pgm_base.h>
#include <thread_pool.h>
#include <trace_helpers.h>
#include <wildcards_and_files_ext.h>
#include <confirm.h>
@@ -38,7 +41,6 @@
#include <wx/datetime.h>
#include <wx/log.h>
#include <wx/msgdlg.h>
#include <wx/choicdlg.h>
#include <vector>
#include <string>
@@ -62,6 +64,7 @@ LOCAL_HISTORY::LOCAL_HISTORY()
LOCAL_HISTORY::~LOCAL_HISTORY()
{
WaitForPendingSave();
}
void LOCAL_HISTORY::NoteFileChange( const wxString& aFile )
@@ -75,8 +78,9 @@ void LOCAL_HISTORY::NoteFileChange( const wxString& aFile )
}
void LOCAL_HISTORY::RegisterSaver( const void* aSaverObject,
const std::function<void( const wxString&, std::vector<wxString>& )>& aSaver )
void LOCAL_HISTORY::RegisterSaver(
const void* aSaverObject,
const std::function<void( const wxString&, std::vector<HISTORY_FILE_DATA>& )>& aSaver )
{
if( m_savers.find( aSaverObject ) != m_savers.end() )
{
@@ -91,6 +95,8 @@ void LOCAL_HISTORY::RegisterSaver( const void* aSaverObject,
void LOCAL_HISTORY::UnregisterSaver( const void* aSaverObject )
{
WaitForPendingSave();
auto it = m_savers.find( aSaverObject );
if( it != m_savers.end() )
@@ -103,6 +109,7 @@ void LOCAL_HISTORY::UnregisterSaver( const void* aSaverObject )
void LOCAL_HISTORY::ClearAllSavers()
{
WaitForPendingSave();
m_savers.clear();
wxLogTrace( traceAutoSave, wxS("[history] Cleared all savers") );
}
@@ -125,88 +132,129 @@ bool LOCAL_HISTORY::RunRegisteredSaversAndCommit( const wxString& aProjectPath,
return false;
}
std::vector<wxString> files;
// Skip if previous background save is still running
if( m_saveInProgress.load( std::memory_order_acquire ) )
{
wxLogTrace( traceAutoSave, wxS("[history] previous save still in progress; skipping cycle") );
return false;
}
// Phase 1 (UI thread): call savers to collect serialized data
std::vector<HISTORY_FILE_DATA> fileData;
for( const auto& [saverObject, saver] : m_savers )
{
size_t before = files.size();
saver( aProjectPath, files );
wxLogTrace( traceAutoSave, wxS("[history] saver %p added %zu files (total=%zu)"),
saverObject, files.size() - before, files.size() );
size_t before = fileData.size();
saver( aProjectPath, fileData );
wxLogTrace( traceAutoSave, wxS("[history] saver %p produced %zu entries (total=%zu)"),
saverObject, fileData.size() - before, fileData.size() );
}
// Filter out any files not within the project directory
// Filter out any entries not within the project directory
wxString projectDir = aProjectPath;
if( !projectDir.EndsWith( wxFileName::GetPathSeparator() ) )
projectDir += wxFileName::GetPathSeparator();
auto it = std::remove_if( files.begin(), files.end(),
[&projectDir]( const wxString& file )
auto it = std::remove_if( fileData.begin(), fileData.end(),
[&projectDir]( const HISTORY_FILE_DATA& entry )
{
if( !file.StartsWith( projectDir ) )
if( !entry.path.StartsWith( projectDir ) )
{
wxLogTrace( traceAutoSave, wxS("[history] filtered out file outside project: %s"), file );
wxLogTrace( traceAutoSave, wxS("[history] filtered out entry outside project: %s"), entry.path );
return true;
}
return false;
} );
files.erase( it, files.end() );
fileData.erase( it, fileData.end() );
if( files.empty() )
if( fileData.empty() )
{
wxLogTrace( traceAutoSave, wxS("[history] saver set produced no files; skipping") );
wxLogTrace( traceAutoSave, wxS("[history] saver set produced no entries; skipping") );
return false;
}
// Phase 2: submit Prettify + file I/O + git to background thread
m_saveInProgress.store( true, std::memory_order_release );
m_pendingFuture = GetKiCadThreadPool().submit_task(
[this, projectPath = aProjectPath, title = aTitle,
data = std::move( fileData )]() mutable -> bool
{
bool result = commitInBackground( projectPath, title, data );
m_saveInProgress.store( false, std::memory_order_release );
return result;
} );
return true;
}
bool LOCAL_HISTORY::commitInBackground( const wxString& aProjectPath, const wxString& aTitle,
const std::vector<HISTORY_FILE_DATA>& aFileData )
{
wxLogTrace( traceAutoSave, wxS("[history] background: writing %zu entries for '%s'"),
aFileData.size(), aProjectPath );
wxString hist = historyPath( aProjectPath );
// Write files to the .history mirror
for( const HISTORY_FILE_DATA& entry : aFileData )
{
if( !entry.content.empty() )
{
std::string buf = entry.content;
if( entry.prettify )
KICAD_FORMAT::Prettify( buf, entry.formatMode );
wxFFile fp( entry.path, wxS( "wb" ) );
if( fp.IsOpened() )
{
fp.Write( buf.data(), buf.size() );
fp.Close();
wxLogTrace( traceAutoSave, wxS("[history] background: wrote %zu bytes to '%s'"),
buf.size(), entry.path );
}
else
{
wxLogTrace( traceAutoSave, wxS("[history] background: failed to open '%s' for writing"),
entry.path );
}
}
else if( !entry.sourcePath.IsEmpty() )
{
wxCopyFile( entry.sourcePath, entry.path, true );
wxLogTrace( traceAutoSave, wxS("[history] background: copied '%s' -> '%s'"),
entry.sourcePath, entry.path );
}
}
// Acquire locks using hybrid locking strategy
HISTORY_LOCK_MANAGER lock( aProjectPath );
if( !lock.IsLocked() )
{
wxLogTrace( traceAutoSave, wxS("[history] failed to acquire lock: %s"), lock.GetLockError() );
wxLogTrace( traceAutoSave, wxS("[history] background: failed to acquire lock: %s"), lock.GetLockError() );
return false;
}
git_repository* repo = lock.GetRepository();
git_index* index = lock.GetIndex();
wxString hist = historyPath( aProjectPath );
// Stage selected files (mirroring logic from CommitSnapshot but limited to given files)
for( const wxString& file : files )
// Stage all written files
for( const HISTORY_FILE_DATA& entry : aFileData )
{
wxFileName src( file );
wxFileName src( entry.path );
if( !src.FileExists() )
{
wxLogTrace( traceAutoSave, wxS("[history] skip missing '%s'"), file );
continue;
}
// If saver already produced a path inside history mirror, just stage it.
if( src.GetFullPath().StartsWith( hist + wxFILE_SEP_PATH ) )
{
std::string relHist = src.GetFullPath().ToStdString().substr( hist.length() + 1 );
git_index_add_bypath( index, relHist.c_str() );
wxLogTrace( traceAutoSave, wxS("[history] staged pre-mirrored '%s'"), file );
continue;
}
wxString relStr;
wxString proj = wxFileName( aProjectPath ).GetFullPath();
if( src.GetFullPath().StartsWith( proj + wxFILE_SEP_PATH ) )
relStr = src.GetFullPath().Mid( proj.length() + 1 );
else
relStr = src.GetFullName();
wxFileName dst( hist + wxFILE_SEP_PATH + relStr );
wxFileName dstDir( dst );
dstDir.SetFullName( wxEmptyString );
wxFileName::Mkdir( dstDir.GetPath(), 0777, wxPATH_MKDIR_FULL );
wxCopyFile( src.GetFullPath(), dst.GetFullPath(), true );
std::string rel = dst.GetFullPath().ToStdString().substr( hist.length() + 1 );
git_index_add_bypath( index, rel.c_str() );
wxLogTrace( traceAutoSave, wxS("[history] staged '%s' as '%s'"), file, wxString::FromUTF8( rel ) );
}
// Compare index to HEAD; if no diff -> abort to avoid empty commit.
@@ -225,7 +273,7 @@ bool LOCAL_HISTORY::RunRegisteredSaversAndCommit( const wxString& aProjectPath,
{
if( head_tree ) git_tree_free( head_tree );
if( head_commit ) git_commit_free( head_commit );
wxLogTrace( traceAutoSave, wxS("[history] failed to write index tree" ) );
wxLogTrace( traceAutoSave, wxS("[history] background: failed to write index tree" ) );
return false;
}
@@ -241,7 +289,7 @@ bool LOCAL_HISTORY::RunRegisteredSaversAndCommit( const wxString& aProjectPath,
if( git_diff_tree_to_tree( &diff, repo, head_tree, indexTree.get(), nullptr ) == 0 )
{
hasChanges = git_diff_num_deltas( diff ) > 0;
wxLogTrace( traceAutoSave, wxS("[history] diff deltas=%u"), (unsigned) git_diff_num_deltas( diff ) );
wxLogTrace( traceAutoSave, wxS("[history] background: diff deltas=%u"), (unsigned) git_diff_num_deltas( diff ) );
git_diff_free( diff );
}
}
@@ -251,7 +299,7 @@ bool LOCAL_HISTORY::RunRegisteredSaversAndCommit( const wxString& aProjectPath,
if( !hasChanges )
{
wxLogTrace( traceAutoSave, wxS("[history] no changes detected; no commit") );
wxLogTrace( traceAutoSave, wxS("[history] background: no changes detected; no commit") );
return false; // Nothing new; skip commit.
}
@@ -278,10 +326,10 @@ bool LOCAL_HISTORY::RunRegisteredSaversAndCommit( const wxString& aProjectPath,
parents ? &constParent : nullptr );
if( rc == 0 )
wxLogTrace( traceAutoSave, wxS("[history] commit created %s (%s files=%zu)"),
wxString::FromUTF8( git_oid_tostr_s( &commit_id ) ), msg, files.size() );
wxLogTrace( traceAutoSave, wxS("[history] background: commit created %s (%s entries=%zu)"),
wxString::FromUTF8( git_oid_tostr_s( &commit_id ) ), msg, aFileData.size() );
else
wxLogTrace( traceAutoSave, wxS("[history] commit failed rc=%d"), rc );
wxLogTrace( traceAutoSave, wxS("[history] background: commit failed rc=%d"), rc );
if( parent ) git_commit_free( parent );
@@ -290,6 +338,16 @@ bool LOCAL_HISTORY::RunRegisteredSaversAndCommit( const wxString& aProjectPath,
}
void LOCAL_HISTORY::WaitForPendingSave()
{
if( m_pendingFuture.valid() )
{
wxLogTrace( traceAutoSave, wxS("[history] waiting for pending background save") );
m_pendingFuture.get();
}
}
bool LOCAL_HISTORY::CommitPending()
{
std::vector<wxString> files( m_pendingFiles.begin(), m_pendingFiles.end() );
@@ -439,9 +497,17 @@ bool LOCAL_HISTORY::Init( const wxString& aProjectPath )
// Helper function to commit files using an already-acquired lock
static bool commitSnapshotWithLock( git_repository* repo, git_index* index,
const wxString& aHistoryPath, const wxString& aProjectPath,
const std::vector<wxString>& aFiles, const wxString& aTitle )
enum class SNAPSHOT_COMMIT_RESULT
{
Error,
NoChanges,
Committed
};
static SNAPSHOT_COMMIT_RESULT commitSnapshotWithLock( git_repository* repo, git_index* index,
const wxString& aHistoryPath, const wxString& aProjectPath,
const std::vector<wxString>& aFiles, const wxString& aTitle )
{
std::vector<std::string> filesArrStr;
@@ -485,7 +551,7 @@ static bool commitSnapshotWithLock( git_repository* repo, git_index* index,
if( filesArrStr.size() == 0 )
{
wxLogTrace( traceAutoSave, wxS( "No changes, skipping" ) );
return false;
return SNAPSHOT_COMMIT_RESULT::NoChanges;
}
int rc = git_index_add_all( index, &filesArrGit, GIT_INDEX_ADD_DISABLE_PATHSPEC_MATCH | GIT_INDEX_ADD_FORCE, NULL,
@@ -493,11 +559,11 @@ static bool commitSnapshotWithLock( git_repository* repo, git_index* index,
wxLogTrace( traceAutoSave, wxS( "Adding %zu files, rc %d" ), filesArrStr.size(), rc );
if( rc != 0 )
return false;
return SNAPSHOT_COMMIT_RESULT::Error;
git_oid tree_id;
if( git_index_write_tree( &tree_id, index ) != 0 )
return false;
return SNAPSHOT_COMMIT_RESULT::Error;
git_tree* rawTree = nullptr;
git_tree_lookup( &rawTree, repo, &tree_id );
@@ -537,7 +603,7 @@ static bool commitSnapshotWithLock( git_repository* repo, git_index* index,
if( numChangedFiles == 0 )
{
wxLogTrace( traceAutoSave, wxS( "No actual changes in tree, skipping commit" ) );
return false;
return SNAPSHOT_COMMIT_RESULT::NoChanges;
}
wxString msg;
@@ -566,11 +632,15 @@ static bool commitSnapshotWithLock( git_repository* repo, git_index* index,
git_oid commit_id;
git_commit* parentPtr = parent.get();
const git_commit* constParentPtr = parentPtr;
git_commit_create( &commit_id, repo, "HEAD", sig.get(), sig.get(), nullptr,
msg.mb_str().data(), tree.get(), parents,
parentPtr ? &constParentPtr : nullptr );
if( git_commit_create( &commit_id, repo, "HEAD", sig.get(), sig.get(), nullptr, msg.mb_str().data(), tree.get(),
parents, parentPtr ? &constParentPtr : nullptr )
!= 0 )
{
return SNAPSHOT_COMMIT_RESULT::Error;
}
git_index_write( index );
return true;
return SNAPSHOT_COMMIT_RESULT::Committed;
}
@@ -595,7 +665,7 @@ bool LOCAL_HISTORY::CommitSnapshot( const std::vector<wxString>& aFiles, const w
git_repository* repo = lock.GetRepository();
git_index* index = lock.GetIndex();
return commitSnapshotWithLock( repo, index, hist, proj, aFiles, aTitle );
return commitSnapshotWithLock( repo, index, hist, proj, aFiles, aTitle ) == SNAPSHOT_COMMIT_RESULT::Committed;
}
@@ -1795,8 +1865,10 @@ bool LOCAL_HISTORY::RestoreCommit( const wxString& aProjectPath, const wxString&
if( !backupFiles.empty() )
{
wxString hist = historyPath( aProjectPath );
if( !commitSnapshotWithLock( repo, lock.GetIndex(), hist, aProjectPath, backupFiles,
wxS( "Pre-restore backup" ) ) )
SNAPSHOT_COMMIT_RESULT backupResult = commitSnapshotWithLock( repo, lock.GetIndex(), hist, aProjectPath,
backupFiles, wxS( "Pre-restore backup" ) );
if( backupResult == SNAPSHOT_COMMIT_RESULT::Error )
{
wxLogTrace( traceAutoSave,
wxS( "[history] RestoreCommit: Failed to create pre-restore backup" ) );
@@ -1804,6 +1876,12 @@ bool LOCAL_HISTORY::RestoreCommit( const wxString& aProjectPath, const wxString&
git_commit_free( commit );
return false;
}
if( backupResult == SNAPSHOT_COMMIT_RESULT::NoChanges )
{
wxLogTrace( traceAutoSave, wxS( "[history] RestoreCommit: Current state already matches HEAD; "
"continuing without a new backup commit" ) );
}
}
// STEP 3: Extract commit to temporary location
@@ -1909,46 +1987,87 @@ void LOCAL_HISTORY::ShowRestoreDialog( const wxString& aProjectPath, wxWindow* a
if( !HistoryExists( aProjectPath ) )
return;
std::vector<LOCAL_HISTORY_SNAPSHOT_INFO> snapshots = LoadSnapshots( aProjectPath );
if( snapshots.empty() )
return;
DIALOG_RESTORE_LOCAL_HISTORY dlg( aParent, snapshots );
if( dlg.ShowModal() == wxID_OK )
{
wxString selectedHash = dlg.GetSelectedHash();
if( !selectedHash.IsEmpty() )
RestoreCommit( aProjectPath, selectedHash, aParent );
}
}
std::vector<LOCAL_HISTORY_SNAPSHOT_INFO> LOCAL_HISTORY::LoadSnapshots( const wxString& aProjectPath )
{
std::vector<LOCAL_HISTORY_SNAPSHOT_INFO> snapshots;
wxString hist = historyPath( aProjectPath );
git_repository* repo = nullptr;
if( git_repository_open( &repo, hist.mb_str().data() ) != 0 )
return;
return snapshots;
git_revwalk* walk = nullptr;
git_revwalk_new( &walk, repo );
if( git_revwalk_new( &walk, repo ) != 0 )
{
git_repository_free( repo );
return snapshots;
}
git_revwalk_push_head( walk );
std::vector<wxString> choices;
std::vector<wxString> hashes;
git_oid oid;
while( git_revwalk_next( &oid, walk ) == 0 )
{
git_commit* commit = nullptr;
git_commit_lookup( &commit, repo, &oid );
git_time_t t = git_commit_time( commit );
wxDateTime dt( (time_t) t );
wxString line;
if( git_commit_lookup( &commit, repo, &oid ) != 0 )
continue;
line.Printf( wxS( "%s %s" ), dt.FormatISOCombined().c_str(),
wxString::FromUTF8( git_commit_summary( commit ) ) );
choices.push_back( line );
hashes.push_back( wxString::FromUTF8( git_oid_tostr_s( &oid ) ) );
LOCAL_HISTORY_SNAPSHOT_INFO info;
info.hash = wxString::FromUTF8( git_oid_tostr_s( &oid ) );
info.date = wxDateTime( static_cast<time_t>( git_commit_time( commit ) ) );
info.message = wxString::FromUTF8( git_commit_message( commit ) );
wxString firstLine = info.message.BeforeFirst( '\n' );
long parsedCount = 0;
wxString remainder;
firstLine.BeforeFirst( ':', &remainder );
remainder.Trim( true ).Trim( false );
if( remainder.EndsWith( wxS( "files changed" ) ) )
{
wxString countText = remainder.BeforeFirst( ' ' );
if( countText.ToLong( &parsedCount ) )
info.filesChanged = static_cast<int>( parsedCount );
}
info.summary = firstLine.BeforeFirst( ':' );
wxString rest;
info.message.BeforeFirst( '\n', &rest );
wxArrayString lines = wxSplit( rest, '\n', '\0' );
for( const wxString& line : lines )
{
if( !line.IsEmpty() )
info.changedFiles.Add( line );
}
snapshots.push_back( std::move( info ) );
git_commit_free( commit );
}
git_revwalk_free( walk );
git_repository_free( repo );
if( choices.empty() )
return;
int index = wxGetSingleChoiceIndex( _( "Select snapshot" ), _( "Restore" ),
(int) choices.size(), &choices[0], aParent );
if( index != wxNOT_FOUND )
RestoreCommit( aProjectPath, hashes[index] );
return snapshots;
}
+298
View File
@@ -0,0 +1,298 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright The 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 <oauth/oauth_loopback_server.h>
#include <wx/tokenzr.h>
#include <wx/uri.h>
#include <wx/intl.h>
wxDEFINE_EVENT( EVT_OAUTH_LOOPBACK_RESULT, wxCommandEvent );
namespace
{
wxString queryValue( const wxString& aQuery, const wxString& aKey )
{
wxStringTokenizer queryTokenizer( aQuery, wxS( "&" ) );
while( queryTokenizer.HasMoreTokens() )
{
const wxString pair = queryTokenizer.GetNextToken();
const int eqPos = pair.Find( '=' );
if( eqPos == wxNOT_FOUND )
continue;
const wxString name = pair.Left( eqPos );
const wxString value = pair.Mid( eqPos + 1 );
if( name == aKey )
return wxURI::Unescape( value );
}
return wxEmptyString;
}
} // namespace
OAUTH_LOOPBACK_SERVER::OAUTH_LOOPBACK_SERVER( wxEvtHandler* aOwner, const wxString& aCallbackPath,
const wxString& aExpectedState ) :
m_owner( aOwner ),
m_callbackPath( aCallbackPath ),
m_expectedState( aExpectedState ),
m_port( 0 ),
m_done( false )
{
m_timeout.SetOwner( this );
Bind( wxEVT_TIMER, &OAUTH_LOOPBACK_SERVER::OnTimeout, this, m_timeout.GetId() );
}
OAUTH_LOOPBACK_SERVER::~OAUTH_LOOPBACK_SERVER()
{
m_timeout.Stop();
Unbind( wxEVT_SOCKET, &OAUTH_LOOPBACK_SERVER::OnSocketEvent, this );
Unbind( wxEVT_TIMER, &OAUTH_LOOPBACK_SERVER::OnTimeout, this, m_timeout.GetId() );
Shutdown();
m_timeout.SetOwner( nullptr );
}
bool OAUTH_LOOPBACK_SERVER::Start()
{
wxIPV4address addr;
addr.Hostname( wxS( "127.0.0.1" ) );
addr.Service( 0 );
std::unique_ptr<wxSocketServer> server =
std::make_unique<wxSocketServer>( addr, wxSOCKET_REUSEADDR );
if( !server->IsOk() )
return false;
server->SetEventHandler( *this );
server->SetNotify( wxSOCKET_CONNECTION_FLAG );
server->Notify( true );
wxIPV4address local;
server->GetLocal( local );
m_port = local.Service();
Bind( wxEVT_SOCKET, &OAUTH_LOOPBACK_SERVER::OnSocketEvent, this );
m_server = std::move( server );
m_timeout.StartOnce( 120000 );
return m_port != 0;
}
wxString OAUTH_LOOPBACK_SERVER::GetRedirectUri() const
{
return wxString::Format( wxS( "http://127.0.0.1:%u%s" ), m_port, m_callbackPath );
}
bool OAUTH_LOOPBACK_SERVER::ParseAuthorizationResponse( const wxString& aRequestLine,
const wxString& aExpectedPath,
const wxString& aExpectedState,
OAUTH_AUTHORIZATION_RESPONSE& aResponse,
wxString& aError )
{
aResponse = OAUTH_AUTHORIZATION_RESPONSE();
aError.clear();
wxStringTokenizer tokenizer( aRequestLine, wxS( " " ) );
if( !tokenizer.HasMoreTokens() )
{
aError = _( "Missing HTTP method in callback request." );
return false;
}
tokenizer.GetNextToken();
if( !tokenizer.HasMoreTokens() )
{
aError = _( "Missing callback URL in request." );
return false;
}
const wxString target = tokenizer.GetNextToken();
const int queryPos = target.Find( '?' );
const wxString path = queryPos == wxNOT_FOUND ? target : target.Left( queryPos );
const wxString query = queryPos == wxNOT_FOUND ? wxString() : target.Mid( queryPos + 1 );
if( path != aExpectedPath )
{
aError = _( "Unexpected callback path." );
return false;
}
wxString state = queryValue( query, wxS( "state" ) );
if( state != aExpectedState )
{
aError = _( "OAuth callback state did not match." );
return false;
}
aResponse.state = state;
aResponse.error = queryValue( query, wxS( "error" ) );
aResponse.error_description = queryValue( query, wxS( "error_description" ) );
if( !aResponse.error.IsEmpty() )
{
aError = _( "Authorization server returned an OAuth error." );
return false;
}
aResponse.code = queryValue( query, wxS( "code" ) );
if( aResponse.code.IsEmpty() )
{
aError = _( "Missing authorization code in callback." );
return false;
}
return true;
}
void OAUTH_LOOPBACK_SERVER::OnSocketEvent( wxSocketEvent& aEvent )
{
if( !m_server || aEvent.GetSocketEvent() != wxSOCKET_CONNECTION )
return;
std::unique_ptr<wxSocketBase> client( m_server->Accept( false ) );
if( client )
HandleClient( client.get() );
}
void OAUTH_LOOPBACK_SERVER::OnTimeout( wxTimerEvent& aEvent )
{
wxUnusedVar( aEvent );
Finish( false );
}
void OAUTH_LOOPBACK_SERVER::HandleClient( wxSocketBase* aClient )
{
if( !aClient )
return;
aClient->SetTimeout( 5 );
aClient->SetFlags( wxSOCKET_NONE );
std::string request;
request.reserve( 512 );
char buffer[512];
while( aClient->IsConnected() )
{
if( !aClient->WaitForRead( 1, 0 ) )
break;
aClient->Read( buffer, sizeof( buffer ) );
const size_t count = aClient->LastCount();
if( count == 0 )
break;
request.append( buffer, count );
if( request.find( "\r\n\r\n" ) != std::string::npos || request.size() > 4096 )
break;
}
const wxString requestWx = wxString::FromUTF8( request.data(), request.size() );
const int endOfLine = requestWx.Find( wxS( "\r\n" ) );
const wxString requestLine = endOfLine == wxNOT_FOUND ? requestWx : requestWx.Mid( 0, endOfLine );
OAUTH_AUTHORIZATION_RESPONSE response;
wxString error;
const bool success = ParseAuthorizationResponse( requestLine, m_callbackPath, m_expectedState,
response, error );
if( success )
m_response = response;
SendHttpResponse( aClient, success );
Finish( success );
}
void OAUTH_LOOPBACK_SERVER::SendHttpResponse( wxSocketBase* aClient, bool aSuccess )
{
if( !aClient )
return;
const wxString body = aSuccess
? wxS( "<!DOCTYPE html><html><body><p>Authentication complete.</p></body></html>" )
: wxS( "<!DOCTYPE html><html><body><p>Authentication failed.</p></body></html>" );
wxScopedCharBuffer bodyUtf8 = body.ToUTF8();
wxString response;
response << wxS( "HTTP/1.1 200 OK\r\n" )
<< wxS( "Content-Type: text/html; charset=utf-8\r\n" )
<< wxS( "Cache-Control: no-store\r\n" )
<< wxS( "Connection: close\r\n" )
<< wxS( "Content-Length: " ) << bodyUtf8.length() << wxS( "\r\n\r\n" );
wxScopedCharBuffer header = response.ToUTF8();
aClient->Write( header.data(), header.length() );
aClient->Write( bodyUtf8.data(), bodyUtf8.length() );
aClient->Close();
}
void OAUTH_LOOPBACK_SERVER::Finish( bool aSuccess )
{
if( m_done )
return;
m_done = true;
m_timeout.Stop();
if( m_owner )
{
wxCommandEvent evt( EVT_OAUTH_LOOPBACK_RESULT );
evt.SetInt( aSuccess ? 1 : 0 );
if( aSuccess && m_response.has_value() )
evt.SetString( m_response->code );
wxQueueEvent( m_owner, evt.Clone() );
}
Shutdown();
}
void OAUTH_LOOPBACK_SERVER::Shutdown()
{
if( m_server )
{
m_server->Notify( false );
m_server.reset();
}
}
+83
View File
@@ -0,0 +1,83 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright The 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 <oauth/oauth_pkce.h>
#include <random>
#include <vector>
#include <picosha2.h>
#include <wx/base64.h>
namespace
{
const char TOKEN_CHARS[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~";
wxString randomToken( size_t aLength )
{
static std::random_device rd;
static std::mt19937_64 gen( rd() );
std::uniform_int_distribution<size_t> dist( 0, sizeof( TOKEN_CHARS ) - 2 );
wxString token;
token.reserve( aLength );
for( size_t ii = 0; ii < aLength; ++ii )
token.Append( TOKEN_CHARS[dist( gen )] );
return token;
}
wxString base64UrlEncode( const std::vector<unsigned char>& aBytes )
{
wxString encoded = wxBase64Encode( aBytes.data(), aBytes.size() );
encoded.Replace( wxS( "+" ), wxS( "-" ) );
encoded.Replace( wxS( "/" ), wxS( "_" ) );
encoded.Replace( wxS( "=" ), wxEmptyString );
encoded.Replace( wxS( "\n" ), wxEmptyString );
return encoded;
}
} // namespace
wxString OAUTH_PKCE::GenerateCodeVerifier()
{
return randomToken( 64 );
}
wxString OAUTH_PKCE::GenerateState()
{
return randomToken( 32 );
}
wxString OAUTH_PKCE::CreateCodeChallenge( const wxString& aVerifier )
{
const std::string verifier = aVerifier.ToStdString();
std::vector<unsigned char> digest( picosha2::k_digest_size );
picosha2::hash256( verifier.begin(), verifier.end(), digest.begin(), digest.end() );
return base64UrlEncode( digest );
}
+42
View File
@@ -0,0 +1,42 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright The 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 <oauth/oauth_session.h>
#include <oauth/oauth_pkce.h>
#include <remote_provider_utils.h>
#include <wx/uri.h>
wxString OAUTH_SESSION::BuildAuthorizationUrl() const
{
wxString url = authorization_endpoint;
url << ( authorization_endpoint.Find( '?' ) == wxNOT_FOUND ? wxS( "?" ) : wxS( "&" ) )
<< wxS( "response_type=code" )
<< wxS( "&client_id=" ) << UrlEncode( client_id )
<< wxS( "&redirect_uri=" ) << UrlEncode( redirect_uri )
<< wxS( "&scope=" ) << UrlEncode( scope )
<< wxS( "&state=" ) << UrlEncode( state )
<< wxS( "&code_challenge_method=S256" )
<< wxS( "&code_challenge=" ) << UrlEncode( OAUTH_PKCE::CreateCodeChallenge( code_verifier ) );
return url;
}
+118
View File
@@ -0,0 +1,118 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright The 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 <oauth/secure_token_store.h>
#include <json_conversions.h>
#include <kiplatform/secrets.h>
#include <nlohmann/json.hpp>
void to_json( nlohmann::json& aJson, const OAUTH_TOKEN_SET& aTokens )
{
aJson = nlohmann::json{
{ "access_token", aTokens.access_token },
{ "refresh_token", aTokens.refresh_token },
{ "id_token", aTokens.id_token },
{ "token_type", aTokens.token_type },
{ "scope", aTokens.scope },
{ "expires_at", aTokens.expires_at }
};
}
void from_json( const nlohmann::json& aJson, OAUTH_TOKEN_SET& aTokens )
{
aTokens = OAUTH_TOKEN_SET();
aJson.at( "access_token" ).get_to( aTokens.access_token );
aJson.at( "refresh_token" ).get_to( aTokens.refresh_token );
aJson.at( "id_token" ).get_to( aTokens.id_token );
aJson.at( "token_type" ).get_to( aTokens.token_type );
aJson.at( "scope" ).get_to( aTokens.scope );
aJson.at( "expires_at" ).get_to( aTokens.expires_at );
}
bool PLATFORM_SECRET_BACKEND::StoreSecret( const wxString& aService, const wxString& aKey,
const wxString& aSecret )
{
return KIPLATFORM::SECRETS::StoreSecret( aService, aKey, aSecret );
}
bool PLATFORM_SECRET_BACKEND::GetSecret( const wxString& aService, const wxString& aKey,
wxString& aSecret ) const
{
return KIPLATFORM::SECRETS::GetSecret( aService, aKey, aSecret );
}
bool PLATFORM_SECRET_BACKEND::DeleteSecret( const wxString& aService, const wxString& aKey )
{
return KIPLATFORM::SECRETS::DeleteSecret( aService, aKey );
}
SECURE_TOKEN_STORE::SECURE_TOKEN_STORE( std::unique_ptr<OAUTH_SECRET_BACKEND> aBackend ) :
m_backend( std::move( aBackend ) )
{
}
bool SECURE_TOKEN_STORE::StoreTokens( const wxString& aProviderId, const wxString& aAccountId,
const OAUTH_TOKEN_SET& aTokens )
{
const wxString secret = wxString::FromUTF8( nlohmann::json( aTokens ).dump().c_str() );
return m_backend->StoreSecret( MakeServiceName( aProviderId ), aAccountId, secret );
}
std::optional<OAUTH_TOKEN_SET> SECURE_TOKEN_STORE::LoadTokens( const wxString& aProviderId,
const wxString& aAccountId ) const
{
wxString secret;
if( !m_backend->GetSecret( MakeServiceName( aProviderId ), aAccountId, secret )
|| secret.IsEmpty() )
{
return std::nullopt;
}
try
{
return nlohmann::json::parse( secret.ToStdString() ).get<OAUTH_TOKEN_SET>();
}
catch( ... )
{
return std::nullopt;
}
}
bool SECURE_TOKEN_STORE::DeleteTokens( const wxString& aProviderId, const wxString& aAccountId )
{
return m_backend->DeleteSecret( MakeServiceName( aProviderId ), aAccountId );
}
wxString SECURE_TOKEN_STORE::MakeServiceName( const wxString& aProviderId )
{
return wxS( "org.kicad.remote_provider." ) + aProviderId;
}
+6
View File
@@ -96,6 +96,7 @@ LANGUAGE_DESCR LanguagesList[] =
{
{ wxLANGUAGE_DEFAULT, ID_LANGUAGE_DEFAULT, _( "Default" ), false },
{ wxLANGUAGE_ARABIC, ID_LANGUAGE_ARABIC, wxT( "العربية" ), true },
{ wxLANGUAGE_FARSI, ID_LANGUAGE_FARSI, wxT( "فارسی" ), true },
{ wxLANGUAGE_INDONESIAN, ID_LANGUAGE_INDONESIAN, wxT( "Bahasa Indonesia" ), true },
{ wxLANGUAGE_BULGARIAN, ID_LANGUAGE_BULGARIAN, wxT( "Български" ), true },
{ wxLANGUAGE_CATALAN, ID_LANGUAGE_CATALAN, wxT( "Català" ), true },
@@ -103,12 +104,15 @@ LANGUAGE_DESCR LanguagesList[] =
{ wxLANGUAGE_DANISH, ID_LANGUAGE_DANISH, wxT( "Dansk" ), true },
{ wxLANGUAGE_GERMAN, ID_LANGUAGE_GERMAN, wxT( "Deutsch" ), true },
{ wxLANGUAGE_GREEK, ID_LANGUAGE_GREEK, wxT( "Ελληνικά" ), true },
{ wxLANGUAGE_ESTONIAN, ID_LANGUAGE_ESTONIAN, wxT( "Eesti" ), true },
{ wxLANGUAGE_ENGLISH, ID_LANGUAGE_ENGLISH, wxT( "English" ), true },
{ wxLANGUAGE_SPANISH, ID_LANGUAGE_SPANISH, wxT( "Español" ), true },
{ wxLANGUAGE_SPANISH_MEXICAN, ID_LANGUAGE_SPANISH_MEXICAN,
wxT( "Español (Latinoamericano)" ), true },
{ wxLANGUAGE_FRENCH, ID_LANGUAGE_FRENCH, wxT( "Français" ), true },
{ wxLANGUAGE_HEBREW, ID_LANGUAGE_HEBREW, wxT( "עברית" ), true },
{ wxLANGUAGE_HINDI, ID_LANGUAGE_HINDI, wxT( "हिन्दी" ), true },
{ wxLANGUAGE_CROATIAN, ID_LANGUAGE_CROATIAN, wxT( "Hrvatski" ), true },
{ wxLANGUAGE_KOREAN, ID_LANGUAGE_KOREAN, wxT( "한국어"), true },
{ wxLANGUAGE_ITALIAN, ID_LANGUAGE_ITALIAN, wxT( "Italiano" ), true },
{ wxLANGUAGE_LATVIAN, ID_LANGUAGE_LATVIAN, wxT( "Latviešu" ), true },
@@ -117,6 +121,7 @@ LANGUAGE_DESCR LanguagesList[] =
{ wxLANGUAGE_DUTCH, ID_LANGUAGE_DUTCH, wxT( "Nederlands" ), true },
{ wxLANGUAGE_NORWEGIAN_BOKMAL, ID_LANGUAGE_NORWEGIAN_BOKMAL, wxT( "Norsk Bokmål" ), true },
{ wxLANGUAGE_JAPANESE, ID_LANGUAGE_JAPANESE, wxT( "日本語" ), true },
{ wxLANGUAGE_GEORGIAN, ID_LANGUAGE_GEORGIAN, wxT( "ქართული" ), true },
{ wxLANGUAGE_THAI, ID_LANGUAGE_THAI, wxT( "ภาษาไทย" ), true },
{ wxLANGUAGE_POLISH, ID_LANGUAGE_POLISH, wxT( "Polski" ), true },
{ wxLANGUAGE_PORTUGUESE, ID_LANGUAGE_PORTUGUESE, wxT( "Português" ),true },
@@ -131,6 +136,7 @@ LANGUAGE_DESCR LanguagesList[] =
{ wxLANGUAGE_SWEDISH, ID_LANGUAGE_SWEDISH, wxT( "Svenska" ), true },
{ wxLANGUAGE_VIETNAMESE, ID_LANGUAGE_VIETNAMESE, wxT( "Tiếng Việt" ), true },
{ wxLANGUAGE_TAMIL, ID_LANGUAGE_TAMIL, wxT( "தமிழ்" ), true },
{ wxLANGUAGE_TELUGU, ID_LANGUAGE_TELUGU, wxT( "తెలుగు" ), true },
{ wxLANGUAGE_TURKISH, ID_LANGUAGE_TURKISH, wxT( "Türkçe" ), true },
{ wxLANGUAGE_UKRAINIAN, ID_LANGUAGE_UKRAINIAN, wxT( "Українська" ), true },
{ wxLANGUAGE_CHINESE_SIMPLIFIED, ID_LANGUAGE_CHINESE_SIMPLIFIED,
+4 -2
View File
@@ -51,8 +51,8 @@ wxString GetDefaultPlotExtension( PLOT_FORMAT aFormat )
void PlotDrawingSheet( PLOTTER* plotter, const PROJECT* aProject, const TITLE_BLOCK& aTitleBlock,
const PAGE_INFO& aPageInfo, const std::map<wxString, wxString>* aProperties,
const wxString& aSheetNumber, int aSheetCount, const wxString& aSheetName,
const wxString& aSheetPath, const wxString& aFilename, COLOR4D aColor,
bool aIsFirstPage )
const wxString& aSheetPath, const wxString& aFilename, COLOR4D aColor, bool aIsFirstPage,
const wxString& aVariantName, const wxString& aVariantDesc )
{
/* Note: Page sizes values are given in mils
*/
@@ -81,6 +81,8 @@ void PlotDrawingSheet( PLOTTER* plotter, const PROJECT* aProject, const TITLE_BL
drawList.SetProject( aProject );
drawList.SetIsFirstPage( aIsFirstPage );
drawList.SetProperties( aProperties );
drawList.SetVariantName( aVariantName );
drawList.SetVariantDesc( aVariantDesc );
drawList.BuildDrawItemsList( aPageInfo, aTitleBlock );
+12 -6
View File
@@ -458,7 +458,7 @@ void PROJECT::SetProjectLock( LOCKFILE* aLockFile )
}
void PROJECT::SaveToHistory( const wxString& aProjectPath, std::vector<wxString>& aFiles )
void PROJECT::SaveToHistory( const wxString& aProjectPath, std::vector<HISTORY_FILE_DATA>& aFileData )
{
wxString projectFile = GetProjectFullName();
@@ -486,11 +486,14 @@ void PROJECT::SaveToHistory( const wxString& aProjectPath, std::vector<wxString>
return;
}
// Save project file (.kicad_pro)
// Save project file (.kicad_pro) via file-copy
wxFileName historyProFile( historyDir.GetFullPath(), projectFn.GetName(),
projectFn.GetExt() );
wxCopyFile( projectFile, historyProFile.GetFullPath(), true );
aFiles.push_back( historyProFile.GetFullPath() );
HISTORY_FILE_DATA proEntry;
proEntry.path = historyProFile.GetFullPath();
proEntry.sourcePath = projectFile;
aFileData.push_back( std::move( proEntry ) );
// Save project local settings (.kicad_prl) if it exists
wxFileName prlFile( projectFn.GetPath(), projectFn.GetName(), FILEEXT::ProjectLocalSettingsFileExtension );
@@ -499,7 +502,10 @@ void PROJECT::SaveToHistory( const wxString& aProjectPath, std::vector<wxString>
{
wxFileName historyPrlFile( historyDir.GetFullPath(), prlFile.GetName(),
prlFile.GetExt() );
wxCopyFile( prlFile.GetFullPath(), historyPrlFile.GetFullPath(), true );
aFiles.push_back( historyPrlFile.GetFullPath() );
HISTORY_FILE_DATA prlEntry;
prlEntry.path = historyPrlFile.GetFullPath();
prlEntry.sourcePath = prlFile.GetFullPath();
aFileData.push_back( std::move( prlEntry ) );
}
}
+6
View File
@@ -195,6 +195,12 @@ PROJECT_FILE::PROJECT_FILE( const wxString& aFullPath ) :
m_params.emplace_back( new PARAM<wxString>( "board.ipc2581.dist",
&m_IP2581Bom.dist, wxEmptyString ) );
m_params.emplace_back( new PARAM<wxString>( "board.ipc2581.bom_rev",
&m_IP2581Bom.bomRev, wxEmptyString ) );
m_params.emplace_back( new PARAM<wxString>( "board.ipc2581.sch_revision",
&m_IP2581Bom.schRevision, wxEmptyString ) );
registerMigration( 1, 2, std::bind( &PROJECT_FILE::migrateSchema1To2, this ) );
registerMigration( 2, 3, std::bind( &PROJECT_FILE::migrateSchema2To3, this ) );
-233
View File
@@ -1,233 +0,0 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright The 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, you may find one here:
* http://www.gnu.org/licenses/gpl-3.0.html
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include <wx/tokenzr.h>
#include <wx/uri.h>
#include <remote_login_server.h>
wxDEFINE_EVENT( EVT_REMOTE_SYMBOL_LOGIN_RESULT, wxCommandEvent );
REMOTE_LOGIN_SERVER::REMOTE_LOGIN_SERVER( wxEvtHandler* aOwner, const wxString& aRedirectUrl ) :
m_owner( aOwner ),
m_redirectUrl( aRedirectUrl ),
m_port( 0 ),
m_done( false )
{
m_timeout.SetOwner( this );
Bind( wxEVT_TIMER, &REMOTE_LOGIN_SERVER::OnTimeout, this, m_timeout.GetId() );
}
REMOTE_LOGIN_SERVER::~REMOTE_LOGIN_SERVER()
{
m_timeout.Stop();
Unbind( wxEVT_SOCKET, &REMOTE_LOGIN_SERVER::OnSocketEvent, this );
Unbind( wxEVT_TIMER, &REMOTE_LOGIN_SERVER::OnTimeout, this, m_timeout.GetId() );
Shutdown();
m_timeout.SetOwner( nullptr );
}
bool REMOTE_LOGIN_SERVER::Start()
{
wxIPV4address addr;
addr.AnyAddress();
addr.Service( 0 );
std::unique_ptr<wxSocketServer> server =
std::make_unique<wxSocketServer>( addr, wxSOCKET_REUSEADDR );
if( !server->IsOk() )
return false;
server->SetEventHandler( *this );
server->SetNotify( wxSOCKET_CONNECTION_FLAG );
server->Notify( true );
wxIPV4address local;
server->GetLocal( local );
m_port = local.Service();
Bind( wxEVT_SOCKET, &REMOTE_LOGIN_SERVER::OnSocketEvent, this );
m_server = std::move( server );
m_timeout.StartOnce( 120000 );
return m_port != 0;
}
void REMOTE_LOGIN_SERVER::OnSocketEvent( wxSocketEvent& aEvent )
{
if( !m_server || aEvent.GetSocketEvent() != wxSOCKET_CONNECTION )
return;
std::unique_ptr<wxSocketBase> client( m_server->Accept( false ) );
if( !client )
return;
HandleClient( client.get() );
}
void REMOTE_LOGIN_SERVER::OnTimeout( wxTimerEvent& aEvent )
{
wxUnusedVar( aEvent );
Finish( false, wxString() );
}
void REMOTE_LOGIN_SERVER::HandleClient( wxSocketBase* aClient )
{
if( !aClient )
return;
aClient->SetTimeout( 5 );
aClient->SetFlags( wxSOCKET_NONE );
std::string request;
request.reserve( 512 );
char buffer[512];
while( aClient->IsConnected() )
{
if( !aClient->WaitForRead( 1, 0 ) )
break;
aClient->Read( buffer, sizeof( buffer ) );
size_t count = aClient->LastCount();
if( count == 0 )
break;
request.append( buffer, count );
if( request.find( "\r\n\r\n" ) != std::string::npos || request.size() > 4096 )
break;
}
SendHttpResponse( aClient );
wxString requestWx = wxString::FromUTF8( request.data(), request.size() );
int endOfLine = requestWx.Find( wxS( "\r\n" ) );
wxString requestLine = endOfLine == wxNOT_FOUND ? requestWx : requestWx.Mid( 0, endOfLine );
wxString userId = ExtractUserId( requestLine );
Finish( !userId.IsEmpty(), userId );
}
wxString REMOTE_LOGIN_SERVER::ExtractUserId( const wxString& aRequestLine ) const
{
wxStringTokenizer tokenizer( aRequestLine, wxS( " " ) );
if( !tokenizer.HasMoreTokens() )
return wxString();
tokenizer.GetNextToken();
if( !tokenizer.HasMoreTokens() )
return wxString();
wxString path = tokenizer.GetNextToken();
int queryPos = path.Find( '?' );
if( queryPos == wxNOT_FOUND )
return wxString();
wxString query = path.Mid( queryPos + 1 );
wxStringTokenizer queryTokenizer( query, wxS( "&" ) );
while( queryTokenizer.HasMoreTokens() )
{
wxString pair = queryTokenizer.GetNextToken();
int eqPos = pair.Find( '=' );
if( eqPos == wxNOT_FOUND )
continue;
wxString name = pair.Left( eqPos );
wxString value = pair.Mid( eqPos + 1 );
if( name == wxS( "user_id" ) )
return wxURI::Unescape( value );
}
return wxString();
}
void REMOTE_LOGIN_SERVER::SendHttpResponse( wxSocketBase* aClient )
{
if( !aClient )
return;
wxString redirect = m_redirectUrl;
if( redirect.IsEmpty() )
redirect = wxS( "about:blank" );
wxString html;
html << wxS( "<!DOCTYPE html><html><head>" )
<< wxS( "<meta http-equiv=\"refresh\" content=\"0;url=" ) << redirect << wxS( "\">" )
<< wxS( "</head><body>" )
<< wxS( "<script>window.location.href = '" ) << redirect << wxS( "';</script>" )
<< wxS( "<p>Login successful. Redirecting...</p>" )
<< wxS( "</body></html>" );
wxScopedCharBuffer body = html.ToUTF8();
wxString response;
response << wxS( "HTTP/1.1 200 OK\r\n" )
<< wxS( "Content-Type: text/html; charset=utf-8\r\n" )
<< wxS( "Access-Control-Allow-Origin: *\r\n" )
<< wxS( "Cache-Control: no-store\r\n" )
<< wxS( "Connection: close\r\n" )
<< wxS( "Content-Length: " ) << body.length() << wxS( "\r\n\r\n" );
wxScopedCharBuffer header = response.ToUTF8();
aClient->Write( header.data(), header.length() );
aClient->Write( body.data(), body.length() );
aClient->Close();
}
void REMOTE_LOGIN_SERVER::Finish( bool aSuccess, const wxString& aUserId )
{
if( m_done )
return;
m_done = true;
m_timeout.Stop();
wxCommandEvent evt( EVT_REMOTE_SYMBOL_LOGIN_RESULT );
evt.SetInt( aSuccess ? 1 : 0 );
evt.SetString( aUserId );
wxQueueEvent( m_owner, evt.Clone() );
Shutdown();
}
void REMOTE_LOGIN_SERVER::Shutdown()
{
if( m_server )
{
m_server->Notify( false );
m_server.reset();
}
}
+491
View File
@@ -0,0 +1,491 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright The 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 <remote_provider_client.h>
#include <curl/curl.h>
#include <kicad_curl/kicad_curl_easy.h>
#include <oauth/oauth_session.h>
#include <remote_provider_utils.h>
#include <wx/datetime.h>
#include <wx/intl.h>
namespace
{
wxString joinUrl( const wxString& aBaseUrl, const wxString& aPath )
{
if( aPath.StartsWith( wxS( "https://" ) ) || aPath.StartsWith( wxS( "http://" ) ) )
return aPath;
wxString base = aBaseUrl;
while( base.EndsWith( wxS( "/" ) ) )
base.RemoveLast();
if( aPath.StartsWith( wxS( "/" ) ) )
return base + aPath;
return base + wxS( "/" ) + aPath;
}
wxString buildPartsUrl( const REMOTE_PROVIDER_METADATA& aProvider, const wxString& aPartId )
{
wxString endpoint = aProvider.parts_endpoint_template;
endpoint.Replace( wxS( "{part_id}" ), UrlEncode( aPartId ) );
return joinUrl( aProvider.api_base_url, endpoint );
}
bool defaultHttpHandler( const REMOTE_PROVIDER_HTTP_REQUEST& aRequest, REMOTE_PROVIDER_HTTP_RESPONSE& aResponse,
wxString& aError )
{
KICAD_CURL_EASY curl;
curl.SetUserAgent( "KiCad-RemoteProvider/1.0" );
curl.SetFollowRedirects( true );
curl.SetConnectTimeout( 10 );
if( !curl.SetURL( aRequest.url.ToStdString() ) )
{
aError = wxString::Format( wxS( "Unable to set URL '%s'." ), aRequest.url );
return false;
}
for( const REMOTE_PROVIDER_HTTP_HEADER& header : aRequest.headers )
curl.SetHeader( header.name.ToStdString(), header.value.ToStdString() );
if( aRequest.method == REMOTE_PROVIDER_HTTP_METHOD::POST )
curl.SetPostFields( aRequest.body.ToStdString() );
int result = curl.Perform();
if( result != CURLE_OK )
{
aError = wxString::FromUTF8( curl.GetErrorText( result ).c_str() );
return false;
}
aResponse.status_code = curl.GetResponseStatusCode();
aResponse.body = wxString::FromUTF8( curl.GetBuffer().c_str() );
return true;
}
} // namespace
REMOTE_PROVIDER_CLIENT::REMOTE_PROVIDER_CLIENT() :
m_handler( defaultHttpHandler )
{
}
REMOTE_PROVIDER_CLIENT::REMOTE_PROVIDER_CLIENT( REMOTE_PROVIDER_HTTP_HANDLER aHandler ) :
m_handler( std::move( aHandler ) )
{
}
wxString REMOTE_PROVIDER_CLIENT::MetadataDiscoveryUrl( const wxString& aProviderUrl )
{
static const wxString suffix = wxS( "/.well-known/kicad-remote-provider" );
if( aProviderUrl.EndsWith( suffix ) )
return aProviderUrl;
wxString base = aProviderUrl;
while( base.EndsWith( wxS( "/" ) ) )
base.RemoveLast();
return base + suffix;
}
bool REMOTE_PROVIDER_CLIENT::DiscoverProvider( const wxString& aProviderUrl, REMOTE_PROVIDER_METADATA& aMetadata,
REMOTE_PROVIDER_ERROR& aError ) const
{
aError.Clear();
REMOTE_PROVIDER_HTTP_REQUEST request;
request.method = REMOTE_PROVIDER_HTTP_METHOD::GET;
request.url = MetadataDiscoveryUrl( aProviderUrl );
request.headers.push_back( { wxS( "Accept" ), wxS( "application/json" ) } );
nlohmann::json responseJson;
if( !FetchJson( request, responseJson, aError ) )
return false;
wxString error;
std::optional<REMOTE_PROVIDER_METADATA> metadata = REMOTE_PROVIDER_METADATA::FromJson( responseJson, error );
if( !metadata )
{
aError.type = REMOTE_PROVIDER_ERROR_TYPE::INVALID_RESPONSE;
aError.message = error;
return false;
}
aMetadata = *metadata;
return true;
}
bool REMOTE_PROVIDER_CLIENT::FetchOAuthServerMetadata( const REMOTE_PROVIDER_METADATA& aProvider,
REMOTE_PROVIDER_OAUTH_SERVER_METADATA& aMetadata,
REMOTE_PROVIDER_ERROR& aError ) const
{
aError.Clear();
if( aProvider.auth.type != REMOTE_PROVIDER_AUTH_TYPE::OAUTH2 )
{
aMetadata = REMOTE_PROVIDER_OAUTH_SERVER_METADATA();
return true;
}
REMOTE_PROVIDER_HTTP_REQUEST request;
request.method = REMOTE_PROVIDER_HTTP_METHOD::GET;
request.url = aProvider.auth.metadata_url;
request.headers.push_back( { wxS( "Accept" ), wxS( "application/json" ) } );
nlohmann::json responseJson;
if( !FetchJson( request, responseJson, aError ) )
return false;
wxString error;
std::optional<REMOTE_PROVIDER_OAUTH_SERVER_METADATA> metadata =
REMOTE_PROVIDER_OAUTH_SERVER_METADATA::FromJson( responseJson, aProvider.allow_insecure_localhost, error );
if( !metadata )
{
aError.type = REMOTE_PROVIDER_ERROR_TYPE::INVALID_RESPONSE;
aError.message = error;
return false;
}
aMetadata = *metadata;
return true;
}
bool REMOTE_PROVIDER_CLIENT::ExchangeAuthorizationCode(
const REMOTE_PROVIDER_OAUTH_SERVER_METADATA& aMetadata, const OAUTH_SESSION& aSession,
const wxString& aCode, OAUTH_TOKEN_SET& aTokens, REMOTE_PROVIDER_ERROR& aError ) const
{
aError.Clear();
REMOTE_PROVIDER_HTTP_REQUEST request;
request.method = REMOTE_PROVIDER_HTTP_METHOD::POST;
request.url = aMetadata.token_endpoint;
request.body = wxString( wxS( "grant_type=authorization_code" ) )
+ wxS( "&code=" ) + UrlEncode( aCode )
+ wxS( "&client_id=" ) + UrlEncode( aSession.client_id )
+ wxS( "&redirect_uri=" ) + UrlEncode( aSession.redirect_uri )
+ wxS( "&code_verifier=" ) + UrlEncode( aSession.code_verifier );
request.headers.push_back( { wxS( "Accept" ), wxS( "application/json" ) } );
request.headers.push_back(
{ wxS( "Content-Type" ), wxS( "application/x-www-form-urlencoded" ) } );
request.headers.push_back( { wxS( "Cache-Control" ), wxS( "no-store" ) } );
REMOTE_PROVIDER_HTTP_RESPONSE response;
if( !SendRequest( request, response, aError ) )
return false;
return ParseTokenResponse( response, aTokens, aError );
}
bool REMOTE_PROVIDER_CLIENT::RefreshAccessToken(
const REMOTE_PROVIDER_OAUTH_SERVER_METADATA& aMetadata, const wxString& aClientId,
const wxString& aRefreshToken, OAUTH_TOKEN_SET& aTokens, REMOTE_PROVIDER_ERROR& aError ) const
{
aError.Clear();
REMOTE_PROVIDER_HTTP_REQUEST request;
request.method = REMOTE_PROVIDER_HTTP_METHOD::POST;
request.url = aMetadata.token_endpoint;
request.body = wxString( wxS( "grant_type=refresh_token" ) )
+ wxS( "&refresh_token=" ) + UrlEncode( aRefreshToken )
+ wxS( "&client_id=" ) + UrlEncode( aClientId );
request.headers.push_back( { wxS( "Accept" ), wxS( "application/json" ) } );
request.headers.push_back(
{ wxS( "Content-Type" ), wxS( "application/x-www-form-urlencoded" ) } );
request.headers.push_back( { wxS( "Cache-Control" ), wxS( "no-store" ) } );
REMOTE_PROVIDER_HTTP_RESPONSE response;
if( !SendRequest( request, response, aError ) )
return false;
return ParseTokenResponse( response, aTokens, aError );
}
bool REMOTE_PROVIDER_CLIENT::RevokeToken( const REMOTE_PROVIDER_OAUTH_SERVER_METADATA& aMetadata,
const wxString& aClientId, const wxString& aToken,
REMOTE_PROVIDER_ERROR& aError ) const
{
aError.Clear();
if( aMetadata.revocation_endpoint.IsEmpty() )
return true;
REMOTE_PROVIDER_HTTP_REQUEST request;
request.method = REMOTE_PROVIDER_HTTP_METHOD::POST;
request.url = aMetadata.revocation_endpoint;
request.body = wxString( wxS( "token=" ) ) + UrlEncode( aToken )
+ wxS( "&client_id=" ) + UrlEncode( aClientId );
request.headers.push_back( { wxS( "Accept" ), wxS( "application/json" ) } );
request.headers.push_back(
{ wxS( "Content-Type" ), wxS( "application/x-www-form-urlencoded" ) } );
REMOTE_PROVIDER_HTTP_RESPONSE response;
return SendRequest( request, response, aError );
}
REMOTE_PROVIDER_SIGNIN_STATE REMOTE_PROVIDER_CLIENT::GetSignInState( const REMOTE_PROVIDER_METADATA& aProvider,
const wxString& aAccessToken ) const
{
if( aProvider.auth.type != REMOTE_PROVIDER_AUTH_TYPE::OAUTH2 )
return REMOTE_PROVIDER_SIGNIN_STATE::NOT_REQUIRED;
if( aAccessToken.IsEmpty() )
return REMOTE_PROVIDER_SIGNIN_STATE::REQUIRED;
return REMOTE_PROVIDER_SIGNIN_STATE::AVAILABLE;
}
bool REMOTE_PROVIDER_CLIENT::FetchManifest( const REMOTE_PROVIDER_METADATA& aProvider, const wxString& aPartId,
const wxString& aAccessToken, REMOTE_PROVIDER_PART_MANIFEST& aManifest,
REMOTE_PROVIDER_ERROR& aError ) const
{
aError.Clear();
if( GetSignInState( aProvider, aAccessToken ) == REMOTE_PROVIDER_SIGNIN_STATE::REQUIRED )
{
aError.type = REMOTE_PROVIDER_ERROR_TYPE::AUTH_REQUIRED;
aError.message = _( "Sign in required for this provider." );
return false;
}
REMOTE_PROVIDER_HTTP_REQUEST request;
request.method = REMOTE_PROVIDER_HTTP_METHOD::GET;
request.url = buildPartsUrl( aProvider, aPartId );
request.headers.push_back( { wxS( "Accept" ), wxS( "application/json" ) } );
if( !aAccessToken.IsEmpty() )
request.headers.push_back( { wxS( "Authorization" ), wxS( "Bearer " ) + aAccessToken } );
nlohmann::json responseJson;
if( !FetchJson( request, responseJson, aError ) )
return false;
wxString error;
std::optional<REMOTE_PROVIDER_PART_MANIFEST> manifest =
REMOTE_PROVIDER_PART_MANIFEST::FromJson( responseJson, aProvider.allow_insecure_localhost, error );
if( !manifest )
{
aError.type = REMOTE_PROVIDER_ERROR_TYPE::INVALID_RESPONSE;
aError.message = error;
return false;
}
aManifest = *manifest;
return true;
}
bool REMOTE_PROVIDER_CLIENT::ExchangeBootstrapNonce( const REMOTE_PROVIDER_METADATA& aMetadata,
const wxString& aAccessToken, wxString& aNonceUrl,
REMOTE_PROVIDER_ERROR& aError ) const
{
aError.Clear();
if( aMetadata.session_bootstrap_url.IsEmpty() )
{
aError.type = REMOTE_PROVIDER_ERROR_TYPE::INVALID_RESPONSE;
aError.message = _( "Provider metadata does not include a session bootstrap URL." );
return false;
}
nlohmann::json body;
body["access_token"] = aAccessToken.ToStdString();
body["next_url"] = aMetadata.panel_url.ToStdString();
REMOTE_PROVIDER_HTTP_REQUEST request;
request.method = REMOTE_PROVIDER_HTTP_METHOD::POST;
request.url = aMetadata.session_bootstrap_url;
request.body = wxString::FromUTF8( body.dump().c_str() );
request.headers.push_back( { wxS( "Accept" ), wxS( "application/json" ) } );
request.headers.push_back( { wxS( "Content-Type" ), wxS( "application/json" ) } );
nlohmann::json responseJson;
if( !FetchJson( request, responseJson, aError ) )
return false;
if( !responseJson.contains( "nonce_url" ) || !responseJson["nonce_url"].is_string() )
{
aError.type = REMOTE_PROVIDER_ERROR_TYPE::INVALID_RESPONSE;
aError.message = _( "Bootstrap response did not include a nonce URL." );
return false;
}
aNonceUrl = wxString::FromUTF8( responseJson["nonce_url"].get_ref<const std::string&>().c_str() );
wxString securityError;
if( !ValidateRemoteUrlSecurity( aNonceUrl, aMetadata.allow_insecure_localhost, securityError,
wxS( "Bootstrap nonce URL" ) ) )
{
aError.type = REMOTE_PROVIDER_ERROR_TYPE::INVALID_RESPONSE;
aError.message = securityError;
return false;
}
if( NormalizedUrlOrigin( aNonceUrl ) != NormalizedUrlOrigin( aMetadata.session_bootstrap_url ) )
{
aError.type = REMOTE_PROVIDER_ERROR_TYPE::INVALID_RESPONSE;
aError.message = _( "Bootstrap nonce URL origin does not match the bootstrap endpoint." );
return false;
}
return true;
}
bool REMOTE_PROVIDER_CLIENT::SendRequest( const REMOTE_PROVIDER_HTTP_REQUEST& aRequest,
REMOTE_PROVIDER_HTTP_RESPONSE& aResponse,
REMOTE_PROVIDER_ERROR& aError ) const
{
wxString transportError;
if( !m_handler( aRequest, aResponse, transportError ) )
{
aError.type = REMOTE_PROVIDER_ERROR_TYPE::NETWORK;
aError.message = transportError;
return false;
}
aError.http_status = aResponse.status_code;
if( aResponse.status_code < 200 || aResponse.status_code >= 300 )
{
if( aResponse.status_code == 401 )
aError.type = REMOTE_PROVIDER_ERROR_TYPE::AUTH_REQUIRED;
else if( aResponse.status_code == 403 )
aError.type = REMOTE_PROVIDER_ERROR_TYPE::ACCESS_DENIED;
else if( aResponse.status_code == 404 )
aError.type = REMOTE_PROVIDER_ERROR_TYPE::NOT_FOUND;
else if( aResponse.status_code >= 500 )
aError.type = REMOTE_PROVIDER_ERROR_TYPE::SERVER;
else
aError.type = REMOTE_PROVIDER_ERROR_TYPE::INVALID_RESPONSE;
aError.message = wxString::Format( _( "Remote provider request failed with HTTP %d." ),
aResponse.status_code );
return false;
}
return true;
}
bool REMOTE_PROVIDER_CLIENT::FetchJson( const REMOTE_PROVIDER_HTTP_REQUEST& aRequest, nlohmann::json& aJson,
REMOTE_PROVIDER_ERROR& aError ) const
{
REMOTE_PROVIDER_HTTP_RESPONSE response;
if( !SendRequest( aRequest, response, aError ) )
return false;
try
{
aJson = nlohmann::json::parse( response.body.ToStdString() );
}
catch( const std::exception& e )
{
aError.type = REMOTE_PROVIDER_ERROR_TYPE::INVALID_RESPONSE;
aError.message =
wxString::Format( _( "Remote provider returned invalid JSON: %s" ), wxString::FromUTF8( e.what() ) );
return false;
}
return true;
}
bool REMOTE_PROVIDER_CLIENT::ParseTokenResponse( const REMOTE_PROVIDER_HTTP_RESPONSE& aResponse,
OAUTH_TOKEN_SET& aTokens,
REMOTE_PROVIDER_ERROR& aError ) const
{
nlohmann::json json;
try
{
json = nlohmann::json::parse( aResponse.body.ToStdString() );
}
catch( const std::exception& e )
{
aError.type = REMOTE_PROVIDER_ERROR_TYPE::INVALID_RESPONSE;
aError.message = wxString::Format( _( "Remote provider returned invalid token JSON: %s" ),
wxString::FromUTF8( e.what() ) );
return false;
}
try
{
aTokens = OAUTH_TOKEN_SET();
aTokens.access_token =
wxString::FromUTF8( json.at( "access_token" ).get_ref<const std::string&>().c_str() );
aTokens.refresh_token = json.contains( "refresh_token" )
? wxString::FromUTF8(
json.at( "refresh_token" ).get_ref<const std::string&>().c_str() )
: wxString();
aTokens.id_token = json.contains( "id_token" )
? wxString::FromUTF8(
json.at( "id_token" ).get_ref<const std::string&>().c_str() )
: wxString();
aTokens.token_type = json.contains( "token_type" )
? wxString::FromUTF8(
json.at( "token_type" ).get_ref<const std::string&>().c_str() )
: wxString( "Bearer" );
aTokens.scope = json.contains( "scope" )
? wxString::FromUTF8( json.at( "scope" ).get_ref<const std::string&>().c_str() )
: wxString();
const long long expiresIn = json.contains( "expires_in" ) ? json.at( "expires_in" ).get<long long>() : 0;
aTokens.expires_at = static_cast<long long>( wxDateTime::Now().GetTicks() ) + expiresIn;
}
catch( const std::exception& e )
{
aError.type = REMOTE_PROVIDER_ERROR_TYPE::INVALID_RESPONSE;
aError.message = wxString::Format( _( "Remote provider token response was incomplete: %s" ),
wxString::FromUTF8( e.what() ) );
return false;
}
return true;
}
+203
View File
@@ -0,0 +1,203 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright The 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 <remote_provider_metadata.h>
#include <set>
#include <json_schema_validator.h>
#include <paths.h>
#include <remote_provider_utils.h>
#include <wx_filename.h>
#include <wx/intl.h>
wxFileName REMOTE_PROVIDER_METADATA::DefaultSchemaPath()
{
wxFileName schemaFile( PATHS::GetStockDataPath( true ),
wxS( "kicad-remote-provider-metadata-v1.schema.json" ) );
schemaFile.AppendDir( wxS( "schemas" ) );
schemaFile.Normalize( FN_NORMALIZE_FLAGS );
return schemaFile;
}
std::optional<REMOTE_PROVIDER_METADATA> REMOTE_PROVIDER_METADATA::FromJson(
const nlohmann::json& aJson, wxString& aError )
{
return FromJson( aJson, DefaultSchemaPath(), aError );
}
std::optional<REMOTE_PROVIDER_METADATA> REMOTE_PROVIDER_METADATA::FromJson(
const nlohmann::json& aJson, const wxFileName& aSchemaFile, wxString& aError )
{
if( !aSchemaFile.IsFileReadable() )
{
aError = wxString::Format( _( "Remote provider metadata schema '%s' is not readable." ),
aSchemaFile.GetFullPath() );
return std::nullopt;
}
COLLECTING_JSON_ERROR_HANDLER handler;
JSON_SCHEMA_VALIDATOR validator( aSchemaFile );
validator.Validate( aJson, handler );
if( handler.HasErrors() )
{
aError = wxString::Format( _( "Remote provider metadata failed schema validation: %s" ),
handler.FirstError() );
return std::nullopt;
}
REMOTE_PROVIDER_METADATA metadata;
try
{
metadata.provider_name =
wxString::FromUTF8( aJson.at( "provider_name" ).get_ref<const std::string&>().c_str() );
metadata.provider_version =
wxString::FromUTF8( aJson.at( "provider_version" ).get_ref<const std::string&>().c_str() );
metadata.api_base_url =
wxString::FromUTF8( aJson.at( "api_base_url" ).get_ref<const std::string&>().c_str() );
metadata.panel_url = RemoteProviderJsonString( aJson, "panel_url" );
metadata.session_bootstrap_url = RemoteProviderJsonString( aJson, "session_bootstrap_url" );
metadata.max_download_bytes = aJson.at( "max_download_bytes" ).get<long long>();
metadata.allow_insecure_localhost = aJson.value( "allow_insecure_localhost", false );
metadata.documentation_url = RemoteProviderJsonString( aJson, "documentation_url" );
metadata.terms_url = RemoteProviderJsonString( aJson, "terms_url" );
metadata.privacy_url = RemoteProviderJsonString( aJson, "privacy_url" );
for( const nlohmann::json& assetType : aJson.at( "supported_asset_types" ) )
metadata.supported_asset_types.emplace_back( wxString::FromUTF8(
assetType.get_ref<const std::string&>().c_str() ) );
const nlohmann::json& auth = aJson.at( "auth" );
wxString authType = RemoteProviderJsonString( auth, "type" );
if( authType.IsSameAs( wxS( "oauth2" ), false ) )
{
metadata.auth.type = REMOTE_PROVIDER_AUTH_TYPE::OAUTH2;
metadata.auth.metadata_url = RemoteProviderJsonString( auth, "metadata_url" );
metadata.auth.client_id = RemoteProviderJsonString( auth, "client_id" );
if( auth.contains( "scopes" ) )
{
for( const nlohmann::json& scope : auth.at( "scopes" ) )
metadata.auth.scopes.emplace_back(
wxString::FromUTF8( scope.get_ref<const std::string&>().c_str() ) );
}
}
else
{
metadata.auth.type = REMOTE_PROVIDER_AUTH_TYPE::NONE;
}
const nlohmann::json& capabilities = aJson.at( "capabilities" );
static const std::set<std::string> supportedCapabilities = {
"web_ui_v1",
"parts_v1",
"direct_downloads_v1",
"inline_payloads_v1"
};
for( const auto& [name, value] : capabilities.items() )
{
if( !supportedCapabilities.count( name ) )
{
aError = wxString::Format( _( "Unsupported provider capability '%s'." ),
wxString::FromUTF8( name.c_str() ) );
return std::nullopt;
}
if( name == "web_ui_v1" )
metadata.web_ui_v1 = value.get<bool>();
else if( name == "parts_v1" )
metadata.parts_v1 = value.get<bool>();
else if( name == "direct_downloads_v1" )
metadata.direct_downloads_v1 = value.get<bool>();
else if( name == "inline_payloads_v1" )
metadata.inline_payloads_v1 = value.get<bool>();
}
if( aJson.contains( "parts" ) )
{
const nlohmann::json& parts = aJson.at( "parts" );
metadata.parts_endpoint_template = RemoteProviderJsonString( parts, "endpoint_template" );
}
}
catch( const std::exception& e )
{
aError = wxString::Format( _( "Unable to parse remote provider metadata: %s" ),
wxString::FromUTF8( e.what() ) );
return std::nullopt;
}
if( !metadata.web_ui_v1 )
{
aError = _( "Remote provider metadata must enable web_ui_v1." );
return std::nullopt;
}
if( !metadata.direct_downloads_v1 && !metadata.inline_payloads_v1 )
{
aError = _(
"Remote provider metadata must enable direct_downloads_v1, inline_payloads_v1, or both." );
return std::nullopt;
}
if( metadata.auth.type == REMOTE_PROVIDER_AUTH_TYPE::OAUTH2
&& metadata.session_bootstrap_url.IsEmpty() )
{
aError = _( "Remote provider metadata must define session_bootstrap_url for oauth2." );
return std::nullopt;
}
if( !ValidateRemoteUrlSecurity( metadata.api_base_url, metadata.allow_insecure_localhost, aError, "api_base_url" ) )
{
return std::nullopt;
}
if( !ValidateRemoteUrlSecurity( metadata.panel_url, metadata.allow_insecure_localhost, aError, "panel_url" ) )
{
return std::nullopt;
}
if( !ValidateRemoteUrlSecurity( metadata.session_bootstrap_url, metadata.allow_insecure_localhost, aError,
"session_bootstrap_url" ) )
{
return std::nullopt;
}
if( metadata.auth.type == REMOTE_PROVIDER_AUTH_TYPE::OAUTH2
&& NormalizedUrlOrigin( metadata.panel_url ) != NormalizedUrlOrigin( metadata.session_bootstrap_url ) )
{
aError = _( "session_bootstrap_url must share the same origin as panel_url." );
return std::nullopt;
}
if( metadata.auth.type == REMOTE_PROVIDER_AUTH_TYPE::OAUTH2
&& !ValidateRemoteUrlSecurity( metadata.auth.metadata_url, metadata.allow_insecure_localhost, aError,
"auth.metadata_url" ) )
{
return std::nullopt;
}
return metadata;
}
+152
View File
@@ -0,0 +1,152 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright The 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 <remote_provider_models.h>
#include <json_schema_validator.h>
#include <paths.h>
#include <remote_provider_utils.h>
#include <wx_filename.h>
#include <wx/intl.h>
std::optional<REMOTE_PROVIDER_OAUTH_SERVER_METADATA>
REMOTE_PROVIDER_OAUTH_SERVER_METADATA::FromJson( const nlohmann::json& aJson, bool aAllowInsecureLocalhost,
wxString& aError )
{
REMOTE_PROVIDER_OAUTH_SERVER_METADATA metadata;
try
{
metadata.issuer = RemoteProviderJsonString( aJson, "issuer" );
metadata.authorization_endpoint = RemoteProviderJsonString( aJson, "authorization_endpoint" );
metadata.token_endpoint = RemoteProviderJsonString( aJson, "token_endpoint" );
metadata.revocation_endpoint = RemoteProviderJsonString( aJson, "revocation_endpoint" );
}
catch( const std::exception& e )
{
aError = wxString::Format( _( "Unable to parse OAuth metadata: %s" ), wxString::FromUTF8( e.what() ) );
return std::nullopt;
}
if( metadata.authorization_endpoint.IsEmpty() || metadata.token_endpoint.IsEmpty() )
{
aError = _( "OAuth metadata must include authorization_endpoint and token_endpoint." );
return std::nullopt;
}
if( !ValidateRemoteUrlSecurity( metadata.authorization_endpoint, aAllowInsecureLocalhost, aError,
_( "authorization_endpoint" ) ) )
{
return std::nullopt;
}
if( !ValidateRemoteUrlSecurity( metadata.token_endpoint, aAllowInsecureLocalhost, aError, _( "token_endpoint" ) ) )
{
return std::nullopt;
}
if( !ValidateRemoteUrlSecurity( metadata.revocation_endpoint, aAllowInsecureLocalhost, aError,
_( "revocation_endpoint" ) ) )
{
return std::nullopt;
}
return metadata;
}
wxFileName REMOTE_PROVIDER_PART_MANIFEST::DefaultSchemaPath()
{
wxFileName schemaFile( PATHS::GetStockDataPath( true ), wxS( "kicad-remote-symbol-manifest-v1.schema.json" ) );
schemaFile.AppendDir( wxS( "schemas" ) );
schemaFile.Normalize( FN_NORMALIZE_FLAGS );
return schemaFile;
}
std::optional<REMOTE_PROVIDER_PART_MANIFEST>
REMOTE_PROVIDER_PART_MANIFEST::FromJson( const nlohmann::json& aJson, bool aAllowInsecureLocalhost, wxString& aError )
{
return FromJson( aJson, DefaultSchemaPath(), aAllowInsecureLocalhost, aError );
}
std::optional<REMOTE_PROVIDER_PART_MANIFEST> REMOTE_PROVIDER_PART_MANIFEST::FromJson( const nlohmann::json& aJson,
const wxFileName& aSchemaFile,
bool aAllowInsecureLocalhost,
wxString& aError )
{
if( !aSchemaFile.IsFileReadable() )
{
aError = wxString::Format( _( "Remote provider manifest schema '%s' is not readable." ),
aSchemaFile.GetFullPath() );
return std::nullopt;
}
COLLECTING_JSON_ERROR_HANDLER handler;
JSON_SCHEMA_VALIDATOR validator( aSchemaFile );
validator.Validate( aJson, handler );
if( handler.HasErrors() )
{
aError = wxString::Format( _( "Remote provider manifest failed schema validation: %s" ), handler.FirstError() );
return std::nullopt;
}
REMOTE_PROVIDER_PART_MANIFEST manifest;
try
{
manifest.part_id = RemoteProviderJsonString( aJson, "part_id" );
manifest.display_name = RemoteProviderJsonString( aJson, "display_name" );
manifest.summary = RemoteProviderJsonString( aJson, "summary" );
manifest.license = RemoteProviderJsonString( aJson, "license" );
for( const nlohmann::json& assetJson : aJson.at( "assets" ) )
{
REMOTE_PROVIDER_PART_ASSET asset;
asset.asset_type = RemoteProviderJsonString( assetJson, "asset_type" );
asset.name = RemoteProviderJsonString( assetJson, "name" );
asset.target_library = RemoteProviderJsonString( assetJson, "target_library" );
asset.target_name = RemoteProviderJsonString( assetJson, "target_name" );
asset.content_type = RemoteProviderJsonString( assetJson, "content_type" );
asset.size_bytes = assetJson.at( "size_bytes" ).get<long long>();
asset.sha256 = RemoteProviderJsonString( assetJson, "sha256" );
asset.download_url = RemoteProviderJsonString( assetJson, "download_url" );
asset.required = assetJson.at( "required" ).get<bool>();
if( !ValidateRemoteUrlSecurity( asset.download_url, aAllowInsecureLocalhost, aError,
_( "assets[].download_url" ) ) )
{
return std::nullopt;
}
manifest.assets.push_back( asset );
}
}
catch( const std::exception& e )
{
aError =
wxString::Format( _( "Unable to parse remote provider manifest: %s" ), wxString::FromUTF8( e.what() ) );
return std::nullopt;
}
return manifest;
}
+203
View File
@@ -0,0 +1,203 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright The 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 <remote_provider_settings.h>
#include <algorithm>
#include <json_conversions.h>
#include <picosha2.h>
#include <nlohmann/json.hpp>
namespace
{
wxString normalizeProviderUrl( const wxString& aUrl )
{
wxString normalized = aUrl;
normalized.Trim( true ).Trim( false );
if( normalized.EndsWith( wxS( "/" ) ) )
normalized.RemoveLast();
return normalized.Lower();
}
} // namespace
wxString REMOTE_PROVIDER_SETTINGS::DefaultDestinationDir()
{
return wxS( "${KIPRJMOD}/RemoteLibrary" );
}
wxString REMOTE_PROVIDER_SETTINGS::DefaultLibraryPrefix()
{
return wxS( "remote" );
}
wxString REMOTE_PROVIDER_SETTINGS::CreateProviderId( const wxString& aMetadataUrl )
{
const std::string normalized = normalizeProviderUrl( aMetadataUrl ).ToStdString();
std::string hashHex;
picosha2::hash256_hex_string( normalized, hashHex );
return wxString::Format( wxS( "provider-%s" ),
wxString::FromUTF8( hashHex.substr( 0, 12 ).c_str() ) );
}
void REMOTE_PROVIDER_SETTINGS::ResetToDefaults()
{
providers.clear();
last_used_provider_id.clear();
destination_dir = DefaultDestinationDir();
library_prefix = DefaultLibraryPrefix();
add_to_global_table = false;
}
REMOTE_PROVIDER_ENTRY* REMOTE_PROVIDER_SETTINGS::FindProviderById( const wxString& aProviderId )
{
auto it = std::find_if( providers.begin(), providers.end(),
[&]( const REMOTE_PROVIDER_ENTRY& aEntry )
{
return aEntry.provider_id == aProviderId;
} );
return it == providers.end() ? nullptr : &(*it);
}
const REMOTE_PROVIDER_ENTRY* REMOTE_PROVIDER_SETTINGS::FindProviderById(
const wxString& aProviderId ) const
{
return const_cast<REMOTE_PROVIDER_SETTINGS*>( this )->FindProviderById( aProviderId );
}
REMOTE_PROVIDER_ENTRY* REMOTE_PROVIDER_SETTINGS::FindProviderByMetadataUrl(
const wxString& aMetadataUrl )
{
const wxString normalized = normalizeProviderUrl( aMetadataUrl );
auto it = std::find_if( providers.begin(), providers.end(),
[&]( const REMOTE_PROVIDER_ENTRY& aEntry )
{
return normalizeProviderUrl( aEntry.metadata_url ) == normalized;
} );
return it == providers.end() ? nullptr : &(*it);
}
const REMOTE_PROVIDER_ENTRY* REMOTE_PROVIDER_SETTINGS::FindProviderByMetadataUrl(
const wxString& aMetadataUrl ) const
{
return const_cast<REMOTE_PROVIDER_SETTINGS*>( this )->FindProviderByMetadataUrl( aMetadataUrl );
}
REMOTE_PROVIDER_ENTRY& REMOTE_PROVIDER_SETTINGS::UpsertProvider( const wxString& aMetadataUrl )
{
if( REMOTE_PROVIDER_ENTRY* existing = FindProviderByMetadataUrl( aMetadataUrl ) )
return *existing;
REMOTE_PROVIDER_ENTRY provider;
provider.metadata_url = normalizeProviderUrl( aMetadataUrl );
provider.provider_id = CreateProviderId( provider.metadata_url );
provider.last_auth_status = wxS( "signed_out" );
providers.push_back( provider );
return providers.back();
}
void to_json( nlohmann::json& aJson, const REMOTE_PROVIDER_ENTRY& aEntry )
{
aJson = nlohmann::json{
{ "provider_id", aEntry.provider_id },
{ "metadata_url", aEntry.metadata_url },
{ "display_name_override", aEntry.display_name_override },
{ "last_account_label", aEntry.last_account_label },
{ "last_auth_status", aEntry.last_auth_status }
};
}
void from_json( const nlohmann::json& aJson, REMOTE_PROVIDER_ENTRY& aEntry )
{
aEntry = REMOTE_PROVIDER_ENTRY();
if( aJson.contains( "provider_id" ) )
aEntry.provider_id = aJson.at( "provider_id" ).get<wxString>();
if( aJson.contains( "metadata_url" ) )
aEntry.metadata_url = aJson.at( "metadata_url" ).get<wxString>();
if( aJson.contains( "display_name_override" ) )
aEntry.display_name_override = aJson.at( "display_name_override" ).get<wxString>();
if( aJson.contains( "last_account_label" ) )
aEntry.last_account_label = aJson.at( "last_account_label" ).get<wxString>();
if( aJson.contains( "last_auth_status" ) )
aEntry.last_auth_status = aJson.at( "last_auth_status" ).get<wxString>();
aEntry.metadata_url = normalizeProviderUrl( aEntry.metadata_url );
if( aEntry.provider_id.IsEmpty() && !aEntry.metadata_url.IsEmpty() )
aEntry.provider_id = REMOTE_PROVIDER_SETTINGS::CreateProviderId( aEntry.metadata_url );
}
void to_json( nlohmann::json& aJson, const REMOTE_PROVIDER_SETTINGS& aSettings )
{
aJson = nlohmann::json{
{ "providers", aSettings.providers },
{ "last_used_provider_id", aSettings.last_used_provider_id },
{ "destination_dir", aSettings.destination_dir },
{ "library_prefix", aSettings.library_prefix },
{ "add_to_global_table", aSettings.add_to_global_table }
};
}
void from_json( const nlohmann::json& aJson, REMOTE_PROVIDER_SETTINGS& aSettings )
{
aSettings.ResetToDefaults();
if( aJson.contains( "providers" ) )
aSettings.providers = aJson.at( "providers" ).get<std::vector<REMOTE_PROVIDER_ENTRY>>();
if( aJson.contains( "last_used_provider_id" ) )
aSettings.last_used_provider_id = aJson.at( "last_used_provider_id" ).get<wxString>();
if( aJson.contains( "destination_dir" ) )
aSettings.destination_dir = aJson.at( "destination_dir" ).get<wxString>();
if( aJson.contains( "library_prefix" ) )
aSettings.library_prefix = aJson.at( "library_prefix" ).get<wxString>();
if( aJson.contains( "add_to_global_table" ) )
aSettings.add_to_global_table = aJson.at( "add_to_global_table" ).get<bool>();
}
+143
View File
@@ -0,0 +1,143 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright The 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 <remote_provider_utils.h>
#include <wx/intl.h>
#include <wx/uri.h>
wxString UrlEncode( const wxString& aValue )
{
wxString encoded;
const wxScopedCharBuffer utf8 = aValue.ToUTF8();
const char* p = utf8.data();
size_t len = utf8.length();
for( size_t i = 0; i < len; ++i )
{
unsigned char byte = static_cast<unsigned char>( p[i] );
if( ( byte >= 'A' && byte <= 'Z' ) || ( byte >= 'a' && byte <= 'z' )
|| ( byte >= '0' && byte <= '9' ) || byte == '-' || byte == '_'
|| byte == '.' || byte == '~' )
{
encoded.Append( static_cast<char>( byte ) );
}
else
{
encoded.Append( wxString::Format( wxS( "%%%02X" ), byte ) );
}
}
return encoded;
}
wxString RemoteProviderJsonString( const nlohmann::json& aObject, const char* aKey )
{
auto it = aObject.find( aKey );
if( it != aObject.end() && it->is_string() )
return wxString::FromUTF8( it->get_ref<const std::string&>().c_str() );
return wxString();
}
bool IsLoopbackHost( const wxString& aHost )
{
wxString host = aHost.Lower();
if( host.StartsWith( wxS( "[" ) ) && host.EndsWith( wxS( "]" ) ) )
{
host.RemoveLast();
host.Remove( 0, 1 );
}
return host == wxS( "localhost" ) || host == wxS( "127.0.0.1" ) || host == wxS( "::1" );
}
bool ValidateRemoteUrlSecurity( const wxString& aUrl, bool aAllowInsecureLocalhost,
wxString& aError, const wxString& aLabel )
{
if( aUrl.IsEmpty() )
return true;
wxURI uri( aUrl );
wxString scheme = uri.GetScheme().Lower();
if( scheme == wxS( "https" ) )
return true;
if( scheme == wxS( "http" ) && aAllowInsecureLocalhost && IsLoopbackHost( uri.GetServer() ) )
return true;
aError = wxString::Format(
_( "%s must use HTTPS unless allow_insecure_localhost is enabled for a loopback URL." ),
aLabel );
return false;
}
wxString NormalizedUrlOrigin( const wxString& aUrl )
{
if( aUrl.IsEmpty() )
return wxString();
wxURI uri( aUrl );
if( !uri.HasScheme() || !uri.HasServer() )
return wxString();
wxString scheme = uri.GetScheme().Lower();
wxString host = uri.GetServer().Lower();
wxString port = uri.GetPort();
if( port.IsEmpty() )
{
if( scheme == wxS( "https" ) )
port = wxS( "443" );
else if( scheme == wxS( "http" ) )
port = wxS( "80" );
}
return scheme + wxS( "://" ) + host + wxS( ":" ) + port;
}
void COLLECTING_JSON_ERROR_HANDLER::error( const nlohmann::json::json_pointer& aPointer,
const nlohmann::json& aInstance,
const std::string& aMessage )
{
wxUnusedVar( aInstance );
m_errors.emplace_back( wxString::Format( wxS( "%s: %s" ),
wxString::FromUTF8( aPointer.to_string().c_str() ),
wxString::FromUTF8( aMessage.c_str() ) ) );
}
wxString COLLECTING_JSON_ERROR_HANDLER::FirstError() const
{
if( m_errors.empty() )
return wxString();
return m_errors.front();
}
@@ -23,6 +23,7 @@
#include <bitmaps/bitmap_types.h>
#include <dialogs/panel_startwizard_libraries_base.h>
#include <libraries/library_manager.h>
#include <paths.h>
#include <startwizard/startwizard.h>
#include <startwizard/startwizard_provider_libraries.h>
#include <startwizard/startwizard_provider_settings.h>
@@ -37,6 +38,7 @@ public:
m_model( aModel ),
m_wizard( aWizard )
{
wxWindowBase::SetMaxSize( { FromDIP( 640 ), -1 } );
m_bmpWarning->SetBitmap( KiBitmapBundle( BITMAPS::dialog_warning ) );
m_sizerWarning->Layout();
@@ -88,7 +90,8 @@ public:
}
}
m_sizerWarning->Hide( !m_showWarning );
m_bmpWarning->Show( m_showWarning );
m_stWarning->Show( m_showWarning );
return true;
}
@@ -100,7 +103,7 @@ public:
for( const LIBRARY_TABLE_TYPE& type : m_model->missing_tables )
{
if( !LIBRARY_MANAGER::IsTableValid( LIBRARY_MANAGER::DefaultGlobalTablePath( type ) ) )
if( !LIBRARY_MANAGER::IsTableValid( LIBRARY_MANAGER::StockTablePath( type ) ) )
m_showWarning = true;
switch( type )
@@ -125,6 +128,13 @@ public:
m_stRequiredTables->SetLabel( missingTablesText.BeforeLast( '\n' ) );
}
void OnSize( wxSizeEvent& aEvt ) override
{
aEvt.Skip();
m_stIntro->Wrap( GetClientSize().x - FromDIP( 20 ) );
m_stWarning->Wrap( GetClientSize().x - m_bmpWarning->GetSize().x - FromDIP( 28 ) );
}
private:
std::shared_ptr<STARTWIZARD_PROVIDER_LIBRARIES_MODEL> m_model;
STARTWIZARD* m_wizard;
+1
View File
@@ -75,6 +75,7 @@ principle should be easily implemented by adapting the current STL containers.
%ignore InitKiCadAbout;
%ignore GetCommandOptions;
%ignore EDA_TEXT_RENDER_CACHE_DATA;
%rename(getWxRect) operator wxRect;
%rename(getBOX2I) operator BOX2I;
+37 -2
View File
@@ -521,7 +521,6 @@ void ACTION_TOOLBAR::AddGroup( std::unique_ptr<ACTION_GROUP> aGroup )
for( const auto& act : aGroup->GetActions() )
isToggleEntry |= act->CheckToolbarState( TOOLBAR_STATE::TOGGLE );
m_toolKinds[ groupId ] = isToggleEntry;
m_toolActions[ groupId ] = defaultAction;
m_actionGroups[ groupId ] = std::move( aGroup );
@@ -730,6 +729,7 @@ void ACTION_TOOLBAR::onToolEvent( wxAuiToolBarEvent& aEvent )
{
const auto actionIt = m_toolActions.find( id );
const auto cancelIt = m_toolCancellable.find( id );
const auto groupIt = m_actionGroups.find( id );
// Determine if the tool is actually cancellable
bool isCancellable = ( cancelIt != m_toolCancellable.end() ) ? cancelIt->second : false;
@@ -742,6 +742,40 @@ void ACTION_TOOLBAR::onToolEvent( wxAuiToolBarEvent& aEvent )
m_toolManager->CancelTool();
handled = true;
}
else if( groupIt != m_actionGroups.end()
&& std::none_of( groupIt->second->GetActions().begin(),
groupIt->second->GetActions().end(),
[]( const TOOL_ACTION* a )
{
return a->IsActivation();
} ) )
{
// For non-tool toggle groups (units, crosshair, line modes), cycle to the next
// action on click. Tool groups (route track, etc.) fall through and just dispatch
// the currently displayed action.
ACTION_GROUP* group = groupIt->second.get();
const std::vector<const TOOL_ACTION*>& actions = group->GetActions();
const TOOL_ACTION* current = actionIt->second;
const TOOL_ACTION* next = actions[0];
for( size_t i = 0; i < actions.size(); ++i )
{
if( actions[i]->GetId() == current->GetId() )
{
next = actions[( i + 1 ) % actions.size()];
break;
}
}
evt = next->MakeEvent();
evt->SetHasPosition( false );
m_toolManager->ProcessEvent( *evt );
m_toolManager->GetToolHolder()->RefreshCanvas();
doSelectAction( group, *next );
handled = true;
}
else if( actionIt != m_toolActions.end() )
{
// Dispatch a tool event
@@ -999,7 +1033,8 @@ void ACTION_TOOLBAR::popupPalette( wxAuiToolBarItem* aItem )
}
// Release the mouse to ensure the first click will be recognized in the palette
ReleaseMouse();
if( HasCapture() )
ReleaseMouse();
m_palette->SetPosition( pos );
m_palette->Popup();
-6
View File
@@ -1105,7 +1105,6 @@ TOOL_ACTION ACTIONS::inchesUnits( TOOL_ACTION_ARGS()
.Scope( AS_GLOBAL )
.FriendlyName( _( "Inches" ) )
.Icon( BITMAPS::unit_inch )
.ToolbarState( TOOLBAR_STATE::TOGGLE )
.Flags( AF_NONE )
.Parameter( EDA_UNITS::INCH ) );
@@ -1113,7 +1112,6 @@ TOOL_ACTION ACTIONS::milsUnits( TOOL_ACTION_ARGS()
.Name( "common.Control.mils" )
.Scope( AS_GLOBAL )
.FriendlyName( _( "Mils" ) )
.ToolbarState( TOOLBAR_STATE::TOGGLE )
.Icon( BITMAPS::unit_mil )
.Flags( AF_NONE )
.Parameter( EDA_UNITS::MILS ) );
@@ -1122,7 +1120,6 @@ TOOL_ACTION ACTIONS::millimetersUnits( TOOL_ACTION_ARGS()
.Name( "common.Control.metricUnits" )
.Scope( AS_GLOBAL )
.FriendlyName( _( "Millimeters" ) )
.ToolbarState( TOOLBAR_STATE::TOGGLE )
.Icon( BITMAPS::unit_mm )
.Flags( AF_NONE )
.Parameter( EDA_UNITS::MM ) );
@@ -1181,7 +1178,6 @@ TOOL_ACTION ACTIONS::cursorSmallCrosshairs( TOOL_ACTION_ARGS()
.Scope( AS_GLOBAL )
.FriendlyName( _( "Small crosshairs" ) )
.Tooltip( _( "Use small crosshairs aligned at 0 and 90 degrees" ) )
.ToolbarState( TOOLBAR_STATE::TOGGLE )
.Icon( BITMAPS::cursor_shape ) );
TOOL_ACTION ACTIONS::cursorFullCrosshairs( TOOL_ACTION_ARGS()
@@ -1189,7 +1185,6 @@ TOOL_ACTION ACTIONS::cursorFullCrosshairs( TOOL_ACTION_ARGS()
.Scope( AS_GLOBAL )
.FriendlyName( _( "Full-Window Crosshairs" ) )
.Tooltip( _( "Display full-window crosshairs aligned at 0 and 90 degrees" ) )
.ToolbarState( TOOLBAR_STATE::TOGGLE )
.Icon( BITMAPS::cursor_fullscreen ) );
TOOL_ACTION ACTIONS::cursor45Crosshairs( TOOL_ACTION_ARGS()
@@ -1197,7 +1192,6 @@ TOOL_ACTION ACTIONS::cursor45Crosshairs( TOOL_ACTION_ARGS()
.Scope( AS_GLOBAL )
.FriendlyName( _( "45 Degree Crosshairs" ) )
.Tooltip( _( "Display full-window crosshairs aligned at 45 and 135 degrees" ) )
.ToolbarState( TOOLBAR_STATE::TOGGLE )
.Icon( BITMAPS::cursor_fullscreen45 ) );
TOOL_ACTION ACTIONS::highContrastMode( TOOL_ACTION_ARGS()
+5 -1
View File
@@ -434,7 +434,11 @@ VECTOR2I GRID_HELPER::AlignGrid( const VECTOR2I& aPoint ) const
VECTOR2I GRID_HELPER::AlignGrid( const VECTOR2I& aPoint, const VECTOR2D& aGrid,
const VECTOR2D& aOffset ) const
{
return computeNearest( aPoint, aGrid, aOffset );
// Round the grid size and offset rather than relying on the implicit VECTOR2D->VECTOR2I
// truncation in computeNearest. Grid sizes that aren't exact in IEEE 754 (e.g., 0.254mm =
// 10 mil) would otherwise truncate to the wrong integer (253999 instead of 254000),
// producing positions that aren't true grid multiples.
return computeNearest( aPoint, KiROUND( aGrid ), KiROUND( aOffset ) );
}
@@ -45,6 +45,11 @@ public:
DESIGN_BLOCK_PREVIEW_WIDGET( wxWindow* aParent ) : wxPanel( aParent ) {}
~DESIGN_BLOCK_PREVIEW_WIDGET() = default;
/**
* Return whether the widget initialized properly. This could return false if Kiway is
* not available. If this returns false, no other methods should be called.
*/
virtual bool IsInitialized() const = 0;
/**
* Set the contents of the status label and display it.
+76 -24
View File
@@ -75,33 +75,14 @@ KISTATUSBAR::KISTATUSBAR( int aNumberFields, wxWindow* parent, wxWindowID id, ST
SetFieldsCount( aNumberFields + extraFields );
int* widths = new int[aNumberFields + extraFields];
for( int i = 0; i < aNumberFields; i++ )
widths[i] = -1;
if( std::optional<int> idx = fieldIndex( FIELD::BGJOB_LABEL ) )
widths[aNumberFields + *idx] = -1; // background status text field (variable size)
if( std::optional<int> idx = fieldIndex( FIELD::BGJOB_GAUGE ) )
widths[aNumberFields + *idx] = 75; // background progress button
if( std::optional<int> idx = fieldIndex( FIELD::BGJOB_CANCEL ) )
widths[aNumberFields + *idx] = 20; // background stop button
if( std::optional<int> idx = fieldIndex( FIELD::WARNING ) )
widths[aNumberFields + *idx] = 20; // warning button
if( std::optional<int> idx = fieldIndex( FIELD::NOTIFICATION ) )
widths[aNumberFields + *idx] = 20; // notifications button
m_fieldWidths.assign( aNumberFields + extraFields, -1 );
#ifdef __WXOSX__
// offset from the right edge
widths[aNumberFields + extraFields - 1] = 10;
m_fieldWidths[aNumberFields + extraFields - 1] = 10;
#endif
SetStatusWidths( aNumberFields + extraFields, widths );
delete[] widths;
SetStatusWidths( aNumberFields + extraFields, m_fieldWidths.data() );
int* styles = new int[aNumberFields + extraFields];
@@ -111,7 +92,8 @@ KISTATUSBAR::KISTATUSBAR( int aNumberFields, wxWindow* parent, wxWindowID id, ST
SetStatusStyles( aNumberFields + extraFields, styles );
delete[] styles;
m_backgroundTxt = new wxStaticText( this, wxID_ANY, wxT( "" ) );
m_backgroundTxt = new wxStaticText( this, wxID_ANY, wxT( "" ), wxDefaultPosition,
wxDefaultSize, wxALIGN_RIGHT | wxST_NO_AUTORESIZE );
m_backgroundProgressBar = new wxGauge( this, wxID_ANY, 100, wxDefaultPosition, wxDefaultSize,
wxGA_HORIZONTAL | wxGA_SMOOTH );
@@ -203,6 +185,12 @@ void KISTATUSBAR::onBackgroundProgressClick( wxMouseEvent& aEvent )
void KISTATUSBAR::onSize( wxSizeEvent& aEvent )
{
layoutControls();
}
void KISTATUSBAR::layoutControls()
{
constexpr int padding = 5;
@@ -216,6 +204,8 @@ void KISTATUSBAR::onSize( wxSizeEvent& aEvent )
y += ( r.GetHeight() - textHeight ) / 2;
m_backgroundTxt->SetPosition( { x, y } );
m_backgroundTxt->SetSize( r.GetWidth(), textHeight );
updateBackgroundText();
GetFieldRect( m_normalFieldsCount + *fieldIndex( FIELD::BGJOB_GAUGE ), r );
x = r.GetLeft();
@@ -265,6 +255,8 @@ void KISTATUSBAR::ShowBackgroundProgressBar( bool aCancellable )
if( m_backgroundStopButton )
m_backgroundStopButton->Show( aCancellable );
updateAuxFieldWidths();
}
@@ -274,6 +266,8 @@ void KISTATUSBAR::HideBackgroundProgressBar()
if( m_backgroundStopButton )
m_backgroundStopButton->Hide();
updateAuxFieldWidths();
}
@@ -296,7 +290,8 @@ void KISTATUSBAR::SetBackgroundProgressMax( int aAmount )
void KISTATUSBAR::SetBackgroundStatusText( const wxString& aTxt )
{
m_backgroundTxt->SetLabel( aTxt );
m_backgroundRawText = aTxt;
updateBackgroundText();
// When there are multiple normal fields, the last normal field (typically used for
// file watcher status on Windows) can visually overlap with the background job label
@@ -320,6 +315,61 @@ void KISTATUSBAR::SetBackgroundStatusText( const wxString& aTxt )
}
void KISTATUSBAR::updateAuxFieldWidths()
{
if( m_fieldWidths.empty() )
return;
if( std::optional<int> idx = fieldIndex( FIELD::BGJOB_LABEL ) )
m_fieldWidths[m_normalFieldsCount + *idx] = -2;
if( std::optional<int> idx = fieldIndex( FIELD::BGJOB_GAUGE ) )
m_fieldWidths[m_normalFieldsCount + *idx] = 75;
if( std::optional<int> idx = fieldIndex( FIELD::BGJOB_CANCEL ) )
{
m_fieldWidths[m_normalFieldsCount + *idx] =
m_backgroundStopButton && m_backgroundStopButton->IsShown() ? 20 : 0;
}
if( std::optional<int> idx = fieldIndex( FIELD::WARNING ) )
{
m_fieldWidths[m_normalFieldsCount + *idx] =
m_warningButton && m_warningButton->IsShown() ? 20 : 0;
}
if( std::optional<int> idx = fieldIndex( FIELD::NOTIFICATION ) )
{
m_fieldWidths[m_normalFieldsCount + *idx] =
m_notificationsButton && m_notificationsButton->IsShown() ? 20 : 0;
}
SetStatusWidths( static_cast<int>( m_fieldWidths.size() ), m_fieldWidths.data() );
layoutControls();
updateBackgroundText();
}
void KISTATUSBAR::updateBackgroundText()
{
wxRect r;
if( !GetFieldRect( m_normalFieldsCount + *fieldIndex( FIELD::BGJOB_LABEL ), r ) )
return;
wxString text = m_backgroundRawText;
if( !text.empty() && r.GetWidth() > 4 )
{
wxClientDC dc( this );
int margin = KIUI::GetTextSize( wxT( "XX" ), this ).x;
text = wxControl::Ellipsize( text, dc, wxELLIPSIZE_END, std::max( 0, r.GetWidth() - margin ) );
}
m_backgroundTxt->SetLabel( text );
}
void KISTATUSBAR::SetNotificationCount( int aCount )
{
wxCHECK( m_notificationsButton, /* void */ );
@@ -404,6 +454,7 @@ void KISTATUSBAR::updateWarningUI()
messageCount, messageCount > 0 ? "true" : "false" );
m_warningButton->Show( messageCount > 0 );
updateAuxFieldWidths();
if( messageCount > 0 )
{
@@ -437,6 +488,7 @@ void KISTATUSBAR::ClearLoadWarningMessages()
m_warningButton->Hide();
m_warningButton->SetShowBadge( false );
m_warningButton->SetBadgeText( wxEmptyString );
updateAuxFieldWidths();
Layout();
Refresh();
}
@@ -318,6 +318,9 @@ void PANEL_DESIGN_BLOCK_CHOOSER::onOpenLibsTimer( wxTimerEvent& aEvent )
void PANEL_DESIGN_BLOCK_CHOOSER::onDesignBlockSelected( wxCommandEvent& aEvent )
{
if( !m_preview || !m_preview->IsInitialized() )
return;
if( GetSelectedLibId().IsValid() )
{
std::unique_ptr<DESIGN_BLOCK> designBlock( m_parent->GetDesignBlock( GetSelectedLibId(), true, true ) );
+9 -9
View File
@@ -29,16 +29,12 @@
TEXT_CTRL_EVAL::TEXT_CTRL_EVAL( wxWindow* aParent, wxWindowID aId, const wxString& aValue,
const wxPoint& aPos, const wxSize& aSize, long aStyle,
const wxValidator& aValidator, const wxString& aName ) :
wxTextCtrl( aParent, aId, aValue, aPos, aSize, aStyle | wxTE_PROCESS_ENTER, aValidator,
aName ),
wxTextCtrl( aParent, aId, aValue, aPos, aSize, aStyle | wxTE_PROCESS_ENTER, aValidator, aName ),
m_eval( EDA_UNITS::UNSCALED )
{
Connect( wxEVT_SET_FOCUS, wxFocusEventHandler( TEXT_CTRL_EVAL::onTextFocusGet ), nullptr,
this );
Connect( wxEVT_KILL_FOCUS, wxFocusEventHandler( TEXT_CTRL_EVAL::onTextFocusLost ), nullptr,
this );
Connect( wxEVT_TEXT_ENTER, wxCommandEventHandler( TEXT_CTRL_EVAL::onTextEnter ), nullptr,
this );
Connect( wxEVT_SET_FOCUS, wxFocusEventHandler( TEXT_CTRL_EVAL::onTextFocusGet ), nullptr, this );
Connect( wxEVT_KILL_FOCUS, wxFocusEventHandler( TEXT_CTRL_EVAL::onTextFocusLost ), nullptr, this );
Connect( wxEVT_TEXT_ENTER, wxCommandEventHandler( TEXT_CTRL_EVAL::onTextEnter ), nullptr, this );
}
@@ -62,7 +58,11 @@ void TEXT_CTRL_EVAL::onTextFocusGet( wxFocusEvent& aEvent )
void TEXT_CTRL_EVAL::onTextFocusLost( wxFocusEvent& aEvent )
{
evaluate();
if( m_customEval.has_value() )
m_customEval.value()( this );
else
evaluate();
aEvent.Skip();
}
+116 -62
View File
@@ -23,6 +23,7 @@
#include <tool/tool_base.h>
#include <widgets/webview_panel.h>
#include <wx/evtloop.h>
#include <wx/sizer.h>
#include <wx/webviewarchivehandler.h>
#include <wx/webviewfshandler.h>
@@ -76,29 +77,37 @@ WEBVIEW_PANEL::WEBVIEW_PANEL( wxWindow* aParent, wxWindowID aId, const wxPoint&
m_backend = wxWebViewBackendDefault;
#endif
wxWebView* browser = GetWebView();
if( !browser )
return;
#ifdef __WXMAC__
m_browser->RegisterHandler( wxSharedPtr<wxWebViewHandler>( new wxWebViewArchiveHandler( "wxfs" ) ) );
m_browser->RegisterHandler( wxSharedPtr<wxWebViewHandler>( new wxWebViewFSHandler( "memory" ) ) );
browser->RegisterHandler( wxSharedPtr<wxWebViewHandler>( new wxWebViewArchiveHandler( "wxfs" ) ) );
browser->RegisterHandler( wxSharedPtr<wxWebViewHandler>( new wxWebViewFSHandler( "memory" ) ) );
#endif
m_browser->SetUserAgent( wxString::Format( "KiCad/%s WebView/%s", GetMajorMinorPatchVersion(), wxGetOsDescription() ) );
m_browser->Create( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize );
sizer->Add( m_browser, 1, wxEXPAND );
browser->SetUserAgent( wxString::Format( "KiCad/%s WebView/%s", GetMajorMinorPatchVersion(), wxGetOsDescription() ) );
browser->Create( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize );
sizer->Add( browser, 1, wxEXPAND );
SetSizer( sizer );
#ifndef __WXMAC__
m_browser->RegisterHandler( wxSharedPtr<wxWebViewHandler>( new wxWebViewArchiveHandler( "wxfs" ) ) );
m_browser->RegisterHandler( wxSharedPtr<wxWebViewHandler>( new wxWebViewFSHandler( "memory" ) ) );
browser->RegisterHandler( wxSharedPtr<wxWebViewHandler>( new wxWebViewArchiveHandler( "wxfs" ) ) );
browser->RegisterHandler( wxSharedPtr<wxWebViewHandler>( new wxWebViewFSHandler( "memory" ) ) );
#endif
Bind( wxEVT_WEBVIEW_NAVIGATING, &WEBVIEW_PANEL::OnNavigationRequest, this, m_browser->GetId() );
Bind( wxEVT_WEBVIEW_NEWWINDOW, &WEBVIEW_PANEL::OnNewWindow, this, m_browser->GetId() );
Bind( wxEVT_WEBVIEW_SCRIPT_MESSAGE_RECEIVED, &WEBVIEW_PANEL::OnScriptMessage, this, m_browser->GetId() );
Bind( wxEVT_WEBVIEW_SCRIPT_RESULT, &WEBVIEW_PANEL::OnScriptResult, this, m_browser->GetId() );
Bind( wxEVT_WEBVIEW_ERROR, &WEBVIEW_PANEL::OnError, this, m_browser->GetId() );
Bind( wxEVT_WEBVIEW_NAVIGATING, &WEBVIEW_PANEL::OnNavigationRequest, this, browser->GetId() );
Bind( wxEVT_WEBVIEW_NEWWINDOW, &WEBVIEW_PANEL::OnNewWindow, this, browser->GetId() );
Bind( wxEVT_WEBVIEW_SCRIPT_MESSAGE_RECEIVED, &WEBVIEW_PANEL::OnScriptMessage, this, browser->GetId() );
Bind( wxEVT_WEBVIEW_SCRIPT_RESULT, &WEBVIEW_PANEL::OnScriptResult, this, browser->GetId() );
Bind( wxEVT_WEBVIEW_ERROR, &WEBVIEW_PANEL::OnError, this, browser->GetId() );
m_initRetryTimer.Bind( wxEVT_TIMER, [this]( wxTimerEvent& ) { DoInitHandlers(); } );
}
WEBVIEW_PANEL::~WEBVIEW_PANEL()
{
m_initRetryTimer.Stop();
}
void WEBVIEW_PANEL::BindLoadedEvent()
@@ -106,7 +115,12 @@ void WEBVIEW_PANEL::BindLoadedEvent()
if( m_loadedEventBound )
return;
Bind( wxEVT_WEBVIEW_LOADED, &WEBVIEW_PANEL::OnWebViewLoaded, this, m_browser->GetId() );
wxWebView* browser = GetWebView();
if( !browser )
return;
Bind( wxEVT_WEBVIEW_LOADED, &WEBVIEW_PANEL::OnWebViewLoaded, this, browser->GetId() );
m_loadedEventBound = true;
}
@@ -117,7 +131,10 @@ void WEBVIEW_PANEL::LoadURL( const wxString& aURL )
if( aURL.starts_with( "file:/" ) && !aURL.starts_with( "file:///" ) )
{
wxString new_url = wxString( "file:///" ) + aURL.AfterFirst( '/' );
m_browser->LoadURL( new_url );
if( wxWebView* browser = GetWebView() )
browser->LoadURL( new_url );
return;
}
@@ -127,13 +144,16 @@ void WEBVIEW_PANEL::LoadURL( const wxString& aURL )
return;
}
m_browser->LoadURL( aURL );
if( wxWebView* browser = GetWebView() )
browser->LoadURL( aURL );
}
void WEBVIEW_PANEL::SetPage( const wxString& aHtmlContent )
{
wxLogTrace( "webview", "Setting page content" );
m_browser->SetPage( aHtmlContent, "file://" );
if( wxWebView* browser = GetWebView() )
browser->SetPage( aHtmlContent, "file://" );
}
bool WEBVIEW_PANEL::AddMessageHandler( const wxString& aName, MESSAGE_HANDLER aHandler )
@@ -151,8 +171,22 @@ bool WEBVIEW_PANEL::AddMessageHandler( const wxString& aName, MESSAGE_HANDLER aH
if( m_initialized )
{
if( !m_browser->AddScriptMessageHandler( aName ) )
wxLogTrace( "webview", "Could not add script message handler %s", aName );
wxWebView* browser = GetWebView();
if( !browser )
return true;
wxEventLoopBase* activeLoop = wxEventLoopBase::GetActive();
if( activeLoop && ( !activeLoop->IsMain() || activeLoop->IsYielding() ) )
{
m_initRetryTimer.StartOnce( 200 );
}
else
{
if( !browser->AddScriptMessageHandler( aName ) )
wxLogTrace( "webview", "Could not add script message handler %s", aName );
}
}
return true;
@@ -162,8 +196,11 @@ void WEBVIEW_PANEL::ClearMessageHandlers()
{
wxLogTrace( "webview", "Clearing all message handlers" );
for( const auto& handler : m_msgHandlers )
m_browser->RemoveScriptMessageHandler( handler.first );
if( wxWebView* browser = GetWebView() )
{
for( const auto& handler : m_msgHandlers )
browser->RemoveScriptMessageHandler( handler.first );
}
m_msgHandlers.clear();
}
@@ -183,54 +220,69 @@ void WEBVIEW_PANEL::OnNavigationRequest( wxWebViewEvent& aEvt )
}
}
void WEBVIEW_PANEL::DoInitHandlers()
{
wxWebView* browser = GetWebView();
if( !browser )
return;
// WebKit's AddScriptMessageHandler internally calls RunScript which yields the
// event loop via wxGUIEventLoop::DoYieldFor. If we're inside a nested event loop
// or the main loop is already mid-yield (e.g., wxProgressDialog pumping events),
// this causes WebKit's JSC to crash in sanitizeStackForVM when the reentrant
// yield tries to create a JS context. Re-defer until the loop is idle.
wxEventLoopBase* activeLoop = wxEventLoopBase::GetActive();
if( activeLoop && ( !activeLoop->IsMain() || activeLoop->IsYielding() ) )
{
m_initRetryTimer.StartOnce( 200 );
return;
}
for( const auto& handler : m_msgHandlers )
{
if( !browser->AddScriptMessageHandler( handler.first ) )
wxLogTrace( "webview", "Could not add script message handler %s", handler.first );
}
browser->AddUserScript( R"(
(function() {
// Change window.open to navigate in the same window
window.open = function(url) { if (url) window.location.href = url; return null; };
window.showModalDialog = function() { return null; };
if (window.external && window.external.invoke) {
function notifyHost() {
window.external.invoke('navigation:' + window.location.href);
}
window.addEventListener('popstate', notifyHost);
window.addEventListener('pushstate', notifyHost);
window.addEventListener('replacestate', notifyHost);
['pushState', 'replaceState'].forEach(function(type) {
var orig = history[type];
history[type] = function() {
var rv = orig.apply(this, arguments);
window.dispatchEvent(new Event(type.toLowerCase()));
return rv;
};
});
}
})();
)" );
}
void WEBVIEW_PANEL::OnWebViewLoaded( wxWebViewEvent& aEvt )
{
if( !m_initialized )
{
// Defer handler registration to avoid running during modal dialog/yield
auto initFunc = [this]() {
for( const auto& handler : m_msgHandlers )
{
if( !m_browser->AddScriptMessageHandler( handler.first ) )
{
wxLogTrace( "webview", "Could not add script message handler %s", handler.first );
}
}
// Inject navigation hook for SPA/JS navigation to prevent webkit crashing without new window
m_browser->AddUserScript( R"(
(function() {
// Change window.open to navigate in the same window
window.open = function(url) { if (url) window.location.href = url; return null; };
window.showModalDialog = function() { return null; };
if (window.external && window.external.invoke) {
function notifyHost() {
window.external.invoke('navigation:' + window.location.href);
}
window.addEventListener('popstate', notifyHost);
window.addEventListener('pushstate', notifyHost);
window.addEventListener('replacestate', notifyHost);
['pushState', 'replaceState'].forEach(function(type) {
var orig = history[type];
history[type] = function() {
var rv = orig.apply(this, arguments);
window.dispatchEvent(new Event(type.toLowerCase()));
return rv;
};
});
}
})();
)" );
};
m_initialized = true;
if( m_toolManager && m_tool )
m_toolManager->RunMainStack( m_tool, initFunc );
m_toolManager->RunMainStack( m_tool, [this]() { DoInitHandlers(); } );
else
CallAfter( initFunc );
m_initialized = true;
m_initRetryTimer.StartOnce( 0 );
}
aEvt.Skip();
@@ -238,7 +290,9 @@ void WEBVIEW_PANEL::OnWebViewLoaded( wxWebViewEvent& aEvt )
void WEBVIEW_PANEL::OnNewWindow( wxWebViewEvent& aEvt )
{
m_browser->LoadURL( aEvt.GetURL() );
if( wxWebView* browser = GetWebView() )
browser->LoadURL( aEvt.GetURL() );
aEvt.Veto(); // Prevent default behavior of opening a new window
wxLogTrace( "webview", "New window requested for URL: %s", aEvt.GetURL() );
wxLogTrace( "webview", "Target: %s", aEvt.GetTarget() );
+3
View File
@@ -180,6 +180,9 @@ set( EESCHEMA_DLGS
dialogs/dialog_update_symbol_fields_base.cpp
dialogs/dialog_wire_bus_properties.cpp
dialogs/dialog_wire_bus_properties_base.cpp
remote_symbol_download_manager.cpp
remote_symbol_import_job.cpp
remote_symbol_import_utils.cpp
dialogs/panel_bom_presets.cpp
dialogs/panel_bom_presets_base.cpp
dialogs/panel_eeschema_color_settings.cpp
+38 -8
View File
@@ -4238,12 +4238,30 @@ bool CONNECTION_GRAPH::ercCheckLabels( const CONNECTION_SUBGRAPH* aSubgraph )
{
size_t allPins = pinCount;
size_t localPins = pinCount;
bool hasLocalHierarchy = false;
// For local labels that are bus members, track local pins separately.
// A local label connected to a bus that crosses hierarchy boundaries should
// still have a local connection to component pins. Without this check, a label
// that only connects to pins through the hierarchical bus would not be flagged.
bool isBusMemberLabel = ( type == SCH_LABEL_T ) && !aSubgraph->m_bus_parents.empty();
// A label that bridges a local hierarchical connection (sheet
// pin) to a bus with hierarchical routing is serving a valid
// purpose even without local component pins.
if( !aSubgraph->m_hier_pins.empty() || !aSubgraph->m_hier_ports.empty() )
{
for( auto& [connection, busParents] : aSubgraph->m_bus_parents )
{
for( const CONNECTION_SUBGRAPH* busParent : busParents )
{
if( busParent->m_sheet == sheet
&& ( !busParent->m_hier_pins.empty()
|| !busParent->m_hier_ports.empty() ) )
{
hasLocalHierarchy = true;
break;
}
}
if( hasLocalHierarchy )
break;
}
}
auto it = m_net_name_to_subgraphs_map.find( netName );
@@ -4261,7 +4279,15 @@ bool CONNECTION_GRAPH::ercCheckLabels( const CONNECTION_SUBGRAPH* aSubgraph )
allPins += neighborPins;
if( neighbor->m_sheet == sheet )
{
localPins += neighborPins;
if( !neighbor->m_hier_pins.empty()
|| !neighbor->m_hier_ports.empty() )
{
hasLocalHierarchy = true;
}
}
}
}
@@ -4271,9 +4297,13 @@ bool CONNECTION_GRAPH::ercCheckLabels( const CONNECTION_SUBGRAPH* aSubgraph )
ok = false;
}
// For local bus member labels, check that there's at least one local pin connection.
// Labels that only connect to pins through a hierarchical bus should be flagged.
if( allPins == 0 || ( isBusMemberLabel && localPins == 0 && !has_nc ) )
// A local label that connects to other subgraphs with
// hierarchical connections on the same sheet (through bus
// parents or net-name neighbors) is routing signals and should
// not be flagged even without local component pins.
if( allPins == 0
|| ( type == SCH_LABEL_T && localPins == 0 && allPins > 1
&& !has_nc && !hasLocalHierarchy ) )
{
reportError( text, ERCE_LABEL_NOT_CONNECTED );
ok = false;
+1
View File
@@ -929,6 +929,7 @@ void SCH_EDIT_FRAME::KiwayMailIn( KIWAY_MAIL_EVENT& mail )
if( success )
{
manager.AbortAsyncLoads();
manager.LoadProjectTables( { LIBRARY_TABLE_TYPE::SYMBOL } );
std::ranges::for_each( toLoad,
+8 -4
View File
@@ -101,10 +101,14 @@ public:
protected:
void showPopupMenu( wxMenu& menu, wxGridEvent& aEvent ) override
{
wxMenuItem* revertMenu = menu.Append( MYID_REVERT_ROW, _( "Revert symbol" ), _( "Revert the symbol to its last saved state" ), wxITEM_NORMAL );
wxMenuItem* clearMenu = menu.Append( MYID_CLEAR_CELL, _( "Clear cell" ), _( "Clear the cell value" ), wxITEM_NORMAL );
wxMenuItem* revertMenu = menu.Append( MYID_REVERT_ROW, _( "Revert symbol" ),
_( "Revert the symbol to its last saved state" ), wxITEM_NORMAL );
wxMenuItem* clearMenu = menu.Append( MYID_CLEAR_CELL, _( "Clear cell" ),
_( "Clear the cell value" ), wxITEM_NORMAL );
menu.AppendSeparator();
wxMenuItem* createDerivedSymbolMenu = menu.Append( MYID_CREATE_DERIVED_SYMBOL, _( "Create Derived Symbol" ), _( "Create a new symbol derived from the selected one" ), wxITEM_NORMAL );
wxMenuItem* deriveMenu = menu.Append( MYID_CREATE_DERIVED_SYMBOL, _( "Create Derived Symbol" ),
_( "Create a new symbol derived from the selected one" ),
wxITEM_NORMAL );
// Get global mouse position and convert to grid client coords
wxPoint mousePos = wxGetMousePosition();
@@ -122,7 +126,7 @@ protected:
revertMenu->Enable( m_dataModel->IsCellEdited( row, col ) );
clearMenu->Enable( !m_dataModel->IsCellClear( row, col ) );
createDerivedSymbolMenu->Enable( m_dataModel->IsRowSingleSymbol( row ) );
deriveMenu->Enable( m_dataModel->IsRowSingleSymbol( row ) );
if( m_dataModel->GetColFieldName( col ) == GetCanonicalFieldName( FIELD_T::FOOTPRINT ) )
{
+2 -1
View File
@@ -40,6 +40,7 @@
#include <settings/color_settings.h>
#include <settings/settings_manager.h>
#include <wx_filename.h>
#include <gestfich.h>
#include <pgm_base.h>
#include <sch_edit_frame.h>
#include <sch_painter.h>
@@ -360,7 +361,7 @@ void DIALOG_PLOT_SCHEMATIC::plotSchematic( bool aPlotAll )
schPlotter->Plot( getPlotFileFormat(), plotOpts, &renderSettings, &m_MessagesBox->Reporter() );
if( getPlotFileFormat() == PLOT_FORMAT::PDF && m_openFileAfterPlot->GetValue() )
wxLaunchDefaultApplication( schPlotter->GetLastOutputFilePath() );
OpenPDF( schPlotter->GetLastOutputFilePath() );
}
+425 -164
View File
@@ -8,24 +8,22 @@
* 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.
* 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, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
* 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 "dialog_remote_symbol_config.h"
#include <common.h>
#include <oauth/secure_token_store.h>
#include <kiplatform/environment.h>
#include <pgm_base.h>
#include <remote_provider_client.h>
#include <settings/settings_manager.h>
#include <widgets/ui_common.h>
@@ -33,6 +31,7 @@
#include <wx/dirdlg.h>
#include <wx/filename.h>
#include <wx/intl.h>
#include <wx/listbox.h>
#include <wx/msgdlg.h>
#include <wx/radiobut.h>
#include <wx/sizer.h>
@@ -41,227 +40,489 @@
DIALOG_REMOTE_SYMBOL_CONFIG::DIALOG_REMOTE_SYMBOL_CONFIG( wxWindow* aParent ) :
DIALOG_SHIM( aParent, wxID_ANY, _( "Remote Symbol Settings" ), wxDefaultPosition,
wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER ),
m_destinationCtrl( nullptr ),
m_prefixCtrl( nullptr ),
m_prefixHint( nullptr ),
m_projectRadio( nullptr ),
m_globalRadio( nullptr ),
m_resetButton( nullptr ),
m_browseButton( nullptr ),
m_settings( GetAppSettings<EESCHEMA_SETTINGS>( "eeschema" ) )
DIALOG_SHIM( aParent, wxID_ANY, _( "Remote Symbol Settings" ), wxDefaultPosition,
wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER ),
m_providerList( nullptr ),
m_providerUrlCtrl( nullptr ),
m_providerNameCtrl( nullptr ),
m_providerAccountLabel( nullptr ),
m_providerAuthLabel( nullptr ),
m_addProviderButton( nullptr ),
m_removeProviderButton( nullptr ),
m_refreshProviderButton( nullptr ),
m_signOutProviderButton( nullptr ),
m_destinationCtrl( nullptr ),
m_prefixCtrl( nullptr ),
m_prefixHint( nullptr ),
m_projectRadio( nullptr ),
m_globalRadio( nullptr ),
m_resetButton( nullptr ),
m_browseButton( nullptr ),
m_settings( GetAppSettings<EESCHEMA_SETTINGS>( "eeschema" ) )
{
wxBoxSizer* topSizer = new wxBoxSizer( wxVERTICAL );
wxBoxSizer* topSizer = new wxBoxSizer( wxVERTICAL );
wxStaticText* intro = new wxStaticText( this, wxID_ANY,
_( "Configure where downloaded remote libraries are stored and how they are named." ) );
intro->Wrap( FromDIP( 420 ) );
topSizer->Add( intro, 0, wxALL | wxEXPAND, FromDIP( 10 ) );
wxStaticText* intro = new wxStaticText( this, wxID_ANY,
_( "Configure remote symbol providers and where downloaded libraries are stored." ) );
intro->Wrap( FromDIP( 460 ) );
topSizer->Add( intro, 0, wxALL | wxEXPAND, FromDIP( 10 ) );
wxFlexGridSizer* gridSizer = new wxFlexGridSizer( 2, FromDIP( 6 ), FromDIP( 6 ) );
gridSizer->AddGrowableCol( 1, 1 );
wxStaticBoxSizer* providerSizer = new wxStaticBoxSizer( wxVERTICAL, this, _( "Providers" ) );
gridSizer->Add( new wxStaticText( this, wxID_ANY, _( "Destination directory:" ) ),
0, wxALIGN_CENTER_VERTICAL );
wxBoxSizer* providerTopSizer = new wxBoxSizer( wxHORIZONTAL );
m_providerList = new wxListBox( this, wxID_ANY );
m_providerList->SetMinSize( FromDIP( wxSize( 280, 150 ) ) );
providerTopSizer->Add( m_providerList, 1, wxRIGHT | wxEXPAND, FromDIP( 8 ) );
wxBoxSizer* destSizer = new wxBoxSizer( wxHORIZONTAL );
m_destinationCtrl = new wxTextCtrl( this, wxID_ANY );
m_destinationCtrl->SetMinSize( FromDIP( wxSize( 320, -1 ) ) );
m_destinationCtrl->SetToolTip( _( "Directory where downloaded symbol, footprint, and 3D model data will be written." ) );
destSizer->Add( m_destinationCtrl, 1, wxALIGN_CENTER_VERTICAL );
wxBoxSizer* providerButtonSizer = new wxBoxSizer( wxVERTICAL );
m_addProviderButton = new wxButton( this, wxID_ANY, _( "Add / Update" ) );
m_removeProviderButton = new wxButton( this, wxID_ANY, _( "Remove" ) );
m_refreshProviderButton = new wxButton( this, wxID_ANY, _( "Refresh Metadata" ) );
m_signOutProviderButton = new wxButton( this, wxID_ANY, _( "Sign Out" ) );
providerButtonSizer->Add( m_addProviderButton, 0, wxBOTTOM | wxEXPAND, FromDIP( 4 ) );
providerButtonSizer->Add( m_removeProviderButton, 0, wxBOTTOM | wxEXPAND, FromDIP( 4 ) );
providerButtonSizer->Add( m_refreshProviderButton, 0, wxBOTTOM | wxEXPAND, FromDIP( 4 ) );
providerButtonSizer->Add( m_signOutProviderButton, 0, wxEXPAND );
providerTopSizer->Add( providerButtonSizer, 0, wxEXPAND );
providerSizer->Add( providerTopSizer, 0, wxALL | wxEXPAND, FromDIP( 8 ) );
m_browseButton = new wxButton( this, wxID_ANY, _( "Browse..." ) );
destSizer->Add( m_browseButton, 0, wxLEFT, FromDIP( 4 ) );
gridSizer->Add( destSizer, 1, wxEXPAND );
wxFlexGridSizer* providerGrid = new wxFlexGridSizer( 2, FromDIP( 6 ), FromDIP( 6 ) );
providerGrid->AddGrowableCol( 1, 1 );
providerGrid->Add( new wxStaticText( this, wxID_ANY, _( "Metadata URL:" ) ),
0, wxALIGN_CENTER_VERTICAL );
m_providerUrlCtrl = new wxTextCtrl( this, wxID_ANY );
providerGrid->Add( m_providerUrlCtrl, 1, wxEXPAND );
providerGrid->Add( new wxStaticText( this, wxID_ANY, _( "Display name:" ) ),
0, wxALIGN_CENTER_VERTICAL );
m_providerNameCtrl = new wxTextCtrl( this, wxID_ANY );
providerGrid->Add( m_providerNameCtrl, 1, wxEXPAND );
providerGrid->Add( new wxStaticText( this, wxID_ANY, _( "Last account:" ) ),
0, wxALIGN_CENTER_VERTICAL );
m_providerAccountLabel = new wxStaticText( this, wxID_ANY, _( "Not signed in" ) );
providerGrid->Add( m_providerAccountLabel, 1, wxEXPAND );
providerGrid->Add( new wxStaticText( this, wxID_ANY, _( "Auth status:" ) ),
0, wxALIGN_CENTER_VERTICAL );
m_providerAuthLabel = new wxStaticText( this, wxID_ANY, _( "Not configured" ) );
providerGrid->Add( m_providerAuthLabel, 1, wxEXPAND );
providerSizer->Add( providerGrid, 0, wxLEFT | wxRIGHT | wxBOTTOM | wxEXPAND, FromDIP( 8 ) );
gridSizer->Add( new wxStaticText( this, wxID_ANY, _( "Library prefix:" ) ),
0, wxALIGN_CENTER_VERTICAL );
m_prefixCtrl = new wxTextCtrl( this, wxID_ANY );
m_prefixCtrl->SetToolTip( _( "Prefix that will be applied to the generated libraries." ) );
gridSizer->Add( m_prefixCtrl, 0, wxEXPAND );
topSizer->Add( providerSizer, 0, wxLEFT | wxRIGHT | wxBOTTOM | wxEXPAND, FromDIP( 10 ) );
gridSizer->AddSpacer( 0 );
m_prefixHint = new wxStaticText( this, wxID_ANY, wxString() );
m_prefixHint->SetFont( KIUI::GetSmallInfoFont( this ).Italic() );
gridSizer->Add( m_prefixHint, 0, wxEXPAND );
wxFlexGridSizer* gridSizer = new wxFlexGridSizer( 2, FromDIP( 6 ), FromDIP( 6 ) );
gridSizer->AddGrowableCol( 1, 1 );
gridSizer->Add( new wxStaticText( this, wxID_ANY, _( "Add libraries to:" ) ),
0, wxALIGN_CENTER_VERTICAL );
gridSizer->Add( new wxStaticText( this, wxID_ANY, _( "Destination directory:" ) ),
0, wxALIGN_CENTER_VERTICAL );
wxBoxSizer* radioSizer = new wxBoxSizer( wxHORIZONTAL );
m_projectRadio = new wxRadioButton( this, wxID_ANY, _( "Project library table" ),
wxDefaultPosition, wxDefaultSize, wxRB_GROUP );
m_projectRadio->SetToolTip( _( "Adds the generated libraries to the project's library tables." ) );
radioSizer->Add( m_projectRadio, 0, wxRIGHT | wxALIGN_CENTER_VERTICAL, FromDIP( 12 ) );
wxBoxSizer* destSizer = new wxBoxSizer( wxHORIZONTAL );
m_destinationCtrl = new wxTextCtrl( this, wxID_ANY );
m_destinationCtrl->SetMinSize( FromDIP( wxSize( 320, -1 ) ) );
m_destinationCtrl->SetToolTip( _(
"Directory where downloaded symbol, footprint, and 3D model data will be written." ) );
destSizer->Add( m_destinationCtrl, 1, wxALIGN_CENTER_VERTICAL );
m_globalRadio = new wxRadioButton( this, wxID_ANY, _( "Global library table" ) );
m_globalRadio->SetToolTip( _( "Adds the generated libraries to the global library tables." ) );
radioSizer->Add( m_globalRadio, 0, wxALIGN_CENTER_VERTICAL );
m_browseButton = new wxButton( this, wxID_ANY, _( "Browse..." ) );
destSizer->Add( m_browseButton, 0, wxLEFT, FromDIP( 4 ) );
gridSizer->Add( destSizer, 1, wxEXPAND );
gridSizer->Add( radioSizer, 0, wxEXPAND );
gridSizer->Add( new wxStaticText( this, wxID_ANY, _( "Library prefix:" ) ),
0, wxALIGN_CENTER_VERTICAL );
m_prefixCtrl = new wxTextCtrl( this, wxID_ANY );
m_prefixCtrl->SetToolTip( _( "Prefix that will be applied to the generated libraries." ) );
gridSizer->Add( m_prefixCtrl, 0, wxEXPAND );
topSizer->Add( gridSizer, 0, wxALL | wxEXPAND, FromDIP( 10 ) );
gridSizer->AddSpacer( 0 );
m_prefixHint = new wxStaticText( this, wxID_ANY, wxString() );
m_prefixHint->SetFont( KIUI::GetSmallInfoFont( this ).Italic() );
gridSizer->Add( m_prefixHint, 0, wxEXPAND );
m_resetButton = new wxButton( this, wxID_ANY, _( "Reset to Defaults" ) );
m_resetButton->SetToolTip( _( "Restore the default destination and prefix." ) );
topSizer->Add( m_resetButton, 0, wxLEFT | wxBOTTOM, FromDIP( 10 ) );
gridSizer->Add( new wxStaticText( this, wxID_ANY, _( "Add libraries to:" ) ),
0, wxALIGN_CENTER_VERTICAL );
wxStdDialogButtonSizer* buttonSizer = CreateStdDialogButtonSizer( wxOK | wxCANCEL );
topSizer->Add( buttonSizer, 0, wxALL | wxEXPAND, FromDIP( 10 ) );
wxBoxSizer* radioSizer = new wxBoxSizer( wxHORIZONTAL );
m_projectRadio = new wxRadioButton( this, wxID_ANY, _( "Project library table" ),
wxDefaultPosition, wxDefaultSize, wxRB_GROUP );
m_projectRadio->SetToolTip(
_( "Adds the generated libraries to the project's library tables." ) );
radioSizer->Add( m_projectRadio, 0, wxRIGHT | wxALIGN_CENTER_VERTICAL, FromDIP( 12 ) );
SetSizer( topSizer );
topSizer->Fit( this );
m_globalRadio = new wxRadioButton( this, wxID_ANY, _( "Global library table" ) );
m_globalRadio->SetToolTip(
_( "Adds the generated libraries to the global library tables." ) );
radioSizer->Add( m_globalRadio, 0, wxALIGN_CENTER_VERTICAL );
SetupStandardButtons();
finishDialogSettings();
gridSizer->Add( radioSizer, 0, wxEXPAND );
SetInitialFocus( m_destinationCtrl );
topSizer->Add( gridSizer, 0, wxALL | wxEXPAND, FromDIP( 10 ) );
m_browseButton->Bind( wxEVT_BUTTON, &DIALOG_REMOTE_SYMBOL_CONFIG::onBrowseDestination, this );
m_resetButton->Bind( wxEVT_BUTTON, &DIALOG_REMOTE_SYMBOL_CONFIG::onResetDefaults, this );
m_prefixCtrl->Bind( wxEVT_TEXT, &DIALOG_REMOTE_SYMBOL_CONFIG::onPrefixChanged, this );
m_resetButton = new wxButton( this, wxID_ANY, _( "Reset to Defaults" ) );
m_resetButton->SetToolTip( _( "Restore the default destination and prefix." ) );
topSizer->Add( m_resetButton, 0, wxLEFT | wxBOTTOM, FromDIP( 10 ) );
wxStdDialogButtonSizer* buttonSizer = CreateStdDialogButtonSizer( wxOK | wxCANCEL );
topSizer->Add( buttonSizer, 0, wxALL | wxEXPAND, FromDIP( 10 ) );
SetSizer( topSizer );
topSizer->Fit( this );
SetupStandardButtons();
finishDialogSettings();
SetInitialFocus( m_providerUrlCtrl );
m_browseButton->Bind( wxEVT_BUTTON, &DIALOG_REMOTE_SYMBOL_CONFIG::onBrowseDestination, this );
m_resetButton->Bind( wxEVT_BUTTON, &DIALOG_REMOTE_SYMBOL_CONFIG::onResetDefaults, this );
m_prefixCtrl->Bind( wxEVT_TEXT, &DIALOG_REMOTE_SYMBOL_CONFIG::onPrefixChanged, this );
m_providerList->Bind( wxEVT_LISTBOX, &DIALOG_REMOTE_SYMBOL_CONFIG::onProviderSelected, this );
m_addProviderButton->Bind( wxEVT_BUTTON, &DIALOG_REMOTE_SYMBOL_CONFIG::onAddProvider, this );
m_removeProviderButton->Bind( wxEVT_BUTTON, &DIALOG_REMOTE_SYMBOL_CONFIG::onRemoveProvider,
this );
m_refreshProviderButton->Bind( wxEVT_BUTTON,
&DIALOG_REMOTE_SYMBOL_CONFIG::onRefreshProvider, this );
m_signOutProviderButton->Bind( wxEVT_BUTTON,
&DIALOG_REMOTE_SYMBOL_CONFIG::onSignOutProvider, this );
}
bool DIALOG_REMOTE_SYMBOL_CONFIG::TransferDataToWindow()
{
if( m_settings )
applyRemoteSettings( m_settings->m_RemoteSymbol );
else
{
EESCHEMA_SETTINGS::REMOTE_SYMBOL_CONFIG defaults;
applyRemoteSettings( defaults );
}
if( m_settings )
applyRemoteSettings( m_settings->m_RemoteSymbol );
else
applyRemoteSettings( REMOTE_PROVIDER_SETTINGS() );
return true;
return true;
}
bool DIALOG_REMOTE_SYMBOL_CONFIG::TransferDataFromWindow()
{
wxString destination = m_destinationCtrl->GetValue();
wxString prefix = m_prefixCtrl->GetValue();
wxString destination = m_destinationCtrl->GetValue();
wxString prefix = m_prefixCtrl->GetValue();
destination.Trim( true ).Trim( false );
prefix.Trim( true ).Trim( false );
destination.Trim( true ).Trim( false );
prefix.Trim( true ).Trim( false );
if( destination.IsEmpty() )
{
wxMessageBox( _( "Please choose a destination directory." ), GetTitle(), wxOK | wxICON_WARNING, this );
m_destinationCtrl->SetFocus();
return false;
}
if( destination.IsEmpty() )
{
wxMessageBox( _( "Please choose a destination directory." ), GetTitle(),
wxOK | wxICON_WARNING, this );
m_destinationCtrl->SetFocus();
return false;
}
if( prefix.IsEmpty() )
{
wxMessageBox( _( "Please enter a library prefix." ), GetTitle(), wxOK | wxICON_WARNING, this );
m_prefixCtrl->SetFocus();
return false;
}
if( prefix.IsEmpty() )
{
wxMessageBox( _( "Please enter a library prefix." ), GetTitle(), wxOK | wxICON_WARNING,
this );
m_prefixCtrl->SetFocus();
return false;
}
if( !m_settings )
m_settings = GetAppSettings<EESCHEMA_SETTINGS>( "eeschema" );
if( !m_settings )
return true;
m_settings->m_RemoteSymbol.destination_dir = destination;
m_settings->m_RemoteSymbol.library_prefix = prefix;
m_settings->m_RemoteSymbol.add_to_global_table = m_globalRadio->GetValue();
if( !m_settings )
m_settings = GetAppSettings<EESCHEMA_SETTINGS>( "eeschema" );
if( !m_settings )
return true;
commitProviderEdits();
m_remoteSettings.destination_dir = destination;
m_remoteSettings.library_prefix = prefix;
m_remoteSettings.add_to_global_table = m_globalRadio->GetValue();
m_settings->m_RemoteSymbol = m_remoteSettings;
return true;
}
void DIALOG_REMOTE_SYMBOL_CONFIG::onBrowseDestination( wxCommandEvent& aEvent )
{
wxUnusedVar( aEvent );
wxUnusedVar( aEvent );
wxString initialPath = ExpandEnvVarSubstitutions( m_destinationCtrl->GetValue(), &Prj() );
wxString initialPath = ExpandEnvVarSubstitutions( m_destinationCtrl->GetValue(), &Prj() );
if( initialPath.IsEmpty() )
if( initialPath.IsEmpty() )
{
if( Prj().IsNullProject() )
initialPath = KIPLATFORM::ENV::GetDocumentsPath();
else
initialPath = Prj().GetProjectPath();
}
wxDirDialog dlg( this, _( "Select Destination Directory" ), initialPath );
if( dlg.ShowModal() != wxID_OK )
return;
wxString path = dlg.GetPath();
if( !Prj().IsNullProject() )
{
wxString projectRoot = Prj().GetProjectPath();
wxFileName selectedDir = wxFileName::DirName( path );
if( selectedDir.MakeRelativeTo( projectRoot ) )
{
if( Prj().IsNullProject() )
initialPath = KIPLATFORM::ENV::GetDocumentsPath();
else
initialPath = Prj().GetProjectPath();
wxString relative = selectedDir.GetFullPath();
if( relative.IsEmpty() || relative == wxS( "." ) )
path = wxS( "${KIPRJMOD}" );
else
path = wxString::Format( wxS( "${KIPRJMOD}/%s" ), relative );
}
}
wxDirDialog dlg( this, _( "Select Destination Directory" ), initialPath );
if( dlg.ShowModal() != wxID_OK )
return;
wxString path = dlg.GetPath();
if( !Prj().IsNullProject() )
{
wxString projectRoot = Prj().GetProjectPath();
wxFileName selectedDir = wxFileName::DirName( path );
if( selectedDir.MakeRelativeTo( projectRoot ) )
{
wxString relative = selectedDir.GetFullPath();
if( relative.IsEmpty() || relative == wxS( "." ) )
path = wxS( "${KIPRJMOD}" );
else
path = wxString::Format( wxS( "${KIPRJMOD}/%s" ), relative );
}
}
path.Replace( wxS( "\\" ), wxS( "/" ) );
m_destinationCtrl->ChangeValue( path );
path.Replace( wxS( "\\" ), wxS( "/" ) );
m_destinationCtrl->ChangeValue( path );
}
void DIALOG_REMOTE_SYMBOL_CONFIG::onResetDefaults( wxCommandEvent& aEvent )
{
wxUnusedVar( aEvent );
EESCHEMA_SETTINGS::REMOTE_SYMBOL_CONFIG defaults;
applyRemoteSettings( defaults );
wxUnusedVar( aEvent );
applyRemoteSettings( REMOTE_PROVIDER_SETTINGS() );
}
void DIALOG_REMOTE_SYMBOL_CONFIG::onPrefixChanged( wxCommandEvent& aEvent )
{
wxUnusedVar( aEvent );
updatePrefixHint();
wxUnusedVar( aEvent );
updatePrefixHint();
}
void DIALOG_REMOTE_SYMBOL_CONFIG::applyRemoteSettings(
const EESCHEMA_SETTINGS::REMOTE_SYMBOL_CONFIG& aConfig )
void DIALOG_REMOTE_SYMBOL_CONFIG::onProviderSelected( wxCommandEvent& aEvent )
{
m_destinationCtrl->ChangeValue( aConfig.destination_dir );
m_prefixCtrl->ChangeValue( aConfig.library_prefix );
wxUnusedVar( aEvent );
updateProviderEditor();
updateProviderButtons();
}
if( aConfig.add_to_global_table )
m_globalRadio->SetValue( true );
else
m_projectRadio->SetValue( true );
updatePrefixHint();
void DIALOG_REMOTE_SYMBOL_CONFIG::onAddProvider( wxCommandEvent& aEvent )
{
wxUnusedVar( aEvent );
wxString url = m_providerUrlCtrl->GetValue();
wxString name = m_providerNameCtrl->GetValue();
url.Trim( true ).Trim( false );
name.Trim( true ).Trim( false );
if( url.IsEmpty() )
{
wxMessageBox( _( "Enter a provider metadata URL first." ), GetTitle(),
wxOK | wxICON_WARNING, this );
m_providerUrlCtrl->SetFocus();
return;
}
REMOTE_PROVIDER_ENTRY& provider = m_remoteSettings.UpsertProvider( url );
provider.metadata_url = url;
provider.display_name_override = name;
if( provider.last_auth_status.IsEmpty() )
provider.last_auth_status = wxS( "signed_out" );
m_remoteSettings.last_used_provider_id = provider.provider_id;
reloadProviderList();
for( size_t ii = 0; ii < m_remoteSettings.providers.size(); ++ii )
{
if( m_remoteSettings.providers[ii].provider_id == provider.provider_id )
{
m_providerList->SetSelection( static_cast<int>( ii ) );
break;
}
}
updateProviderEditor();
updateProviderButtons();
}
void DIALOG_REMOTE_SYMBOL_CONFIG::onRemoveProvider( wxCommandEvent& aEvent )
{
wxUnusedVar( aEvent );
const int selection = m_providerList->GetSelection();
if( selection == wxNOT_FOUND )
return;
const wxString removedId = m_remoteSettings.providers[selection].provider_id;
m_remoteSettings.providers.erase( m_remoteSettings.providers.begin() + selection );
if( m_remoteSettings.last_used_provider_id == removedId )
m_remoteSettings.last_used_provider_id.clear();
reloadProviderList();
}
void DIALOG_REMOTE_SYMBOL_CONFIG::onRefreshProvider( wxCommandEvent& aEvent )
{
wxUnusedVar( aEvent );
const int selection = m_providerList->GetSelection();
if( selection == wxNOT_FOUND )
return;
REMOTE_PROVIDER_CLIENT client;
REMOTE_PROVIDER_METADATA metadata;
REMOTE_PROVIDER_ERROR error;
if( !client.DiscoverProvider( m_remoteSettings.providers[selection].metadata_url, metadata, error ) )
{
wxMessageBox( error.message, GetTitle(), wxOK | wxICON_ERROR, this );
return;
}
if( m_remoteSettings.providers[selection].display_name_override.IsEmpty() )
m_providerNameCtrl->ChangeValue( metadata.provider_name );
wxMessageBox( _( "Provider metadata refreshed." ), GetTitle(), wxOK | wxICON_INFORMATION, this );
}
void DIALOG_REMOTE_SYMBOL_CONFIG::onSignOutProvider( wxCommandEvent& aEvent )
{
wxUnusedVar( aEvent );
const int selection = m_providerList->GetSelection();
if( selection == wxNOT_FOUND )
return;
SECURE_TOKEN_STORE tokenStore;
REMOTE_PROVIDER_ENTRY& provider = m_remoteSettings.providers[selection];
tokenStore.DeleteTokens( provider.provider_id, wxS( "default" ) );
provider.last_account_label.clear();
provider.last_auth_status = wxS( "signed_out" );
updateProviderEditor();
}
void DIALOG_REMOTE_SYMBOL_CONFIG::applyRemoteSettings( const REMOTE_PROVIDER_SETTINGS& aConfig )
{
m_remoteSettings = aConfig;
m_destinationCtrl->ChangeValue( aConfig.destination_dir );
m_prefixCtrl->ChangeValue( aConfig.library_prefix );
if( aConfig.add_to_global_table )
m_globalRadio->SetValue( true );
else
m_projectRadio->SetValue( true );
reloadProviderList();
updatePrefixHint();
}
void DIALOG_REMOTE_SYMBOL_CONFIG::reloadProviderList()
{
m_providerList->Clear();
for( const REMOTE_PROVIDER_ENTRY& provider : m_remoteSettings.providers )
{
wxString label = provider.display_name_override.IsEmpty()
? provider.metadata_url
: wxString::Format( wxS( "%s [%s]" ),
provider.display_name_override,
provider.metadata_url );
m_providerList->Append( label );
}
if( !m_remoteSettings.last_used_provider_id.IsEmpty() )
{
for( size_t ii = 0; ii < m_remoteSettings.providers.size(); ++ii )
{
if( m_remoteSettings.providers[ii].provider_id == m_remoteSettings.last_used_provider_id )
{
m_providerList->SetSelection( static_cast<int>( ii ) );
break;
}
}
}
updateProviderEditor();
updateProviderButtons();
}
void DIALOG_REMOTE_SYMBOL_CONFIG::updateProviderEditor()
{
const int selection = m_providerList->GetSelection();
if( selection == wxNOT_FOUND )
{
m_providerUrlCtrl->ChangeValue( wxEmptyString );
m_providerNameCtrl->ChangeValue( wxEmptyString );
m_providerAccountLabel->SetLabel( _( "Not signed in" ) );
m_providerAuthLabel->SetLabel( _( "Not configured" ) );
return;
}
const REMOTE_PROVIDER_ENTRY& provider = m_remoteSettings.providers[selection];
m_providerUrlCtrl->ChangeValue( provider.metadata_url );
m_providerNameCtrl->ChangeValue( provider.display_name_override );
m_providerAccountLabel->SetLabel( provider.last_account_label.IsEmpty()
? _( "Not signed in" )
: provider.last_account_label );
m_providerAuthLabel->SetLabel( provider.last_auth_status.IsEmpty()
? _( "Unknown" )
: provider.last_auth_status );
}
void DIALOG_REMOTE_SYMBOL_CONFIG::updateProviderButtons()
{
const bool hasSelection = m_providerList->GetSelection() != wxNOT_FOUND;
m_removeProviderButton->Enable( hasSelection );
m_refreshProviderButton->Enable( hasSelection );
m_signOutProviderButton->Enable( hasSelection );
}
void DIALOG_REMOTE_SYMBOL_CONFIG::commitProviderEdits()
{
const int selection = m_providerList->GetSelection();
if( selection == wxNOT_FOUND || selection >= static_cast<int>( m_remoteSettings.providers.size() ) )
return;
REMOTE_PROVIDER_ENTRY& provider = m_remoteSettings.providers[selection];
wxString url = m_providerUrlCtrl->GetValue();
wxString name = m_providerNameCtrl->GetValue();
url.Trim( true ).Trim( false );
name.Trim( true ).Trim( false );
if( url.IsEmpty() )
return;
provider.metadata_url = url;
provider.display_name_override = name;
if( provider.provider_id.IsEmpty() )
provider.provider_id = REMOTE_PROVIDER_SETTINGS::CreateProviderId( url );
}
void DIALOG_REMOTE_SYMBOL_CONFIG::updatePrefixHint()
{
const wxString prefix = m_prefixCtrl->GetValue();
const wxString prefix = m_prefixCtrl->GetValue();
if( prefix.IsEmpty() )
{
m_prefixHint->SetLabel(
_( "Library names will be created with suffixes such as _symbols, _fp, and _3d." ) );
}
else
{
m_prefixHint->SetLabel( wxString::Format(
_( "Will create libraries like %1$s_symbols, %1$s_fp, %1$s_3d, etc." ), prefix ) );
}
if( prefix.IsEmpty() )
{
m_prefixHint->SetLabel(
_( "Library names will be created with suffixes such as _symbols, _fp, and _3d." ) );
}
else
{
m_prefixHint->SetLabel( wxString::Format(
_( "Will create libraries like %1$s_symbols, %1$s_fp, %1$s_3d, etc." ), prefix ) );
}
m_prefixHint->Wrap( FromDIP( 360 ) );
m_prefixHint->Wrap( FromDIP( 360 ) );
}
+31 -16
View File
@@ -8,17 +8,13 @@
* 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.
* 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, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
* 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_REMOTE_SYMBOL_CONFIG_H
@@ -27,10 +23,11 @@
#include <dialog_shim.h>
#include <eeschema_settings.h>
class wxTextCtrl;
class wxStaticText;
class wxRadioButton;
class wxButton;
class wxListBox;
class wxRadioButton;
class wxStaticText;
class wxTextCtrl;
class EESCHEMA_SETTINGS;
@@ -46,11 +43,29 @@ private:
void onBrowseDestination( wxCommandEvent& aEvent );
void onResetDefaults( wxCommandEvent& aEvent );
void onPrefixChanged( wxCommandEvent& aEvent );
void onProviderSelected( wxCommandEvent& aEvent );
void onAddProvider( wxCommandEvent& aEvent );
void onRemoveProvider( wxCommandEvent& aEvent );
void onRefreshProvider( wxCommandEvent& aEvent );
void onSignOutProvider( wxCommandEvent& aEvent );
void applyRemoteSettings( const EESCHEMA_SETTINGS::REMOTE_SYMBOL_CONFIG& aConfig );
void applyRemoteSettings( const REMOTE_PROVIDER_SETTINGS& aConfig );
void updatePrefixHint();
void reloadProviderList();
void updateProviderEditor();
void updateProviderButtons();
void commitProviderEdits();
private:
wxListBox* m_providerList;
wxTextCtrl* m_providerUrlCtrl;
wxTextCtrl* m_providerNameCtrl;
wxStaticText* m_providerAccountLabel;
wxStaticText* m_providerAuthLabel;
wxButton* m_addProviderButton;
wxButton* m_removeProviderButton;
wxButton* m_refreshProviderButton;
wxButton* m_signOutProviderButton;
wxTextCtrl* m_destinationCtrl;
wxTextCtrl* m_prefixCtrl;
wxStaticText* m_prefixHint;
@@ -59,8 +74,8 @@ private:
wxButton* m_resetButton;
wxButton* m_browseButton;
EESCHEMA_SETTINGS* m_settings;
EESCHEMA_SETTINGS* m_settings;
REMOTE_PROVIDER_SETTINGS m_remoteSettings;
};
#endif // DIALOG_REMOTE_SYMBOL_CONFIG_H
@@ -2750,6 +2750,7 @@ void DIALOG_SYMBOL_FIELDS_TABLE::onDeleteVariant( wxCommandEvent& aEvent )
wxString variantName = m_variantListBox->GetString( selection );
m_variantListBox->Delete( selection );
m_parent->Schematic().DeleteVariant( variantName );
m_parent->OnModify();
int newSelection = std::max( 0, selection - 1 );
m_variantListBox->SetSelection( newSelection );
@@ -2830,6 +2831,7 @@ void DIALOG_SYMBOL_FIELDS_TABLE::onRenameVariant( wxCommandEvent& aEvent )
}
m_parent->Schematic().RenameVariant( oldVariantName, newVariantName );
m_parent->OnModify();
wxArrayString ctrlContents = m_variantListBox->GetStrings();
ctrlContents.Remove( oldVariantName );
@@ -2886,6 +2888,7 @@ void DIALOG_SYMBOL_FIELDS_TABLE::onCopyVariant( wxCommandEvent& aEvent )
}
m_parent->Schematic().CopyVariant( sourceVariantName, newVariantName );
m_parent->OnModify();
wxArrayString ctrlContents = m_variantListBox->GetStrings();
ctrlContents.Add( newVariantName );
@@ -1,5 +1,5 @@
///////////////////////////////////////////////////////////////////////////
// C++ code generated with wxFormBuilder (version 4.2.1-62-g497c85bd-dirty)
// C++ code generated with wxFormBuilder (version 4.2.1-0-g80c4cb6)
// http://www.wxformbuilder.org/
//
// PLEASE DO *NOT* EDIT THIS FILE!
@@ -78,7 +78,7 @@ DIALOG_SYMBOL_FIELDS_TABLE_BASE::DIALOG_SYMBOL_FIELDS_TABLE_BASE( wxWindow* pare
m_addFieldButton = new STD_BITMAP_BUTTON( m_viewControlsPanel, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxDefaultSize, wxBU_AUTODRAW|0 );
m_addFieldButton->SetToolTip( _("Add a new field") );
bFieldsButtons->Add( m_addFieldButton, 0, wxBOTTOM, 5 );
bFieldsButtons->Add( m_addFieldButton, 0, wxBOTTOM|wxLEFT, 5 );
m_renameFieldButton = new STD_BITMAP_BUTTON( m_viewControlsPanel, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxDefaultSize, wxBU_AUTODRAW|0 );
m_renameFieldButton->SetToolTip( _("Rename selected field") );
@@ -104,7 +104,7 @@ DIALOG_SYMBOL_FIELDS_TABLE_BASE::DIALOG_SYMBOL_FIELDS_TABLE_BASE( wxWindow* pare
m_bomPresetsLabel = new wxStaticText( m_viewControlsPanel, wxID_ANY, _("View presets:"), wxDefaultPosition, wxDefaultSize, 0 );
m_bomPresetsLabel->Wrap( -1 );
bPresets->Add( m_bomPresetsLabel, 0, 0, 5 );
bPresets->Add( m_bomPresetsLabel, 0, wxLEFT, 5 );
bPresets->Add( 0, 2, 0, 0, 5 );
@@ -113,7 +113,7 @@ DIALOG_SYMBOL_FIELDS_TABLE_BASE::DIALOG_SYMBOL_FIELDS_TABLE_BASE( wxWindow* pare
int m_cbBomPresetsNChoices = sizeof( m_cbBomPresetsChoices ) / sizeof( wxString );
m_cbBomPresets = new wxChoice( m_viewControlsPanel, wxID_ANY, wxDefaultPosition, wxDefaultSize, m_cbBomPresetsNChoices, m_cbBomPresetsChoices, 0 );
m_cbBomPresets->SetSelection( 0 );
bPresets->Add( m_cbBomPresets, 0, wxEXPAND, 5 );
bPresets->Add( m_cbBomPresets, 0, wxEXPAND|wxRIGHT|wxLEFT, 5 );
bPresets->Add( 0, 5, 0, wxEXPAND, 5 );
@@ -122,7 +122,7 @@ DIALOG_SYMBOL_FIELDS_TABLE_BASE::DIALOG_SYMBOL_FIELDS_TABLE_BASE( wxWindow* pare
bMargins->Add( bPresets, 0, wxEXPAND|wxTOP|wxBOTTOM, 5 );
bViewControlsSizer->Add( bMargins, 1, wxALL|wxEXPAND, 5 );
bViewControlsSizer->Add( bMargins, 1, wxEXPAND|wxBOTTOM, 5 );
m_viewControlsPanel->SetSizer( bViewControlsSizer );
@@ -145,25 +145,25 @@ DIALOG_SYMBOL_FIELDS_TABLE_BASE::DIALOG_SYMBOL_FIELDS_TABLE_BASE( wxWindow* pare
bSizer14 = new wxBoxSizer( wxHORIZONTAL );
m_addVariantButton = new STD_BITMAP_BUTTON( m_variantsPanel, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxDefaultSize, wxBU_AUTODRAW|0 );
bSizer14->Add( m_addVariantButton, 0, wxRIGHT, 5 );
bSizer14->Add( m_addVariantButton, 0, wxBOTTOM|wxRIGHT|wxLEFT, 5 );
m_renameVariantButton = new STD_BITMAP_BUTTON( m_variantsPanel, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxDefaultSize, wxBU_AUTODRAW|0 );
bSizer14->Add( m_renameVariantButton, 0, 0, 5 );
bSizer14->Add( m_renameVariantButton, 0, wxBOTTOM, 5 );
m_copyVariantButton = new STD_BITMAP_BUTTON( m_variantsPanel, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxDefaultSize, wxBU_AUTODRAW|0 );
bSizer14->Add( m_copyVariantButton, 0, 0, 5 );
bSizer14->Add( m_copyVariantButton, 0, wxBOTTOM|wxLEFT, 5 );
bSizer14->Add( 15, 0, 0, 0, 5 );
bSizer14->Add( 20, 0, 0, 0, 5 );
m_deleteVariantButton = new STD_BITMAP_BUTTON( m_variantsPanel, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxDefaultSize, wxBU_AUTODRAW|0 );
bSizer14->Add( m_deleteVariantButton, 0, wxLEFT, 5 );
bSizer14->Add( m_deleteVariantButton, 0, wxBOTTOM|wxLEFT, 5 );
bMargins2->Add( bSizer14, 0, wxEXPAND|wxTOP|wxLEFT, 2 );
bVariantsSizer->Add( bMargins2, 1, wxALL|wxEXPAND, 3 );
bVariantsSizer->Add( bMargins2, 1, wxEXPAND|wxTOP|wxBOTTOM, 3 );
m_variantsPanel->SetSizer( bVariantsSizer );
@@ -263,7 +263,7 @@ DIALOG_SYMBOL_FIELDS_TABLE_BASE::DIALOG_SYMBOL_FIELDS_TABLE_BASE( wxWindow* pare
m_panelEdit->SetSizer( bEditSizer );
m_panelEdit->Layout();
bEditSizer->Fit( m_panelEdit );
m_nbPages->AddPage( m_panelEdit, _("Edit"), true );
m_nbPages->AddPage( m_panelEdit, _("Edit"), false );
m_panelExport = new wxPanel( m_nbPages, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL );
wxGridBagSizer* gbExport;
gbExport = new wxGridBagSizer( 0, 5 );
@@ -378,7 +378,7 @@ DIALOG_SYMBOL_FIELDS_TABLE_BASE::DIALOG_SYMBOL_FIELDS_TABLE_BASE( wxWindow* pare
m_panelExport->SetSizer( gbExport );
m_panelExport->Layout();
gbExport->Fit( m_panelExport );
m_nbPages->AddPage( m_panelExport, _("Export"), false );
m_nbPages->AddPage( m_panelExport, _("Export"), true );
bMargins1->Add( m_nbPages, 1, wxEXPAND|wxALL, 5 );
@@ -307,7 +307,7 @@
<property name="permission">none</property>
<object class="sizeritem" expanded="true">
<property name="border">5</property>
<property name="flag">wxALL|wxEXPAND</property>
<property name="flag">wxEXPAND|wxBOTTOM</property>
<property name="proportion">1</property>
<object class="wxBoxSizer" expanded="true">
<property name="minimum_size"></property>
@@ -416,7 +416,7 @@
<property name="permission">none</property>
<object class="sizeritem" expanded="true">
<property name="border">5</property>
<property name="flag">wxBOTTOM</property>
<property name="flag">wxBOTTOM|wxLEFT</property>
<property name="proportion">0</property>
<object class="wxBitmapButton" expanded="true">
<property name="BottomDockable">1</property>
@@ -721,7 +721,7 @@
</object>
<object class="sizeritem" expanded="true">
<property name="border">5</property>
<property name="flag"></property>
<property name="flag">wxLEFT</property>
<property name="proportion">0</property>
<object class="wxStaticText" expanded="true">
<property name="BottomDockable">1</property>
@@ -793,7 +793,7 @@
</object>
<object class="sizeritem" expanded="true">
<property name="border">5</property>
<property name="flag">wxEXPAND</property>
<property name="flag">wxEXPAND|wxRIGHT|wxLEFT</property>
<property name="proportion">0</property>
<object class="wxChoice" expanded="true">
<property name="BottomDockable">1</property>
@@ -933,7 +933,7 @@
<property name="permission">none</property>
<object class="sizeritem" expanded="true">
<property name="border">3</property>
<property name="flag">wxALL|wxEXPAND</property>
<property name="flag">wxEXPAND|wxTOP|wxBOTTOM</property>
<property name="proportion">1</property>
<object class="wxBoxSizer" expanded="true">
<property name="minimum_size"></property>
@@ -1078,7 +1078,7 @@
<property name="permission">none</property>
<object class="sizeritem" expanded="true">
<property name="border">5</property>
<property name="flag">wxRIGHT</property>
<property name="flag">wxBOTTOM|wxRIGHT|wxLEFT</property>
<property name="proportion">0</property>
<object class="wxBitmapButton" expanded="true">
<property name="BottomDockable">1</property>
@@ -1153,7 +1153,7 @@
</object>
<object class="sizeritem" expanded="true">
<property name="border">5</property>
<property name="flag"></property>
<property name="flag">wxBOTTOM</property>
<property name="proportion">0</property>
<object class="wxBitmapButton" expanded="true">
<property name="BottomDockable">1</property>
@@ -1228,7 +1228,7 @@
</object>
<object class="sizeritem" expanded="true">
<property name="border">5</property>
<property name="flag"></property>
<property name="flag">wxBOTTOM|wxLEFT</property>
<property name="proportion">0</property>
<object class="wxBitmapButton" expanded="true">
<property name="BottomDockable">1</property>
@@ -1308,12 +1308,12 @@
<object class="spacer" expanded="true">
<property name="height">0</property>
<property name="permission">protected</property>
<property name="width">15</property>
<property name="width">20</property>
</object>
</object>
<object class="sizeritem" expanded="true">
<property name="border">5</property>
<property name="flag">wxLEFT</property>
<property name="flag">wxBOTTOM|wxLEFT</property>
<property name="proportion">0</property>
<object class="wxBitmapButton" expanded="true">
<property name="BottomDockable">1</property>
@@ -1,5 +1,5 @@
///////////////////////////////////////////////////////////////////////////
// C++ code generated with wxFormBuilder (version 4.2.1-62-g497c85bd-dirty)
// C++ code generated with wxFormBuilder (version 4.2.1-0-g80c4cb6)
// http://www.wxformbuilder.org/
//
// PLEASE DO *NOT* EDIT THIS FILE!
+22 -5
View File
@@ -95,12 +95,29 @@ static std::unique_ptr<SCHEMATIC> readSchematicFromFile( const std::string& aFil
SETTINGS_MANAGER& manager = Pgm().GetSettingsManager();
// TODO: this must load the schematic's project, not a default project. At the very minimum
// variable resolution won't work without the project, but there might also be issues with
// netclasses, etc.
manager.LoadProject( "" );
wxFileName pro( aFilename );
pro.SetExt( FILEEXT::ProjectFileExtension );
pro.MakeAbsolute();
wxString projectPath = pro.GetFullPath();
PROJECT* project = manager.GetProject( projectPath );
if( !project )
{
if( wxFileExists( projectPath ) )
{
// cli
manager.LoadProject( projectPath, true );
project = manager.GetProject( projectPath );
}
else
{
manager.LoadProject( "" );
}
}
schematic->Reset();
schematic->SetProject( &manager.Prj() );
schematic->SetProject( project );
SCH_SHEET* rootSheet = pi->LoadSchematicFile( aFilename, schematic.get() );
if( !rootSheet )
+7
View File
@@ -223,6 +223,13 @@ void SCH_EDIT_FRAME::saveProjectSettings()
}
}
// Propagate the root schematic revision to the project file for IPC-2581 BOM export
if( Schematic().RootScreen() )
{
Prj().GetProjectFile().m_IP2581Bom.schRevision =
Schematic().RootScreen()->GetTitleBlock().GetRevision();
}
// Update top-level sheets information in the project file
const std::vector<SCH_SHEET*>& topLevelSheets = Schematic().GetTopLevelSheets();
+6 -42
View File
@@ -40,7 +40,6 @@
SCH_EDIT_FRAME* EESCHEMA_HELPERS::s_SchEditFrame = nullptr;
SETTINGS_MANAGER* EESCHEMA_HELPERS::s_SettingsManager = nullptr;
void EESCHEMA_HELPERS::SetSchEditFrame( SCH_EDIT_FRAME* aSchEditFrame )
@@ -49,42 +48,6 @@ void EESCHEMA_HELPERS::SetSchEditFrame( SCH_EDIT_FRAME* aSchEditFrame )
}
SETTINGS_MANAGER* EESCHEMA_HELPERS::GetSettingsManager()
{
if( !s_SettingsManager )
{
if( s_SchEditFrame )
{
s_SettingsManager = s_SchEditFrame->GetSettingsManager();
}
else
{
s_SettingsManager = new SETTINGS_MANAGER();
}
}
return s_SettingsManager;
}
PROJECT* EESCHEMA_HELPERS::GetDefaultProject( bool aSetActive )
{
// For some reasons, LoadProject() needs a C locale, so ensure we have the right locale
// This is mainly when running QA Python tests
LOCALE_IO dummy;
PROJECT* project = GetSettingsManager()->GetProject( "" );
if( !project )
{
GetSettingsManager()->LoadProject( "", aSetActive );
project = GetSettingsManager()->GetProject( "" );
}
return project;
}
SCHEMATIC* EESCHEMA_HELPERS::LoadSchematic( const wxString& aFileName, bool aSetActive,
bool aForceDefaultProject, PROJECT* aProject, bool aCalculateConnectivity )
{
@@ -118,10 +81,11 @@ SCHEMATIC* EESCHEMA_HELPERS::LoadSchematic( const wxString& aFileName,
LOCALE_IO dummy;
PROJECT* project = aProject;
SETTINGS_MANAGER& mgr = Pgm().GetSettingsManager();
if( !project )
{
project = GetSettingsManager()->GetProject( projectPath );
project = mgr.GetProject( projectPath );
}
if( !aForceDefaultProject )
@@ -130,11 +94,11 @@ SCHEMATIC* EESCHEMA_HELPERS::LoadSchematic( const wxString& aFileName,
{
if( wxFileExists( projectPath ) )
{
GetSettingsManager()->LoadProject( projectPath, aSetActive );
project = GetSettingsManager()->GetProject( projectPath );
mgr.LoadProject( projectPath, aSetActive );
project = mgr.GetProject( projectPath );
}
}
else if( s_SchEditFrame && project == &GetSettingsManager()->Prj() )
else if( s_SchEditFrame && project == &mgr.Prj() )
{
// Project is already loaded? Then so is the board
return &s_SchEditFrame->Schematic();
@@ -143,7 +107,7 @@ SCHEMATIC* EESCHEMA_HELPERS::LoadSchematic( const wxString& aFileName,
// Board cannot be loaded without a project, so create the default project
if( !project || aForceDefaultProject )
project = GetDefaultProject( aSetActive );
project = &mgr.Prj();
IO_RELEASER<SCH_IO> pi( SCH_IO_MGR::FindPlugin( aFormat ) );
-3
View File
@@ -41,9 +41,7 @@ class PROJECT;
class EESCHEMA_HELPERS
{
public:
static SETTINGS_MANAGER* GetSettingsManager();
static void SetSchEditFrame( SCH_EDIT_FRAME* aSchEditFrame );
static PROJECT* GetDefaultProject( bool aSetActive );
static SCHEMATIC* LoadSchematic( const wxString& aFileName, bool aSetActive,
bool aForceDefaultProject,
PROJECT* aProject = nullptr,
@@ -56,7 +54,6 @@ public:
private:
static SCH_EDIT_FRAME* s_SchEditFrame;
static SETTINGS_MANAGER* s_SettingsManager;
};
#endif
+5
View File
@@ -1414,6 +1414,11 @@ DS_PROXY_VIEW_ITEM* EESCHEMA_JOBS_HANDLER::getDrawingSheetProxyView( SCHEMATIC*
drawingSheet->SetPageBorderColorLayer( LAYER_SCHEMATIC_PAGE_LIMITS );
drawingSheet->SetIsFirstPage( aSch->RootScreen()->GetVirtualPageNumber() == 1 );
wxString currentVariant = aSch->GetCurrentVariant();
wxString variantDesc = aSch->GetVariantDescription( currentVariant );
drawingSheet->SetVariantName( TO_UTF8( currentVariant ) );
drawingSheet->SetVariantDesc( TO_UTF8( variantDesc ) );
drawingSheet->SetSheetName( "" );
drawingSheet->SetSheetPath( "" );
+7 -25
View File
@@ -173,27 +173,6 @@ const wxAuiPaneInfo& defaultRemoteSymbolPaneInfo( wxWindow* aWindow )
}
wxString EESCHEMA_SETTINGS::REMOTE_SYMBOL_CONFIG::DefaultDestinationDir()
{
return wxS( "${KIPRJMOD}/RemoteLibrary" );
}
wxString EESCHEMA_SETTINGS::REMOTE_SYMBOL_CONFIG::DefaultLibraryPrefix()
{
return wxS( "remote" );
}
void EESCHEMA_SETTINGS::REMOTE_SYMBOL_CONFIG::ResetToDefaults()
{
destination_dir = DefaultDestinationDir();
library_prefix = DefaultLibraryPrefix();
add_to_global_table = false;
user_ids.clear();
}
EESCHEMA_SETTINGS::EESCHEMA_SETTINGS() :
APP_SETTINGS_BASE( "eeschema", eeschemaSchemaVersion ),
m_Appearance(),
@@ -356,17 +335,20 @@ EESCHEMA_SETTINGS::EESCHEMA_SETTINGS() :
m_params.emplace_back( new PARAM<wxString>( "remote_symbols.destination_dir",
&m_RemoteSymbol.destination_dir,
REMOTE_SYMBOL_CONFIG::DefaultDestinationDir() ) );
REMOTE_PROVIDER_SETTINGS::DefaultDestinationDir() ) );
m_params.emplace_back( new PARAM<wxString>( "remote_symbols.library_prefix",
&m_RemoteSymbol.library_prefix,
REMOTE_SYMBOL_CONFIG::DefaultLibraryPrefix() ) );
REMOTE_PROVIDER_SETTINGS::DefaultLibraryPrefix() ) );
m_params.emplace_back( new PARAM<bool>( "remote_symbols.add_to_global_table",
&m_RemoteSymbol.add_to_global_table, false ) );
m_params.emplace_back( new PARAM_WXSTRING_MAP( "remote_symbols.user_ids",
&m_RemoteSymbol.user_ids, {} ) );
m_params.emplace_back( new PARAM<wxString>( "remote_symbols.last_used_provider_id",
&m_RemoteSymbol.last_used_provider_id, wxEmptyString ) );
m_params.emplace_back( new PARAM_LIST<REMOTE_PROVIDER_ENTRY>( "remote_symbols.providers",
&m_RemoteSymbol.providers, {} ) );
m_params.emplace_back( new PARAM<int>( "drawing.default_bus_thickness",
&m_Drawing.default_bus_thickness, DEFAULT_BUS_WIDTH_MILS ) );
+2 -18
View File
@@ -27,6 +27,7 @@
#include <map>
#include <remote_provider_settings.h>
#include <settings/app_settings.h>
#include <sim/sim_preferences.h>
@@ -113,23 +114,6 @@ public:
int remote_symbol_panel_float_height;
};
struct REMOTE_SYMBOL_CONFIG
{
REMOTE_SYMBOL_CONFIG()
{
ResetToDefaults();
}
wxString destination_dir;
wxString library_prefix;
bool add_to_global_table;
std::map<wxString, wxString> user_ids;
void ResetToDefaults();
static wxString DefaultDestinationDir();
static wxString DefaultLibraryPrefix();
};
struct AUTOPLACE_FIELDS
{
bool enable;
@@ -348,7 +332,7 @@ private:
public:
APPEARANCE m_Appearance;
AUI_PANELS m_AuiPanels;
REMOTE_SYMBOL_CONFIG m_RemoteSymbol;
REMOTE_PROVIDER_SETTINGS m_RemoteSymbol;
DRAWING m_Drawing;
INPUT m_Input;
+2 -2
View File
@@ -1016,7 +1016,7 @@ void FIELDS_EDITOR_GRID_DATA_MODEL::RebuildRows()
{
for( const wxString& variantName : m_variantNames )
{
if( ref.GetSymbol()->GetExcludedFromBOM( &ref.GetSheetPath(), variantName )
if( ref.GetSymbol()->ResolveExcludedFromBOM( &ref.GetSheetPath(), variantName )
|| ref.GetSheetPath().GetExcludedFromBOM( variantName ) )
{
isExcluded = true;
@@ -1026,7 +1026,7 @@ void FIELDS_EDITOR_GRID_DATA_MODEL::RebuildRows()
}
else
{
isExcluded = ref.GetSymbol()->GetExcludedFromBOM( &ref.GetSheetPath(), m_currentVariant )
isExcluded = ref.GetSymbol()->ResolveExcludedFromBOM( &ref.GetSheetPath(), m_currentVariant )
|| ref.GetSheetPath().GetExcludedFromBOM( m_currentVariant );
}
+9
View File
@@ -1463,6 +1463,15 @@ const BOX2I LIB_SYMBOL::GetBodyBoundingBox( int aUnit, int aBodyStyle, bool aInc
}
void LIB_SYMBOL::RefreshLibraryTreeCaches()
{
cacheSearchTerms();
cachePinCount();
cacheShownDescription();
cacheChooserFields();
}
void LIB_SYMBOL::deleteAllFields()
{
m_drawings[SCH_FIELD_T].clear();
+2
View File
@@ -850,6 +850,8 @@ public:
*/
double Similarity( const SCH_ITEM& aSymbol ) const override;
void RefreshLibraryTreeCaches();
void SetParentName( const wxString& aParentName ) { m_parentName = aParentName; }
const wxString& GetParentName() const { return m_parentName; }
+7 -8
View File
@@ -165,10 +165,10 @@ void SCH_EDIT_FRAME::doReCreateMenuBar()
ACTION_MENU* submenuAttributes = new ACTION_MENU( false, selTool );
submenuAttributes->SetTitle( _( "Attributes" ) );
submenuAttributes->Add( SCH_ACTIONS::setExcludeFromSimulation, ACTION_MENU::CHECK );
submenuAttributes->Add( SCH_ACTIONS::setExcludeFromBOM, ACTION_MENU::CHECK );
submenuAttributes->Add( SCH_ACTIONS::setExcludeFromBoard, ACTION_MENU::CHECK );
submenuAttributes->Add( SCH_ACTIONS::setDNP, ACTION_MENU::CHECK );
submenuAttributes->Add( SCH_ACTIONS::setExcludeFromSim, ACTION_MENU::CHECK );
submenuAttributes->Add( SCH_ACTIONS::setExcludeFromBOM, ACTION_MENU::CHECK );
submenuAttributes->Add( SCH_ACTIONS::setExcludeFromBoard, ACTION_MENU::CHECK );
submenuAttributes->Add( SCH_ACTIONS::setDNP, ACTION_MENU::CHECK );
editMenu->Add( submenuAttributes );
@@ -180,8 +180,8 @@ void SCH_EDIT_FRAME::doReCreateMenuBar()
ACTION_MENU* showHidePanels = new ACTION_MENU( false, selTool );
showHidePanels->SetTitle( _( "Panels" ) );
showHidePanels->Add( ACTIONS::showProperties, ACTION_MENU::CHECK );
showHidePanels->Add( ACTIONS::showSearch, ACTION_MENU::CHECK );
showHidePanels->Add( ACTIONS::showProperties, ACTION_MENU::CHECK );
showHidePanels->Add( ACTIONS::showSearch, ACTION_MENU::CHECK );
showHidePanels->Add( SCH_ACTIONS::showHierarchy, ACTION_MENU::CHECK );
if( ADVANCED_CFG::GetCfg().m_IncrementalConnectivity )
@@ -193,7 +193,7 @@ void SCH_EDIT_FRAME::doReCreateMenuBar()
if( m_remoteSymbolPane && !m_remoteSymbolPane->HasDataSources() )
{
remoteSymbolItem->Enable( false );
remoteSymbolItem->SetHelp( _( "Install a remote symbol server using the Plugin and Content Manager to enable" ) );
remoteSymbolItem->SetHelp( _( "Search signed-in remote symbol providers and download verified libraries." ) );
}
viewMenu->Add( showHidePanels );
@@ -364,4 +364,3 @@ void SCH_EDIT_FRAME::doReCreateMenuBar()
SetMenuBar( menuBar );
delete oldMenuBar;
}
+181
View File
@@ -0,0 +1,181 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright The 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 <remote_symbol_download_manager.h>
#include <curl/curl.h>
#include <kicad_curl/kicad_curl_easy.h>
#include <picosha2.h>
#include <remote_provider_utils.h>
#include <wx/intl.h>
namespace
{
bool validateAssetUrl( const REMOTE_PROVIDER_METADATA& aProvider, const wxString& aUrl,
wxString& aError )
{
if( !ValidateRemoteUrlSecurity( aUrl, aProvider.allow_insecure_localhost, aError,
_( "Remote asset URL" ) ) )
{
return false;
}
const wxString assetOrigin = NormalizedUrlOrigin( aUrl );
const wxString apiOrigin = NormalizedUrlOrigin( aProvider.api_base_url );
const wxString panelOrigin = NormalizedUrlOrigin( aProvider.panel_url );
const bool originAllowed =
( !apiOrigin.IsEmpty() && assetOrigin == apiOrigin )
|| ( !panelOrigin.IsEmpty() && assetOrigin == panelOrigin );
if( assetOrigin.IsEmpty() || !originAllowed )
{
aError = _( "Remote asset URL origin must match the selected provider." );
return false;
}
return true;
}
bool defaultFetchHandler( const wxString& aUrl, REMOTE_SYMBOL_FETCH_RESPONSE& aResponse, wxString& aError )
{
KICAD_CURL_EASY curl;
curl.SetUserAgent( "KiCad-RemoteProvider/1.0" );
curl.SetFollowRedirects( false );
curl.SetConnectTimeout( 10 );
if( !curl.SetURL( aUrl.ToStdString() ) )
{
aError = wxString::Format( _( "Unable to set download URL '%s'." ), aUrl );
return false;
}
const int result = curl.Perform();
if( result != CURLE_OK )
{
aError = wxString::FromUTF8( curl.GetErrorText( result ).c_str() );
return false;
}
aResponse.status_code = curl.GetResponseStatusCode();
char* contentType = nullptr;
curl_easy_getinfo( static_cast<CURL*>( curl.GetCurl() ), CURLINFO_CONTENT_TYPE, &contentType );
if( contentType )
aResponse.content_type = wxString::FromUTF8( contentType );
const std::string& buffer = curl.GetBuffer();
aResponse.payload.assign( buffer.begin(), buffer.end() );
return true;
}
wxString sha256Hex( const std::vector<uint8_t>& aPayload )
{
std::string hashHex;
picosha2::hash256_hex_string( aPayload.begin(), aPayload.end(), hashHex );
return wxString::FromUTF8( hashHex.c_str() );
}
} // namespace
REMOTE_SYMBOL_DOWNLOAD_MANAGER::REMOTE_SYMBOL_DOWNLOAD_MANAGER() :
m_handler( defaultFetchHandler )
{
}
REMOTE_SYMBOL_DOWNLOAD_MANAGER::REMOTE_SYMBOL_DOWNLOAD_MANAGER( FETCH_HANDLER aHandler ) :
m_handler( std::move( aHandler ) )
{
}
bool REMOTE_SYMBOL_DOWNLOAD_MANAGER::DownloadAndVerify( const REMOTE_PROVIDER_METADATA& aProvider,
const REMOTE_PROVIDER_PART_ASSET& aAsset,
long long aRemainingBudget,
REMOTE_SYMBOL_FETCHED_ASSET& aFetched,
wxString& aError ) const
{
aFetched = REMOTE_SYMBOL_FETCHED_ASSET();
aError.clear();
if( aAsset.size_bytes <= 0 )
{
aError = _( "Remote asset manifest declared an invalid size." );
return false;
}
if( aAsset.sha256.IsEmpty() )
{
aError = _( "Remote asset manifest must declare sha256 for URL-based downloads." );
return false;
}
if( !validateAssetUrl( aProvider, aAsset.download_url, aError ) )
return false;
if( aRemainingBudget >= 0 && aAsset.size_bytes > aRemainingBudget )
{
aError = _( "Remote asset exceeds the provider download limit." );
return false;
}
REMOTE_SYMBOL_FETCH_RESPONSE response;
if( !m_handler( aAsset.download_url, response, aError ) )
return false;
if( response.status_code < 200 || response.status_code >= 300 )
{
aError = wxString::Format( _( "Remote download failed with HTTP %d." ), response.status_code );
return false;
}
if( response.content_type != aAsset.content_type )
{
aError = _( "Remote asset content type did not match the manifest." );
return false;
}
if( static_cast<long long>( response.payload.size() ) != aAsset.size_bytes )
{
aError = _( "Remote asset size did not match the manifest." );
return false;
}
if( aRemainingBudget >= 0 && static_cast<long long>( response.payload.size() ) > aRemainingBudget )
{
aError = _( "Remote asset exceeds the remaining download limit." );
return false;
}
if( !aAsset.sha256.IsEmpty() && !sha256Hex( response.payload ).IsSameAs( aAsset.sha256, false ) )
{
aError = _( "Remote asset digest did not match the manifest." );
return false;
}
aFetched.content_type = response.content_type;
aFetched.payload = std::move( response.payload );
return true;
}
+63
View File
@@ -0,0 +1,63 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright The 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 REMOTE_SYMBOL_DOWNLOAD_MANAGER_H
#define REMOTE_SYMBOL_DOWNLOAD_MANAGER_H
#include <functional>
#include <vector>
#include <remote_provider_metadata.h>
#include <remote_provider_models.h>
#include <wx/string.h>
struct REMOTE_SYMBOL_FETCH_RESPONSE
{
int status_code = 0;
wxString content_type;
std::vector<uint8_t> payload;
};
struct REMOTE_SYMBOL_FETCHED_ASSET
{
wxString content_type;
std::vector<uint8_t> payload;
};
class REMOTE_SYMBOL_DOWNLOAD_MANAGER
{
public:
using FETCH_HANDLER =
std::function<bool( const wxString&, REMOTE_SYMBOL_FETCH_RESPONSE&, wxString& )>;
REMOTE_SYMBOL_DOWNLOAD_MANAGER();
explicit REMOTE_SYMBOL_DOWNLOAD_MANAGER( FETCH_HANDLER aHandler );
bool DownloadAndVerify( const REMOTE_PROVIDER_METADATA& aProvider,
const REMOTE_PROVIDER_PART_ASSET& aAsset, long long aRemainingBudget,
REMOTE_SYMBOL_FETCHED_ASSET& aFetched, wxString& aError ) const;
private:
FETCH_HANDLER m_handler;
};
#endif // REMOTE_SYMBOL_DOWNLOAD_MANAGER_H
+249
View File
@@ -0,0 +1,249 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright The 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 <remote_symbol_import_job.h>
#include "remote_symbol_import_utils.h"
#include <eeschema_settings.h>
#include <string_view>
#include <libraries/library_manager.h>
#include <pgm_base.h>
#include <remote_symbol_download_manager.h>
#include <settings/settings_manager.h>
#include <wx/intl.h>
namespace
{
bool validateSymbolPayload( const std::vector<uint8_t>& aPayload, const wxString& aExpectedSymbolName,
wxString& aError )
{
if( aExpectedSymbolName.IsEmpty() )
return true;
if( aPayload.empty() )
{
aError = _( "Downloaded symbol payload was empty." );
return false;
}
std::string_view payload( reinterpret_cast<const char*>( aPayload.data() ), aPayload.size() );
if( payload.find( "(kicad_symbol_lib" ) == std::string_view::npos )
{
aError = _( "Downloaded symbol payload was not a KiCad symbol library." );
return false;
}
const std::string symbolToken =
wxString::Format( wxS( "(symbol \"%s\"" ), aExpectedSymbolName ).ToStdString();
if( payload.find( symbolToken ) == std::string_view::npos )
{
aError = wxString::Format(
_( "Downloaded symbol payload did not include expected symbol '%s'." ),
aExpectedSymbolName );
return false;
}
return true;
}
} // namespace
REMOTE_SYMBOL_IMPORT_JOB::REMOTE_SYMBOL_IMPORT_JOB( SCH_EDIT_FRAME* aFrame,
REMOTE_SYMBOL_DOWNLOAD_MANAGER* aDownloader ) :
m_frame( aFrame ),
m_downloader( aDownloader )
{
if( !m_downloader )
{
m_ownedDownloader = std::make_unique<REMOTE_SYMBOL_DOWNLOAD_MANAGER>();
m_downloader = m_ownedDownloader.get();
}
}
bool REMOTE_SYMBOL_IMPORT_JOB::Import( const REMOTE_PROVIDER_METADATA& aProvider,
const REMOTE_SYMBOL_IMPORT_CONTEXT& aContext,
const REMOTE_PROVIDER_PART_MANIFEST& aManifest,
bool aPlaceSymbol, wxString& aError )
{
aError.clear();
EESCHEMA_SETTINGS* settings = GetAppSettings<EESCHEMA_SETTINGS>( "eeschema" );
if( !settings )
{
aError = _( "Unable to load schematic settings." );
return false;
}
wxFileName baseDir;
if( !EnsureRemoteDestinationRoot( baseDir, aError ) )
return false;
long long remainingBudget = aProvider.max_download_bytes;
const bool addToGlobal = settings->m_RemoteSymbol.add_to_global_table;
const bool strictLibraryTables = m_frame != nullptr;
const wxString prefix = RemoteLibraryPrefix();
bool importedSymbol = false;
wxString placedNickname;
wxString placedSymbolName;
for( const REMOTE_PROVIDER_PART_ASSET& asset : aManifest.assets )
{
REMOTE_SYMBOL_FETCHED_ASSET fetched;
if( !downloader().DownloadAndVerify( aProvider, asset, remainingBudget, fetched, aError ) )
return false;
remainingBudget -= asset.size_bytes;
if( asset.asset_type == wxS( "symbol" ) )
{
wxFileName symbolDir = baseDir;
symbolDir.AppendDir( wxS( "symbols" ) );
const wxString libraryName = SanitizeRemoteFileComponent(
asset.target_library.IsEmpty() ? aContext.library_name : asset.target_library,
wxS( "symbols" ), true );
const wxString symbolName =
asset.target_name.IsEmpty() ? aContext.symbol_name : asset.target_name;
const wxString nickname = prefix + wxS( "_" ) + libraryName;
wxFileName outFile( symbolDir );
outFile.SetFullName( nickname + wxS( ".kicad_sym" ) );
if( !validateSymbolPayload( fetched.payload, symbolName, aError ) )
return false;
if( !WriteRemoteBinaryFile( outFile, fetched.payload, aError ) )
return false;
if( strictLibraryTables )
{
if( !EnsureRemoteLibraryEntry( LIBRARY_TABLE_TYPE::SYMBOL, outFile, nickname,
addToGlobal, true, aError ) )
return false;
Pgm().GetLibraryManager().ReloadLibraryEntry(
LIBRARY_TABLE_TYPE::SYMBOL, nickname,
addToGlobal ? LIBRARY_TABLE_SCOPE::GLOBAL : LIBRARY_TABLE_SCOPE::PROJECT );
}
importedSymbol = true;
placedNickname = nickname;
placedSymbolName = symbolName;
}
else if( asset.asset_type == wxS( "footprint" ) )
{
wxFileName fpRoot = baseDir;
fpRoot.AppendDir( wxS( "footprints" ) );
const wxString libraryName = SanitizeRemoteFileComponent(
asset.target_library.IsEmpty() ? asset.name : asset.target_library,
wxS( "footprints" ), true );
const wxString nickname = prefix + wxS( "_" ) + libraryName;
wxFileName libDir = fpRoot;
libDir.AppendDir( nickname + wxS( ".pretty" ) );
wxString fileName = SanitizeRemoteFileComponent(
asset.target_name.IsEmpty() ? asset.name : asset.target_name,
wxS( "footprint" ) );
if( !fileName.Lower().EndsWith( wxS( ".kicad_mod" ) ) )
fileName += wxS( ".kicad_mod" );
wxFileName outFile( libDir );
outFile.SetFullName( fileName );
if( !WriteRemoteBinaryFile( outFile, fetched.payload, aError ) )
return false;
if( strictLibraryTables )
{
if( !EnsureRemoteLibraryEntry( LIBRARY_TABLE_TYPE::FOOTPRINT, libDir, nickname,
addToGlobal, true, aError ) )
return false;
Pgm().GetLibraryManager().ReloadLibraryEntry(
LIBRARY_TABLE_TYPE::FOOTPRINT, nickname,
addToGlobal ? LIBRARY_TABLE_SCOPE::GLOBAL : LIBRARY_TABLE_SCOPE::PROJECT );
}
}
else if( asset.asset_type == wxS( "3dmodel" ) )
{
wxFileName modelDir = baseDir;
modelDir.AppendDir( prefix + wxS( "_3d" ) );
wxString fileName = SanitizeRemoteFileComponent(
asset.target_name.IsEmpty() ? asset.name : asset.target_name,
prefix + wxS( "_model" ) );
wxFileName outFile( modelDir );
outFile.SetFullName( fileName );
if( !WriteRemoteBinaryFile( outFile, fetched.payload, aError ) )
return false;
}
else if( asset.asset_type == wxS( "spice" ) )
{
wxFileName spiceDir = baseDir;
spiceDir.AppendDir( prefix + wxS( "_spice" ) );
wxString fileName = SanitizeRemoteFileComponent(
asset.target_name.IsEmpty() ? asset.name : asset.target_name,
prefix + wxS( "_model.cir" ) );
if( !fileName.Lower().EndsWith( wxS( ".cir" ) ) )
fileName += wxS( ".cir" );
wxFileName outFile( spiceDir );
outFile.SetFullName( fileName );
if( !WriteRemoteBinaryFile( outFile, fetched.payload, aError ) )
return false;
}
}
if( aPlaceSymbol )
{
if( !importedSymbol )
{
aError = _( "No symbol asset was available to place." );
return false;
}
if( !PlaceRemoteDownloadedSymbol( m_frame, placedNickname, placedSymbolName, aError ) )
return false;
}
return true;
}
const REMOTE_SYMBOL_DOWNLOAD_MANAGER& REMOTE_SYMBOL_IMPORT_JOB::downloader() const
{
return *m_downloader;
}
+57
View File
@@ -0,0 +1,57 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright The 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 REMOTE_SYMBOL_IMPORT_JOB_H
#define REMOTE_SYMBOL_IMPORT_JOB_H
#include <memory>
#include <remote_provider_metadata.h>
#include <remote_provider_models.h>
#include <remote_symbol_download_manager.h>
class SCH_EDIT_FRAME;
struct REMOTE_SYMBOL_IMPORT_CONTEXT
{
wxString symbol_name;
wxString library_name;
};
class REMOTE_SYMBOL_IMPORT_JOB
{
public:
explicit REMOTE_SYMBOL_IMPORT_JOB( SCH_EDIT_FRAME* aFrame,
REMOTE_SYMBOL_DOWNLOAD_MANAGER* aDownloader = nullptr );
bool Import( const REMOTE_PROVIDER_METADATA& aProvider, const REMOTE_SYMBOL_IMPORT_CONTEXT& aContext,
const REMOTE_PROVIDER_PART_MANIFEST& aManifest, bool aPlaceSymbol, wxString& aError );
private:
const REMOTE_SYMBOL_DOWNLOAD_MANAGER& downloader() const;
private:
SCH_EDIT_FRAME* m_frame;
REMOTE_SYMBOL_DOWNLOAD_MANAGER* m_downloader;
std::unique_ptr<REMOTE_SYMBOL_DOWNLOAD_MANAGER> m_ownedDownloader;
};
#endif // REMOTE_SYMBOL_IMPORT_JOB_H
+245
View File
@@ -0,0 +1,245 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright The 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 "remote_symbol_import_utils.h"
#include <common.h>
#include <eeschema_settings.h>
#include <lib_symbol.h>
#include <libraries/library_manager.h>
#include <pgm_base.h>
#include <remote_provider_settings.h>
#include <sch_edit_frame.h>
#include <sch_symbol.h>
#include <settings/settings_manager.h>
#include <tool/tool_manager.h>
#include <tools/sch_actions.h>
#include <wx/ffile.h>
#include <wx/filefn.h>
#include <wx/intl.h>
wxString SanitizeRemoteFileComponent( const wxString& aValue, const wxString& aDefault, bool aLower )
{
wxString result = aValue;
result.Trim( true ).Trim( false );
if( result.IsEmpty() )
result = aDefault;
for( size_t i = 0; i < result.length(); ++i )
{
const wxUniChar ch = result[i];
if( !( wxIsalnum( ch ) || ch == '_' || ch == '-' || ch == '.' ) )
result[i] = '_';
}
return aLower ? result.Lower() : result;
}
wxString RemoteLibraryPrefix()
{
EESCHEMA_SETTINGS* settings = GetAppSettings<EESCHEMA_SETTINGS>( "eeschema" );
wxString prefix = settings ? settings->m_RemoteSymbol.library_prefix : wxString();
if( prefix.IsEmpty() )
prefix = REMOTE_PROVIDER_SETTINGS::DefaultLibraryPrefix();
return SanitizeRemoteFileComponent( prefix, wxS( "remote" ), true );
}
bool WriteRemoteBinaryFile( const wxFileName& aOutput, const std::vector<uint8_t>& aPayload,
wxString& aError )
{
if( aPayload.empty() )
{
aError = _( "Payload was empty." );
return false;
}
wxFileName targetDir = aOutput;
targetDir.SetFullName( wxEmptyString );
if( !targetDir.DirExists() && !targetDir.Mkdir( wxS_DIR_DEFAULT, wxPATH_MKDIR_FULL ) )
{
aError = wxString::Format( _( "Unable to create '%s'." ), targetDir.GetFullPath() );
return false;
}
wxFFile file( aOutput.GetFullPath(), wxS( "wb" ) );
if( !file.IsOpened() )
{
aError = wxString::Format( _( "Unable to open '%s' for writing." ), aOutput.GetFullPath() );
return false;
}
if( file.Write( aPayload.data(), aPayload.size() ) != aPayload.size() )
{
aError = wxString::Format( _( "Failed to write '%s'." ), aOutput.GetFullPath() );
return false;
}
file.Close();
return true;
}
bool EnsureRemoteDestinationRoot( wxFileName& aOutDir, wxString& aError )
{
EESCHEMA_SETTINGS* settings = GetAppSettings<EESCHEMA_SETTINGS>( "eeschema" );
if( !settings )
{
aError = _( "Unable to load schematic settings." );
return false;
}
wxString destination = settings->m_RemoteSymbol.destination_dir;
if( destination.IsEmpty() )
destination = REMOTE_PROVIDER_SETTINGS::DefaultDestinationDir();
destination = ExpandEnvVarSubstitutions( destination, &Pgm().GetSettingsManager().Prj() );
destination.Trim( true ).Trim( false );
if( destination.IsEmpty() )
{
aError = _( "Destination directory is not configured." );
return false;
}
wxFileName dir = wxFileName::DirName( destination );
dir.Normalize( FN_NORMALIZE_FLAGS );
if( !dir.DirExists() && !dir.Mkdir( wxS_DIR_DEFAULT, wxPATH_MKDIR_FULL ) )
{
aError = wxString::Format( _( "Unable to create directory '%s'." ), dir.GetFullPath() );
return false;
}
aOutDir = dir;
return true;
}
bool EnsureRemoteLibraryEntry( LIBRARY_TABLE_TYPE aTableType, const wxFileName& aLibraryPath,
const wxString& aNickname, bool aGlobalTable, bool aStrict,
wxString& aError )
{
LIBRARY_MANAGER& manager = Pgm().GetLibraryManager();
std::optional<LIBRARY_TABLE*> tableOpt = manager.Table(
aTableType,
aGlobalTable ? LIBRARY_TABLE_SCOPE::GLOBAL : LIBRARY_TABLE_SCOPE::PROJECT );
if( !tableOpt )
{
if( aStrict )
aError = _( "Unable to access the library table." );
return !aStrict;
}
LIBRARY_TABLE* table = *tableOpt;
const wxString fullPath = aLibraryPath.GetFullPath();
if( table->HasRow( aNickname ) )
{
if( std::optional<LIBRARY_TABLE_ROW*> rowOpt = table->Row( aNickname ); rowOpt )
{
LIBRARY_TABLE_ROW* row = *rowOpt;
if( row->URI() != fullPath )
{
row->SetURI( fullPath );
if( !table->Save() )
{
aError = _( "Failed to update the library table." );
return false;
}
}
}
return true;
}
LIBRARY_TABLE_ROW& row = table->InsertRow();
row.SetNickname( aNickname );
row.SetURI( fullPath );
row.SetType( wxS( "KiCad" ) );
row.SetOptions( wxString() );
row.SetDescription( _( "Remote download" ) );
row.SetOk( true );
if( !table->Save() )
{
aError = _( "Failed to save the library table." );
return false;
}
return true;
}
bool PlaceRemoteDownloadedSymbol( SCH_EDIT_FRAME* aFrame, const wxString& aNickname,
const wxString& aLibItemName, wxString& aError )
{
if( !aFrame )
{
aError = _( "No schematic editor is available for placement." );
return false;
}
LIB_ID libId;
libId.SetLibNickname( aNickname );
libId.SetLibItemName( aLibItemName );
LIB_SYMBOL* libSymbol = aFrame->GetLibSymbol( libId );
if( !libSymbol )
{
aError = _( "Unable to load the downloaded symbol for placement." );
return false;
}
SCH_SYMBOL* symbol = new SCH_SYMBOL( *libSymbol, libId, &aFrame->GetCurrentSheet(), 1 );
symbol->SetParent( aFrame->GetScreen() );
if( EESCHEMA_SETTINGS* cfg = aFrame->eeconfig(); cfg && cfg->m_AutoplaceFields.enable )
symbol->AutoplaceFields( nullptr, AUTOPLACE_AUTO );
TOOL_MANAGER* toolMgr = aFrame->GetToolManager();
if( !toolMgr )
{
delete symbol;
aError = _( "Unable to access the schematic placement tools." );
return false;
}
aFrame->Raise();
toolMgr->PostAction( SCH_ACTIONS::placeSymbol,
SCH_ACTIONS::PLACE_SYMBOL_PARAMS{ symbol, true } );
return true;
}
+72
View File
@@ -0,0 +1,72 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright The 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 REMOTE_SYMBOL_IMPORT_UTILS_H
#define REMOTE_SYMBOL_IMPORT_UTILS_H
#include <cstdint>
#include <vector>
#include <wx/filename.h>
#include <wx/string.h>
class SCH_EDIT_FRAME;
enum class LIBRARY_TABLE_TYPE;
/**
* Replace non-alphanumeric characters (other than _ - .) with underscores.
* Returns \a aDefault when \a aValue is empty after trimming.
*/
wxString SanitizeRemoteFileComponent( const wxString& aValue, const wxString& aDefault,
bool aLower = false );
/**
* Return the configured (or default) library prefix for remote downloads,
* sanitized for use as a filename component.
*/
wxString RemoteLibraryPrefix();
/**
* Write binary data to a file, creating parent directories as needed.
*/
bool WriteRemoteBinaryFile( const wxFileName& aOutput, const std::vector<uint8_t>& aPayload,
wxString& aError );
/**
* Resolve and create the configured destination root directory for remote
* symbol downloads.
*/
bool EnsureRemoteDestinationRoot( wxFileName& aOutDir, wxString& aError );
/**
* Add or update a library table entry for a remote download library.
* When \a aStrict is false, a missing library table is not treated as an error.
*/
bool EnsureRemoteLibraryEntry( LIBRARY_TABLE_TYPE aTableType, const wxFileName& aLibraryPath,
const wxString& aNickname, bool aGlobalTable, bool aStrict,
wxString& aError );
/**
* Place a symbol from a remote download into the schematic editor.
*/
bool PlaceRemoteDownloadedSymbol( SCH_EDIT_FRAME* aFrame, const wxString& aNickname,
const wxString& aLibItemName, wxString& aError );
#endif // REMOTE_SYMBOL_IMPORT_UTILS_H
+15 -2
View File
@@ -368,7 +368,9 @@ SCH_EDIT_FRAME::SCH_EDIT_FRAME( KIWAY* aKiway, wxWindow* aParent ) :
SetAuiPaneSize( m_auimgr, designBlocksPane, aui_cfg.design_blocks_panel_docked_width, -1 );
if( aui_cfg.remote_symbol_show )
{
SetAuiPaneSize( m_auimgr, remoteSymbolPane, aui_cfg.remote_symbol_panel_docked_width, -1 );
}
if( aui_cfg.hierarchy_panel_docked_width > 0 )
{
@@ -412,6 +414,14 @@ SCH_EDIT_FRAME::SCH_EDIT_FRAME( KIWAY* aKiway, wxWindow* aParent ) :
m_auimgr.Update();
}
CallAfter( [this]()
{
wxAuiPaneInfo& remotePane = m_auimgr.GetPane( RemoteSymbolPaneName() );
if( remotePane.IsShown() && m_remoteSymbolPane )
m_remoteSymbolPane->Activate();
} );
resolveCanvasType();
SwitchCanvas( m_canvasType );
@@ -1471,9 +1481,9 @@ void SCH_EDIT_FRAME::ProjectChanged()
// Register schematic saver for autosave history
Kiway().LocalHistory().RegisterSaver( m_schematic,
[this]( const wxString& aProjectPath, std::vector<wxString>& aFiles )
[this]( const wxString& aProjectPath, std::vector<HISTORY_FILE_DATA>& aFileData )
{
m_schematic->SaveToHistory( aProjectPath, aFiles );
m_schematic->SaveToHistory( aProjectPath, aFileData );
} );
m_designBlocksPane->ProjectChanged();
@@ -2954,6 +2964,9 @@ void SCH_EDIT_FRAME::ToggleRemoteSymbolPanel()
if( remotePane.IsShown() )
{
if( m_remoteSymbolPane )
m_remoteSymbolPane->Activate();
if( remotePane.IsFloating() )
{
remotePane.FloatingSize( cfg->m_AuiPanels.remote_symbol_panel_float_width,
+26 -40
View File
@@ -56,7 +56,6 @@ SCH_FIELD::SCH_FIELD() :
m_isGeneratedField( false ),
m_autoAdded( false ),
m_showInChooser( true ),
m_renderCacheValid( false ),
m_lastResolvedColor( COLOR4D::UNSPECIFIED )
{
}
@@ -116,21 +115,9 @@ SCH_FIELD::SCH_FIELD( const SCH_FIELD& aField ) :
m_isGeneratedField = aField.m_isGeneratedField;
m_autoAdded = aField.m_autoAdded;
m_showInChooser = aField.m_showInChooser;
m_renderCache.clear();
for( const std::unique_ptr<KIFONT::GLYPH>& glyph : aField.m_renderCache )
{
if( KIFONT::OUTLINE_GLYPH* outline = dynamic_cast<KIFONT::OUTLINE_GLYPH*>( glyph.get() ) )
m_renderCache.emplace_back( std::make_unique<KIFONT::OUTLINE_GLYPH>( *outline ) );
else if( KIFONT::STROKE_GLYPH* stroke = dynamic_cast<KIFONT::STROKE_GLYPH*>( glyph.get() ) )
m_renderCache.emplace_back( std::make_unique<KIFONT::STROKE_GLYPH>( *stroke ) );
}
m_renderCacheValid = aField.m_renderCacheValid;
m_renderCachePos = aField.m_renderCachePos;
m_lastResolvedColor = aField.m_lastResolvedColor;
m_renderCache.reset();
}
@@ -145,22 +132,10 @@ SCH_FIELD& SCH_FIELD::operator=( const SCH_FIELD& aField )
m_showName = aField.m_showName;
m_allowAutoPlace = aField.m_allowAutoPlace;
m_isGeneratedField = aField.m_isGeneratedField;
m_renderCache.clear();
for( const std::unique_ptr<KIFONT::GLYPH>& glyph : aField.m_renderCache )
{
if( KIFONT::OUTLINE_GLYPH* outline = dynamic_cast<KIFONT::OUTLINE_GLYPH*>( glyph.get() ) )
m_renderCache.emplace_back( std::make_unique<KIFONT::OUTLINE_GLYPH>( *outline ) );
else if( KIFONT::STROKE_GLYPH* stroke = dynamic_cast<KIFONT::STROKE_GLYPH*>( glyph.get() ) )
m_renderCache.emplace_back( std::make_unique<KIFONT::STROKE_GLYPH>( *stroke ) );
}
m_renderCacheValid = aField.m_renderCacheValid;
m_renderCachePos = aField.m_renderCachePos;
m_lastResolvedColor = aField.m_lastResolvedColor;
m_renderCache.reset();
return *this;
}
@@ -226,7 +201,9 @@ wxString SCH_FIELD::GetShownText( bool aAllowExtraText, int aDepth ) const
return GetShownText( &currentSheet, aAllowExtraText, aDepth, variantName );
}
else
{
return GetShownText( nullptr, aAllowExtraText, aDepth );
}
}
@@ -272,7 +249,7 @@ void SCH_FIELD::ClearCaches()
void SCH_FIELD::ClearRenderCache()
{
EDA_TEXT::ClearRenderCache();
m_renderCacheValid = false;
m_renderCache.reset();
}
@@ -285,21 +262,24 @@ SCH_FIELD::GetRenderCache( const wxString& forResolvedText, const VECTOR2I& forP
{
KIFONT::OUTLINE_FONT* outlineFont = static_cast<KIFONT::OUTLINE_FONT*>( font );
if( m_renderCache.empty() || !m_renderCacheValid )
if( !m_renderCache )
m_renderCache = std::make_unique<SCH_FIELD_RENDER_CACHE_DATA>();
if( m_renderCache->glyphs.empty() )
{
m_renderCache.clear();
m_renderCache->glyphs.clear();
outlineFont->GetLinesAsGlyphs( &m_renderCache, forResolvedText, forPosition, aAttrs, GetFontMetrics() );
outlineFont->GetLinesAsGlyphs( &m_renderCache->glyphs, forResolvedText, forPosition, aAttrs,
GetFontMetrics() );
m_renderCachePos = forPosition;
m_renderCacheValid = true;
m_renderCache->pos = forPosition;
}
if( m_renderCachePos != forPosition )
if( m_renderCache->pos != forPosition )
{
VECTOR2I delta = forPosition - m_renderCachePos;
VECTOR2I delta = forPosition - m_renderCache->pos;
for( std::unique_ptr<KIFONT::GLYPH>& glyph : m_renderCache )
for( std::unique_ptr<KIFONT::GLYPH>& glyph : m_renderCache->glyphs )
{
if( glyph->IsOutline() )
static_cast<KIFONT::OUTLINE_GLYPH*>( glyph.get() )->Move( delta );
@@ -307,10 +287,10 @@ SCH_FIELD::GetRenderCache( const wxString& forResolvedText, const VECTOR2I& forP
static_cast<KIFONT::STROKE_GLYPH*>( glyph.get() )->Move( delta );
}
m_renderCachePos = forPosition;
m_renderCache->pos = forPosition;
}
return &m_renderCache;
return &m_renderCache->glyphs;
}
return nullptr;
@@ -1297,6 +1277,12 @@ void SCH_FIELD::Plot( PLOTTER* aPlotter, bool aBackground, const SCH_PLOT_OPTS&
vjustify = GR_TEXT_V_ALIGN_CENTER;
textpos = GetBoundingBox().Centre();
}
else if( m_parent && m_parent->Type() == LIB_SYMBOL_T )
{
// Library-symbol exports (CLI/symbol editor) provide an item offset in the same coordinate
// frame as body graphics/pins. Apply the same transform+offset pipeline to field text.
textpos = renderSettings->TransformCoordinate( textpos ) + aOffset;
}
else if( m_parent && m_parent->Type() == SCH_GLOBAL_LABEL_T )
{
SCH_GLOBALLABEL* label = static_cast<SCH_GLOBALLABEL*>( m_parent );
+8 -3
View File
@@ -38,6 +38,13 @@ class SCH_EDIT_FRAME;
class SCH_TEXT;
struct SCH_FIELD_RENDER_CACHE_DATA
{
VECTOR2I pos;
std::vector<std::unique_ptr<KIFONT::GLYPH>> glyphs;
};
class SCH_FIELD : public SCH_ITEM, public EDA_TEXT
{
public:
@@ -343,9 +350,7 @@ private:
bool m_autoAdded; ///< Was this field automatically added to a LIB_SYMBOL?
bool m_showInChooser; ///< This field is available as a data column for the chooser
mutable bool m_renderCacheValid;
mutable VECTOR2I m_renderCachePos;
mutable std::vector<std::unique_ptr<KIFONT::GLYPH>> m_renderCache;
mutable std::unique_ptr<SCH_FIELD_RENDER_CACHE_DATA> m_renderCache;
mutable COLOR4D m_lastResolvedColor;
};
+2 -1
View File
@@ -134,4 +134,5 @@
//#define SEXPR_SCHEMATIC_FILE_VERSION 20250922 // Schematic variants.
//#define SEXPR_SCHEMATIC_FILE_VERSION 20251012 // Flat schematic hierarchy support
//#define SEXPR_SCHEMATIC_FILE_VERSION 20251028 // Updated properties formatting (do_not_autoplace, show_name)
#define SEXPR_SCHEMATIC_FILE_VERSION 20260101 // PCB variants
//#define SEXPR_SCHEMATIC_FILE_VERSION 20260101 // PCB variants
#define SEXPR_SCHEMATIC_FILE_VERSION 20260306 // Variant in_bom semantics corrected
+104
View File
@@ -29,6 +29,7 @@
#include <io/altium/altium_binary_parser.h>
#include <io/altium/altium_ascii_parser.h>
#include <io/altium/altium_parser_utils.h>
#include <io/altium/altium_project_variants.h>
#include <sch_io/altium/sch_io_altium.h>
#include <progress_reporter.h>
@@ -639,6 +640,106 @@ SCH_SHEET* SCH_IO_ALTIUM::LoadSchematicFile( const wxString& aFileName, SCHEMATI
allSheets.UpdateSymbolLinks( &LOAD_INFO_REPORTER::GetInstance() ); // Update all symbol library links for all sheets.
allSheets.ClearEditFlags();
// Apply Altium project variants to schematic symbols
if( aProperties && aProperties->count( "project_file" ) )
{
auto variants = ParseAltiumProjectVariants( aProperties->at( "project_file" ) );
if( !variants.empty() )
{
// Build lookups keyed by both UniqueId and designator. UniqueId is preferred
// because repeated-channel designs can have multiple components sharing a
// designator but with distinct UniqueIds.
using ENTRY_LIST =
std::vector<std::pair<wxString, const ALTIUM_VARIANT_ENTRY*>>;
std::map<wxString, ENTRY_LIST> variantsByUid;
std::map<wxString, ENTRY_LIST> variantsByDesignator;
for( const ALTIUM_PROJECT_VARIANT& pv : variants )
{
m_schematic->AddVariant( pv.name );
if( !pv.description.empty() && pv.description != pv.name )
m_schematic->SetVariantDescription( pv.name, pv.description );
for( const ALTIUM_VARIANT_ENTRY& entry : pv.variations )
{
if( !entry.uniqueId.empty() )
variantsByUid[entry.uniqueId].push_back( { pv.name, &entry } );
variantsByDesignator[entry.designator].push_back( { pv.name, &entry } );
}
}
SCH_SHEET_LIST sheetList( m_rootSheet );
for( const SCH_SHEET_PATH& path : sheetList )
{
SCH_SCREEN* screen = path.LastScreen();
if( !screen )
continue;
for( SCH_ITEM* item : screen->Items().OfType( SCH_SYMBOL_T ) )
{
SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
const ENTRY_LIST* entries = nullptr;
auto symUidIt = m_altiumSymbolToUid.find( symbol );
if( symUidIt != m_altiumSymbolToUid.end() )
{
auto varIt = variantsByUid.find( symUidIt->second );
if( varIt != variantsByUid.end() )
entries = &varIt->second;
}
if( !entries )
{
wxString ref = symbol->GetRef( &path );
auto varIt = variantsByDesignator.find( ref );
if( varIt != variantsByDesignator.end() )
entries = &varIt->second;
}
if( !entries )
continue;
for( const auto& [variantName, entry] : *entries )
{
SCH_SYMBOL_VARIANT variant( variantName );
variant.InitializeAttributes( *symbol );
if( entry->kind == 1 )
{
variant.m_DNP = true;
variant.m_ExcludedFromBOM = true;
variant.m_ExcludedFromPosFiles = true;
}
else if( entry->kind == 0 )
{
for( const auto& [key, value] : entry->alternateFields )
{
if( key.CmpNoCase( wxS( "LibReference" ) ) == 0 )
variant.m_Fields[wxS( "Value" )] = value;
else if( key.CmpNoCase( wxS( "Description" ) ) == 0 )
variant.m_Fields[wxS( "Description" )] = value;
else if( key.CmpNoCase( wxS( "Footprint" ) ) == 0 )
variant.m_Fields[wxS( "Footprint" )] = value;
}
}
symbol->AddVariant( path, variant );
}
}
}
}
}
// Set up the default netclass wire & bus width based on imported wires & buses.
//
@@ -1730,6 +1831,9 @@ void SCH_IO_ALTIUM::ParseComponent( int aIndex, const std::map<wxString, wxStrin
screen->Append( symbol );
m_symbols.insert( { aIndex, symbol } );
if( !elem.uniqueid.empty() )
m_altiumSymbolToUid[symbol] = elem.uniqueid;
}
+3
View File
@@ -260,6 +260,9 @@ private:
// List of available fonts with font name and font size in pt
std::vector<std::pair<wxString, int>> m_fonts;
// Persists across sheets so variant application can match by Altium UniqueId
std::map<const SCH_SYMBOL*, wxString> m_altiumSymbolToUid;
// Cache the error messages to avoid duplicate messages
std::unordered_map<wxString, SEVERITY > m_errorMessages;
};
@@ -88,6 +88,9 @@ SCH_IO_KICAD_SEXPR::~SCH_IO_KICAD_SEXPR()
void SCH_IO_KICAD_SEXPR::init( SCHEMATIC* aSchematic,
const std::map<std::string, UTF8>* aProperties )
{
if( m_schematic != aSchematic )
m_loadedRootSheets.clear();
m_version = 0;
m_appending = false;
m_rootSheet = nullptr;
@@ -160,6 +163,7 @@ SCH_SHEET* SCH_IO_KICAD_SEXPR::LoadSchematicFile( const wxString& aFileName, SCH
// If we got here, the schematic loaded successfully.
sheet = newSheet.release();
m_rootSheet = nullptr; // Quiet Coverity warning.
m_loadedRootSheets.push_back( sheet );
}
else
{
@@ -231,6 +235,17 @@ void SCH_IO_KICAD_SEXPR::loadHierarchy( const SCH_SHEET_PATH& aParentSheetPath,
// load path so we have to check both.
if( !m_rootSheet->SearchHierarchy( fileName.GetFullPath(), &screen ) )
m_currentSheetPath.at( 0 )->SearchHierarchy( fileName.GetFullPath(), &screen );
// When loading multiple top-level sheets that reference the same sub-sheet file,
// the screen may have already been loaded by a previous top-level sheet.
if( !screen )
{
for( SCH_SHEET* prevRoot : m_loadedRootSheets )
{
if( prevRoot->SearchHierarchy( fileName.GetFullPath(), &screen ) )
break;
}
}
}
if( screen )
@@ -352,8 +367,6 @@ void SCH_IO_KICAD_SEXPR::SaveSchematicFile( const wxString& aFileName, SCH_SHEET
}
}
init( aSchematic, aProperties );
wxFileName fn = aFileName;
// File names should be absolute. Don't assume everything relative to the project path
@@ -361,16 +374,29 @@ void SCH_IO_KICAD_SEXPR::SaveSchematicFile( const wxString& aFileName, SCH_SHEET
wxASSERT( fn.IsAbsolute() );
PRETTIFIED_FILE_OUTPUTFORMATTER formatter( fn.GetFullPath() );
m_out = &formatter; // no ownership
Format( aSheet );
FormatSchematicToFormatter( &formatter, aSheet, aSchematic, aProperties );
if( aSheet->GetScreen() )
aSheet->GetScreen()->SetFileExists( true );
}
void SCH_IO_KICAD_SEXPR::FormatSchematicToFormatter( OUTPUTFORMATTER* aOut, SCH_SHEET* aSheet,
SCHEMATIC* aSchematic,
const std::map<std::string, UTF8>* aProperties )
{
wxCHECK_RET( aSheet != nullptr, "NULL SCH_SHEET object." );
init( aSchematic, aProperties );
m_out = aOut;
Format( aSheet );
m_out = nullptr;
}
void SCH_IO_KICAD_SEXPR::Format( SCH_SHEET* aSheet )
{
wxCHECK_RET( aSheet != nullptr, "NULL SCH_SHEET* object." );
@@ -927,7 +953,7 @@ void SCH_IO_KICAD_SEXPR::saveSymbol( SCH_SYMBOL* aSymbol, const SCHEMATIC& aSche
KICAD_FORMAT::FormatBool( m_out, "exclude_from_sim", variant.m_ExcludedFromSim );
if( variant.m_ExcludedFromBOM != aSymbol->GetExcludedFromBOM() )
KICAD_FORMAT::FormatBool( m_out, "in_bom", variant.m_ExcludedFromBOM );
KICAD_FORMAT::FormatBool( m_out, "in_bom", !variant.m_ExcludedFromBOM );
if( variant.m_ExcludedFromBoard != aSymbol->GetExcludedFromBoard() )
KICAD_FORMAT::FormatBool( m_out, "on_board", !variant.m_ExcludedFromBoard );
@@ -1180,7 +1206,7 @@ void SCH_IO_KICAD_SEXPR::saveSheet( SCH_SHEET* aSheet, const SCH_SHEET_LIST& aSh
KICAD_FORMAT::FormatBool( m_out, "exclude_from_sim", variant.m_ExcludedFromSim );
if( variant.m_ExcludedFromBOM != aSheet->GetExcludedFromBOM() )
KICAD_FORMAT::FormatBool( m_out, "in_bom", variant.m_ExcludedFromBOM );
KICAD_FORMAT::FormatBool( m_out, "in_bom", !variant.m_ExcludedFromBOM );
for( const auto&[fname, fvalue] : variant.m_Fields )
{
@@ -1654,7 +1680,7 @@ void SCH_IO_KICAD_SEXPR::cacheLib( const wxString& aLibraryFileName,
delete m_cache;
m_cache = new SCH_IO_KICAD_SEXPR_LIB_CACHE( aLibraryFileName );
if( !isBuffering( aProperties ) || isNewCache )
if( !isBuffering( aProperties ) || ( isNewCache && m_cache->isLibraryPathValid() ) )
{
m_cache->Load();
m_cache->m_modHash = oldModifyHash + 1;
@@ -102,6 +102,13 @@ public:
void SaveSchematicFile( const wxString& aFileName, SCH_SHEET* aSheet, SCHEMATIC* aSchematic,
const std::map<std::string, UTF8>* aProperties = nullptr ) override;
/** Serialize a schematic sheet to an OUTPUTFORMATTER without file I/O or Prettify.
* Handles init() and Format().
* Skips GroupsSanityCheck and SetFileExists side effects. */
void FormatSchematicToFormatter( OUTPUTFORMATTER* aOut, SCH_SHEET* aSheet,
SCHEMATIC* aSchematic,
const std::map<std::string, UTF8>* aProperties = nullptr );
void Format( SCH_SHEET* aSheet );
void Format( SCH_SELECTION* aSelection, SCH_SHEET_PATH* aSelectionPath,
@@ -174,6 +181,9 @@ protected:
wxString m_path; ///< Root project path for loading child sheets.
std::stack<wxString> m_currentPath; ///< Stack to maintain nested sheet paths
SCH_SHEET* m_rootSheet; ///< The root sheet of the schematic being loaded.
std::vector<SCH_SHEET*> m_loadedRootSheets; ///< Root sheets from previous LoadSchematicFile()
///< calls, enabling screen reuse across top-level
///< sheets that share sub-sheet files.
SCH_SHEET_PATH m_currentSheetPath;
SCHEMATIC* m_schematic;
OUTPUTFORMATTER* m_out; ///< The formatter for saving SCH_SCREEN objects.
@@ -645,6 +645,8 @@ LIB_SYMBOL* SCH_IO_KICAD_SEXPR_PARSER::parseLibSymbol( LIB_SYMBOL_MAP& aSymbolLi
if( m_requiredVersion < 20250827 )
symbol->SetHasDeMorganBodyStyles( symbol->HasLegacyAlternateBodyStyle() );
symbol->RefreshLibraryTreeCaches();
return symbol.release();
}
@@ -3380,6 +3382,7 @@ SCH_SYMBOL* SCH_IO_KICAD_SEXPR_PARSER::parseSchematicSymbol()
case T_variant:
{
SCH_SYMBOL_VARIANT variant;
variant.InitializeAttributes( *symbol );
for( token = NextTok(); token != T_RIGHT; token = NextTok() )
{
@@ -3408,6 +3411,13 @@ SCH_SYMBOL* SCH_IO_KICAD_SEXPR_PARSER::parseSchematicSymbol()
case T_in_bom:
variant.m_ExcludedFromBOM = parseBool();
// This fixes the incorrect logic from prior file versions. The "in_bom" token
// used in the file format is the positive logic. However, in the UI the term
// excluded from BOM is used which is the inverted logic.
if( m_requiredVersion >= 20260306 )
variant.m_ExcludedFromBOM = !variant.m_ExcludedFromBOM;
NeedRIGHT();
break;
@@ -3843,6 +3853,7 @@ SCH_SHEET* SCH_IO_KICAD_SEXPR_PARSER::parseSheet()
case T_variant:
{
SCH_SHEET_VARIANT variant;
variant.InitializeAttributes( *sheet );
for( token = NextTok(); token != T_RIGHT; token = NextTok() )
{
@@ -3871,6 +3882,13 @@ SCH_SHEET* SCH_IO_KICAD_SEXPR_PARSER::parseSheet()
case T_in_bom:
variant.m_ExcludedFromBOM = parseBool();
// This fixes the incorrect logic from prior file versions. The "in_bom" token
// used in the file format is the positive logic. However, in the UI the term
// excluded from BOM is used which is the inverted logic.
if( m_requiredVersion >= 20260306 )
variant.m_ExcludedFromBOM = !variant.m_ExcludedFromBOM;
NeedRIGHT();
break;
+24 -4
View File
@@ -794,6 +794,8 @@ bool SCH_LABEL_BASE::ResolveTextVar( const SCH_SHEET_PATH* aPath, wxString* toke
if( !schematic )
return false;
wxString variant = schematic->GetCurrentVariant();
if( operatingPoint.Matches( *token ) )
{
int precision = 3;
@@ -865,7 +867,7 @@ bool SCH_LABEL_BASE::ResolveTextVar( const SCH_SHEET_PATH* aPath, wxString* toke
for( SCH_RULE_AREA* ruleArea : directive->GetConnectedRuleAreas() )
{
if( ruleArea->GetExcludedFromBOM() )
if( ruleArea->GetExcludedFromBOM( aPath, variant ) )
*token = _( "Excluded from BOM" );
}
@@ -878,7 +880,7 @@ bool SCH_LABEL_BASE::ResolveTextVar( const SCH_SHEET_PATH* aPath, wxString* toke
for( SCH_RULE_AREA* ruleArea : directive->GetConnectedRuleAreas() )
{
if( ruleArea->GetExcludedFromBoard() )
if( ruleArea->GetExcludedFromBoard( aPath, variant ) )
*token = _( "Excluded from board" );
}
@@ -891,7 +893,7 @@ bool SCH_LABEL_BASE::ResolveTextVar( const SCH_SHEET_PATH* aPath, wxString* toke
for( SCH_RULE_AREA* ruleArea : directive->GetConnectedRuleAreas() )
{
if( ruleArea->GetExcludedFromSim() )
if( ruleArea->GetExcludedFromSim( aPath, variant ) )
*token = _( "Excluded from simulation" );
}
@@ -904,7 +906,7 @@ bool SCH_LABEL_BASE::ResolveTextVar( const SCH_SHEET_PATH* aPath, wxString* toke
for( SCH_RULE_AREA* ruleArea : directive->GetConnectedRuleAreas() )
{
if( ruleArea->GetDNP() )
if( ruleArea->GetDNP( aPath, variant ) )
*token = _( "DNP" );
}
@@ -1967,6 +1969,24 @@ bool SCH_DIRECTIVE_LABEL::IsDangling() const
return m_isDangling && m_connected_rule_areas.empty();
}
bool SCH_DIRECTIVE_LABEL::IncrementLabel( int aIncrement )
{
for( SCH_FIELD& field : m_fields )
{
if( field.GetCanonicalName() == wxT( "Netclass" ) || field.GetCanonicalName() == wxT( "Component Class" ) )
{
wxString text = field.GetText();
if( IncrementString( text, aIncrement ) )
{
field.SetText( text );
}
}
}
return true;
}
SCH_GLOBALLABEL::SCH_GLOBALLABEL( const VECTOR2I& pos, const wxString& text ) :
SCH_LABEL_BASE( pos, text, SCH_GLOBAL_LABEL_T )
+4 -1
View File
@@ -237,7 +237,7 @@ public:
*
* @param aIncrement = the increment value to add to the number ending the text.
*/
bool IncrementLabel( int aIncrement );
virtual bool IncrementLabel( int aIncrement );
void Move( const VECTOR2I& aMoveVector ) override;
void Rotate( const VECTOR2I& aCenter, bool aRotateCCW ) override;
@@ -516,6 +516,9 @@ public:
/// @brief Determines dangling state from connectivity and cached connected rule areas
virtual bool IsDangling() const override;
/// Increment the netclass and component class labels if possible
bool IncrementLabel( int aIncrement ) override;
private:
int m_pinLength;
int m_symbolSize;
+3 -4
View File
@@ -2704,8 +2704,8 @@ void SCH_PAINTER::draw( const SCH_SYMBOL* aSymbol, int aLayer )
int bodyStyle = aSymbol->GetBodyStyle();
// Use dummy symbol if the actual couldn't be found (or couldn't be locked).
LIB_SYMBOL* originalSymbol =
aSymbol->GetLibSymbolRef() ? aSymbol->GetLibSymbolRef().get() : LIB_SYMBOL::GetDummy();
LIB_SYMBOL* originalSymbol = aSymbol->GetLibSymbolRef() ? aSymbol->GetLibSymbolRef().get()
: LIB_SYMBOL::GetDummy();
std::vector<SCH_PIN*> originalPins = originalSymbol->GetGraphicalPins( unit, bodyStyle );
// Copy the source so we can re-orient and translate it.
@@ -2796,8 +2796,7 @@ void SCH_PAINTER::draw( const SCH_SYMBOL* aSymbol, int aLayer )
BOX2I bbox = aSymbol->GetBodyBoundingBox();
BOX2I pins = aSymbol->GetBodyAndPinsBoundingBox();
VECTOR2D margins( std::max( bbox.GetX() - pins.GetX(), pins.GetEnd().x - bbox.GetEnd().x ),
std::max( bbox.GetY() - pins.GetY(),
pins.GetEnd().y - bbox.GetEnd().y ) );
std::max( bbox.GetY() - pins.GetY(), pins.GetEnd().y - bbox.GetEnd().y ) );
int strokeWidth = 3 * schIUScale.MilsToIU( DEFAULT_LINE_WIDTH_MILS );
margins.x = std::max( margins.x * 0.6, margins.y * 0.3 );
+31 -17
View File
@@ -128,8 +128,7 @@ SCH_PIN::SCH_PIN( LIB_SYMBOL* aParentSymbol ) :
m_hidden( false ),
m_numTextSize( schIUScale.MilsToIU( DEFAULT_PINNUM_SIZE ) ),
m_nameTextSize( schIUScale.MilsToIU( DEFAULT_PINNAME_SIZE ) ),
m_isDangling( true ),
m_layoutCache( std::make_unique<PIN_LAYOUT_CACHE>( *this ) )
m_isDangling( true )
{
if( SYMBOL_EDITOR_SETTINGS* cfg = GetAppSettings<SYMBOL_EDITOR_SETTINGS>( "symbol_editor" ) )
{
@@ -156,8 +155,7 @@ SCH_PIN::SCH_PIN( LIB_SYMBOL* aParentSymbol, const wxString& aName, const wxStri
m_hidden( false ),
m_numTextSize( aNumTextSize ),
m_nameTextSize( aNameTextSize ),
m_isDangling( true ),
m_layoutCache( std::make_unique<PIN_LAYOUT_CACHE>( *this ) )
m_isDangling( true )
{
SetName( aName );
SetNumber( aNumber );
@@ -172,8 +170,7 @@ SCH_PIN::SCH_PIN( SCH_SYMBOL* aParentSymbol, SCH_PIN* aLibPin ) :
m_orientation( PIN_ORIENTATION::INHERIT ),
m_shape( GRAPHIC_PINSHAPE::INHERIT ),
m_type( ELECTRICAL_PINTYPE::PT_INHERIT ),
m_isDangling( true ),
m_layoutCache( std::make_unique<PIN_LAYOUT_CACHE>( *this ) )
m_isDangling( true )
{
wxASSERT( aParentSymbol );
@@ -194,8 +191,7 @@ SCH_PIN::SCH_PIN( SCH_SYMBOL* aParentSymbol, const wxString& aNumber, const wxSt
m_type( ELECTRICAL_PINTYPE::PT_INHERIT ),
m_number( aNumber ),
m_alt( aAlt ),
m_isDangling( true ),
m_layoutCache( std::make_unique<PIN_LAYOUT_CACHE>( *this ) )
m_isDangling( true )
{
wxASSERT( aParentSymbol );
@@ -217,8 +213,7 @@ SCH_PIN::SCH_PIN( const SCH_PIN& aPin ) :
m_numTextSize( aPin.m_numTextSize ),
m_nameTextSize( aPin.m_nameTextSize ),
m_alt( aPin.m_alt ),
m_isDangling( aPin.m_isDangling ),
m_layoutCache( std::make_unique<PIN_LAYOUT_CACHE>( *this ) )
m_isDangling( aPin.m_isDangling )
{
SetName( aPin.m_name );
SetNumber( aPin.m_number );
@@ -250,6 +245,7 @@ SCH_PIN& SCH_PIN::operator=( const SCH_PIN& aPin )
m_numTextSize = aPin.m_numTextSize;
m_nameTextSize = aPin.m_nameTextSize;
m_isDangling = aPin.m_isDangling;
m_layoutCache.reset();
return *this;
}
@@ -338,7 +334,9 @@ void SCH_PIN::SetType( ELECTRICAL_PINTYPE aType )
return;
m_type = aType;
m_layoutCache->MarkDirty( PIN_LAYOUT_CACHE::DIRTY_FLAGS::ELEC_TYPE );
if( m_layoutCache )
m_layoutCache->MarkDirty( PIN_LAYOUT_CACHE::DIRTY_FLAGS::ELEC_TYPE );
}
@@ -430,7 +428,8 @@ void SCH_PIN::SetName( const wxString& aName )
// pin name string does not support spaces
m_name.Replace( wxT( " " ), wxT( "_" ) );
m_layoutCache->MarkDirty( PIN_LAYOUT_CACHE::DIRTY_FLAGS::NAME );
if( m_layoutCache )
m_layoutCache->MarkDirty( PIN_LAYOUT_CACHE::DIRTY_FLAGS::NAME );
}
@@ -650,7 +649,8 @@ void SCH_PIN::SetNumber( const wxString& aNumber )
// pin number string does not support spaces
m_number.Replace( wxT( " " ), wxT( "_" ) );
m_layoutCache->MarkDirty( PIN_LAYOUT_CACHE::DIRTY_FLAGS::NUMBER );
if( m_layoutCache )
m_layoutCache->MarkDirty( PIN_LAYOUT_CACHE::DIRTY_FLAGS::NUMBER );
}
@@ -674,7 +674,9 @@ void SCH_PIN::SetNameTextSize( int aSize )
return;
m_nameTextSize = aSize;
m_layoutCache->MarkDirty( PIN_LAYOUT_CACHE::DIRTY_FLAGS::NAME );
if( m_layoutCache )
m_layoutCache->MarkDirty( PIN_LAYOUT_CACHE::DIRTY_FLAGS::NAME );
}
@@ -698,7 +700,9 @@ void SCH_PIN::SetNumberTextSize( int aSize )
return;
m_numTextSize = aSize;
m_layoutCache->MarkDirty( PIN_LAYOUT_CACHE::DIRTY_FLAGS::NUMBER );
if( m_layoutCache )
m_layoutCache->MarkDirty( PIN_LAYOUT_CACHE::DIRTY_FLAGS::NUMBER );
}
@@ -1576,8 +1580,18 @@ BOX2I SCH_PIN::GetBoundingBox( bool aIncludeLabelsOnInvisiblePins, bool aInclude
bool aIncludeElectricalType ) const
{
// Just defer to the cache
return m_layoutCache->GetPinBoundingBox( aIncludeLabelsOnInvisiblePins, aIncludeNameAndNumber,
aIncludeElectricalType );
return GetLayoutCache().GetPinBoundingBox( aIncludeLabelsOnInvisiblePins,
aIncludeNameAndNumber,
aIncludeElectricalType );
}
PIN_LAYOUT_CACHE& SCH_PIN::GetLayoutCache() const
{
if( !m_layoutCache )
m_layoutCache = std::make_unique<PIN_LAYOUT_CACHE>( *this );
return *m_layoutCache;
}
+1 -1
View File
@@ -348,7 +348,7 @@ public:
* laid out than just the bounding box, you can use this. The SCH_PAINTER,
* for example, can use this to avoid having to duplicate text extent calcs.
*/
PIN_LAYOUT_CACHE& GetLayoutCache() const { return *m_layoutCache; }
PIN_LAYOUT_CACHE& GetLayoutCache() const;
protected:
wxString getItemDescription( ALT* aAlt ) const;
+28 -23
View File
@@ -259,12 +259,14 @@ void SCH_PLOTTER::plotOneSheetPDF( PLOTTER* aPlotter, SCH_SCREEN* aScreen,
wxString sheetPath = m_schematic->CurrentSheet().PathHumanReadable();
const PAGE_INFO& actualPage = aScreen->GetPageSettings(); // page size selected in schematic
PlotDrawingSheet( aPlotter, &aScreen->Schematic()->Project(),
aScreen->GetTitleBlock(),
actualPage,
aScreen->Schematic()->GetProperties(),
SCHEMATIC* sch = aScreen->Schematic();
wxString variantName = sch->GetCurrentVariant();
wxString variantDesc = sch->GetVariantDescription( variantName );
PlotDrawingSheet( aPlotter, &sch->Project(), aScreen->GetTitleBlock(), actualPage, sch->GetProperties(),
aScreen->GetPageNumber(), aScreen->GetPageCount(), sheetName, sheetPath,
aScreen->GetFileName(), color, aScreen->GetVirtualPageNumber() == 1 );
aScreen->GetFileName(), color, aScreen->GetVirtualPageNumber() == 1, variantName,
variantDesc );
}
aScreen->Plot( aPlotter, aPlotOpts );
@@ -471,12 +473,14 @@ bool SCH_PLOTTER::plotOneSheetPS( const wxString& aFileName, SCH_SCREEN* aScreen
wxString sheetPath = m_schematic->CurrentSheet().PathHumanReadable();
COLOR4D color = plotter->RenderSettings()->GetLayerColor( LAYER_SCHEMATIC_DRAWINGSHEET );
PlotDrawingSheet( plotter, &aScreen->Schematic()->Project(),
aScreen->GetTitleBlock(),
aPageInfo, aScreen->Schematic()->GetProperties(),
SCHEMATIC* sch = aScreen->Schematic();
wxString variantName = sch->GetCurrentVariant();
wxString variantDesc = sch->GetVariantDescription( variantName );
PlotDrawingSheet( plotter, &sch->Project(), aScreen->GetTitleBlock(), aPageInfo, sch->GetProperties(),
aScreen->GetPageNumber(), aScreen->GetPageCount(), sheetName, sheetPath,
aScreen->GetFileName(), plotter->GetColorMode() ? color : COLOR4D::BLACK,
aScreen->GetVirtualPageNumber() == 1 );
aScreen->GetVirtualPageNumber() == 1, variantName, variantDesc );
}
aScreen->Plot( plotter, aPlotOpts );
@@ -648,13 +652,14 @@ bool SCH_PLOTTER::plotOneSheetSVG( const wxString& aFileName, SCH_SCREEN* aScree
wxString sheetPath = m_schematic->CurrentSheet().PathHumanReadable();
COLOR4D color = plotter->RenderSettings()->GetLayerColor( LAYER_SCHEMATIC_DRAWINGSHEET );
PlotDrawingSheet( plotter, &aScreen->Schematic()->Project(),
aScreen->GetTitleBlock(),
actualPage, aScreen->Schematic()->GetProperties(),
aScreen->GetPageNumber(),
aScreen->GetPageCount(), sheetName, sheetPath, aScreen->GetFileName(),
plotter->GetColorMode() ? color : COLOR4D::BLACK,
aScreen->GetVirtualPageNumber() == 1 );
SCHEMATIC* sch = aScreen->Schematic();
wxString variantName = sch->GetCurrentVariant();
wxString variantDesc = sch->GetVariantDescription( variantName );
PlotDrawingSheet( plotter, &sch->Project(), aScreen->GetTitleBlock(), actualPage, sch->GetProperties(),
aScreen->GetPageNumber(), aScreen->GetPageCount(), sheetName, sheetPath,
aScreen->GetFileName(), plotter->GetColorMode() ? color : COLOR4D::BLACK,
aScreen->GetVirtualPageNumber() == 1, variantName, variantDesc );
}
aScreen->Plot( plotter, aPlotOpts );
@@ -796,13 +801,13 @@ bool SCH_PLOTTER::plotOneSheetDXF( const wxString& aFileName, SCH_SCREEN* aScree
wxString sheetPath = m_schematic->CurrentSheet().PathHumanReadable();
COLOR4D color = plotter->RenderSettings()->GetLayerColor( LAYER_SCHEMATIC_DRAWINGSHEET );
PlotDrawingSheet( plotter, &m_schematic->Project(),
aScreen->GetTitleBlock(),
pageInfo,
aScreen->Schematic()->GetProperties(), aScreen->GetPageNumber(),
aScreen->GetPageCount(), sheetName, sheetPath, aScreen->GetFileName(),
plotter->GetColorMode() ? color : COLOR4D::BLACK,
aScreen->GetVirtualPageNumber() == 1 );
wxString variantName = m_schematic->GetCurrentVariant();
wxString variantDesc = m_schematic->GetVariantDescription( variantName );
PlotDrawingSheet( plotter, &m_schematic->Project(), aScreen->GetTitleBlock(), pageInfo,
m_schematic->GetProperties(), aScreen->GetPageNumber(), aScreen->GetPageCount(), sheetName,
sheetPath, aScreen->GetFileName(), plotter->GetColorMode() ? color : COLOR4D::BLACK,
aScreen->GetVirtualPageNumber() == 1, variantName, variantDesc );
}
aScreen->Plot( plotter, aPlotOpts );
+1 -1
View File
@@ -131,7 +131,7 @@ void SCH_RULE_AREA::Plot( PLOTTER* aPlotter, bool aBackground, const SCH_PLOT_OP
ptList.clear();
const std::vector<VECTOR2I>& polyPoints = m_poly.Outline( 0 ).CPoints();
const std::vector<VECTOR2I>& polyPoints = GetPolyShape().Outline( 0 ).CPoints();
for( const VECTOR2I& pt : polyPoints )
ptList.push_back( pt );
+6 -6
View File
@@ -214,7 +214,7 @@ void SCH_SHAPE::Plot( PLOTTER* aPlotter, bool aBackground, const SCH_PLOT_OPTS&
{
ptList.clear();
for( const VECTOR2I& pt : m_poly.Outline( 0 ).CPoints() )
for( const VECTOR2I& pt : GetPolyShape().Outline( 0 ).CPoints() )
ptList.push_back( renderSettings->TransformCoordinate( pt ) + aOffset );
}
else if( GetShape() == SHAPE_T::BEZIER )
@@ -399,7 +399,7 @@ wxString SCH_SHAPE::GetItemDescription( UNITS_PROVIDER* aUnitsProvider, bool aFu
case SHAPE_T::POLY:
return wxString::Format( _( "Polyline, %d points" ),
int( m_poly.Outline( 0 ).GetPointCount() ) );
int( GetPolyShape().Outline( 0 ).GetPointCount() ) );
case SHAPE_T::BEZIER:
return wxString::Format( _( "Bezier Curve, %d points" ),
@@ -458,13 +458,13 @@ void SCH_SHAPE::AddPoint( const VECTOR2I& aPosition )
{
if( GetShape() == SHAPE_T::POLY )
{
if( m_poly.IsEmpty() )
if( GetPolyShape().IsEmpty() )
{
m_poly.NewOutline();
m_poly.Outline( 0 ).SetClosed( false );
GetPolyShape().NewOutline();
GetPolyShape().Outline( 0 ).SetClosed( false );
}
m_poly.Outline( 0 ).Append( aPosition, true );
GetPolyShape().Outline( 0 ).Append( aPosition, true );
}
else
{
+11 -14
View File
@@ -44,7 +44,6 @@
#include <sch_symbol.h>
#include <sch_painter.h>
#include <schematic.h>
#include <settings/color_settings.h>
#include <settings/settings_manager.h>
#include <trace_helpers.h>
#include <validators.h>
@@ -259,6 +258,7 @@ bool SCH_SHEET::ResolveTextVar( const SCH_SHEET_PATH* aPath, wxString* token, in
}
PROJECT* project = &schematic->Project();
wxString variant = schematic->GetCurrentVariant();
// We cannot resolve text variables initially on load as we need to first load the screen and
// then parse the hierarchy. So skip the resolution if the screen isn't set yet
@@ -286,7 +286,7 @@ bool SCH_SHEET::ResolveTextVar( const SCH_SHEET_PATH* aPath, wxString* token, in
{
*token = wxEmptyString;
if( aPath->GetExcludedFromBOM() || this->ResolveExcludedFromBOM() )
if( aPath->GetExcludedFromBOM( variant ) || this->ResolveExcludedFromBOM( aPath, variant ) )
*token = _( "Excluded from BOM" );
return true;
@@ -295,7 +295,7 @@ bool SCH_SHEET::ResolveTextVar( const SCH_SHEET_PATH* aPath, wxString* token, in
{
*token = wxEmptyString;
if( aPath->GetExcludedFromBoard() || this->ResolveExcludedFromBoard() )
if( aPath->GetExcludedFromBoard( variant ) || this->ResolveExcludedFromBoard( aPath, variant ) )
*token = _( "Excluded from board" );
return true;
@@ -304,7 +304,7 @@ bool SCH_SHEET::ResolveTextVar( const SCH_SHEET_PATH* aPath, wxString* token, in
{
*token = wxEmptyString;
if( aPath->GetExcludedFromSim() || this->ResolveExcludedFromSim() )
if( aPath->GetExcludedFromSim( variant ) || this->ResolveExcludedFromSim( aPath, variant ) )
*token = _( "Excluded from simulation" );
return true;
@@ -313,7 +313,7 @@ bool SCH_SHEET::ResolveTextVar( const SCH_SHEET_PATH* aPath, wxString* token, in
{
*token = wxEmptyString;
if( aPath->GetDNP() || this->ResolveDNP() )
if( aPath->GetDNP( variant ) || this->ResolveDNP( aPath, variant ) )
*token = _( "DNP" );
return true;
@@ -1450,20 +1450,17 @@ void SCH_SHEET::Plot( PLOTTER* aPlotter, bool aBackground, const SCH_PLOT_OPTS&
if( GetDNP( &instance, variantName) )
{
COLOR_SETTINGS* colors = ::GetColorSettings( DEFAULT_THEME );
BOX2I bbox = GetBodyBoundingBox();
BOX2I pins = GetBoundingBox();
VECTOR2D margins( std::max( bbox.GetX() - pins.GetX(),
pins.GetEnd().x - bbox.GetEnd().x ),
std::max( bbox.GetY() - pins.GetY(),
pins.GetEnd().y - bbox.GetEnd().y ) );
int strokeWidth = 3.0 * schIUScale.MilsToIU( DEFAULT_LINE_WIDTH_MILS );
BOX2I bbox = GetBodyBoundingBox();
BOX2I pins = GetBoundingBox();
VECTOR2D margins( std::max( bbox.GetX() - pins.GetX(), pins.GetEnd().x - bbox.GetEnd().x ),
std::max( bbox.GetY() - pins.GetY(), pins.GetEnd().y - bbox.GetEnd().y ) );
int strokeWidth = 3.0 * schIUScale.MilsToIU( DEFAULT_LINE_WIDTH_MILS );
margins.x = std::max( margins.x * 0.6, margins.y * 0.3 );
margins.y = std::max( margins.y * 0.6, margins.x * 0.3 );
bbox.Inflate( KiROUND( margins.x ), KiROUND( margins.y ) );
aPlotter->SetColor( colors->GetColor( LAYER_DNP_MARKER ) );
aPlotter->SetColor( renderSettings->GetLayerColor( LAYER_DNP_MARKER ) );
aPlotter->ThickSegment( bbox.GetOrigin(), bbox.GetEnd(), strokeWidth, nullptr );
+28 -8
View File
@@ -309,9 +309,14 @@ bool SCH_SHEET_PATH::GetExcludedFromSim( const wxString& aVariantName ) const
if( aVariantName.IsEmpty() )
return GetExcludedFromSim();
for( SCH_SHEET* sheet : m_sheets )
SCH_SHEET_PATH copy = *this;
while( !copy.empty() )
{
if( sheet->GetExcludedFromSim( this, aVariantName ) )
SCH_SHEET* sheet = copy.Last();
copy.pop_back();
if( sheet->GetExcludedFromSim( &copy, aVariantName ) )
return true;
}
@@ -336,9 +341,14 @@ bool SCH_SHEET_PATH::GetExcludedFromBOM( const wxString& aVariantName ) const
if( aVariantName.IsEmpty() )
return GetExcludedFromBOM();
for( SCH_SHEET* sheet : m_sheets )
SCH_SHEET_PATH copy = *this;
while( !copy.empty() )
{
if( sheet->GetExcludedFromBOM( this, aVariantName ) )
SCH_SHEET* sheet = copy.Last();
copy.pop_back();
if( sheet->GetExcludedFromBOM( &copy, aVariantName ) )
return true;
}
@@ -363,9 +373,14 @@ bool SCH_SHEET_PATH::GetExcludedFromBoard( const wxString& aVariantName ) const
if( aVariantName.IsEmpty() )
return GetExcludedFromBoard();
for( SCH_SHEET* sheet : m_sheets )
SCH_SHEET_PATH copy = *this;
while( !copy.empty() )
{
if( sheet->GetExcludedFromBoard( this, aVariantName ) )
SCH_SHEET* sheet = copy.Last();
copy.pop_back();
if( sheet->GetExcludedFromBoard( &copy, aVariantName ) )
return true;
}
@@ -390,9 +405,14 @@ bool SCH_SHEET_PATH::GetDNP( const wxString& aVariantName ) const
if( aVariantName.IsEmpty() )
return GetDNP();
for( SCH_SHEET* sheet : m_sheets )
SCH_SHEET_PATH copy = *this;
while( !copy.empty() )
{
if( sheet->GetDNP( this, aVariantName ) )
SCH_SHEET* sheet = copy.Last();
copy.pop_back();
if( sheet->GetDNP( &copy, aVariantName ) )
return true;
}

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