Compare commits

...

344 Commits

Author SHA1 Message Date
Fabien Corona
872d2e9724 Merge branch 'ibisUpdate2024' into 'master'
Ibis version update

See merge request kicad/code/kicad!2177
2025-09-11 14:25:13 +00:00
jean-pierre charras
45166bf5c3 Gerbview: fix broken behavior for deprecated command IPPOS and IPNEG
Fixes https://gitlab.com/kicad/code/kicad/-/issues/21715
2025-09-11 14:30:50 +02:00
Jeff Young
6ab6283e2e LIBEVAL::CONTEXT manages its own local VALUEs.
Don't use std::unique_ptr as we'll just free the
value right after storing it.

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

Fixes https://gitlab.com/kicad/code/kicad/-/issues/21697
2025-09-11 12:49:41 +01:00
Seth Hillbrand
fc7d91214d Make pasting in lib tables easier
You generally copy/paste whole rows in lib tables, so make this workflow
easier.  Allows pasting rows as new data.  Prevent overwriting existing
data and don't force pasting from the first column
2025-09-11 02:30:49 -07:00
Seth Hillbrand
dcbadb5857 Allow drag-drop for schematic elements
Dragging screen elements over a subsheet allows moving elements into a
subsheet
2025-09-11 02:16:47 -07:00
jean-pierre charras
3b97804cb6 DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR: add missing layers to always allowed list 2025-09-11 11:07:16 +02:00
Mark Roszko
e72def55a9 Remove moronic pybind forcing expectation of python release builds 2025-09-11 07:16:52 +00:00
Seth Hillbrand
fcf40deae2 Scale down icons that are too big
In template view, if the icon is too big, try to fit to our size
2025-09-10 21:58:02 -07:00
Seth Hillbrand
ef602be91f Allow drawing subsheet with click+drag
Interestingly, the majority of people in a KiCad training course wanted
to draw subsheets this way.  There is no real reason to keep the
existing select behavior, so this greases some skids
2025-09-10 21:55:31 -07:00
Seth Hillbrand
bd5cb76fcd Sync pin shape between sheet/hier labels 2025-09-10 21:47:09 -07:00
Seth Hillbrand
de26550b5a Add stubs for compiling 2025-09-10 21:23:37 -07:00
Seth Hillbrand
7deff606be Update Pybind11 to 3.0.1 2025-09-10 13:02:24 -07:00
Seth Hillbrand
6e2b20ed0e Update BS Threadpool to 5.0 2025-09-10 13:02:24 -07:00
Jeff Young
2f1a91279f Make sure DRC inspection dialogs come up in front
of DRC dialog.
2025-09-10 17:52:09 +01:00
Jeff Young
6e316d9faa ADDED: menu items to control cross-probing from ERC
dialog.

Fixes https://gitlab.com/kicad/code/kicad/-/issues/17916
2025-09-10 17:52:09 +01:00
Jeff Young
3c5fb9d90d CHANGED: progressive disclosure in DRC dialog.
CHANGED: moved Report All Track Errors to config menu.

ADDED: menu items to control cross-probing from DRC
dialog.

Fixes https://gitlab.com/kicad/code/kicad/-/issues/17916
2025-09-10 17:52:09 +01:00
jean-pierre charras
11cc86e586 Hotkey handling: disable usage of keyboard modifier flag wxMOD_ALTGR.
The flag wxMOD_ALTGR is defined in wxWidgets as wxMOD_CONTROL|wxMOD_ALT
So AltGr key cannot used as modifier key because it is the same as
Alt key + Ctrl key that is already handled.
So the previous code did not work with modifiers Alt key, Ctrl key and Altgr key

Fixes https://gitlab.com/kicad/code/kicad/-/issues/21696
2025-09-10 18:10:43 +02:00
Roberto Fernandez Bautista
5e2fd084b9 Disable vcpkg compiler tracking 2025-09-10 09:48:50 +00:00
Seth Hillbrand
a1f816e8be Add additional modifies to hotkeys
Allows (depending on system) AltGr, Meta, Win, Super in combination with
other keys

Fixes https://gitlab.com/kicad/code/kicad/issues/1908
2025-09-09 13:30:01 -07:00
Seth Hillbrand
abf3438ed6 Remove noise from orthographic projection raytracing
We generally add some jitter to the raytracing lines in order to smooth
out over multiple iterations some of the imperfections.  However, when
we do this to an orthographic projection (where all lines are parallel
to start, we don't average and just introduce noticeable noise in the
render

Fixes https://gitlab.com/kicad/code/kicad/issues/8863
2025-09-09 13:16:57 -07:00
Seth Hillbrand
cb4c8e6647 Make global delete tracks remove tuning patterns
If we are removing the generated item, we should remove the generator as
well

Fixes https://gitlab.com/kicad/code/kicad/issues/21572
2025-09-09 13:06:52 -07:00
Seth Hillbrand
d356073798 ADDED: synthetic parameters for graphics
Allows editing start/end/radius instead of underlying properties

Fixes https://gitlab.com/kicad/code/kicad/issues/16279
2025-09-09 12:58:43 -07:00
Mark Roszko
b38d9d7f81 Edit Windows-CI.yml, remove after_script 2025-09-09 15:47:03 +00:00
Mark Roszko
297ca1bb7b Fix windows builds with a temporary hackfix for now 2025-09-09 11:12:39 -04:00
Seth Hillbrand
f9e25c2e06 ADDED: Cross-probing from 3d-viewer
Send cross-probe messages to pcb and schematic editors to highlight
objects when clicked in the 3d viewer
2025-09-09 07:50:51 -07:00
Seth Hillbrand
b0a6dc4acf Use actual value for symbol chooser options
When we moved to the single element, the pointer always resolved to
true, which was sometimes not what we wanted
2025-09-09 07:16:28 -07:00
Seth Hillbrand
59dcdb4a4f ADDED: proper icons for datasheet and fp in props
The properties panel needs to look like the data fields for user
experience.  In wx3.3 we get a helpful action button but until then, we
need to make our own
2025-09-09 07:12:27 -07:00
jean-pierre charras
39889f8446 fix a compil issue. 2025-09-09 15:41:28 +02:00
Seth Hillbrand
3f8abe3744 Update properties to show units
The function duplicated our built-in funcitonality and did not properly
handly outputs

Fixes https://gitlab.com/kicad/code/kicad/issues/21685
2025-09-09 06:39:39 -07:00
Seth Hillbrand
0acc659676 Try to fix MSW build error 2025-09-09 06:15:30 -07:00
Jeff Young
78c93ee0fb Clear stale local ratsnest flags when performing undo/redo.
Also removes some dangerous C-style casts.

Fixes https://gitlab.com/kicad/code/kicad/-/issues/17894
2025-09-09 14:09:19 +01:00
jean-pierre charras
9622cf8ff1 SCH_BITMAP, SCH_TABLE: add missing HitTest(SHAPE_LINE_CHAIN& aPoly, ...)
Fixes https://gitlab.com/kicad/code/kicad/-/issues/21669
2025-09-09 09:45:46 +02:00
jean-pierre charras
3cca1e87d8 French translation update 2025-09-09 09:45:46 +02:00
Seth Hillbrand
aac15f4596 Encapsulate libgit commands into single backend
Sets stage for allowing alternate backends for version control
2025-09-08 21:04:31 -07:00
Seth Hillbrand
ceed9ca5f8 ADDED: Place missing units
Adds a contextual menu for symbols that will look for units that are not
currently instantiated and offer to place them
2025-09-08 16:38:49 -07:00
Alex Shvartzkop
6c4edd178e Update translations 2025-09-09 01:19:11 +03:00
dsa-t
cfa87cfc2c
Translated using Weblate (Hungarian)
Currently translated at 34.7% (3659 of 10519 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/hu/
2025-09-09 00:18:30 +02:00
CloverGit
b3b75270ce
Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 97.4% (10247 of 10519 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/zh_Hans/
2025-09-09 00:16:20 +02:00
KB
f1db857804
Translated using Weblate (Hungarian)
Currently translated at 34.7% (3658 of 10519 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/hu/
2025-09-09 00:16:20 +02:00
Frank Sonnenberg
cdd43fe5fa
Translated using Weblate (German)
Currently translated at 99.9% (10518 of 10519 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/de/
2025-09-09 00:16:20 +02:00
Frank Sonnenberg
836b3267bb
Translated using Weblate (German)
Currently translated at 99.9% (10518 of 10519 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/de/
2025-09-09 00:16:20 +02:00
Nguyễn Ngọc Khánh
66930ea703
Translated using Weblate (Vietnamese)
Currently translated at 21.7% (2284 of 10519 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/vi/
2025-09-09 00:16:20 +02:00
ZbeeGin
0e60722c4b
Translated using Weblate (Polish)
Currently translated at 97.9% (10305 of 10519 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/pl/
2025-09-09 00:16:20 +02:00
Frank Sonnenberg
2b3f21b9ff
Translated using Weblate (German)
Currently translated at 99.9% (10518 of 10519 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/de/
2025-09-09 00:16:20 +02:00
ssantos
dd8a059925
Translated using Weblate (Portuguese)
Currently translated at 93.6% (9851 of 10519 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/pt/
2025-09-09 00:16:20 +02:00
Frank Sonnenberg
63fe36847e
Translated using Weblate (German)
Currently translated at 99.9% (10518 of 10519 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/de/
2025-09-09 00:16:19 +02:00
CloverGit
99a16e4306
Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 97.4% (10247 of 10519 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/zh_Hans/
2025-09-09 00:16:19 +02:00
Frank Sonnenberg
5ca8fdb7cd
Translated using Weblate (German)
Currently translated at 99.9% (10518 of 10519 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/de/
2025-09-09 00:16:19 +02:00
Frank Sonnenberg
88ee07e910
Translated using Weblate (German)
Currently translated at 99.9% (10518 of 10519 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/de/
2025-09-09 00:16:19 +02:00
Pferd O
71907f0888
Translated using Weblate (German)
Currently translated at 99.9% (10517 of 10519 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/de/
2025-09-09 00:16:19 +02:00
Frank Sonnenberg
6397b6d3c6
Translated using Weblate (German)
Currently translated at 99.9% (10517 of 10519 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/de/
2025-09-09 00:16:19 +02:00
Hesham Eina Abdalla
d1356140fa
Translated using Weblate (Arabic)
Currently translated at 1.0% (115 of 10519 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ar/
2025-09-09 00:16:19 +02:00
Frank Sonnenberg
30d158a60f
Translated using Weblate (German)
Currently translated at 100.0% (10519 of 10519 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/de/
2025-09-09 00:16:19 +02:00
Ivan Chuba
c674e1749e
Translated using Weblate (Estonian)
Currently translated at 3.3% (350 of 10519 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/et/
2025-09-09 00:16:19 +02:00
Frank Sonnenberg
c783218f93
Translated using Weblate (German)
Currently translated at 99.9% (10518 of 10519 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/de/
2025-09-09 00:16:19 +02:00
Frank Sonnenberg
07885145b3
Translated using Weblate (German)
Currently translated at 99.9% (10518 of 10519 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/de/
2025-09-09 00:16:18 +02:00
Frank Sonnenberg
500da3c15d
Translated using Weblate (German)
Currently translated at 99.9% (10518 of 10519 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/de/
2025-09-09 00:16:18 +02:00
Frank Sonnenberg
fbd2e36b79
Translated using Weblate (German)
Currently translated at 99.9% (10518 of 10519 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/de/
2025-09-09 00:16:18 +02:00
Frank Sonnenberg
61fd5e7413
Translated using Weblate (German)
Currently translated at 99.9% (10518 of 10519 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/de/
2025-09-09 00:16:18 +02:00
Frank Sonnenberg
bf8d2d7bf6
Translated using Weblate (German)
Currently translated at 99.9% (10518 of 10519 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/de/
2025-09-09 00:16:18 +02:00
Pferd O
2a93e1bfb1
Translated using Weblate (German)
Currently translated at 99.9% (10518 of 10519 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/de/
2025-09-09 00:16:18 +02:00
ZbeeGin
9f097d5ae8
Translated using Weblate (Polish)
Currently translated at 97.9% (10305 of 10519 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/pl/
2025-09-09 00:16:18 +02:00
2tama3
80996e70f8
Translated using Weblate (Japanese)
Currently translated at 100.0% (10519 of 10519 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ja/
2025-09-09 00:16:18 +02:00
Frank Sonnenberg
ec8131c7bf
Translated using Weblate (German)
Currently translated at 99.9% (10518 of 10519 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/de/
2025-09-09 00:16:18 +02:00
Sárkány Lőrinc
2ad7c345ec
Translated using Weblate (Hungarian)
Currently translated at 34.6% (3648 of 10519 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/hu/
2025-09-09 00:16:17 +02:00
Pferd O
a2e0d07c87
Translated using Weblate (German)
Currently translated at 99.9% (10518 of 10519 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/de/
2025-09-09 00:16:17 +02:00
Frank Sonnenberg
4e1dd875ae
Translated using Weblate (German)
Currently translated at 99.9% (10518 of 10519 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/de/
2025-09-09 00:16:17 +02:00
CloverGit
c737e0b360
Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 97.4% (10247 of 10519 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/zh_Hans/
2025-09-09 00:16:17 +02:00
Sárkány Lőrinc
c29aa7643c
Translated using Weblate (Hungarian)
Currently translated at 34.6% (3641 of 10519 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/hu/
2025-09-09 00:16:17 +02:00
Pferd O
58b2ccb3d5
Translated using Weblate (German)
Currently translated at 99.6% (10484 of 10519 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/de/
2025-09-09 00:16:17 +02:00
Pferd O
a05f8b9e36
Translated using Weblate (German)
Currently translated at 99.4% (10458 of 10519 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/de/
2025-09-09 00:16:17 +02:00
CloverGit
9f2b84ba52
Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 97.3% (10245 of 10519 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/zh_Hans/
2025-09-09 00:16:17 +02:00
Sárkány Lőrinc
b345e34423
Translated using Weblate (Hungarian)
Currently translated at 33.0% (3480 of 10519 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/hu/
2025-09-09 00:16:17 +02:00
Frank Sonnenberg
081b414ad5
Translated using Weblate (German)
Currently translated at 99.1% (10429 of 10519 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/de/
2025-09-09 00:16:17 +02:00
Pferd O
58caa5c496
Translated using Weblate (German)
Currently translated at 99.1% (10429 of 10519 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/de/
2025-09-09 00:16:17 +02:00
Frank Sonnenberg
f0f5472e4d
Translated using Weblate (German)
Currently translated at 99.1% (10429 of 10519 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/de/
2025-09-09 00:16:17 +02:00
CloverGit
0b174b5227
Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 97.0% (10210 of 10519 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/zh_Hans/
2025-09-09 00:16:17 +02:00
2tama3
765838ecf7
Translated using Weblate (Japanese)
Currently translated at 99.9% (10518 of 10519 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ja/
2025-09-09 00:16:16 +02:00
Sárkány Lőrinc
2276ae05e3
Translated using Weblate (Hungarian)
Currently translated at 32.9% (3465 of 10519 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/hu/
2025-09-09 00:16:16 +02:00
Frank Sonnenberg
6838d55051
Translated using Weblate (German)
Currently translated at 98.9% (10405 of 10519 strings)

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

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/uk/
2025-09-09 00:16:16 +02:00
CloverGit
41425ac32d
Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 96.8% (10185 of 10519 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/zh_Hans/
2025-09-09 00:16:16 +02:00
Henrik Kauhanen
0b47169387
Translated using Weblate (Swedish)
Currently translated at 99.8% (10501 of 10519 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/sv/
2025-09-09 00:16:16 +02:00
dsa-t
7b98a8d697
Translated using Weblate (Russian)
Currently translated at 92.9% (9778 of 10519 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ru/
2025-09-09 00:16:16 +02:00
2tama3
4184e60e24
Translated using Weblate (Japanese)
Currently translated at 99.9% (10517 of 10519 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/ja/
2025-09-09 00:16:16 +02:00
Sárkány Lőrinc
36eb0e4a11
Translated using Weblate (Hungarian)
Currently translated at 32.9% (3464 of 10519 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/hu/
2025-09-09 00:16:16 +02:00
Frank Sonnenberg
49c7f62548
Translated using Weblate (German)
Currently translated at 98.9% (10405 of 10519 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/de/
2025-09-09 00:16:15 +02:00
Pferd O
35f0213011
Translated using Weblate (German)
Currently translated at 98.9% (10405 of 10519 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/de/
2025-09-09 00:16:15 +02:00
Frank Sonnenberg
cb87f83dfc
Translated using Weblate (German)
Currently translated at 98.9% (10405 of 10519 strings)

Translation: KiCad EDA/master source
Translate-URL: https://hosted.weblate.org/projects/kicad/master-source/de/
2025-09-09 00:16:15 +02:00
Jeff Young
ead7de69ca Fix periods in ERC gold files. 2025-09-08 20:44:32 +01:00
Jeff Young
dedc10a163 The Include "Exclude from BOM" setting is for editing, not exporting.
There's no reason to put items marked "Exclude
from BOM" into the BOM.
2025-09-08 20:44:32 +01:00
Jeff Young
330361d0cb Fix typo. 2025-09-08 20:44:32 +01:00
Jeff Young
01d32211ba Corner radius not supported on tablecells. 2025-09-08 20:44:32 +01:00
Seth Hillbrand
09c40a0e0f Make KiCad default template the default
Should clear up new project questions

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

Fixes https://gitlab.com/kicad/code/kicad/-/issues/21675
2025-09-08 12:16:59 -07:00
Jeff Young
fdbf740ee2 Corner radius not yet supported on textboxes.
Fixes https://gitlab.com/kicad/code/kicad/-/issues/21598
2025-09-08 19:54:59 +01:00
Jeff Young
93b0004175 Go back to checking points from the front.
We want to prefer a primary point (ie: a rectangle
corner) to a secondary point (ie: a rounded-rect
radius adjuster).
2025-09-08 18:37:47 +01:00
Jeff Young
0a162ded84 Go back to checking points from the front.
We want to prefer a primary point (ie: a rectangle
corner) to a secondary point (ie: a rounded-rect
radius adjuster).
2025-09-08 18:37:47 +01:00
Jeff Young
01f6776226 Fix hit-testing for rounded corner rectangles. 2025-09-08 18:37:47 +01:00
Jeff Young
adbc80aade Tighten corner radius value clearing.
Move loading of values outside of c'tor (where
they get stomped on my dialog restore code).

Fixes https://gitlab.com/kicad/code/kicad/-/issues/21677
2025-09-08 18:37:47 +01:00
Jeff Young
0b102fc085 Use WX_GRID::ClearRows() to avoid assertions.
Fixes KICAD-VM1.
2025-09-08 18:37:47 +01:00
Mark Roszko
22288e02a2 Fix cairo rendering on windows under wx 3.3 2025-09-08 12:32:12 -04:00
jean-pierre charras
58f4ca7ed6 FOOTPRINT_WIZARD_FRAME: Use the drawing engine selected in Preferences.
The FOOTPRINT_WIZARD_FRAME canvas used previously the Cairo engine,
regardless the drawing engine selected for all other canvases. It uses now
the selected engine.
2025-09-08 18:19:48 +02:00
Jeff Young
8ae2ad3586 Only test parameters under the same conditions as we'd write them to the file.
Fixes https://gitlab.com/kicad/code/kicad/-/issues/21520
2025-09-08 12:55:22 +01:00
Mark Roszko
0f97f51ba1 Fix unit binder dropdown not working on windows
Fixes https://gitlab.com/kicad/code/kicad/-/issues/20626
2025-09-08 06:36:20 -04:00
Seth Hillbrand
0c35068e8d ADDED: Optional flashing with cross-probing
Sometimes it is hard to find an element especially if we do not zoom to
the part.  The flash should help draw your eye to the relevant part

Fixes https://gitlab.com/kicad/code/kicad/-/issues/19842
2025-09-07 18:08:04 -07:00
Seth Hillbrand
f66cbaf43a ADDED: Stacked pin notation support
Implement bracket notation for stacked pins ([1,2,3], [1-4], [1,3,5-7]).
Automatic net naming proceeds based on the smallest logical pin number
in stacked groups.

Provide explode/reform commands in symbol editor for conversion.
Supports arbitrary ranges including BGA alphanum ranges like
[AA1-AA3,CD14-CD22]

Adds some additional QA and trace logging

Fixes https://gitlab.com/kicad/code/kicad/-/issues/2004
2025-09-07 14:59:51 -07:00
Seth Hillbrand
ac1b44715b Only dogbone inside corners
Fixes https://gitlab.com/kicad/code/kicad/issues/18880
2025-09-07 13:02:44 -07:00
Jeff Young
b98621c8c8 Formatting. 2025-09-07 20:43:04 +01:00
Jeff Young
28141ed350 Be more consistent with periods at the end of sentences.
Fixes https://gitlab.com/kicad/code/kicad/-/issues/21614
2025-09-07 17:54:22 +01:00
Jeff Young
c33da162d6 Be more consistent with periods at the end of sentences.
Fixes https://gitlab.com/kicad/code/kicad/-/issues/21614
2025-09-07 17:51:52 +01:00
jean-pierre charras
288c93198a Fix compatibility with wxWidgets 3.3.1 2025-09-07 18:46:54 +02:00
jean-pierre charras
46c8a6ee95 DIALOG_LIB_FIELDS_TABLE & DIALOG_SYMBOL_FIELDS_TABLE: avoid empty m_viewControlsGrid.
The fix is more a workaround: if all columns of m_viewControlsGrid are removed by
the right click menu and the grid is empty, there are no way to re-add a column.
When happens, this workaround re-add a column when reopening the dialog to avoid
a empty grid.
2025-09-07 18:26:48 +02:00
Mark Roszko
bbecc4eaa8 Add UUID to PCB tables to ensure stable file sort 2025-09-07 09:56:12 -04:00
Jeff Young
fef84a2c6a Dirty symbols when modified.
Also show changes in library tree and canvas when
"Apply" button is clicked.

Fixes https://gitlab.com/kicad/code/kicad/-/issues/21659
2025-09-07 13:49:59 +01:00
Mark Roszko
963ec84587 Edit Windows-CI.yml 2025-09-07 01:33:01 +00:00
Mark Roszko
4a87dbe472 Edit Windows-CI.yml 2025-09-06 21:24:53 +00:00
Mark Roszko
7d67f82217 Add use of gitlab nuget feed as binary cache 2025-09-06 21:21:41 +00:00
Jeff Young
b7fee045e3 Performance tweak. 2025-09-06 21:50:03 +01:00
Jeff Young
0e5a87546b More consistent action on Show search panel hypertext link.
Fixes https://gitlab.com/kicad/code/kicad/-/issues/21665
2025-09-06 21:29:41 +01:00
Jeff Young
5489daf279 ADDED: collapse/expand for view controls in SYMBOL_FIELDS_TABLE...
... and LIB_FIELDS_TABLE.
2025-09-06 19:06:49 +01:00
Mark Roszko
922699f388 Update ngspice to 45.2 2025-09-06 13:35:28 -04:00
Jeff Young
702f774a1f Bring DIALOG_LIB_FIELDS into line with DIALOG_SYMBOL_FIELDS_TABLE. 2025-09-06 15:10:30 +01:00
Mark Roszko
264029c8e9 Update kicad-vcpkg and ngspice 2025-09-06 08:46:34 -04:00
jean-pierre charras
c889a7fa16 DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR_BASE: fix a incorrect widgets type
Fix also a minor issue in DIALOG_FOOTPRINT_PROPERTIES_BASE

Fixes https://gitlab.com/kicad/code/kicad/-/issues/21662
2025-09-06 13:09:39 +02:00
Adrián García
fb558eee3c Fix crash in LIB_SYMBOL::SetUnitCount when reducing unit count
When decreasing the number of units in a symbol, the previous code erased
items directly from m_drawings using a single iterator. Because m_drawings
is a MULTIVECTOR, this could invalidate iterators and attempt to erase
from the wrong bucket, leading to segmentation faults.

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

Fixes https://gitlab.com/kicad/code/kicad/-/issues/21631
2025-09-05 12:35:54 -07:00
Wayne Stambaugh
6f352ccd96 Improve symbol fields table editor undo/redo memory usage.
- Do not add a modify action to commit for symbols that have no changes.
- Do not add a modify action to commit for each instance of shared symbols.
2025-09-05 11:46:05 -04:00
Jeff Young
c163f0a24c CHANGED: better real-estate usage in Edit Symbol Fields dialog.
1) Moved view controls list to a wx_grid.
2) Allow show/hide of columns in view controls.
3) Allow editing of BOM Names in grid without long-click on Mac.
3) Added column show/hide states and sash pos to prefs.
4) Decreased mininum sash pane width to allow wider main grid.
5) Simplified presentation by moving "include" and "cross-probe"
   settings to config menu.
2025-09-05 13:00:50 +01:00
Jeff Young
fd7da138fd Cleanup dead code. 2025-09-05 13:00:50 +01:00
jean-pierre charras
3bdf44d4a4 PCB_DIM_CENTER: fix incorrect bounding box size for 90deg cross.
Fixes https://gitlab.com/kicad/code/kicad/-/issues/21643
2025-09-05 09:40:33 +02:00
jean-pierre charras
168975b0a8 Fix a compil warning on MSYS2 (POINTS collide with a Windows header define)
POINTS is renamed LY_POINT. no actual code change
2025-09-05 09:34:49 +02:00
Mark Roszko
03b3b642b0 Another qa header fix 2025-09-04 21:33:27 -04:00
Seth Hillbrand
f9f5bb9ed1 Consider keywords as required
Because they actually are

Fixes https://gitlab.com/kicad/code/kicad/-/issues/21635
2025-09-04 16:54:53 -07:00
Mark Roszko
4254673be5 Fix windows build, missing wx header 2025-09-04 19:54:21 -04:00
Mark Roszko
0ce952e705 Fix windows build, IN conflicts with windows header 2025-09-04 19:52:34 -04:00
Seth Hillbrand
9ffb0c8b96 wxString explicit conv 2025-09-04 14:57:16 -07:00
Seth Hillbrand
44cc5b8e93 Move to fmt 2025-09-04 14:57:16 -07:00
Seth Hillbrand
a857ea77d9 ADDED: Text expression evaluation
Arbitrary text strings now support full evaluation with a rich
functional language

Fixes https://gitlab.com/kicad/code/kicad/-/issues/6643
2025-09-04 14:57:16 -07:00
Seth Hillbrand
bae5d43c45 Sadly, msys2 doesn't like condition variables 2025-09-04 13:58:38 -07:00
Seth Hillbrand
2cbd441042 Simplify font locking 2025-09-04 10:55:38 -07:00
jean-pierre charras
9a7088c03c French translation update 2025-09-04 18:15:56 +02:00
Mike Williams
7a09960b46 PCB search: add Drills column
Fixes: https://gitlab.com/kicad/code/kicad/-/issues/1982
2025-09-04 10:04:37 -04:00
Seth Hillbrand
05d04e665a Fix lib_fields column attributes
Need to properly display footprint selector and datasheet globe
2025-09-04 06:59:35 -07:00
Mark Roszko
9f1aa612ec Fix position of package properties that must follow packages 2025-09-04 07:16:02 -04:00
Mark Roszko
9de2548064 Fix typo in allegro output for nets 2025-09-04 07:09:12 -04:00
Graham Keeth
825585847b Fix typo in DRC rules help 2025-09-03 20:53:26 -07:00
Graham Keeth
6c8f25b418 Add DRC syntax help for via_dangling 2025-09-03 20:52:33 -07:00
Mark Roszko
a899da7cb7 Fix double quoting tol for some reason 2025-09-03 22:59:37 -04:00
Mark Roszko
a49e3b9cc5 Fix build 2025-09-03 22:59:21 -04:00
Mark Roszko
9bc1cf006f Fix the allegro netlist export and move mostly to {fmt}
Weirdly $PACKAGES header got shifted out of position.
Drop generating empty references.
2025-09-03 22:54:00 -04:00
Seth Hillbrand
dc7e0665c3 Prevent GTK from providing stale position
When the library name and symbol/footprint name both match the filter,
we try to display both but ensure visible can move things to the wrong
place.  We need to ensure the filtered list is up to date prior to
moving by ensureVisible

Fixes https://gitlab.com/kicad/code/kicad/-/issues/18000
2025-09-03 16:58:38 -07:00
Seth Hillbrand
344fab5741 Prompt for unsaved changes in the lib fields table editor 2025-09-03 15:54:29 -07:00
Seth Hillbrand
9342aea7fa Move new project to templates
If the baseline default project doesn't exist on disk, create it and use
that as an empty project.  Allows the designer to modify the default new
project used or select from existing templates
2025-09-03 15:52:05 -07:00
Seth Hillbrand
11c5e03890 Update Font widget
Now displays the font next to its name

Also keeps a static version of itself for rapid display
2025-09-03 15:48:15 -07:00
Seth Hillbrand
3deb06bf82 Expand the custom fields properties to pcbnew
Allows editing/reviewing custom fields for a set of selected footprints
in pcbnew

Fixes https://gitlab.com/kicad/code/kicad/-/issues/16703
2025-09-03 13:10:22 -07:00
Seth Hillbrand
5c865cab36 Allow full-field filtering in lib_fields_table_editor 2025-09-03 11:47:22 -07:00
Mike Williams
f7fd832c67 design blocks: add routing to exinst group when applying layout 2025-09-03 13:49:55 -04:00
Seth Hillbrand
62e220a8db Reverse cell painting for Windows
Apparently Windows might not respect painting with a transparent alpha,
so reverse the paint order

Fixes https://gitlab.com/kicad/code/kicad/-/issues/21635
2025-09-03 10:35:59 -07:00
jean-pierre charras
622ddd3a37 3D viewer: fix a minor issue, clean code and and a few comments.
Fixes https://gitlab.com/kicad/code/kicad/-/issues/21629
2025-09-03 18:24:56 +02:00
Seth Hillbrand
9f06d1f66b Fix image pasting for MacOS
Apparently, GetImage() on MacOS does not always convert the image
properly.  So do a two-step here to get the Bitmap first, forcing the
conversion and then going back to an image
2025-09-03 09:18:07 -07:00
Seth Hillbrand
f84ba3004d Properly append corners to created poly
Fixes https://gitlab.com/kicad/code/kicad/-/issues/21633
2025-09-03 06:59:59 -07:00
Seth Hillbrand
e85a8056f5 Don't convert URI slashes on Windows
We auto-convert paths for windows boxes but this should not happen for
uri schemes that have the form <URI>://<path>

Fixes https://gitlab.com/kicad/code/kicad/-/issues/20381
2025-09-03 06:56:28 -07:00
Seth Hillbrand
173e02eff7 ADDED: Lasso support to Schematic Editor 2025-09-03 06:45:49 -07:00
jean-pierre charras
876c905e2b DRAWING_TOOL: change POINT to MD_POINT, to avoid colliding with a Windows header define 2025-09-03 11:40:05 +02:00
jean-pierre charras
5914b5aaa8 gendrill_Excellon_writer.cpp: convert fprintf and fputs to fmt::print
It allows write issues to be handled more  easily.
2025-09-03 09:48:09 +02:00
jean-pierre charras
2346be9768 Fix compil warnings 2025-09-03 09:43:41 +02:00
Seth Hillbrand
d4b08f0a8a When unarchiving a project, open it also
Just a little convenience for getting projects open
2025-09-02 21:11:54 -07:00
Seth Hillbrand
f18c4a05fd Don't push names we don't have
Fixes https://gitlab.com/kicad/code/kicad/issues/21628
2025-09-02 20:49:39 -07:00
Seth Hillbrand
ad80113f47 Prevent modifying teardrops on lock/unlock
This action doesn't affect geometry, so don't dirty the teardrops

Fixes https://gitlab.com/kicad/code/kicad/issues/21342
2025-09-02 20:35:59 -07:00
Seth Hillbrand
8f0b3b59f0 Offer to create missing plugin directory 2025-09-02 20:32:14 -07:00
Mark Roszko
bf82217217 Fix leftover printf float in gencad writer 2025-09-02 22:58:43 -04:00
Seth Hillbrand
d9741fd46a Consider visibility when colliding in DRC
Most places we check this but we should also check it in physical
clearance

Fixes https://gitlab.com/kicad/code/kicad/-/issues/21625
2025-09-02 19:24:55 -07:00
Seth Hillbrand
826f15a103 Prevent crash in nettie
We need to avoid collecting invalid layers in the net ties regardless of
their origins
2025-09-02 19:18:58 -07:00
Seth Hillbrand
edf8f45351 Add user fields to editable properties
Fixes https://gitlab.com/kicad/code/kicad/issues/21622
2025-09-02 18:29:59 -07:00
Mike Williams
202619cd43 design blocks: fix PADs getting copied in routing, enable by default 2025-09-02 13:58:18 -04:00
John Beard
8709f73b98 Symbol editor: simplify root symbol-finding 2025-09-03 00:30:56 +08:00
John Beard
e76b2089bb Symbol edit: add symbol flatten action
This removes inheritance from the symbol.

This doesn't play well with undo, but then again, neither does symbol
deletion, so that seems like a higher-level symbol editor issue.

Relates-To: https://gitlab.com/kicad/code/kicad/-/issues/8895
2025-09-03 00:24:32 +08:00
John Beard
2e0088593e Symbol editor: fix flattening during save-as to the same library 2025-09-03 00:24:24 +08:00
John Beard
b34746e06b Symbol editor: allow editing all related symbols from the treeview
This makes it more straightforward to edit a group of related symbols
(related = all derived from the same parent, including the parent).

Relates-To: https://gitlab.com/kicad/code/kicad/-/issues/21067
Relates-To: https://gitlab.com/kicad/code/kicad/-/issues/9742
Relates-To: https://gitlab.com/kicad/code/kicad/-/issues/11506
2025-09-03 00:24:18 +08:00
John Beard
9b14434fc3 Symbol editor: allow to inject the symbol list into DIALOG_LIB_FIELDS
This will permit editing fields for subsets (e.g. only symbols in
a certain inheritance hierarchy)
2025-09-03 00:24:12 +08:00
Seth Hillbrand
1f1f8699e0 Prevent pads from moving inappropriately
Free pads is a setting unless we are in the footprint editor and needs
to be respected by the alignmen tool

Fixes https://gitlab.com/kicad/code/kicad/-/issues/21626
2025-09-02 09:11:31 -07:00
John Beard
0ede830f54 LIB_SYMBOL: When assigning, clear the parent if needed
This allows assigning a symbol with no parent to a symbol with
a parent to work more as expected.
2025-09-02 23:50:17 +08:00
Seth Hillbrand
de8c4d4b01 ADDED: via_dangling constraint
Allows programmatic suppression of this error if you don't care about it

Fixes https://gitlab.com/kicad/code/kicad/-/issues/18058
2025-09-02 08:26:18 -07:00
jean-pierre charras
e01dfd3158 gendrill_Excellon_writer: remove use of LOCALE_IO 2025-09-02 16:18:09 +02:00
Jeff Young
cff261ce2e Don't allow stack addresses to escape via long-life handlers. 2025-09-02 14:19:17 +01:00
Jeff Young
6a171e11fb Clang got cranky on the emplace_back call. 2025-09-02 12:17:07 +01:00
John Beard
1e272ca21b Geom: use SHAPE_SEGMENT for OVAL
OVAL didn't do anything SHAPE_SEGMENT couldn't already do.
2025-09-02 17:38:26 +08:00
jean-pierre charras
60a5c8b742 WX_INFOBAR: Better calculation of the minimal height.
The height was sometimes to big (case of multi-line text or small initial
size of the parent frame).
The height is now calculated from the height of one line of text, even for
multi-line text.
2025-09-02 07:50:50 +02:00
Seth Hillbrand
9cba910d53 ADDED: Library Table Editor
Edits all symbols in a library at once.  Supports copy/paste, multiple
field assignment and selective coloration based on existing data

Fixes https://gitlab.com/kicad/code/kicad/-/issues/11506
2025-09-01 21:47:14 -07:00
Mark Roszko
35ffb28335 Remove the GetCommonSettings mock
There's some sort of internal issue in boost::test and the turtle mocks that causes test crashes
2025-09-01 22:13:36 -04:00
Jeff Young
98b63389c1 Give Mac dock icon menu a kick.
Fixes https://gitlab.com/kicad/code/kicad/-/issues/17596
2025-09-01 22:04:59 +01:00
Jeff Young
ce140d8dfc Formatting. 2025-09-01 22:04:59 +01:00
Mark Roszko
5e2ec53165 Use ADDR2LINE for linux qa for now 2025-09-01 13:57:45 -04:00
Mark Roszko
d5e342b64d Updated turtle mocks to 2.0.0 properly (it was already mostly there being off-tag instead of the mentioned tag) 2025-09-01 13:49:28 -04:00
John Beard
eedfb7a573 Pcbnew: pickup footprints by points, add a selection filter 2025-09-02 01:24:14 +08:00
Ian McInerney
c95c15dd4e Don't throw away old hidden text that was converted to fields 2025-09-01 18:19:46 +01:00
Mark Roszko
4a4725c906 Avoid shadowed variable warning 2025-09-01 12:24:35 -04:00
Mark Roszko
667dccb163 Add rdynamic to QABUILD executables. 2025-09-01 12:20:22 -04:00
Mark Roszko
4fb76404bc Try and disable boost's signal handler 2025-09-01 16:07:03 +00:00
Mark Roszko
267ee811a7 Try and suppress gcc warning 2025-09-01 11:58:13 -04:00
John Beard
e016dc52fd Pcbnew: Add concept of a 'point'
This is a zero-dimensional object that can be used for snapping
and documentation of useful, but non-physical features on a
board or footprint. They do not correspond to any physical
output in exports or plots.

Points do have a "size", but this is a graphical property only
and determines how large they are drawn on the board.

They also have a layer, which allows them to be selected and
made visible according to layer filters.

Fixes: https://gitlab.com/kicad/code/kicad/-/issues/4691
2025-09-01 23:44:21 +08:00
John Beard
c4d9338097 Pcbnew: sort sexpr text items stably
Currently all texts on the same layer do not sort stably in the file
format. Add sorting criteria to sort by position, angle, size
and so on and finally by string.
2025-09-01 23:44:21 +08:00
John Beard
5d967289ee Eeschema: order pins by number, not position
Also use StrNumCmp, then the pin numbers are ordered exactly the
same way as pads in footprints.
2025-09-01 23:44:21 +08:00
John Beard
262f1fdabb Pcbnew: add layer mode/stackup checks to library parity DRC 2025-09-01 23:44:21 +08:00
Mark Roszko
c9476caebf Fix macOS build 2025-09-01 11:31:03 -04:00
Mark Roszko
a8d6292d61 Use boost::stacktrace w/ unit test handlers to start hunting for that copper sliver wabbit 2025-09-01 11:07:12 -04:00
jean-pierre charras
4953e80122 Fix some compil warnings 2025-09-01 16:22:05 +02:00
JamesJCode
bd04d508e0 Fix some compiler warnings 2025-09-01 14:50:22 +01:00
Seth Hillbrand
82c61efcbd Revert "When re-launching on MacOS, create a new instance"
Needs to launch without jumping back in and allow switching

This reverts commit 1885f4bdee6656d988bf088b048fbfbb70ac0f3d.
2025-09-01 06:39:34 -07:00
Jeff Young
4024a15a17 Don't reference stack variables from a long-life lambda.
In particular, a lambda for conditional menus should
never capture more than `[this]`.  Even the tool's
frame pointer could change.

Fixes https://gitlab.com/kicad/code/kicad/-/issues/21615
2025-09-01 12:44:20 +01:00
Jeff Young
0c8e7a7137 Reload symbol chooser on keep symbol, and improve accessibility.
(Respond to hotkey-generated clicks.)

Fixes https://gitlab.com/kicad/code/kicad/-/issues/7698
2025-09-01 11:45:20 +01:00
Jeff Young
1f44417ad0 Attempt to improve ever-growing-window problems. 2025-09-01 11:45:20 +01:00
jean-pierre charras
5b31b11731 SHAPE_RECT: add Normalize method to assure width or height > 0
ROUNDRECT: add option to normalize the rectangle on creation

if the created rectangle has a negative size(width or height) there are issues
when drawing it.

Fixes https://gitlab.com/kicad/code/kicad/-/issues/21613
Fixes https://gitlab.com/kicad/code/kicad/-/issues/21610
2025-09-01 11:56:56 +02:00
Adrián García
5fb55ccb30 jobsets: fix Replace button to overwrite existing files (#19900) 2025-09-01 01:13:23 +00:00
Seth Hillbrand
2eb7ba2fb9 Simplify overlapping points after editing
Fixes https://gitlab.com/kicad/code/kicad/-/issues/21571
2025-08-31 17:48:59 -07:00
Seth Hillbrand
2c4d792358 Stop converging at existing point
Prevents collapsing points into drag element when hitting convergence
2025-08-31 17:48:59 -07:00
Seth Hillbrand
77a2330a33 Fix QA result based on updated behavior 2025-08-31 15:52:38 -07:00
Seth Hillbrand
7b4f4540b4 ADDED: Light snapping to 45° multiples
When modifying the points of a polygon, we add a small snap to the
points preferring multiples of 45° unless you are holding shift

Fixes https://gitlab.com/kicad/code/kicad/-/issues/15709
2025-08-31 13:47:34 -07:00
Seth Hillbrand
1885f4bdee When re-launching on MacOS, create a new instance
Allows people to run multiple copies of KiCad.  Only launches new copies
if the TLW is already shown.  Otherwise, sticks with the default MacOS
behavior of raising the running window
2025-08-31 12:54:55 -07:00
Seth Hillbrand
eba8d0748c Don't show angles for non-polygons 2025-08-31 12:54:38 -07:00
Seth Hillbrand
f5904cf2ac Prevent main KiCad window from expanding based on DPI events
Fixes https://gitlab.com/kicad/code/kicad/-/issues/21602
2025-08-31 11:54:53 -07:00
Seth Hillbrand
bbc762a546 ADDED: Angle preview for polygon mod
Shows angle for the current and adjacent corners and whether they are
congruent
2025-08-31 11:49:41 -07:00
Seth Hillbrand
c6c8e19e39 The smallest angle between two segments is 0-180
Not 0-90.  Subtracting 180-angle and then taking the smaller of angle
and 180-angle will always get you 90 or less.  But obtuse angles are not
< 90
2025-08-31 11:49:41 -07:00
Jeff Young
1309b436da Allow stitching of graphic shapes. 2025-08-31 19:32:48 +01:00
Jeff Young
c47b7459aa Set free vias to graphic net if available.
Fixes https://gitlab.com/kicad/code/kicad/-/issues/21578
2025-08-31 19:21:29 +01:00
Jeff Young
a2e98fb53c Don't set point to a value we're not going to keep.
It just causes flicker.

Fixes https://gitlab.com/kicad/code/kicad/-/issues/19947
2025-08-31 17:13:11 +01:00
Seth Hillbrand
2321285c16 Maybe don't need eary exit here 2025-08-31 08:11:44 -07:00
Seth Hillbrand
2cdeb0cd7c Second pass at fixing warping and grids
First attempt caused additional problems for #21535

Fixes https://gitlab.com/kicad/code/kicad/-/issues/18196
2025-08-31 07:54:21 -07:00
Seth Hillbrand
4af585c531 Revert "Remove the forced ancillary grid"
This reverts commit 29dc45d584a882866f2f3f27a7257481043ecc84.

Fixes https://gitlab.com/kicad/code/kicad/-/issues/21535
2025-08-31 07:54:12 -07:00
Seth Hillbrand
8c6f057f6c Re-organize points to allow missing radius
Not all rectangles want/need the radius point, but we will only be able
to drag one point at a time.  So we re-organize which point of an
overlapping set is selected

Fixes https://gitlab.com/kicad/code/kicad/-/issues/21605
2025-08-31 07:10:14 -07:00
Jeff Young
9d7db3d135 Better interactive feedback.
Don't wait for mouse to move before refreshing after a command.

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

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

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

Fixes https://gitlab.com/kicad/code/kicad/-/issues/16828
2025-08-31 14:25:52 +01:00
Seth Hillbrand
b22f259ccb Make properties panel obey free pads setting
Pads should almost never be moved without their parent.  Only allow this
in the case where free pads has explicitly been checked

Fixes https://gitlab.com/kicad/code/kicad/-/issues/21591
2025-08-31 06:08:27 -07:00
Seth Hillbrand
b86cddbbe9 Fix RRECT handling in processClosedShape 2025-08-31 05:43:59 -07:00
Seth Hillbrand
053c46aa72 Add last point in 3d export 2025-08-31 05:29:37 -07:00
jean-pierre charras
4610a49323 Fix round rect shape STEP export.
Fixes https://gitlab.com/kicad/code/kicad/-/issues/21599
2025-08-31 12:43:40 +02:00
jean-pierre charras
68f9b74ae9 SHAPE RECTANGLE: fix hatching clipping for round rectangle. 2025-08-31 10:05:21 +02:00
Adam Wysocki
814f78f2b2 ADDED: Add pcb/sch upgrade cli command 2025-08-30 20:57:41 +00:00
Jeff Young
be57c1a380 Fix undo for rounded rects.
Fixes https://gitlab.com/kicad/code/kicad/-/issues/21595
2025-08-30 21:16:47 +01:00
Jeff Young
194b7f9dc5 Add corner radius to Shape Properties dialog. 2025-08-30 20:45:02 +01:00
Jeff Young
c6fcf7e0b8 Allow easier code searching for property names. 2025-08-30 19:09:15 +01:00
Mark Roszko
cf09e8ae88 Adjust flags for dynamicdeopt to build 2025-08-30 13:46:38 -04:00
Mark Roszko
1ff5f09c3a Add cmake flag for enabling MSVC Dynamic Debugging in release 2025-08-30 13:35:40 -04:00
jean-pierre charras
7610c02fed 3D view: honor round rectangle shape.
Fixes https://gitlab.com/kicad/code/kicad/-/issues/21597
2025-08-30 18:51:43 +02:00
Jeff Young
7fd8b515b5 Prefer const&. 2025-08-30 17:45:49 +01:00
Jeff Young
ba84f50997 Commenting. 2025-08-30 17:45:49 +01:00
Jeff Young
acc7b1e508 ADDED: separate front/back silk and mask colours for STEP export.
Fixes https://gitlab.com/kicad/code/kicad/-/issues/21593
2025-08-30 17:45:49 +01:00
Jeff Young
67feb2e139 Performance tweaks. 2025-08-30 17:45:49 +01:00
Jeff Young
6f59821930 Prefer const &. 2025-08-30 17:45:49 +01:00
jean-pierre charras
6592c75345 fix issues in ROUNDRECT. This also fix a change commit by mistake in aeafbe48
Fix incorrect ROUNDRECT Ctor. It also fixes a link issue on msys2
- Do not throw  an error in CTor: this is not the place. It is much easy to
fix the value of incorrect radius.
Moreover, the Ctor is called without catching a throw-ed error in code.
- fix the test about radius validity, broken.
2025-08-30 17:35:26 +02:00
Seth Hillbrand
1a3f6028f8 Fix missed last points
Fixes https://gitlab.com/kicad/code/kicad/-/issues/21596
2025-08-30 08:33:46 -07:00
Seth Hillbrand
fe4ddc66eb Limit radius in more places 2025-08-30 08:19:35 -07:00
Seth Hillbrand
e3b550dd13 Add a little radius helper
When rounding a rectangle, add a helper that shows the current radius
2025-08-30 08:19:35 -07:00
Mark Roszko
1baa28a1e6 Kick out more strtod. Actually should have used parseDouble from DSNLEXER years ago. 2025-08-30 10:46:06 -04:00
Seth Hillbrand
0f1b514964 Handle corner radius in Create from selection
Fixes https://gitlab.com/kicad/code/kicad/-/issues/21601
2025-08-30 07:33:30 -07:00
jean-pierre charras
aeafbe48fe Step exporter: fix overzealous validity test.
When converting poly shapes with arcs in STEP_PCB_MODEL::MakeShapes,
when an error happens, a second try is made using a full polygonal shape.
However a fatal error was emitted at the first attempt, before the second try.
Now at first try, only a debug message is emitted on error. The fatal error
is emitted only if the second try fails.

Fixes https://gitlab.com/kicad/code/kicad/-/issues/21589
2025-08-30 12:58:56 +02:00
Mark Roszko
2b8542861c Missed a strtod in kicad legacy pcb parsing 2025-08-30 06:57:48 -04:00
Mark Roszko
9dd642b66c Kick out strtod in legacy parsers 2025-08-29 23:38:00 -04:00
Mark Roszko
d5c0d040b4 Add missing fast_float files 2025-08-29 22:18:08 -04:00
Mark Roszko
b3de964eff Add fast_float for float parsing.
2x faster than both std::from_chars and strtod on Windows.

macOS will get to benefit from a modern from_chars impl too.
2025-08-29 21:48:24 -04:00
Seth Hillbrand
8acf5c1a25 ADDED: Rounded Rectangles
Fixes https://gitlab.com/kicad/code/kicad/-/issues/4742
2025-08-29 17:37:30 -07:00
Seth Hillbrand
e282dca102 Add configurable hysteresis to PCB snapping
Makes it harder to enter and harder to exit a snap.  ideally this should
help make snapping more intuitive and easier to use.  Once you have a
snap, it is harder to lose it but it avoids being overly snappy in the
begining
2025-08-29 16:21:35 -07:00
Seth Hillbrand
a811f61c39 Make Expand Connection respect the filter
Prevents expansion that would require traversing elements that are
disabled in the selection filter

Fixes https://gitlab.com/kicad/code/kicad/-/issues/21581
2025-08-29 16:11:38 -07:00
Seth Hillbrand
50274352b1 Skip exterior segments when splitting
We need to avoid fracture points when choosing how to split exterior
segments
2025-08-29 15:50:34 -07:00
Seth Hillbrand
ec7b831be3 ADDED: Search feature for html message box
Allow search for text in e.g. the custom rules examples

Fixes https://gitlab.com/kicad/code/kicad/-/issues/21550
2025-08-29 10:29:11 -07:00
Jeff Young
9525fae7c8 Run collision check on correct layer.
Fixes https://gitlab.com/kicad/code/kicad/-/issues/21586
2025-08-29 17:13:16 +01:00
Seth Hillbrand
e8cec41355 ADDED: Indication of filter blocking
If the selection filter has blocked all selections under the cursor,
show a subtle flash on which filter(s) did the blocking.  Helpful for
people getting frustrated by not being able to select locked items.

Fixes https://gitlab.com/kicad/code/kicad/-/issues/20487
2025-08-29 07:08:27 -07:00
Jeff Young
8a60893249 Regularize content of item descriptions.
1) Use sentence capitalisation
2) Show text of text items

Fixes https://gitlab.com/kicad/code/kicad/-/issues/21582
2025-08-29 12:03:55 +01:00
Mark Roszko
7115f9e716 Drop the FromChar in ConvertNotation 2025-08-28 18:27:06 -04:00
Jeff Young
736d87aa35 ADDED: directive labels checkbox to Schematic Editor Display Settings panel in Preferences.
Fixes https://gitlab.com/kicad/code/kicad/-/issues/21577
2025-08-28 17:49:06 +01:00
Jeff Young
eb6b2de648 Fix for the fix (for clang). 2025-08-28 13:20:20 +01:00
Jeff Young
83fab7b02c Fix undo for move of group-of-shapes.
Fixes https://gitlab.com/kicad/code/kicad/-/issues/21563
2025-08-28 13:20:14 +01:00
Mark Roszko
af852ea15d Protect from_chars from clang 2025-08-28 07:11:08 -04:00
Mark Roszko
fd57f637ac Revert "Compilers should have complete from_chars support now"
This reverts commit 3a8dd87db4513b7c7ede748a4f30ef5192e1752b.
2025-08-28 07:07:44 -04:00
Jeff Young
5c240efd75 Consolidate to single copy of deletableItems. 2025-08-28 11:54:24 +01:00
Mark Roszko
b01c1f39c1 Add missing header 2025-08-28 01:22:08 +00:00
Mark Roszko
3e019ee4ae pcb plots dont need LOCALE_IO anymore 2025-08-27 20:44:16 -04:00
Mark Roszko
4f32146f9a nlohmann json is locale independent (uses to_chars) 2025-08-27 20:41:47 -04:00
Mark Roszko
9bc463606a More redundant LOCALE_IO 2025-08-27 20:11:26 -04:00
Mark Roszko
747106ea37 Redundant include 2025-08-27 20:07:58 -04:00
Mark Roszko
94d83773d0 Drop a LOCALE_IO via std::from_chars 2025-08-27 20:07:28 -04:00
Mark Roszko
3a8dd87db4 Compilers should have complete from_chars support now 2025-08-27 20:07:28 -04:00
Mark Roszko
2cf6ec2411 Remove some obsolete LOCALE_IO 2025-08-27 20:07:27 -04:00
Seth Hillbrand
408e1feae2 Fix Chessboard splitting
Due to a bug(?) in Clipper2, 45° collinear edges may not be detected.
See https://github.com/AngusJohnson/Clipper2/issues/1008 for current
status.  In the meantime, we pre-process these to remove the extraneous
joints preventing our triangulation from getting mixed up

Fixes https://gitlab.com/kicad/code/kicad/-/issues/18176
2025-08-27 15:00:58 -07:00
Seth Hillbrand
ea8206eca5 Don't both designers with unneeded changes
If we are not asking for fields to be removed when updating, then don't
say we're doing anything if all we have to do is remove fields
2025-08-27 13:30:44 -07:00
Jeff Young
6dd4e01f16 ADDED: custom body styles.
(Also moves editing of unit display names to the
Symbol Properties dialog and retires the Set Unit
Display Name dialog.)

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

Fixes https://gitlab.com/kicad/code/kicad/-/issues/14843
2025-08-27 18:11:56 +01:00
Mark Roszko
3eb6caaec6 Move gencad writer to {fmt} 2025-08-27 08:11:12 -04:00
jean-pierre charras
9725ac2215 GERBER_JOBFILE_WRITER: fix incorrect layer id in File Attributes for inner layers.
Fixes https://gitlab.com/kicad/code/kicad/-/issues/21569
2025-08-27 13:25:24 +02:00
jean-pierre charras
b349f1988a PAD: better HitTest( const VECTOR2I& aPosition, int aAccuracy, PCB_LAYER_ID aLayer ) 2025-08-27 13:23:02 +02:00
jean-pierre charras
963aa47778 Pcbnew: fix teardrop generation for pads having different shapes by layer.
Teardrop generator used pad::HitTest not testing the hit of a specific layer.
It created false test for some complex pads. Now use a test specific to a layer.

Fixes https://gitlab.com/kicad/code/kicad/-/issues/21560
2025-08-27 11:03:00 +02:00
Seth Hillbrand
2f21414186 Revert "Allow netlisting for multi-unit parts"
Breaks QA.  need to debug before re-committing

This reverts commit 635445c096c8624a47c9e0fdd6c1ebefa668e973.
2025-08-26 22:07:40 -07:00
Seth Hillbrand
8bd6da3ec9 Revert "Fix build error"
This reverts commit 19e4c3f498b8b66eacd2b651a570f0f137a8b6b2.
2025-08-26 22:07:26 -07:00
Mark Roszko
19e4c3f498 Fix build error
std::string does not have a overload for appending a wchar
2025-08-26 20:25:56 -04:00
modbw
57ad779797 Fix net assignment messed up in Eagle import
When there is a polygon in the Eagle project withput any pad connected 
netCode was not incremented and so the wrong nets were assigned to the 
following elements.

Fixes https://gitlab.com/kicad/code/kicad/-/issues/21243
2025-08-26 17:11:21 -07:00
Adrián García
46084c04b9 pcbnew: avoid missing or wrong lines inside hatched fill polygons
Avoid considering duplicated intersections between a segment of the
hatched fill and the polygon outline or vertices.
Also, check whether the segments of the lines are inside or outside
the polygon, so no lines are drawn outside when the shape is complex.

Fixes https://gitlab.com/kicad/code/kicad/-/issues/20450
2025-08-26 16:47:26 -07:00
Seth Hillbrand
635445c096 Allow netlisting for multi-unit parts
Merges pin map from each unit into coherent model prior to exporting for
spice simulation

Fixes https://gitlab.com/kicad/code/kicad/-/issues/1779
2025-08-26 15:02:37 -07:00
Seth Hillbrand
394f6be509 Formatting 2025-08-26 14:47:04 -07:00
Seth Hillbrand
fe4de09d71 Add undo/redo functionality to dialog boxes
Fixes https://gitlab.com/kicad/code/kicad/-/issues/18986
2025-08-26 14:39:19 -07:00
Seth Hillbrand
b832ae7f45 Add checks to copper sliver QA
Fedora still doesn't like our copper sliver QA sometimes.  This adds a
bit more to try and get to the bottom of the issue
2025-08-26 13:27:03 -07:00
Seth Hillbrand
8592b2ee70 JP's patch to fix crash in routing empty board 2025-08-26 12:41:54 -07:00
Seth Hillbrand
1e76f1a11d Ensure that we check tracks exiting pads for gaps
The DP gap check should look for sections of track that are coupled by
wider than a given spacing.  Our primitive check of looking for
collisions on the segment between the start poins causes tracks exiting
but not entering pads to be excluded.

Fixes https://gitlab.com/kicad/code/kicad/-/issues/21561
2025-08-26 12:39:59 -07:00
Seth Hillbrand
0a767acb3a Wrap net_selector widget for properties
Provides consistent interface to modify/filter nets in property panel
and dialogs

Fixes https://gitlab.com/kicad/code/kicad/-/issues/17643
2025-08-26 11:50:12 -07:00
Seth Hillbrand
29c4d9b197 Add width/height adjustment to reference image
Allows setting specific width or height on a reference image instead of
just scale

Fixes https://gitlab.com/kicad/code/kicad/-/issues/18567
2025-08-26 11:22:32 -07:00
Seth Hillbrand
2db8c6eca0 Maintain group membership when shoving
Keep track of the original group membership and assign this to the newly
created element as well

Fixes https://gitlab.com/kicad/code/kicad/-/issues/20862
2025-08-26 10:34:10 -07:00
Seth Hillbrand
9c577a4f4c Allow mid-track teardrops
Tracks passing through but not stopping at pads/vias should still get
teardrops

Fixes https://gitlab.com/kicad/code/kicad/-/issues/21246
2025-08-26 10:04:52 -07:00
John Beard
0f0527bd03 Pcbnew: fix sensitivity of via placement to large grids
Another case where large grids are overly "grabby" for snaps.

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

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

Fixes: https://gitlab.com/kicad/code/kicad/-/issues/18626
2025-08-26 23:34:46 +08:00
John Beard
3d8803f579 Pcbnew: use R-tree for pad checks in via place tool
Otherwise this is an O(n-pads-on-board) operation for every new
candidate via position.
2025-08-26 23:34:46 +08:00
John Beard
4bebd09bd0 EDA_LIST_DIALOG: Simplify ctor args
Sometimes you want to add these in the ctor of the child
class based on some logic and having to construct the vector
in the init-list is a bit ugly.

Theoretically allows to not require a vector too.
2025-08-26 23:34:46 +08:00
John Beard
7f4a1bf64a Sym edit: allow to flatten symbol on save as
Sometimes, you don't want to drag the whole inheritance hierarchy with
you.

Relates-To: https://gitlab.com/kicad/code/kicad/-/issues/8895
2025-08-26 23:34:46 +08:00
Seth Hillbrand
ab93dd8a68 Avoid trying to get a display when headless 2025-08-26 06:48:36 -07:00
Seth Hillbrand
cb620338db Prevent stale names in fp browser
When switching libraries, if there is an additional footprint with the
same name, we don't want to select it by default as this will prevent
updating the footprint display.  Instead, force the update

Fixes https://gitlab.com/kicad/code/kicad/-/issues/9763
2025-08-26 06:21:59 -07:00
Seth Hillbrand
dad60f99c0 More GDI conservation 2025-08-26 06:04:30 -07:00
Seth Hillbrand
4660c72c69 Fix qa issue in api 2025-08-26 05:45:08 -07:00
Seth Hillbrand
b5f3d4cf7b Reduce GDI usage by caching layer swatches 2025-08-26 05:29:02 -07:00
Seth Hillbrand
412fc1e6d9 Fix pcbnew QA mock 2025-08-25 22:08:05 -07:00
Seth Hillbrand
8997b7bcf7 Remove old HasCorner 2025-08-25 22:06:26 -07:00
Seth Hillbrand
5b86f20476 Suppress unneeded move corner context
Doesn't really make sense in terms of a group

Fixes https://gitlab.com/kicad/code/kicad/-/issues/21552
2025-08-25 22:04:32 -07:00
Seth Hillbrand
7841476ed6 Make all 4 corners draggable
When scaling, maybe you want to drag from the bottom left or top right

Fixes https://gitlab.com/kicad/code/kicad/-/issues/21554
2025-08-25 22:02:20 -07:00
Seth Hillbrand
a034c30563 Properly add group size mod to commit
Allows escaping the current state

Fixes https://gitlab.com/kicad/code/kicad/-/issues/21553
2025-08-25 21:59:13 -07:00
Seth Hillbrand
6dd03bc735 Fix screen scaling
We don't use wxWidget DPI (which is the screen DPI) for our on-screen
display.  Instead, we use 91 (?!?).  Make this configurable in advanced
config and use the set value in our scaling widget
2025-08-25 18:03:46 -07:00
Seth Hillbrand
1df5ad0e4c Fix circle scaling
We scale the full circle, which is just defined by its points

Fixes https://gitlab.com/kicad/code/kicad/-/issues/21551
2025-08-25 18:03:46 -07:00
Seth Hillbrand
9013ddae43 Suppress deprecation warnings
Treats thread-pool as a system library so we don't see the deprecation
warnings that we're not going to address anyway
2025-08-25 16:31:39 -07:00
Seth Hillbrand
bfe805a221 Add user-controlled scaling factor
Lets the user decide what 100% zoom is for their system based on a
slider.

This is inspired by Inkscape's custom scaling widget

Fixes https://gitlab.com/kicad/code/kicad/-/issues/19256
2025-08-25 14:37:07 -07:00
Addo White
843eea259d Fix for Cursor rendering on Linux+EGL+Nvidia in accelerated graphics mode
EGL/NVidia can sometimes clip the cursor based on its plane regardless of the depth mask.  This avoids the issue by forcing the cursor up over the existing plane.

Fixes https://gitlab.com/kicad/code/kicad/-/issues/12183
2025-08-25 14:35:33 -07:00
Jeff Young
cc9ec7c01c Move assignment operator for SCH_SHEET_PATH. 2025-08-25 20:48:37 +01:00
Jeff Young
537ea6ee0c Move assignment operator for TRIANGULATED_POLYGON. 2025-08-25 20:48:37 +01:00
Seth Hillbrand
cc9402ac9d A better fix for #21543
Instead of making a default parent, we set the parent to invalid
allowing the error to bubble up without an assert

Fixes https://gitlab.com/kicad/code/kicad/-/issues/21543
2025-08-25 12:27:20 -07:00
Seth Hillbrand
20a80a5f94 Fix shadowing variable 2025-08-25 11:49:28 -07:00
Seth Hillbrand
ef0ca4840e Revert "Check for property prefix in DRC"
This reverts commit 85397f6edc835fa6abed8fdc77d53614c94a79b1.
2025-08-25 11:37:13 -07:00
Seth Hillbrand
4e7fa189aa Refactor gfx import cleanup
Break up monolithic function into responsibilities.  Adjust cleanup to
correctly modify each graphical pairing.  Fix drc test to properly
report gap distances that are relevant to outlines

Fixes https://gitlab.com/kicad/code/kicad/-/issues/13090
2025-08-25 11:33:26 -07:00
Seth Hillbrand
87ee9c4b49 Don't preemptively skip previously seen objects
We need to return them in order to detect the self-intersection
2025-08-25 11:31:51 -07:00
Seth Hillbrand
9cabceb773 Properly extend our outline
Previously, if we had a single gap in the outline, we would report
multiple errors depending on the order in which we parsed the outline.
This was confusing as most of those errors were invalid.  Instead, we
build the outline in both directions before reporting gaps
2025-08-25 11:31:51 -07:00
Seth Hillbrand
ba9e9a2368 Be more explicit in the board outline errors
Show the two items that are closest to the gap and put the marker
directly in the gap center.  Then report the space between them to allow
the designer more information about what to look for
2025-08-25 11:31:51 -07:00
Seth Hillbrand
b709439b65 Avoid showing 0.0 if there are non-zeros
If the value we want to show is in nm but we are representing it as mm,
don't show 0.00 unless it is actually 0.  otherwise, convert to
scientific notation to represent the value in nm.
2025-08-25 11:31:51 -07:00
Seth Hillbrand
ad7235e386 Don't add tiny sections
When healing the board, adding nm-sized sections is worse than just
adjusting the elements to create a full outline
2025-08-25 11:31:51 -07:00
Jeff Young
3058bc6355 Expose shape in prop inspector for sheet pins. 2025-08-25 17:19:10 +01:00
Jeff Young
9808889c9c Make 3D view/toolbar/contextmenu command lists more consistent.
Fixes https://gitlab.com/kicad/code/kicad/-/issues/21347
2025-08-25 16:35:01 +01:00
Jeff Young
8c3026cf1a Naming conventions. 2025-08-25 12:13:38 +01:00
Jeff Young
0477fb65ec Better spacing in dialogs.
Also allows Symbol Properties to be narrower.
2025-08-25 10:48:19 +01:00
Fabien Corona
cec87c4096 resolve some merge conflicts 2025-02-28 18:20:11 +01:00
Fabien Corona
9778ca739b correct some merge errors 2025-02-28 18:19:50 +01:00
Fabien Corona
8cffe509fa minor changes 2025-02-28 16:27:23 +01:00
Fabien Corona
47a8701a01 ibis: board description 2025-02-28 16:27:21 +01:00
Fabien Corona
0269851994 ignore [Driver Schedule] for now 2025-02-28 16:18:58 +01:00
Fabien Corona
2757067986 check if models and submodels are compatbile 2025-02-28 16:18:55 +01:00
Fabien Corona
62d8cfbf9f ibis parser: implement [Add Submodel] 2025-02-28 16:18:11 +01:00
1081 changed files with 308457 additions and 222947 deletions

View File

@ -8,6 +8,8 @@ win64_build:
interruptible: false
image: registry.gitlab.com/kicad/kicad-ci/windows-build-image/ltsc2022-msvc:latest
variables:
VCPKG_BINARY_SOURCES: 'nuget,gitlab,readwrite'
VCPKG_DISABLE_COMPILER_TRACKING: '1'
# Switch the compressor to fastzip and reduce the compression level
FF_USE_FASTZIP: "true"
CACHE_COMPRESSION_LEVEL: "fast"
@ -23,6 +25,7 @@ win64_build:
script:
- C:\builder\build.ps1 -Env -Arch x64
- $vcpkgCache=Join-Path -Path (Get-Location) -ChildPath ".vcpkgCache";$env:VCPKG_DEFAULT_BINARY_CACHE=$vcpkgCache;New-Item -ItemType Directory -Force -Path $vcpkgCache
- nuget.exe sources add -Name gitlab -Source "https://gitlab.com/api/v4/projects/27426693/packages/nuget/index.json" -UserName gitlab-ci-token -Password $env:CI_JOB_TOKEN
- mkdir -p build/windows -Force
- cd build/windows
- cmake `
@ -37,8 +40,6 @@ win64_build:
../../
- cmake --build . 2>&1 | tee compilation_log.txt
- cd ../../
after_script:
- Get-Content -Path C:\builder\vcpkg\buildtrees\wxpython-33\python3-tool-post-install-err.log
artifacts:
# Only save the artifacts that are needed for running the tests in the next stage
# and the compilation log. The entire build directory is too large to save as an

View File

@ -20,6 +20,7 @@
variables:
BOOST_TEST_LOGGER: 'JUNIT,warning,test_results.${TEST}.xml:HRF,message'
CTEST_OUTPUT_ON_FAILURE: 1
BOOST_TEST_CATCH_SYSTEM_ERRORS: 'no'
script:
- cd build/linux/qa
- ctest -R qa_${TEST}

View File

@ -368,11 +368,12 @@ private:
void createTrackWithMargin( const PCB_TRACK* aTrack, CONTAINER_2D_BASE* aDstContainer,
PCB_LAYER_ID aLayer, int aMargin = 0 );
// Generate the pad shape on board layers. The pad hole is not generated by createPadWithMargin
void createPadWithMargin( const PAD *aPad, CONTAINER_2D_BASE* aDstContainer,
PCB_LAYER_ID aLayer, const VECTOR2I& aMargin ) const;
void createPadWithHole( const PAD* aPad, CONTAINER_2D_BASE* aDstContainer,
int aInflateValue );
// Generate the hole shape of aPad, stored in aDstContainer
void createPadHoleShape( const PAD* aPad, CONTAINER_2D_BASE* aDstContainer, int aInflateValue );
void addPads( const FOOTPRINT* aFootprint, CONTAINER_2D_BASE* aDstContainer,
PCB_LAYER_ID aLayerId );

View File

@ -47,6 +47,7 @@
#include <geometry/shape_segment.h>
#include <geometry/geometry_utils.h>
#include <geometry/shape_circle.h>
#include <geometry/roundrect.h>
#include <geometry/shape_rect.h>
#include <geometry/shape_simple.h>
#include <utility>
@ -473,12 +474,12 @@ void BOARD_ADAPTER::createPadWithMargin( const PAD* aPad, CONTAINER_2D_BASE* aCo
}
void BOARD_ADAPTER::createPadWithHole( const PAD* aPad, CONTAINER_2D_BASE* aDstContainer,
int aInflateValue )
void BOARD_ADAPTER::createPadHoleShape( const PAD* aPad, CONTAINER_2D_BASE* aDstContainer,
int aInflateValue )
{
if( !aPad->HasHole() )
{
wxLogTrace( m_logTrace, wxT( "BOARD_ADAPTER::createPadWithHole - found an invalid pad" ) );
wxLogTrace( m_logTrace, wxT( "BOARD_ADAPTER::createPadHole pad has no hole" ) );
return;
}
@ -649,16 +650,40 @@ void BOARD_ADAPTER::addShape( const PCB_SHAPE* aShape, CONTAINER_2D_BASE* aConta
}
else
{
std::vector<VECTOR2I> pts = aShape->GetRectCorners();
if( aShape->GetCornerRadius() > 0 )
{
ROUNDRECT rr( SHAPE_RECT( aShape->GetPosition(),
aShape->GetRectangleWidth(),
aShape->GetRectangleHeight() ),
aShape->GetCornerRadius() );
SHAPE_POLY_SET poly;
rr.TransformToPolygon( poly );
SHAPE_LINE_CHAIN& r_outline = poly.Outline( 0 );
r_outline.SetClosed( true );
addROUND_SEGMENT_2D( aContainer, TO_SFVEC2F( pts[0] ), TO_SFVEC2F( pts[1] ),
linewidth3DU, *aOwner );
addROUND_SEGMENT_2D( aContainer, TO_SFVEC2F( pts[1] ), TO_SFVEC2F( pts[2] ),
linewidth3DU, *aOwner );
addROUND_SEGMENT_2D( aContainer, TO_SFVEC2F( pts[2] ), TO_SFVEC2F( pts[3] ),
linewidth3DU, *aOwner );
addROUND_SEGMENT_2D( aContainer, TO_SFVEC2F( pts[3] ), TO_SFVEC2F( pts[0] ),
linewidth3DU, *aOwner );
for( int ii = 0; ii < r_outline.PointCount(); ii++ )
{
addROUND_SEGMENT_2D( aContainer, TO_SFVEC2F( r_outline.CPoint( ii ) ),
TO_SFVEC2F( r_outline.CPoint( ii+1 ) ),
linewidth3DU, *aOwner );
}
addROUND_SEGMENT_2D( aContainer, TO_SFVEC2F( r_outline.CLastPoint() ),
TO_SFVEC2F( r_outline.CPoint( 0 ) ), linewidth3DU, *aOwner );
}
else
{
std::vector<VECTOR2I> pts = aShape->GetRectCorners();
addROUND_SEGMENT_2D( aContainer, TO_SFVEC2F( pts[0] ), TO_SFVEC2F( pts[1] ),
linewidth3DU, *aOwner );
addROUND_SEGMENT_2D( aContainer, TO_SFVEC2F( pts[1] ), TO_SFVEC2F( pts[2] ),
linewidth3DU, *aOwner );
addROUND_SEGMENT_2D( aContainer, TO_SFVEC2F( pts[2] ), TO_SFVEC2F( pts[3] ),
linewidth3DU, *aOwner );
addROUND_SEGMENT_2D( aContainer, TO_SFVEC2F( pts[3] ), TO_SFVEC2F( pts[0] ),
linewidth3DU, *aOwner );
}
}
break;

View File

@ -507,27 +507,32 @@ void BOARD_ADAPTER::createLayers( REPORTER* aStatusReporter )
{
for( PAD* pad : footprint->Pads() )
{
const VECTOR2I padHole = pad->GetDrillSize();
if( !padHole.x ) // Not drilled pad like SMD pad
// Note: holes of NPTH are already built by GetBoardPolygonOutlines
if( !pad->HasHole() )
continue;
// The hole in the body is inflated by copper thickness, if not plated, no copper
int inflate = 0;
if( pad->GetAttribute() != PAD_ATTRIB::NPTH )
inflate = KiROUND( GetHolePlatingThickness() / 2.0 );
m_holeCount++;
double holeDiameter = ( pad->GetDrillSize().x + pad->GetDrillSize().y ) / 2.0;
m_averageHoleDiameter += static_cast<float>( holeDiameter * m_biuTo3Dunits );
createPadWithHole( pad, &m_TH_ODs, inflate );
if( pad->GetAttribute() == PAD_ATTRIB::NPTH )
{
// Ensure the silk drawings are clipped to the NPTH hole, like other pad/via holes
// even if the clip to board body is not activated (remember NPTH holes are part of
// the board body)
createPadHoleShape( pad, &m_TH_ODs, 0 );
continue;
}
// The hole in the body is inflated by copper thickness
int inflate = KiROUND( GetHolePlatingThickness() / 2.0 );
createPadHoleShape( pad, &m_TH_ODs, inflate );
if( cfg.clip_silk_on_via_annuli )
createPadWithHole( pad, &m_viaAnnuli, inflate );
createPadHoleShape( pad, &m_viaAnnuli, inflate );
createPadWithHole( pad, &m_TH_IDs, 0 );
createPadHoleShape( pad, &m_TH_IDs, 0 );
}
}
@ -539,9 +544,7 @@ void BOARD_ADAPTER::createLayers( REPORTER* aStatusReporter )
{
for( PAD* pad : footprint->Pads() )
{
const VECTOR2I padHole = pad->GetDrillSize();
if( !padHole.x ) // Not drilled pad like SMD pad
if( !pad->HasHole() )
continue;
// The hole in the body is inflated by copper thickness.

View File

@ -35,14 +35,22 @@
#include <advanced_config.h>
#include <build_version.h>
#include <board.h>
#include <pad.h>
#include <pcb_field.h>
#include <reporter.h>
#include <gal/opengl/gl_context_mgr.h>
#include <core/profile.h> // To use GetRunningMicroSecs or another profiling utility
#include <bitmaps.h>
#include <kiway_holder.h>
#include <kiway.h>
#include <macros.h>
#include <pgm_base.h>
#include <settings/settings_manager.h>
#include <tool/tool_dispatcher.h>
#include <string_utils.h>
#include <mail_type.h>
#include <kiway_express.h>
#include <fmt/format.h>
#include <widgets/wx_busy_indicator.h>
@ -92,28 +100,12 @@ END_EVENT_TABLE()
EDA_3D_CANVAS::EDA_3D_CANVAS( wxWindow* aParent, const wxGLAttributes& aGLAttribs,
BOARD_ADAPTER& aBoardAdapter, CAMERA& aCamera,
S3D_CACHE* a3DCachePointer ) :
HIDPI_GL_3D_CANVAS( EDA_DRAW_PANEL_GAL::GetVcSettings(), aCamera, aParent, aGLAttribs,
EDA_3D_CANVAS_ID, wxDefaultPosition,
wxDefaultSize, wxFULL_REPAINT_ON_RESIZE ),
m_eventDispatcher( nullptr ),
m_parentStatusBar( nullptr ),
m_parentInfoBar( nullptr ),
m_glRC( nullptr ),
m_is_opengl_initialized( false ),
m_is_opengl_version_supported( true ),
m_editing_timeout_timer( this, wxID_HIGHEST + 1 ),
m_redraw_trigger_timer( this, wxID_HIGHEST + 2 ),
m_render_pivot( false ),
m_camera_moving_speed( 1.0f ),
m_strtime_camera_movement( 0 ),
m_animation_enabled( true ),
m_moving_speed_multiplier( 3 ),
m_boardAdapter( aBoardAdapter ),
m_3d_render( nullptr ),
m_opengl_supports_raytracing( true ),
m_render_raytracing_was_requested( false ),
m_accelerator3DShapes( nullptr ),
m_currentRollOverItem( nullptr )
HIDPI_GL_3D_CANVAS( EDA_DRAW_PANEL_GAL::GetVcSettings(), aCamera, aParent, aGLAttribs,
EDA_3D_CANVAS_ID, wxDefaultPosition,
wxDefaultSize, wxFULL_REPAINT_ON_RESIZE ),
m_editing_timeout_timer( this, wxID_HIGHEST + 1 ),
m_redraw_trigger_timer( this, wxID_HIGHEST + 2 ),
m_boardAdapter( aBoardAdapter )
{
wxLogTrace( m_logTrace, wxT( "EDA_3D_CANVAS::EDA_3D_CANVAS" ) );
@ -481,8 +473,10 @@ void EDA_3D_CANVAS::DoRePaint()
if( m_camera_is_moving )
{
const int64_t curtime_delta = GetRunningMicroSecs() - m_strtime_camera_movement;
curtime_delta_s = ( curtime_delta / 1e6 ) * m_camera_moving_speed;
const int64_t curtime_delta = GetRunningMicroSecs() - m_strtime_camera_movement;
// Convert microseconds to seconds as float and apply speed multiplier
curtime_delta_s = static_cast<float>( static_cast<double>( curtime_delta ) / 1e6 )
* m_camera_moving_speed;
m_camera.Interpolate( curtime_delta_s );
if( curtime_delta_s > 1.0f )
@ -751,7 +745,8 @@ void EDA_3D_CANVAS::RenderToFrameBuffer( unsigned char* buffer, int width, int h
if( m_camera_is_moving )
{
const int64_t curtime_delta = GetRunningMicroSecs() - m_strtime_camera_movement;
curtime_delta_s = ( curtime_delta / 1e6 ) * m_camera_moving_speed;
curtime_delta_s = static_cast<float>( static_cast<double>( curtime_delta ) / 1e6 )
* m_camera_moving_speed;
m_camera.Interpolate( curtime_delta_s );
if( curtime_delta_s > 1.0f )
@ -887,7 +882,7 @@ void EDA_3D_CANVAS::OnZoomGesture( wxZoomGestureEvent& aEvent )
m_camera.Pan( aEvent.GetPosition() );
m_camera.SetCurMousePosition( aEvent.GetPosition() );
m_camera.Zoom( aEvent.GetZoomFactor() / m_gestureLastZoomFactor );
m_camera.Zoom( static_cast<float>( aEvent.GetZoomFactor() / m_gestureLastZoomFactor ) );
m_gestureLastZoomFactor = aEvent.GetZoomFactor();
@ -930,7 +925,7 @@ void EDA_3D_CANVAS::OnRotateGesture( wxRotateGestureEvent& aEvent )
if( m_camera_is_moving )
return;
m_camera.RotateScreen( m_gestureLastAngle - aEvent.GetRotationAngle() );
m_camera.RotateScreen( static_cast<float>( m_gestureLastAngle - aEvent.GetRotationAngle() ) );
m_gestureLastAngle = aEvent.GetRotationAngle();
DisplayStatus();
@ -1066,9 +1061,45 @@ void EDA_3D_CANVAS::OnLeftDown( wxMouseEvent& event )
{
RAY mouseRay = getRayAtCurrentMousePosition();
BOARD_ITEM *intersectedBoardItem = m_3d_render_raytracing->IntersectBoardItem( mouseRay );
BOARD_ITEM* intersectedBoardItem = m_3d_render_raytracing->IntersectBoardItem( mouseRay );
// !TODO: send a selection item to pcbnew, eg: via kiway?
if( intersectedBoardItem )
{
FOOTPRINT* footprint = nullptr;
switch( intersectedBoardItem->Type() )
{
case PCB_FOOTPRINT_T:
footprint = static_cast<FOOTPRINT*>( intersectedBoardItem );
break;
case PCB_PAD_T:
footprint = static_cast<PAD*>( intersectedBoardItem )->GetParentFootprint();
break;
case PCB_FIELD_T:
footprint = static_cast<PCB_FIELD*>( intersectedBoardItem )->GetParentFootprint();
break;
default:
break;
}
if( footprint )
{
std::string command =
fmt::format( "$SELECT: 0,F{}",
EscapeString( footprint->GetReference(), CTX_IPC ).ToStdString() );
EDA_3D_VIEWER_FRAME* frame = static_cast<EDA_3D_VIEWER_FRAME*>( GetParent() );
if( frame )
{
frame->Kiway().ExpressMail( FRAME_PCB_EDITOR, MAIL_SELECTION, command, frame );
frame->Kiway().ExpressMail( FRAME_SCH, MAIL_SELECTION, command, frame );
}
}
}
}
}
@ -1088,14 +1119,14 @@ void EDA_3D_CANVAS::OnLeftUp( wxMouseEvent& event )
int logicalW = logicalSize.GetWidth();
int logicalH = logicalSize.GetHeight();
int gizmo_x, gizmo_y, gizmo_width, gizmo_height;
int gizmo_x = 0, gizmo_y = 0, gizmo_width = 0, gizmo_height = 0;
std::tie( gizmo_x, gizmo_y, gizmo_width, gizmo_height ) = m_3d_render_opengl->getGizmoViewport();
float scaleX = static_cast<float>( gizmo_width ) / logicalW;
float scaleY = static_cast<float>( gizmo_height ) / logicalH;
float scaleX = static_cast<float>( static_cast<double>( gizmo_width ) / static_cast<double>( logicalW ) );
float scaleY = static_cast<float>( static_cast<double>( gizmo_height ) / static_cast<double>( logicalH ) );
int scaledMouseX = static_cast<int>( event.GetX() * scaleX );
int scaledMouseY = static_cast<int>( ( logicalH - event.GetY() ) * scaleY );
int scaledMouseX = static_cast<int>( static_cast<float>( event.GetX() ) * scaleX );
int scaledMouseY = static_cast<int>( static_cast<float>( logicalH - event.GetY() ) * scaleY );
m_3d_render_opengl->handleGizmoMouseInput( scaledMouseX, scaledMouseY );
Refresh();
@ -1229,7 +1260,7 @@ void EDA_3D_CANVAS::request_start_moving_camera( float aMovingSpeed, bool aRende
// Map speed multiplier option to actual multiplier value
// [1,2,3,4,5] -> [0.25, 0.5, 1, 2, 4]
aMovingSpeed *= ( 1 << m_moving_speed_multiplier ) / 8.0f;
aMovingSpeed *= static_cast<float>( ( 1 << m_moving_speed_multiplier ) ) / 8.0f;
m_render_pivot = aRenderPivot;
m_camera_moving_speed = aMovingSpeed;
@ -1249,7 +1280,7 @@ void EDA_3D_CANVAS::move_pivot_based_on_cur_mouse_position()
{
RAY mouseRay = getRayAtCurrentMousePosition();
float hit_t;
float hit_t = 0.0f;
// Test it with the board bounding box
if( m_boardAdapter.GetBBox().Intersect( mouseRay, &hit_t ) )

View File

@ -42,7 +42,7 @@ class RENDER_3D_RAYTRACE_GL;
class RENDER_3D_OPENGL;
#define EDA_3D_CANVAS_ID wxID_HIGHEST + 1321
#define EDA_3D_CANVAS_ID (wxID_HIGHEST + 1321)
/**
* Implement a canvas based on a wxGLCanvas
@ -61,7 +61,7 @@ public:
EDA_3D_CANVAS( wxWindow* aParent, const wxGLAttributes& aGLAttribs, BOARD_ADAPTER& aSettings,
CAMERA& aCamera, S3D_CACHE* a3DCachePointer );
~EDA_3D_CANVAS();
~EDA_3D_CANVAS() override;
/**
* Set a dispatcher that processes events and forwards them to tools.
@ -302,36 +302,36 @@ private:
RAY getRayAtCurrentMousePosition();
private:
TOOL_DISPATCHER* m_eventDispatcher;
wxStatusBar* m_parentStatusBar; // Parent statusbar to report progress
WX_INFOBAR* m_parentInfoBar;
TOOL_DISPATCHER* m_eventDispatcher = nullptr;
wxStatusBar* m_parentStatusBar = nullptr; // Parent statusbar to report progress
WX_INFOBAR* m_parentInfoBar = nullptr;
wxGLContext* m_glRC; // Current OpenGL context
bool m_is_opengl_initialized;
bool m_is_opengl_version_supported;
wxGLContext* m_glRC = nullptr; // Current OpenGL context
bool m_is_opengl_initialized = false;
bool m_is_opengl_version_supported = true;
wxTimer m_editing_timeout_timer; // Expires after some time signaling that
// the mouse / keyboard movements are over
wxTimer m_redraw_trigger_timer; // Used to schedule a redraw event
std::atomic_flag m_is_currently_painting; // Avoid drawing twice at the same time
std::atomic_flag m_is_currently_painting = ATOMIC_FLAG_INIT; // Avoid drawing twice at the same time
bool m_render_pivot; // Render the pivot while camera moving
float m_camera_moving_speed; // 1.0f will be 1:1
int64_t m_strtime_camera_movement; // Ticktime of camera movement start
bool m_animation_enabled; // Camera animation enabled
int m_moving_speed_multiplier; // Camera animation speed multiplier option
bool m_render_pivot = false; // Render the pivot while camera moving
float m_camera_moving_speed = 1.0f; // 1.0f will be 1:1
int64_t m_strtime_camera_movement = 0; // Ticktime of camera movement start
bool m_animation_enabled = true; // Camera animation enabled
int m_moving_speed_multiplier = 3; // Camera animation speed multiplier option
BOARD_ADAPTER& m_boardAdapter; // Pre-computed 3D info and settings
RENDER_3D_BASE* m_3d_render;
RENDER_3D_BASE* m_3d_render = nullptr;
RENDER_3D_RAYTRACE_GL* m_3d_render_raytracing;
RENDER_3D_OPENGL* m_3d_render_opengl;
bool m_opengl_supports_raytracing;
bool m_render_raytracing_was_requested;
bool m_opengl_supports_raytracing = true;
bool m_render_raytracing_was_requested = false;
ACCELERATOR_3D* m_accelerator3DShapes; // used for mouse over searching
ACCELERATOR_3D* m_accelerator3DShapes = nullptr; // used for mouse over searching
BOARD_ITEM* m_currentRollOverItem;
BOARD_ITEM* m_currentRollOverItem = nullptr;
bool m_render3dmousePivot = false; // Render the 3dmouse pivot
SFVEC3F m_3dmousePivotPos; // The position of the 3dmouse pivot

View File

@ -819,10 +819,7 @@ void RENDER_3D_OPENGL::generateViasAndPads()
{
if( pad->GetAttribute() != PAD_ATTRIB::NPTH )
{
const VECTOR2I drillsize = pad->GetDrillSize();
const bool hasHole = drillsize.x && drillsize.y;
if( !hasHole )
if( !pad->HasHole() )
continue;
pad->TransformHoleToPolygon( tht_outer_holes_poly, platingThickness,

View File

@ -277,7 +277,7 @@ void RENDER_3D_RAYTRACE_BASE::renderTracing( uint8_t* ptrPBO, REPORTER* aStatusR
BS::multi_future<void> futures;
for( size_t i = 0; i < tp.get_thread_count(); ++i )
futures.push_back( tp.submit( processBlocks ) );
futures.push_back( tp.submit_task( processBlocks ) );
futures.wait();
@ -486,9 +486,12 @@ void RENDER_3D_RAYTRACE_BASE::renderBlockTracing( uint8_t* ptrPBO, signed int iB
// Initialize ray packets
const SFVEC2UI& blockPos = m_blockPositions[iBlock];
const SFVEC2I blockPosI = SFVEC2I( blockPos.x + m_xoffset, blockPos.y + m_yoffset );
const SFVEC2F randDisp = ( m_camera.GetProjection() == PROJECTION_TYPE::ORTHO ) ?
SFVEC2F( 0.0f, 0.0f ) :
SFVEC2F( DISP_FACTOR, DISP_FACTOR );
RAYPACKET blockPacket( m_camera, (SFVEC2F) blockPosI + SFVEC2F( DISP_FACTOR, DISP_FACTOR ),
SFVEC2F( DISP_FACTOR, DISP_FACTOR ) /* Displacement random factor */ );
RAYPACKET blockPacket( m_camera, (SFVEC2F) blockPosI + randDisp,
randDisp /* Displacement random factor */ );
HITINFO_PACKET hitPacket_X0Y0[RAYPACKET_RAYS_PER_PACKET];
@ -566,7 +569,7 @@ void RENDER_3D_RAYTRACE_BASE::renderBlockTracing( uint8_t* ptrPBO, signed int iB
HITINFO_PACKET_init( hitPacket_AA_X1Y1 );
RAYPACKET blockPacket_AA_X1Y1( m_camera, (SFVEC2F) blockPosI + SFVEC2F( 0.5f, 0.5f ),
SFVEC2F( DISP_FACTOR, DISP_FACTOR ) );
randDisp );
if( !m_accelerator->Intersect( blockPacket_AA_X1Y1, hitPacket_AA_X1Y1 ) )
{
@ -603,16 +606,16 @@ void RENDER_3D_RAYTRACE_BASE::renderBlockTracing( uint8_t* ptrPBO, signed int iB
RAY blockRayPck_AA_X1Y1_half[RAYPACKET_RAYS_PER_PACKET];
RAYPACKET_InitRays_with2DDisplacement(
m_camera, (SFVEC2F) blockPosI + SFVEC2F( 0.5f - DISP_FACTOR, DISP_FACTOR ),
SFVEC2F( DISP_FACTOR, DISP_FACTOR ), blockRayPck_AA_X1Y0 );
m_camera, (SFVEC2F) blockPosI + SFVEC2F( 0.5f - randDisp.x, randDisp.y ),
randDisp, blockRayPck_AA_X1Y0 );
RAYPACKET_InitRays_with2DDisplacement(
m_camera, (SFVEC2F) blockPosI + SFVEC2F( DISP_FACTOR, 0.5f - DISP_FACTOR ),
SFVEC2F( DISP_FACTOR, DISP_FACTOR ), blockRayPck_AA_X0Y1 );
m_camera, (SFVEC2F) blockPosI + SFVEC2F( randDisp.x, 0.5f - randDisp.y ),
randDisp, blockRayPck_AA_X0Y1 );
RAYPACKET_InitRays_with2DDisplacement(
m_camera, (SFVEC2F) blockPosI + SFVEC2F( 0.25f - DISP_FACTOR, 0.25f - DISP_FACTOR ),
SFVEC2F( DISP_FACTOR, DISP_FACTOR ), blockRayPck_AA_X1Y1_half );
m_camera, (SFVEC2F) blockPosI + SFVEC2F( 0.25f - randDisp.x, 0.25f - randDisp.y ),
randDisp, blockRayPck_AA_X1Y1_half );
renderAntiAliasPackets( bgColor, hitPacket_X0Y0, hitPacket_AA_X1Y1, blockRayPck_AA_X1Y0,
hitColor_AA_X1Y0 );

View File

@ -86,22 +86,39 @@ void EDA_3D_VIEWER_FRAME::doReCreateMenuBar()
viewMenu->Add( gridSubmenu );
viewMenu->AppendSeparator();
viewMenu->Add( EDA_3D_ACTIONS::rotateXCW );
viewMenu->Add( EDA_3D_ACTIONS::rotateXCCW );
viewMenu->Add( EDA_3D_ACTIONS::viewTop );
viewMenu->Add( EDA_3D_ACTIONS::viewBottom );
viewMenu->Add( EDA_3D_ACTIONS::viewRight );
viewMenu->Add( EDA_3D_ACTIONS::viewLeft );
viewMenu->Add( EDA_3D_ACTIONS::viewFront );
viewMenu->Add( EDA_3D_ACTIONS::viewBack );
ACTION_MENU* rotateSubmenu = new ACTION_MENU( false, tool );
rotateSubmenu->SetTitle( _( "Rotate Board" ) );
rotateSubmenu->SetIcon( BITMAPS::rotate_cw );
rotateSubmenu->Add( EDA_3D_ACTIONS::rotateXCW );
rotateSubmenu->Add( EDA_3D_ACTIONS::rotateXCCW );
rotateSubmenu->AppendSeparator();
rotateSubmenu->Add( EDA_3D_ACTIONS::rotateYCW );
rotateSubmenu->Add( EDA_3D_ACTIONS::rotateYCCW );
rotateSubmenu->AppendSeparator();
rotateSubmenu->Add( EDA_3D_ACTIONS::rotateZCW );
rotateSubmenu->Add( EDA_3D_ACTIONS::rotateZCCW );
ACTION_MENU* moveSubmenu = new ACTION_MENU( false, tool );
moveSubmenu->SetTitle( _( "Move Board" ) );
moveSubmenu->SetIcon( BITMAPS::move );
moveSubmenu->Add( EDA_3D_ACTIONS::moveLeft );
moveSubmenu->Add( EDA_3D_ACTIONS::moveRight );
moveSubmenu->Add( EDA_3D_ACTIONS::moveUp );
moveSubmenu->Add( EDA_3D_ACTIONS::moveDown );
viewMenu->AppendSeparator();
viewMenu->Add( EDA_3D_ACTIONS::rotateYCW );
viewMenu->Add( EDA_3D_ACTIONS::rotateYCCW );
viewMenu->AppendSeparator();
viewMenu->Add( EDA_3D_ACTIONS::rotateZCW );
viewMenu->Add( EDA_3D_ACTIONS::rotateZCCW );
viewMenu->AppendSeparator();
viewMenu->Add( EDA_3D_ACTIONS::moveLeft );
viewMenu->Add( EDA_3D_ACTIONS::moveRight );
viewMenu->Add( EDA_3D_ACTIONS::moveUp );
viewMenu->Add( EDA_3D_ACTIONS::moveDown );
viewMenu->Add( rotateSubmenu );
viewMenu->Add( EDA_3D_ACTIONS::flipView );
viewMenu->Add( moveSubmenu );
viewMenu->AppendSeparator();
viewMenu->Add( EDA_3D_ACTIONS::showLayersManager, ACTION_MENU::CHECK );

View File

@ -38,6 +38,30 @@
bool EDA_3D_CONTROLLER::Init()
{
std::shared_ptr<ACTION_MENU> rotateSubmenu = std::make_shared<ACTION_MENU>( true, this );
rotateSubmenu->SetTitle( _( "Rotate Board" ) );
rotateSubmenu->SetIcon( BITMAPS::rotate_cw );
m_menu->RegisterSubMenu( rotateSubmenu );
rotateSubmenu->Add( EDA_3D_ACTIONS::rotateXCW );
rotateSubmenu->Add( EDA_3D_ACTIONS::rotateXCCW );
rotateSubmenu->AppendSeparator();
rotateSubmenu->Add( EDA_3D_ACTIONS::rotateYCW );
rotateSubmenu->Add( EDA_3D_ACTIONS::rotateYCCW );
rotateSubmenu->AppendSeparator();
rotateSubmenu->Add( EDA_3D_ACTIONS::rotateZCW );
rotateSubmenu->Add( EDA_3D_ACTIONS::rotateZCCW );
std::shared_ptr<ACTION_MENU> moveSubmenu = std::make_shared<ACTION_MENU>( true, this );
moveSubmenu->SetTitle( _( "Move Board" ) );
moveSubmenu->SetIcon( BITMAPS::move );
m_menu->RegisterSubMenu( moveSubmenu );
moveSubmenu->Add( EDA_3D_ACTIONS::moveLeft );
moveSubmenu->Add( EDA_3D_ACTIONS::moveRight );
moveSubmenu->Add( EDA_3D_ACTIONS::moveUp );
moveSubmenu->Add( EDA_3D_ACTIONS::moveDown );
CONDITIONAL_MENU& ctxMenu = m_menu->GetMenu();
ctxMenu.AddItem( ACTIONS::zoomInCenter, SELECTION_CONDITIONS::ShowAlways );
@ -46,23 +70,15 @@ bool EDA_3D_CONTROLLER::Init()
ctxMenu.AddSeparator();
ctxMenu.AddItem( EDA_3D_ACTIONS::viewTop, SELECTION_CONDITIONS::ShowAlways );
ctxMenu.AddItem( EDA_3D_ACTIONS::viewBottom, SELECTION_CONDITIONS::ShowAlways );
ctxMenu.AddSeparator();
ctxMenu.AddItem( EDA_3D_ACTIONS::viewRight, SELECTION_CONDITIONS::ShowAlways );
ctxMenu.AddItem( EDA_3D_ACTIONS::viewLeft, SELECTION_CONDITIONS::ShowAlways );
ctxMenu.AddSeparator();
ctxMenu.AddItem( EDA_3D_ACTIONS::viewFront, SELECTION_CONDITIONS::ShowAlways );
ctxMenu.AddItem( EDA_3D_ACTIONS::viewBack, SELECTION_CONDITIONS::ShowAlways );
ctxMenu.AddSeparator();
ctxMenu.AddMenu( rotateSubmenu.get(), SELECTION_CONDITIONS::ShowAlways );
ctxMenu.AddItem( EDA_3D_ACTIONS::flipView, SELECTION_CONDITIONS::ShowAlways );
ctxMenu.AddSeparator();
ctxMenu.AddItem( EDA_3D_ACTIONS::moveLeft, SELECTION_CONDITIONS::ShowAlways );
ctxMenu.AddItem( EDA_3D_ACTIONS::moveRight, SELECTION_CONDITIONS::ShowAlways );
ctxMenu.AddItem( EDA_3D_ACTIONS::moveUp, SELECTION_CONDITIONS::ShowAlways );
ctxMenu.AddItem( EDA_3D_ACTIONS::moveDown, SELECTION_CONDITIONS::ShowAlways );
ctxMenu.AddMenu( moveSubmenu.get(), SELECTION_CONDITIONS::ShowAlways );
return true;
}
@ -116,12 +132,6 @@ int EDA_3D_CONTROLLER::UpdateMenu( const TOOL_EVENT& aEvent )
int EDA_3D_CONTROLLER::Main( const TOOL_EVENT& aEvent )
{
// Track right mouse button state and movement
VECTOR2D rightButtonDownPos;
const int DRAG_THRESHOLD = 4; // pixels
bool rightButtonDragged = false;
// Main loop: keep receiving events
while( TOOL_EVENT* evt = Wait() )
{
@ -247,8 +257,7 @@ int EDA_3D_CONTROLLER::ToggleVisibility( const TOOL_EVENT& aEvent )
auto flipLayer =
[&]( int layer )
{
appearanceManager->OnLayerVisibilityChanged( layer,
!visibilityFlags.test( layer ) );
appearanceManager->OnLayerVisibilityChanged( layer, !visibilityFlags.test( layer ) );
};
EDA_BASE_FRAME* frame = dynamic_cast<EDA_BASE_FRAME*>( m_toolMgr->GetToolHolder() );
@ -258,20 +267,13 @@ int EDA_3D_CONTROLLER::ToggleVisibility( const TOOL_EVENT& aEvent )
if( appearanceManager )
{
if( aEvent.IsAction( &EDA_3D_ACTIONS::showTHT ) )
flipLayer( LAYER_3D_TH_MODELS );
else if( aEvent.IsAction( &EDA_3D_ACTIONS::showSMD ) )
flipLayer( LAYER_3D_SMD_MODELS );
else if( aEvent.IsAction( &EDA_3D_ACTIONS::showVirtual ) )
flipLayer( LAYER_3D_VIRTUAL_MODELS );
else if( aEvent.IsAction( &EDA_3D_ACTIONS::showNotInPosFile ) )
flipLayer( LAYER_3D_MODELS_NOT_IN_POS );
else if( aEvent.IsAction( &EDA_3D_ACTIONS::showDNP ) )
flipLayer( LAYER_3D_MODELS_MARKED_DNP );
else if( aEvent.IsAction( &EDA_3D_ACTIONS::showNavigator ) )
flipLayer( LAYER_3D_NAVIGATOR );
else if( aEvent.IsAction( &EDA_3D_ACTIONS::showBBoxes ) )
flipLayer( LAYER_3D_BOUNDING_BOXES );
if( aEvent.IsAction( &EDA_3D_ACTIONS::showTHT ) ) flipLayer( LAYER_3D_TH_MODELS );
else if( aEvent.IsAction( &EDA_3D_ACTIONS::showSMD ) ) flipLayer( LAYER_3D_SMD_MODELS );
else if( aEvent.IsAction( &EDA_3D_ACTIONS::showVirtual ) ) flipLayer( LAYER_3D_VIRTUAL_MODELS );
else if( aEvent.IsAction( &EDA_3D_ACTIONS::showNotInPosFile ) ) flipLayer( LAYER_3D_MODELS_NOT_IN_POS );
else if( aEvent.IsAction( &EDA_3D_ACTIONS::showDNP ) ) flipLayer( LAYER_3D_MODELS_MARKED_DNP );
else if( aEvent.IsAction( &EDA_3D_ACTIONS::showNavigator ) ) flipLayer( LAYER_3D_NAVIGATOR );
else if( aEvent.IsAction( &EDA_3D_ACTIONS::showBBoxes ) ) flipLayer( LAYER_3D_BOUNDING_BOXES );
}
return 0;
@ -325,8 +327,7 @@ int EDA_3D_CONTROLLER::doZoomInOut( bool aDirection, bool aCenterOnCursor )
{
if( m_canvas )
{
m_canvas->SetView3D( aDirection ? VIEW3D_TYPE::VIEW3D_ZOOM_IN
: VIEW3D_TYPE::VIEW3D_ZOOM_OUT );
m_canvas->SetView3D( aDirection ? VIEW3D_TYPE::VIEW3D_ZOOM_IN : VIEW3D_TYPE::VIEW3D_ZOOM_OUT );
m_canvas->DisplayStatus();
}

View File

@ -22,8 +22,7 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#ifndef _3D_VIEWER_CONTROL_H
#define _3D_VIEWER_CONTROL_H
#pragma once
#include <tool/tool_interactive.h>
@ -38,12 +37,12 @@ class BOARD_ADAPTER;
class EDA_3D_CONTROLLER : public TOOL_INTERACTIVE
{
public:
EDA_3D_CONTROLLER()
: TOOL_INTERACTIVE( "3DViewer.Control" ),
m_canvas( nullptr ),
m_boardAdapter( nullptr ),
m_camera( nullptr ),
m_rotationIncrement( 10.0 )
EDA_3D_CONTROLLER() :
TOOL_INTERACTIVE( "3DViewer.Control" ),
m_canvas( nullptr ),
m_boardAdapter( nullptr ),
m_camera( nullptr ),
m_rotationIncrement( 10.0 )
{ }
~EDA_3D_CONTROLLER() override { }
@ -63,20 +62,8 @@ public:
*
* @param aRotIncrement is the rotation increment in degrees
*/
void SetRotationIncrement( double aRotIncrement )
{
m_rotationIncrement = aRotIncrement;
}
/**
* Get the increment used by the RotateView actions.
*
* @return the rotation increment in degrees
*/
double GetRotationIncrement()
{
return m_rotationIncrement;
}
void SetRotationIncrement( double aRotIncrement ) { m_rotationIncrement = aRotIncrement; }
double GetRotationIncrement() { return m_rotationIncrement; }
// View controls
int ZoomRedraw( const TOOL_EVENT& aEvent );
@ -112,5 +99,3 @@ private:
CAMERA* m_camera;
double m_rotationIncrement; ///< Rotation increment for the rotate actions (degrees)
};
#endif

View File

@ -48,6 +48,7 @@ project( kicad )
# Create a default build type for our QA that doesn't include `NDEBUG`
set(CMAKE_CXX_FLAGS_QABUILD "-Os -g1 -ggdb1")
string( APPEND CMAKE_EXE_LINKER_FLAGS_QABUILD " -rdynamic" )
include( GNUInstallDirs )
include( CMakeDependentOption )
@ -193,7 +194,12 @@ option( KICAD_I18N_UNIX_STRICT_PATH
cmake_dependent_option( KICAD_WIN32_INSTALL_PDBS
"Installs debug pdb to the bin folder, DO NOT USE (NOR REQUIRED) FOR DEBUGGING THE SOURCE ON MSVC. This is purely for release building.
MSVC can find the PDBs without this."
OFF "WIN32"
OFF "MSVC"
OFF )
cmake_dependent_option( KICAD_MSVC_DYNDEOPT
"Builds release builds with /dynamicdeopt for dynamic debugging."
OFF "MSVC"
OFF )
####################################
@ -557,6 +563,11 @@ if( MSVC )
# but we want to turn it on to enable debug performance improvements available under C++17 in MSVC 17.5+
string( APPEND CMAKE_CXX_FLAGS " /permissive-" )
if( KICAD_MSVC_DYNDEOPT )
string( APPEND CMAKE_CXX_FLAGS_RELEASE " /dynamicdeopt" )
string( APPEND CMAKE_CXX_FLAGS_RELWITHDEBINFO " /dynamicdeopt" )
endif()
# Exception handling
# Remove the potential default EHsc option cmake doesn't allow us to remove easily
string( REPLACE "/EHsc" "" CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS} )
@ -585,11 +596,20 @@ if( MSVC )
# /DEBUG: create PDB
string( APPEND CMAKE_${type}_LINKER_FLAGS " /DEBUG /MANIFEST:NO" )
# /OPT:REF: omit unreferenced code
string( APPEND CMAKE_${type}_LINKER_FLAGS_RELEASE " /OPT:REF /MANIFEST:NO" )
string( APPEND CMAKE_${type}_LINKER_FLAGS_RELWITHDEBINFO " /OPT:REF /MANIFEST:NO" )
# /OPT:ICF: fold common data
string( APPEND CMAKE_${type}_LINKER_FLAGS_RELEASE " /OPT:ICF /MANIFEST:NO" )
string( APPEND CMAKE_${type}_LINKER_FLAGS_RELWITHDEBINFO " /OPT:ICF /MANIFEST:NO" )
string( APPEND CMAKE_${type}_LINKER_FLAGS_RELEASE " /OPT:REF" )
string( APPEND CMAKE_${type}_LINKER_FLAGS_RELWITHDEBINFO " /OPT:REF" )
# /MANIFEST:NO
string( APPEND CMAKE_${type}_LINKER_FLAGS_RELEASE " /MANIFEST:NO" )
string( APPEND CMAKE_${type}_LINKER_FLAGS_RELWITHDEBINFO " /MANIFEST:NO" )
if( KICAD_MSVC_DYNDEOPT )
string( APPEND CMAKE_${type}_LINKER_FLAGS_RELEASE " /dynamicdeopt" )
string( APPEND CMAKE_${type}_LINKER_FLAGS_RELWITHDEBINFO " /dynamicdeopt" )
else()
# /OPT:ICF: fold common data
string( APPEND CMAKE_${type}_LINKER_FLAGS_RELEASE " /OPT:ICF" )
string( APPEND CMAKE_${type}_LINKER_FLAGS_RELWITHDEBINFO " /OPT:ICF" )
endif()
if( KICAD_WIN32_LTCG )
# we are implementing this manually because CMake's LTCG option is incomplete
@ -598,6 +618,11 @@ if( MSVC )
endif()
endforeach()
if( KICAD_MSVC_DYNDEOPT )
string( APPEND CMAKE_STATIC_LINKER_FLAGS_RELEASE " /dynamicdeopt" )
string( APPEND CMAKE_STATIC_LINKER_FLAGS_RELWITHDEBINFO " /dynamicdeopt" )
endif()
# Let cl.exe parallelize builds
if( KICAD_WIN32_BUILD_PARALLEL_CL_MP )
string( APPEND CMAKE_CXX_FLAGS " /MP" )

View File

@ -371,6 +371,7 @@ message GraphicRectangleAttributes
{
kiapi.common.types.Vector2 top_left = 1;
kiapi.common.types.Vector2 bottom_right = 2;
kiapi.common.types.Distance corner_radius = 3;
}
message GraphicArcAttributes

View File

@ -387,8 +387,6 @@ void BITMAPCONV_INFO::createOutputData( const wxString& aLayer )
potrace_dpoint_t( *c )[3];
LOCALE_IO toggle; // Temporary switch the locale to standard C to r/w floats
// The layer name has meaning only for .kicad_mod files.
// For these files the header creates 2 invisible texts: value and ref
// (needed but not useful) on silk screen layer

View File

@ -103,6 +103,8 @@ set( KICOMMON_SRCS
jobs/job_sch_erc.cpp
jobs/job_sym_export_svg.cpp
jobs/job_sym_upgrade.cpp
jobs/job_pcb_upgrade.cpp
jobs/job_sch_upgrade.cpp
kicad_curl/kicad_curl.cpp
kicad_curl/kicad_curl_easy.cpp
@ -128,6 +130,9 @@ set( KICOMMON_SRCS
project/project_local_settings.cpp
project/time_domain_parameters.cpp
text_eval/text_eval_wrapper.cpp
text_eval/text_eval_parser.cpp
# This is basically a settings object, but for the toolbar
tool/ui/toolbar_configuration.cpp
@ -269,6 +274,7 @@ target_link_libraries( kicommon
kiplatform
nlohmann_json
nlohmann_json_schema_validator
FastFloat::fast_float
fmt::fmt
CURL::libcurl
picosha2
@ -430,10 +436,12 @@ set( COMMON_DLG_SRCS
dialogs/panel_design_block_lib_table.cpp
dialogs/panel_embedded_files.cpp
dialogs/panel_embedded_files_base.cpp
dialogs/panel_gal_display_options.cpp
dialogs/panel_base_display_options.cpp
dialogs/panel_hotkeys_editor.cpp
dialogs/panel_image_editor.cpp
dialogs/panel_image_editor_base.cpp
dialogs/panel_gal_options.cpp
dialogs/panel_gal_options_base.cpp
dialogs/panel_grid_settings.cpp
dialogs/panel_grid_settings_base.cpp
dialogs/panel_maintenance.cpp
@ -477,8 +485,6 @@ set( COMMON_WIDGET_SRCS
widgets/footprint_diff_widget.cpp
widgets/footprint_preview_widget.cpp
widgets/footprint_select_widget.cpp
widgets/gal_options_panel.cpp
widgets/gal_options_panel_base.cpp
widgets/grid_bitmap_toggle.cpp
widgets/grid_button.cpp
widgets/grid_checkbox.cpp
@ -523,6 +529,7 @@ set( COMMON_WIDGET_SRCS
widgets/wx_splitter_window.cpp
widgets/wx_treebook.cpp
widgets/webview_panel.cpp
widgets/zoom_correction_ctrl.cpp
)
set( COMMON_DRAWING_SHEET_SRCS
@ -538,6 +545,7 @@ set( COMMON_DRAWING_SHEET_SRCS
set( COMMON_PREVIEW_ITEMS_SRCS
preview_items/anchor_debug.cpp
preview_items/angle_item.cpp
preview_items/arc_assistant.cpp
preview_items/arc_geom_manager.cpp
preview_items/bezier_assistant.cpp
@ -625,7 +633,8 @@ set( COMMON_GIT_SRCS
git/project_git_utils.cpp
git/kicad_git_common.cpp
git/kicad_git_errors.cpp
git/project_git_utils.cpp
git/git_backend.cpp
git/libgit_backend.cpp
)
set( COMMON_SRCS
@ -872,11 +881,13 @@ set( PCB_COMMON_SRCS
${CMAKE_SOURCE_DIR}/pcbnew/pcb_marker.cpp
${CMAKE_SOURCE_DIR}/pcbnew/footprint.cpp
${CMAKE_SOURCE_DIR}/pcbnew/fix_board_shape.cpp
${CMAKE_SOURCE_DIR}/pcbnew/layer_utils.cpp
${CMAKE_SOURCE_DIR}/pcbnew/netinfo_item.cpp
${CMAKE_SOURCE_DIR}/pcbnew/netinfo_list.cpp
${CMAKE_SOURCE_DIR}/pcbnew/pad.cpp
${CMAKE_SOURCE_DIR}/pcbnew/pad_utils.cpp
${CMAKE_SOURCE_DIR}/pcbnew/padstack.cpp
${CMAKE_SOURCE_DIR}/pcbnew/pcb_point.cpp
${CMAKE_SOURCE_DIR}/pcbnew/pcb_target.cpp
${CMAKE_SOURCE_DIR}/pcbnew/pcb_reference_image.cpp
${CMAKE_SOURCE_DIR}/pcbnew/pcb_field.cpp
@ -1007,6 +1018,13 @@ generate_lemon_grammar(
libeval_compiler/grammar.lemon
)
generate_lemon_grammar(
kicommon
text_eval
text_eval/text_eval_wrapper.cpp
text_eval/text_eval.lemon
)
# auto-generate stroke_params_lexer.h and stroke_params_keywords.cpp
# Called twice one for common and one for gal, to ensure the files are created
# on all devel tools ( Linux and msys2 )

View File

@ -119,6 +119,7 @@ static const wxChar EnableExtensionSnaps[] = wxT( "EnableExtensionSnaps" );
static const wxChar ExtensionSnapTimeoutMs[] = wxT( "ExtensionSnapTimeoutMs" );
static const wxChar ExtensionSnapActivateOnHover[] = wxT( "ExtensionSnapActivateOnHover" );
static const wxChar EnableSnapAnchorsDebug[] = wxT( "EnableSnapAnchorsDebug" );
static const wxChar SnapHysteresis[] = wxT( "SnapHysteresis" );
static const wxChar MinParallelAngle[] = wxT( "MinParallelAngle" );
static const wxChar HoleWallPaintingMultiplier[] = wxT( "HoleWallPaintingMultiplier" );
static const wxChar MsgPanelShowUuids[] = wxT( "MsgPanelShowUuids" );
@ -131,6 +132,7 @@ static const wxChar ConfigurableToolbars[] = wxT( "ConfigurableToolbars" );
static const wxChar MaxPastedTextLength[] = wxT( "MaxPastedTextLength" );
static const wxChar PNSProcessClusterTimeout[] = wxT( "PNSProcessClusterTimeout" );
static const wxChar ImportSkipComponentBodies[] = wxT( "ImportSkipComponentBodies" );
static const wxChar ScreenDPI[] = wxT( "ScreenDPI" );
} // namespace KEYS
@ -260,7 +262,7 @@ ADVANCED_CFG::ADVANCED_CFG()
m_CompactSave = false;
m_UpdateUIEventInterval = 0;
m_ShowRepairSchematic = false;
m_EnablePcbDesignBlocks = false;
m_EnablePcbDesignBlocks = true;
m_EnableGenerators = false;
m_EnableLibWithText = false;
m_EnableLibDir = false;
@ -298,6 +300,7 @@ ADVANCED_CFG::ADVANCED_CFG()
m_ExtensionSnapTimeoutMs = 500;
m_ExtensionSnapActivateOnHover = true;
m_EnableSnapAnchorsDebug = false;
m_SnapHysteresis = 5;
m_MinParallelAngle = 0.001;
m_HoleWallPaintingMultiplier = 1.5;
@ -320,6 +323,8 @@ ADVANCED_CFG::ADVANCED_CFG()
m_ImportSkipComponentBodies = false;
m_ScreenDPI = 91;
loadFromConfigFile();
}
@ -589,6 +594,10 @@ void ADVANCED_CFG::loadSettings( wxConfigBase& aCfg )
&m_EnableSnapAnchorsDebug,
m_EnableSnapAnchorsDebug ) );
m_entries.push_back( std::make_unique<PARAM_CFG_INT>( true, AC_KEYS::SnapHysteresis,
&m_SnapHysteresis, m_SnapHysteresis,
0, 100 ) );
m_entries.push_back( std::make_unique<PARAM_CFG_DOUBLE>( true, AC_KEYS::MinParallelAngle,
&m_MinParallelAngle, m_MinParallelAngle,
0.0, 45.0 ) );
@ -634,6 +643,10 @@ void ADVANCED_CFG::loadSettings( wxConfigBase& aCfg )
&m_ImportSkipComponentBodies,
m_ImportSkipComponentBodies ) );
m_entries.push_back( std::make_unique<PARAM_CFG_INT>( true, AC_KEYS::ScreenDPI,
&m_ScreenDPI, m_ScreenDPI,
50, 500 ) );
// Special case for trace mask setting...we just grab them and set them immediately
// Because we even use wxLogTrace inside of advanced config
m_entries.push_back( std::make_unique<PARAM_CFG_WXSTRING>( true, AC_KEYS::TraceMasks, &m_traceMasks,

View File

@ -397,6 +397,7 @@ void BuildBitmapInfo( std::unordered_map<BITMAPS, std::vector<BITMAP_INFO>>& aBi
aBitmapInfoCache[BITMAPS::add_line].emplace_back( BITMAPS::add_line, wxT( "add_line_24.png" ), 24, wxT( "light" ) );
aBitmapInfoCache[BITMAPS::add_orthogonal_dimension].emplace_back( BITMAPS::add_orthogonal_dimension, wxT( "add_orthogonal_dimension_24.png" ), 24, wxT( "light" ) );
aBitmapInfoCache[BITMAPS::add_pcb_target].emplace_back( BITMAPS::add_pcb_target, wxT( "add_pcb_target_24.png" ), 24, wxT( "light" ) );
aBitmapInfoCache[BITMAPS::add_point].emplace_back( BITMAPS::add_point, wxT( "add_point_24.png" ), 24, wxT( "light" ) );
aBitmapInfoCache[BITMAPS::add_power].emplace_back( BITMAPS::add_power, wxT( "add_power_24.png" ), 24, wxT( "light" ) );
aBitmapInfoCache[BITMAPS::add_radial_dimension].emplace_back( BITMAPS::add_radial_dimension, wxT( "add_radial_dimension_24.png" ), 24, wxT( "light" ) );
aBitmapInfoCache[BITMAPS::add_rectangle].emplace_back( BITMAPS::add_rectangle, wxT( "add_rectangle_24.png" ), 24, wxT( "light" ) );
@ -836,6 +837,7 @@ void BuildBitmapInfo( std::unordered_map<BITMAPS, std::vector<BITMAP_INFO>>& aBi
aBitmapInfoCache[BITMAPS::add_line].emplace_back( BITMAPS::add_line, wxT( "add_line_dark_24.png" ), 24, wxT( "dark" ) );
aBitmapInfoCache[BITMAPS::add_orthogonal_dimension].emplace_back( BITMAPS::add_orthogonal_dimension, wxT( "add_orthogonal_dimension_dark_24.png" ), 24, wxT( "dark" ) );
aBitmapInfoCache[BITMAPS::add_pcb_target].emplace_back( BITMAPS::add_pcb_target, wxT( "add_pcb_target_dark_24.png" ), 24, wxT( "dark" ) );
aBitmapInfoCache[BITMAPS::add_point].emplace_back( BITMAPS::add_point, wxT( "add_point_dark_24.png" ), 24, wxT( "dark" ) );
aBitmapInfoCache[BITMAPS::add_power].emplace_back( BITMAPS::add_power, wxT( "add_power_dark_24.png" ), 24, wxT( "dark" ) );
aBitmapInfoCache[BITMAPS::add_radial_dimension].emplace_back( BITMAPS::add_radial_dimension, wxT( "add_radial_dimension_dark_24.png" ), 24, wxT( "dark" ) );
aBitmapInfoCache[BITMAPS::add_rectangle].emplace_back( BITMAPS::add_rectangle, wxT( "add_rectangle_dark_24.png" ), 24, wxT( "dark" ) );
@ -1275,6 +1277,7 @@ void BuildBitmapInfo( std::unordered_map<BITMAPS, std::vector<BITMAP_INFO>>& aBi
aBitmapInfoCache[BITMAPS::add_line].emplace_back( BITMAPS::add_line, wxT( "add_line_16.png" ), 16, wxT( "light" ) );
aBitmapInfoCache[BITMAPS::add_orthogonal_dimension].emplace_back( BITMAPS::add_orthogonal_dimension, wxT( "add_orthogonal_dimension_16.png" ), 16, wxT( "light" ) );
aBitmapInfoCache[BITMAPS::add_pcb_target].emplace_back( BITMAPS::add_pcb_target, wxT( "add_pcb_target_16.png" ), 16, wxT( "light" ) );
aBitmapInfoCache[BITMAPS::add_point].emplace_back( BITMAPS::add_point, wxT( "add_point_16.png" ), 16, wxT( "light" ) );
aBitmapInfoCache[BITMAPS::add_power].emplace_back( BITMAPS::add_power, wxT( "add_power_16.png" ), 16, wxT( "light" ) );
aBitmapInfoCache[BITMAPS::add_radial_dimension].emplace_back( BITMAPS::add_radial_dimension, wxT( "add_radial_dimension_16.png" ), 16, wxT( "light" ) );
aBitmapInfoCache[BITMAPS::add_rectangle].emplace_back( BITMAPS::add_rectangle, wxT( "add_rectangle_16.png" ), 16, wxT( "light" ) );
@ -1714,6 +1717,7 @@ void BuildBitmapInfo( std::unordered_map<BITMAPS, std::vector<BITMAP_INFO>>& aBi
aBitmapInfoCache[BITMAPS::add_line].emplace_back( BITMAPS::add_line, wxT( "add_line_dark_16.png" ), 16, wxT( "dark" ) );
aBitmapInfoCache[BITMAPS::add_orthogonal_dimension].emplace_back( BITMAPS::add_orthogonal_dimension, wxT( "add_orthogonal_dimension_dark_16.png" ), 16, wxT( "dark" ) );
aBitmapInfoCache[BITMAPS::add_pcb_target].emplace_back( BITMAPS::add_pcb_target, wxT( "add_pcb_target_dark_16.png" ), 16, wxT( "dark" ) );
aBitmapInfoCache[BITMAPS::add_point].emplace_back( BITMAPS::add_point, wxT( "add_point_dark_16.png" ), 16, wxT( "dark" ) );
aBitmapInfoCache[BITMAPS::add_power].emplace_back( BITMAPS::add_power, wxT( "add_power_dark_16.png" ), 16, wxT( "dark" ) );
aBitmapInfoCache[BITMAPS::add_radial_dimension].emplace_back( BITMAPS::add_radial_dimension, wxT( "add_radial_dimension_dark_16.png" ), 16, wxT( "dark" ) );
aBitmapInfoCache[BITMAPS::add_rectangle].emplace_back( BITMAPS::add_rectangle, wxT( "add_rectangle_dark_16.png" ), 16, wxT( "dark" ) );
@ -2153,6 +2157,7 @@ void BuildBitmapInfo( std::unordered_map<BITMAPS, std::vector<BITMAP_INFO>>& aBi
aBitmapInfoCache[BITMAPS::add_line].emplace_back( BITMAPS::add_line, wxT( "add_line_32.png" ), 32, wxT( "light" ) );
aBitmapInfoCache[BITMAPS::add_orthogonal_dimension].emplace_back( BITMAPS::add_orthogonal_dimension, wxT( "add_orthogonal_dimension_32.png" ), 32, wxT( "light" ) );
aBitmapInfoCache[BITMAPS::add_pcb_target].emplace_back( BITMAPS::add_pcb_target, wxT( "add_pcb_target_32.png" ), 32, wxT( "light" ) );
aBitmapInfoCache[BITMAPS::add_point].emplace_back( BITMAPS::add_point, wxT( "add_point_32.png" ), 32, wxT( "light" ) );
aBitmapInfoCache[BITMAPS::add_power].emplace_back( BITMAPS::add_power, wxT( "add_power_32.png" ), 32, wxT( "light" ) );
aBitmapInfoCache[BITMAPS::add_radial_dimension].emplace_back( BITMAPS::add_radial_dimension, wxT( "add_radial_dimension_32.png" ), 32, wxT( "light" ) );
aBitmapInfoCache[BITMAPS::add_rectangle].emplace_back( BITMAPS::add_rectangle, wxT( "add_rectangle_32.png" ), 32, wxT( "light" ) );
@ -2592,6 +2597,7 @@ void BuildBitmapInfo( std::unordered_map<BITMAPS, std::vector<BITMAP_INFO>>& aBi
aBitmapInfoCache[BITMAPS::add_line].emplace_back( BITMAPS::add_line, wxT( "add_line_dark_32.png" ), 32, wxT( "dark" ) );
aBitmapInfoCache[BITMAPS::add_orthogonal_dimension].emplace_back( BITMAPS::add_orthogonal_dimension, wxT( "add_orthogonal_dimension_dark_32.png" ), 32, wxT( "dark" ) );
aBitmapInfoCache[BITMAPS::add_pcb_target].emplace_back( BITMAPS::add_pcb_target, wxT( "add_pcb_target_dark_32.png" ), 32, wxT( "dark" ) );
aBitmapInfoCache[BITMAPS::add_point].emplace_back( BITMAPS::add_point, wxT( "add_point_dark_32.png" ), 32, wxT( "dark" ) );
aBitmapInfoCache[BITMAPS::add_power].emplace_back( BITMAPS::add_power, wxT( "add_power_dark_32.png" ), 32, wxT( "dark" ) );
aBitmapInfoCache[BITMAPS::add_radial_dimension].emplace_back( BITMAPS::add_radial_dimension, wxT( "add_radial_dimension_dark_32.png" ), 32, wxT( "dark" ) );
aBitmapInfoCache[BITMAPS::add_rectangle].emplace_back( BITMAPS::add_rectangle, wxT( "add_rectangle_dark_32.png" ), 32, wxT( "dark" ) );
@ -3031,6 +3037,7 @@ void BuildBitmapInfo( std::unordered_map<BITMAPS, std::vector<BITMAP_INFO>>& aBi
aBitmapInfoCache[BITMAPS::add_line].emplace_back( BITMAPS::add_line, wxT( "add_line_48.png" ), 48, wxT( "light" ) );
aBitmapInfoCache[BITMAPS::add_orthogonal_dimension].emplace_back( BITMAPS::add_orthogonal_dimension, wxT( "add_orthogonal_dimension_48.png" ), 48, wxT( "light" ) );
aBitmapInfoCache[BITMAPS::add_pcb_target].emplace_back( BITMAPS::add_pcb_target, wxT( "add_pcb_target_48.png" ), 48, wxT( "light" ) );
aBitmapInfoCache[BITMAPS::add_point].emplace_back( BITMAPS::add_point, wxT( "add_point_48.png" ), 48, wxT( "light" ) );
aBitmapInfoCache[BITMAPS::add_power].emplace_back( BITMAPS::add_power, wxT( "add_power_48.png" ), 48, wxT( "light" ) );
aBitmapInfoCache[BITMAPS::add_radial_dimension].emplace_back( BITMAPS::add_radial_dimension, wxT( "add_radial_dimension_48.png" ), 48, wxT( "light" ) );
aBitmapInfoCache[BITMAPS::add_rectangle].emplace_back( BITMAPS::add_rectangle, wxT( "add_rectangle_48.png" ), 48, wxT( "light" ) );
@ -3470,6 +3477,7 @@ void BuildBitmapInfo( std::unordered_map<BITMAPS, std::vector<BITMAP_INFO>>& aBi
aBitmapInfoCache[BITMAPS::add_line].emplace_back( BITMAPS::add_line, wxT( "add_line_dark_48.png" ), 48, wxT( "dark" ) );
aBitmapInfoCache[BITMAPS::add_orthogonal_dimension].emplace_back( BITMAPS::add_orthogonal_dimension, wxT( "add_orthogonal_dimension_dark_48.png" ), 48, wxT( "dark" ) );
aBitmapInfoCache[BITMAPS::add_pcb_target].emplace_back( BITMAPS::add_pcb_target, wxT( "add_pcb_target_dark_48.png" ), 48, wxT( "dark" ) );
aBitmapInfoCache[BITMAPS::add_point].emplace_back( BITMAPS::add_point, wxT( "add_point_dark_48.png" ), 48, wxT( "dark" ) );
aBitmapInfoCache[BITMAPS::add_power].emplace_back( BITMAPS::add_power, wxT( "add_power_dark_48.png" ), 48, wxT( "dark" ) );
aBitmapInfoCache[BITMAPS::add_radial_dimension].emplace_back( BITMAPS::add_radial_dimension, wxT( "add_radial_dimension_dark_48.png" ), 48, wxT( "dark" ) );
aBitmapInfoCache[BITMAPS::add_rectangle].emplace_back( BITMAPS::add_rectangle, wxT( "add_rectangle_dark_48.png" ), 48, wxT( "dark" ) );
@ -3909,6 +3917,7 @@ void BuildBitmapInfo( std::unordered_map<BITMAPS, std::vector<BITMAP_INFO>>& aBi
aBitmapInfoCache[BITMAPS::add_line].emplace_back( BITMAPS::add_line, wxT( "add_line_64.png" ), 64, wxT( "light" ) );
aBitmapInfoCache[BITMAPS::add_orthogonal_dimension].emplace_back( BITMAPS::add_orthogonal_dimension, wxT( "add_orthogonal_dimension_64.png" ), 64, wxT( "light" ) );
aBitmapInfoCache[BITMAPS::add_pcb_target].emplace_back( BITMAPS::add_pcb_target, wxT( "add_pcb_target_64.png" ), 64, wxT( "light" ) );
aBitmapInfoCache[BITMAPS::add_point].emplace_back( BITMAPS::add_point, wxT( "add_point_64.png" ), 64, wxT( "light" ) );
aBitmapInfoCache[BITMAPS::add_power].emplace_back( BITMAPS::add_power, wxT( "add_power_64.png" ), 64, wxT( "light" ) );
aBitmapInfoCache[BITMAPS::add_radial_dimension].emplace_back( BITMAPS::add_radial_dimension, wxT( "add_radial_dimension_64.png" ), 64, wxT( "light" ) );
aBitmapInfoCache[BITMAPS::add_rectangle].emplace_back( BITMAPS::add_rectangle, wxT( "add_rectangle_64.png" ), 64, wxT( "light" ) );
@ -4348,6 +4357,7 @@ void BuildBitmapInfo( std::unordered_map<BITMAPS, std::vector<BITMAP_INFO>>& aBi
aBitmapInfoCache[BITMAPS::add_line].emplace_back( BITMAPS::add_line, wxT( "add_line_dark_64.png" ), 64, wxT( "dark" ) );
aBitmapInfoCache[BITMAPS::add_orthogonal_dimension].emplace_back( BITMAPS::add_orthogonal_dimension, wxT( "add_orthogonal_dimension_dark_64.png" ), 64, wxT( "dark" ) );
aBitmapInfoCache[BITMAPS::add_pcb_target].emplace_back( BITMAPS::add_pcb_target, wxT( "add_pcb_target_dark_64.png" ), 64, wxT( "dark" ) );
aBitmapInfoCache[BITMAPS::add_point].emplace_back( BITMAPS::add_point, wxT( "add_point_dark_64.png" ), 64, wxT( "dark" ) );
aBitmapInfoCache[BITMAPS::add_power].emplace_back( BITMAPS::add_power, wxT( "add_power_dark_64.png" ), 64, wxT( "dark" ) );
aBitmapInfoCache[BITMAPS::add_radial_dimension].emplace_back( BITMAPS::add_radial_dimension, wxT( "add_radial_dimension_dark_64.png" ), 64, wxT( "dark" ) );
aBitmapInfoCache[BITMAPS::add_rectangle].emplace_back( BITMAPS::add_rectangle, wxT( "add_rectangle_dark_64.png" ), 64, wxT( "dark" ) );

View File

@ -24,6 +24,7 @@
#include "clipboard.h"
#include <wx/clipbrd.h>
#include <wx/dataobj.h>
#include <wx/image.h>
#include <wx/log.h>
#include <wx/string.h>
@ -90,10 +91,10 @@ std::unique_ptr<wxImage> GetImageFromClipboard()
{
if( wxTheClipboard->IsSupported( wxDF_BITMAP ) )
{
wxImageDataObject data;
wxBitmapDataObject data;
if( wxTheClipboard->GetData( data ) )
{
image = std::make_unique<wxImage>( data.GetImage() );
image = std::make_unique<wxImage>( data.GetBitmap().ConvertToImage() );
}
}
else if( wxTheClipboard->IsSupported( wxDF_FILENAME ) )

View File

@ -190,7 +190,7 @@ void DESIGN_BLOCK_LIST_IMPL::loadDesignBlocks()
};
for( size_t ii = 0; ii < num_elements; ++ii )
returns[ii] = tp.submit( db_thread );
returns[ii] = tp.submit_task( db_thread );
for( const std::future<size_t>& ret : returns )
{

View File

@ -41,6 +41,9 @@
#include <wx/app.h>
#include <wx/event.h>
#include <wx/grid.h>
#include <wx/propgrid/propgrid.h>
#include <wx/checklst.h>
#include <wx/dataview.h>
#include <wx/bmpbuttn.h>
#include <wx/textctrl.h>
#include <wx/stc/stc.h>
@ -79,7 +82,8 @@ DIALOG_SHIM::DIALOG_SHIM( wxWindow* aParent, wxWindowID id, const wxString& titl
m_qmodal_parent_disabler( nullptr ),
m_parentFrame( nullptr ),
m_userPositioned( false ),
m_userResized( false )
m_userResized( false ),
m_handlingUndoRedo( false )
{
KIWAY_HOLDER* kiwayHolder = nullptr;
m_initialSize = size;
@ -174,6 +178,75 @@ DIALOG_SHIM::~DIALOG_SHIM()
disconnectFocusHandlers( GetChildren() );
std::function<void( wxWindowList& )> disconnectUndoRedoHandlers =
[&]( wxWindowList& children )
{
for( wxWindow* child : children )
{
if( wxTextCtrl* textCtrl = dynamic_cast<wxTextCtrl*>( child ) )
{
textCtrl->Unbind( wxEVT_TEXT, &DIALOG_SHIM::onCommandEvent, this );
}
else if( wxStyledTextCtrl* scintilla = dynamic_cast<wxStyledTextCtrl*>( child ) )
{
scintilla->Unbind( wxEVT_STC_CHANGE, &DIALOG_SHIM::onStyledTextChanged, this );
}
else if( wxComboBox* combo = dynamic_cast<wxComboBox*>( child ) )
{
combo->Unbind( wxEVT_TEXT, &DIALOG_SHIM::onCommandEvent, this );
combo->Unbind( wxEVT_COMBOBOX, &DIALOG_SHIM::onCommandEvent, this );
}
else if( wxChoice* choice = dynamic_cast<wxChoice*>( child ) )
{
choice->Unbind( wxEVT_CHOICE, &DIALOG_SHIM::onCommandEvent, this );
}
else if( wxCheckBox* check = dynamic_cast<wxCheckBox*>( child ) )
{
check->Unbind( wxEVT_CHECKBOX, &DIALOG_SHIM::onCommandEvent, this );
}
else if( wxSpinCtrl* spin = dynamic_cast<wxSpinCtrl*>( child ) )
{
spin->Unbind( wxEVT_SPINCTRL, &DIALOG_SHIM::onSpinEvent, this );
spin->Unbind( wxEVT_TEXT, &DIALOG_SHIM::onCommandEvent, this );
}
else if( wxSpinCtrlDouble* spinD = dynamic_cast<wxSpinCtrlDouble*>( child ) )
{
spinD->Unbind( wxEVT_SPINCTRLDOUBLE, &DIALOG_SHIM::onSpinDoubleEvent, this );
spinD->Unbind( wxEVT_TEXT, &DIALOG_SHIM::onCommandEvent, this );
}
else if( wxRadioButton* radio = dynamic_cast<wxRadioButton*>( child ) )
{
radio->Unbind( wxEVT_RADIOBUTTON, &DIALOG_SHIM::onCommandEvent, this );
}
else if( wxRadioBox* radioBox = dynamic_cast<wxRadioBox*>( child ) )
{
radioBox->Unbind( wxEVT_RADIOBOX, &DIALOG_SHIM::onCommandEvent, this );
}
else if( wxGrid* grid = dynamic_cast<wxGrid*>( child ) )
{
grid->Unbind( wxEVT_GRID_CELL_CHANGED, &DIALOG_SHIM::onGridCellChanged, this );
}
else if( wxPropertyGrid* propGrid = dynamic_cast<wxPropertyGrid*>( child ) )
{
propGrid->Unbind( wxEVT_PG_CHANGED, &DIALOG_SHIM::onPropertyGridChanged, this );
}
else if( wxCheckListBox* checkList = dynamic_cast<wxCheckListBox*>( child ) )
{
checkList->Unbind( wxEVT_CHECKLISTBOX, &DIALOG_SHIM::onCommandEvent, this );
}
else if( wxDataViewListCtrl* dataList = dynamic_cast<wxDataViewListCtrl*>( child ) )
{
dataList->Unbind( wxEVT_DATAVIEW_ITEM_VALUE_CHANGED, &DIALOG_SHIM::onDataViewListChanged, this );
}
else
{
disconnectUndoRedoHandlers( child->GetChildren() );
}
}
};
disconnectUndoRedoHandlers( GetChildren() );
// if the dialog is quasi-modal, this will end its event loop
if( IsQuasiModal() )
EndQuasiModal( wxID_CANCEL );
@ -732,6 +805,373 @@ void DIALOG_SHIM::SelectAllInTextCtrls( wxWindowList& children )
}
void DIALOG_SHIM::registerUndoRedoHandlers( wxWindowList& children )
{
for( wxWindow* child : children )
{
if( wxTextCtrl* textCtrl = dynamic_cast<wxTextCtrl*>( child ) )
{
textCtrl->Bind( wxEVT_TEXT, &DIALOG_SHIM::onCommandEvent, this );
m_currentValues[ textCtrl ] = textCtrl->GetValue();
}
else if( wxStyledTextCtrl* scintilla = dynamic_cast<wxStyledTextCtrl*>( child ) )
{
scintilla->Bind( wxEVT_STC_CHANGE, &DIALOG_SHIM::onStyledTextChanged, this );
m_currentValues[ scintilla ] = scintilla->GetText();
}
else if( wxComboBox* combo = dynamic_cast<wxComboBox*>( child ) )
{
combo->Bind( wxEVT_TEXT, &DIALOG_SHIM::onCommandEvent, this );
combo->Bind( wxEVT_COMBOBOX, &DIALOG_SHIM::onCommandEvent, this );
m_currentValues[ combo ] = combo->GetValue();
}
else if( wxChoice* choice = dynamic_cast<wxChoice*>( child ) )
{
choice->Bind( wxEVT_CHOICE, &DIALOG_SHIM::onCommandEvent, this );
m_currentValues[ choice ] = static_cast<long>( choice->GetSelection() );
}
else if( wxCheckBox* check = dynamic_cast<wxCheckBox*>( child ) )
{
check->Bind( wxEVT_CHECKBOX, &DIALOG_SHIM::onCommandEvent, this );
m_currentValues[ check ] = check->GetValue();
}
else if( wxSpinCtrl* spin = dynamic_cast<wxSpinCtrl*>( child ) )
{
spin->Bind( wxEVT_SPINCTRL, &DIALOG_SHIM::onSpinEvent, this );
spin->Bind( wxEVT_TEXT, &DIALOG_SHIM::onCommandEvent, this );
m_currentValues[ spin ] = static_cast<long>( spin->GetValue() );
}
else if( wxSpinCtrlDouble* spinD = dynamic_cast<wxSpinCtrlDouble*>( child ) )
{
spinD->Bind( wxEVT_SPINCTRLDOUBLE, &DIALOG_SHIM::onSpinDoubleEvent, this );
spinD->Bind( wxEVT_TEXT, &DIALOG_SHIM::onCommandEvent, this );
m_currentValues[ spinD ] = spinD->GetValue();
}
else if( wxRadioButton* radio = dynamic_cast<wxRadioButton*>( child ) )
{
radio->Bind( wxEVT_RADIOBUTTON, &DIALOG_SHIM::onCommandEvent, this );
m_currentValues[ radio ] = radio->GetValue();
}
else if( wxRadioBox* radioBox = dynamic_cast<wxRadioBox*>( child ) )
{
radioBox->Bind( wxEVT_RADIOBOX, &DIALOG_SHIM::onCommandEvent, this );
m_currentValues[ radioBox ] = static_cast<long>( radioBox->GetSelection() );
}
else if( wxGrid* grid = dynamic_cast<wxGrid*>( child ) )
{
grid->Bind( wxEVT_GRID_CELL_CHANGED, &DIALOG_SHIM::onGridCellChanged, this );
m_currentValues[ grid ] = getControlValue( grid );
}
else if( wxPropertyGrid* propGrid = dynamic_cast<wxPropertyGrid*>( child ) )
{
propGrid->Bind( wxEVT_PG_CHANGED, &DIALOG_SHIM::onPropertyGridChanged, this );
m_currentValues[ propGrid ] = getControlValue( propGrid );
}
else if( wxCheckListBox* checkList = dynamic_cast<wxCheckListBox*>( child ) )
{
checkList->Bind( wxEVT_CHECKLISTBOX, &DIALOG_SHIM::onCommandEvent, this );
m_currentValues[ checkList ] = getControlValue( checkList );
}
else if( wxDataViewListCtrl* dataList = dynamic_cast<wxDataViewListCtrl*>( child ) )
{
dataList->Bind( wxEVT_DATAVIEW_ITEM_VALUE_CHANGED, &DIALOG_SHIM::onDataViewListChanged, this );
m_currentValues[ dataList ] = getControlValue( dataList );
}
else
{
registerUndoRedoHandlers( child->GetChildren() );
}
}
}
void DIALOG_SHIM::recordControlChange( wxWindow* aCtrl )
{
wxVariant before = m_currentValues[ aCtrl ];
wxVariant after = getControlValue( aCtrl );
if( before != after )
{
m_undoStack.push_back( { aCtrl, before, after } );
m_redoStack.clear();
m_currentValues[ aCtrl ] = after;
}
}
void DIALOG_SHIM::onCommandEvent( wxCommandEvent& aEvent )
{
if( !m_handlingUndoRedo )
recordControlChange( static_cast<wxWindow*>( aEvent.GetEventObject() ) );
aEvent.Skip();
}
void DIALOG_SHIM::onSpinEvent( wxSpinEvent& aEvent )
{
if( !m_handlingUndoRedo )
recordControlChange( static_cast<wxWindow*>( aEvent.GetEventObject() ) );
aEvent.Skip();
}
void DIALOG_SHIM::onSpinDoubleEvent( wxSpinDoubleEvent& aEvent )
{
if( !m_handlingUndoRedo )
recordControlChange( static_cast<wxWindow*>( aEvent.GetEventObject() ) );
aEvent.Skip();
}
void DIALOG_SHIM::onStyledTextChanged( wxStyledTextEvent& aEvent )
{
if( !m_handlingUndoRedo )
recordControlChange( static_cast<wxWindow*>( aEvent.GetEventObject() ) );
aEvent.Skip();
}
void DIALOG_SHIM::onGridCellChanged( wxGridEvent& aEvent )
{
if( !m_handlingUndoRedo )
recordControlChange( static_cast<wxWindow*>( aEvent.GetEventObject() ) );
aEvent.Skip();
}
void DIALOG_SHIM::onPropertyGridChanged( wxPropertyGridEvent& aEvent )
{
if( !m_handlingUndoRedo )
recordControlChange( static_cast<wxWindow*>( aEvent.GetEventObject() ) );
aEvent.Skip();
}
void DIALOG_SHIM::onDataViewListChanged( wxDataViewEvent& aEvent )
{
if( !m_handlingUndoRedo )
recordControlChange( static_cast<wxWindow*>( aEvent.GetEventObject() ) );
aEvent.Skip();
}
wxVariant DIALOG_SHIM::getControlValue( wxWindow* aCtrl )
{
if( wxTextCtrl* textCtrl = dynamic_cast<wxTextCtrl*>( aCtrl ) )
return wxVariant( textCtrl->GetValue() );
else if( wxStyledTextCtrl* scintilla = dynamic_cast<wxStyledTextCtrl*>( aCtrl ) )
return wxVariant( scintilla->GetText() );
else if( wxComboBox* combo = dynamic_cast<wxComboBox*>( aCtrl ) )
return wxVariant( combo->GetValue() );
else if( wxChoice* choice = dynamic_cast<wxChoice*>( aCtrl ) )
return wxVariant( (long) choice->GetSelection() );
else if( wxCheckBox* check = dynamic_cast<wxCheckBox*>( aCtrl ) )
return wxVariant( check->GetValue() );
else if( wxSpinCtrl* spin = dynamic_cast<wxSpinCtrl*>( aCtrl ) )
return wxVariant( (long) spin->GetValue() );
else if( wxSpinCtrlDouble* spinD = dynamic_cast<wxSpinCtrlDouble*>( aCtrl ) )
return wxVariant( spinD->GetValue() );
else if( wxRadioButton* radio = dynamic_cast<wxRadioButton*>( aCtrl ) )
return wxVariant( radio->GetValue() );
else if( wxRadioBox* radioBox = dynamic_cast<wxRadioBox*>( aCtrl ) )
return wxVariant( (long) radioBox->GetSelection() );
else if( wxGrid* grid = dynamic_cast<wxGrid*>( aCtrl ) )
{
nlohmann::json j = nlohmann::json::array();
int rows = grid->GetNumberRows();
int cols = grid->GetNumberCols();
for( int r = 0; r < rows; ++r )
{
nlohmann::json row = nlohmann::json::array();
for( int c = 0; c < cols; ++c )
row.push_back( std::string( grid->GetCellValue( r, c ).ToUTF8() ) );
j.push_back( row );
}
return wxVariant( wxString( j.dump() ) );
}
else if( wxPropertyGrid* propGrid = dynamic_cast<wxPropertyGrid*>( aCtrl ) )
{
nlohmann::json j;
for( wxPropertyGridIterator it = propGrid->GetIterator(); !it.AtEnd(); ++it )
{
wxPGProperty* prop = *it;
j[ prop->GetName().ToStdString() ] = prop->GetValueAsString().ToStdString();
}
return wxVariant( wxString( j.dump() ) );
}
else if( wxCheckListBox* checkList = dynamic_cast<wxCheckListBox*>( aCtrl ) )
{
nlohmann::json j = nlohmann::json::array();
unsigned int count = checkList->GetCount();
for( unsigned int i = 0; i < count; ++i )
{
if( checkList->IsChecked( i ) )
j.push_back( i );
}
return wxVariant( wxString( j.dump() ) );
}
else if( wxDataViewListCtrl* dataList = dynamic_cast<wxDataViewListCtrl*>( aCtrl ) )
{
nlohmann::json j = nlohmann::json::array();
unsigned int rows = dataList->GetItemCount();
unsigned int cols = dataList->GetColumnCount();
for( unsigned int r = 0; r < rows; ++r )
{
nlohmann::json row = nlohmann::json::array();
for( unsigned int c = 0; c < cols; ++c )
{
wxVariant val;
dataList->GetValue( val, r, c );
row.push_back( std::string( val.GetString().ToUTF8() ) );
}
j.push_back( row );
}
return wxVariant( wxString( j.dump() ) );
}
else
return wxVariant();
}
void DIALOG_SHIM::setControlValue( wxWindow* aCtrl, const wxVariant& aValue )
{
if( wxTextCtrl* textCtrl = dynamic_cast<wxTextCtrl*>( aCtrl ) )
textCtrl->SetValue( aValue.GetString() );
else if( wxStyledTextCtrl* scintilla = dynamic_cast<wxStyledTextCtrl*>( aCtrl ) )
scintilla->SetText( aValue.GetString() );
else if( wxComboBox* combo = dynamic_cast<wxComboBox*>( aCtrl ) )
combo->SetValue( aValue.GetString() );
else if( wxChoice* choice = dynamic_cast<wxChoice*>( aCtrl ) )
choice->SetSelection( (int) aValue.GetLong() );
else if( wxCheckBox* check = dynamic_cast<wxCheckBox*>( aCtrl ) )
check->SetValue( aValue.GetBool() );
else if( wxSpinCtrl* spin = dynamic_cast<wxSpinCtrl*>( aCtrl ) )
spin->SetValue( (int) aValue.GetLong() );
else if( wxSpinCtrlDouble* spinD = dynamic_cast<wxSpinCtrlDouble*>( aCtrl ) )
spinD->SetValue( aValue.GetDouble() );
else if( wxRadioButton* radio = dynamic_cast<wxRadioButton*>( aCtrl ) )
radio->SetValue( aValue.GetBool() );
else if( wxRadioBox* radioBox = dynamic_cast<wxRadioBox*>( aCtrl ) )
radioBox->SetSelection( (int) aValue.GetLong() );
else if( wxGrid* grid = dynamic_cast<wxGrid*>( aCtrl ) )
{
nlohmann::json j = nlohmann::json::parse( aValue.GetString().ToStdString(), nullptr, false );
if( j.is_array() )
{
int rows = std::min( (int) j.size(), grid->GetNumberRows() );
for( int r = 0; r < rows; ++r )
{
nlohmann::json row = j[r];
int cols = std::min( (int) row.size(), grid->GetNumberCols() );
for( int c = 0; c < cols; ++c )
grid->SetCellValue( r, c, wxString( row[c].get<std::string>() ) );
}
}
}
else if( wxPropertyGrid* propGrid = dynamic_cast<wxPropertyGrid*>( aCtrl ) )
{
nlohmann::json j = nlohmann::json::parse( aValue.GetString().ToStdString(), nullptr, false );
if( j.is_object() )
{
for( auto it = j.begin(); it != j.end(); ++it )
propGrid->SetPropertyValue( wxString( it.key() ), wxString( it.value().get<std::string>() ) );
}
}
else if( wxCheckListBox* checkList = dynamic_cast<wxCheckListBox*>( aCtrl ) )
{
nlohmann::json j = nlohmann::json::parse( aValue.GetString().ToStdString(), nullptr, false );
if( j.is_array() )
{
unsigned int count = checkList->GetCount();
for( unsigned int i = 0; i < count; ++i )
checkList->Check( i, false );
for( auto& idx : j )
{
unsigned int i = idx.get<unsigned int>();
if( i < count )
checkList->Check( i, true );
}
}
}
else if( wxDataViewListCtrl* dataList = dynamic_cast<wxDataViewListCtrl*>( aCtrl ) )
{
nlohmann::json j = nlohmann::json::parse( aValue.GetString().ToStdString(), nullptr, false );
if( j.is_array() )
{
unsigned int rows = std::min( static_cast<unsigned int>( j.size() ),
static_cast<unsigned int>( dataList->GetItemCount() ) );
for( unsigned int r = 0; r < rows; ++r )
{
nlohmann::json row = j[r];
unsigned int cols = std::min( (unsigned int) row.size(), dataList->GetColumnCount() );
for( unsigned int c = 0; c < cols; ++c )
{
wxVariant val( wxString( row[c].get<std::string>() ) );
dataList->SetValue( val, r, c );
}
}
}
}
}
void DIALOG_SHIM::doUndo()
{
if( m_undoStack.empty() )
return;
m_handlingUndoRedo = true;
UNDO_STEP step = m_undoStack.back();
m_undoStack.pop_back();
setControlValue( step.ctrl, step.before );
m_currentValues[ step.ctrl ] = step.before;
m_redoStack.push_back( step );
m_handlingUndoRedo = false;
}
void DIALOG_SHIM::doRedo()
{
if( m_redoStack.empty() )
return;
m_handlingUndoRedo = true;
UNDO_STEP step = m_redoStack.back();
m_redoStack.pop_back();
setControlValue( step.ctrl, step.after );
m_currentValues[ step.ctrl ] = step.after;
m_undoStack.push_back( step );
m_handlingUndoRedo = false;
}
void DIALOG_SHIM::OnPaint( wxPaintEvent &event )
{
if( m_firstPaintEvent )
@ -739,6 +1179,7 @@ void DIALOG_SHIM::OnPaint( wxPaintEvent &event )
KIPLATFORM::UI::FixupCancelButtonCmdKeyCollision( this );
SelectAllInTextCtrls( GetChildren() );
registerUndoRedoHandlers( GetChildren() );
if( m_initialFocusTarget )
KIPLATFORM::UI::ForceFocus( m_initialFocusTarget );
@ -966,6 +1407,30 @@ void DIALOG_SHIM::onChildSetFocus( wxFocusEvent& aEvent )
void DIALOG_SHIM::OnCharHook( wxKeyEvent& aEvt )
{
int key = aEvt.GetKeyCode();
int mods = 0;
if( aEvt.ControlDown() )
mods |= MD_CTRL;
if( aEvt.ShiftDown() )
mods |= MD_SHIFT;
if( aEvt.AltDown() )
mods |= MD_ALT;
int hotkey = key | mods;
// Check for standard undo/redo hotkeys
if( hotkey == (MD_CTRL + 'Z') )
{
doUndo();
return;
}
else if( hotkey == (MD_CTRL + MD_SHIFT + 'Z') || hotkey == (MD_CTRL + 'Y') )
{
doRedo();
return;
}
if( aEvt.GetKeyCode() == 'U' && aEvt.GetModifiers() == wxMOD_CONTROL )
{
if( m_parentFrame )

View File

@ -1,5 +1,5 @@
///////////////////////////////////////////////////////////////////////////
// C++ code generated with wxFormBuilder (version 4.0.0-0-g0efcecf)
// C++ code generated with wxFormBuilder (version 4.2.1-0-g80c4cb6)
// http://www.wxformbuilder.org/
//
// PLEASE DO *NOT* EDIT THIS FILE!
@ -26,25 +26,6 @@ WX_TEXT_ENTRY_DIALOG_BASE::WX_TEXT_ENTRY_DIALOG_BASE( wxWindow* parent, wxWindow
m_ContentSizer->Add( m_textCtrl, 0, wxEXPAND|wxALL, 5 );
wxBoxSizer* bSizer3;
bSizer3 = new wxBoxSizer( wxHORIZONTAL );
m_choiceLabel = new wxStaticText( this, wxID_ANY, _("MyLabel"), wxDefaultPosition, wxDefaultSize, 0 );
m_choiceLabel->Wrap( -1 );
m_choiceLabel->Hide();
bSizer3->Add( m_choiceLabel, 0, wxALIGN_CENTER_VERTICAL|wxLEFT|wxRIGHT, 5 );
wxArrayString m_choiceChoices;
m_choice = new wxChoice( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, m_choiceChoices, 0 );
m_choice->SetSelection( 0 );
m_choice->Hide();
bSizer3->Add( m_choice, 3, wxALIGN_CENTER_VERTICAL|wxLEFT|wxRIGHT, 5 );
m_ContentSizer->Add( bSizer3, 1, wxEXPAND, 5 );
m_mainSizer->Add( m_ContentSizer, 1, wxALL|wxEXPAND, 5 );

View File

@ -1,34 +1,36 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<wxFormBuilder_Project>
<FileVersion major="1" minor="17"/>
<FileVersion major="1" minor="18"/>
<object class="Project" expanded="true">
<property name="class_decoration"></property>
<property name="code_generation">C++</property>
<property name="disconnect_events">1</property>
<property name="disconnect_mode">source_name</property>
<property name="disconnect_php_events">0</property>
<property name="disconnect_python_events">0</property>
<property name="cpp_class_decoration"></property>
<property name="cpp_disconnect_events">1</property>
<property name="cpp_event_generation">connect</property>
<property name="cpp_help_provider">none</property>
<property name="cpp_namespace"></property>
<property name="cpp_precompiled_header"></property>
<property name="cpp_use_array_enum">0</property>
<property name="cpp_use_enum">0</property>
<property name="embedded_files_path">res</property>
<property name="encoding">UTF-8</property>
<property name="event_generation">connect</property>
<property name="file">dialog_text_entry_base</property>
<property name="first_id">1000</property>
<property name="help_provider">none</property>
<property name="image_path_wrapper_function_name"></property>
<property name="indent_with_spaces"></property>
<property name="internationalize">1</property>
<property name="lua_skip_events">1</property>
<property name="lua_ui_table">UI</property>
<property name="name">dialog_text_entry_base</property>
<property name="namespace"></property>
<property name="path">.</property>
<property name="precompiled_header"></property>
<property name="php_disconnect_events">0</property>
<property name="php_disconnect_mode">source_name</property>
<property name="php_skip_events">1</property>
<property name="python_disconnect_events">0</property>
<property name="python_disconnect_mode">source_name</property>
<property name="python_image_path_wrapper_function_name"></property>
<property name="python_indent_with_spaces"></property>
<property name="python_skip_events">1</property>
<property name="relative_path">1</property>
<property name="skip_lua_events">1</property>
<property name="skip_php_events">1</property>
<property name="skip_python_events">1</property>
<property name="ui_table">UI</property>
<property name="use_array_enum">0</property>
<property name="use_enum">0</property>
<property name="use_microsoft_bom">0</property>
<property name="use_native_eol">0</property>
<object class="Dialog" expanded="true">
<property name="aui_managed">0</property>
<property name="aui_manager_style">wxAUI_MGR_DEFAULT</property>
@ -80,10 +82,10 @@
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
<property name="TopDockable">1</property>
<property name="aui_layer"></property>
<property name="aui_layer">0</property>
<property name="aui_name"></property>
<property name="aui_position"></property>
<property name="aui_row"></property>
<property name="aui_position">0</property>
<property name="aui_row">0</property>
<property name="best_size"></property>
<property name="bg"></property>
<property name="caption"></property>
@ -142,10 +144,10 @@
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
<property name="TopDockable">1</property>
<property name="aui_layer"></property>
<property name="aui_layer">0</property>
<property name="aui_name"></property>
<property name="aui_position"></property>
<property name="aui_row"></property>
<property name="aui_position">0</property>
<property name="aui_row">0</property>
<property name="best_size"></property>
<property name="bg"></property>
<property name="caption"></property>
@ -169,7 +171,7 @@
<property name="max_size"></property>
<property name="maximize_button">0</property>
<property name="maximum_size"></property>
<property name="maxlength"></property>
<property name="maxlength">0</property>
<property name="min_size"></property>
<property name="minimize_button">0</property>
<property name="minimum_size">300,-1</property>
@ -198,144 +200,6 @@
<property name="window_style"></property>
</object>
</object>
<object class="sizeritem" expanded="true">
<property name="border">5</property>
<property name="flag">wxEXPAND</property>
<property name="proportion">1</property>
<object class="wxBoxSizer" expanded="true">
<property name="minimum_size"></property>
<property name="name">bSizer3</property>
<property name="orient">wxHORIZONTAL</property>
<property name="permission">none</property>
<object class="sizeritem" expanded="true">
<property name="border">5</property>
<property name="flag">wxALIGN_CENTER_VERTICAL|wxLEFT|wxRIGHT</property>
<property name="proportion">0</property>
<object class="wxStaticText" expanded="true">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
<property name="TopDockable">1</property>
<property name="aui_layer"></property>
<property name="aui_name"></property>
<property name="aui_position"></property>
<property name="aui_row"></property>
<property name="best_size"></property>
<property name="bg"></property>
<property name="caption"></property>
<property name="caption_visible">1</property>
<property name="center_pane">0</property>
<property name="close_button">1</property>
<property name="context_help"></property>
<property name="context_menu">1</property>
<property name="default_pane">0</property>
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="drag_accept_files">0</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
<property name="font"></property>
<property name="gripper">0</property>
<property name="hidden">1</property>
<property name="id">wxID_ANY</property>
<property name="label">MyLabel</property>
<property name="markup">0</property>
<property name="max_size"></property>
<property name="maximize_button">0</property>
<property name="maximum_size"></property>
<property name="min_size"></property>
<property name="minimize_button">0</property>
<property name="minimum_size"></property>
<property name="moveable">1</property>
<property name="name">m_choiceLabel</property>
<property name="pane_border">1</property>
<property name="pane_position"></property>
<property name="pane_size"></property>
<property name="permission">protected</property>
<property name="pin_button">1</property>
<property name="pos"></property>
<property name="resize">Resizable</property>
<property name="show">1</property>
<property name="size"></property>
<property name="style"></property>
<property name="subclass">; ; forward_declare</property>
<property name="toolbar_pane">0</property>
<property name="tooltip"></property>
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style"></property>
<property name="wrap">-1</property>
</object>
</object>
<object class="sizeritem" expanded="true">
<property name="border">5</property>
<property name="flag">wxALIGN_CENTER_VERTICAL|wxLEFT|wxRIGHT</property>
<property name="proportion">3</property>
<object class="wxChoice" expanded="true">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
<property name="TopDockable">1</property>
<property name="aui_layer"></property>
<property name="aui_name"></property>
<property name="aui_position"></property>
<property name="aui_row"></property>
<property name="best_size"></property>
<property name="bg"></property>
<property name="caption"></property>
<property name="caption_visible">1</property>
<property name="center_pane">0</property>
<property name="choices"></property>
<property name="close_button">1</property>
<property name="context_help"></property>
<property name="context_menu">1</property>
<property name="default_pane">0</property>
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="drag_accept_files">0</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
<property name="font"></property>
<property name="gripper">0</property>
<property name="hidden">1</property>
<property name="id">wxID_ANY</property>
<property name="max_size"></property>
<property name="maximize_button">0</property>
<property name="maximum_size"></property>
<property name="min_size"></property>
<property name="minimize_button">0</property>
<property name="minimum_size"></property>
<property name="moveable">1</property>
<property name="name">m_choice</property>
<property name="pane_border">1</property>
<property name="pane_position"></property>
<property name="pane_size"></property>
<property name="permission">protected</property>
<property name="pin_button">1</property>
<property name="pos"></property>
<property name="resize">Resizable</property>
<property name="selection">0</property>
<property name="show">1</property>
<property name="size"></property>
<property name="style"></property>
<property name="subclass">; ; forward_declare</property>
<property name="toolbar_pane">0</property>
<property name="tooltip"></property>
<property name="validator_data_type"></property>
<property name="validator_style">wxFILTER_NONE</property>
<property name="validator_type">wxDefaultValidator</property>
<property name="validator_variable"></property>
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style"></property>
</object>
</object>
</object>
</object>
</object>
</object>
<object class="sizeritem" expanded="false">

View File

@ -1,5 +1,5 @@
///////////////////////////////////////////////////////////////////////////
// C++ code generated with wxFormBuilder (version 4.0.0-0-g0efcecf)
// C++ code generated with wxFormBuilder (version 4.2.1-0-g80c4cb6)
// http://www.wxformbuilder.org/
//
// PLEASE DO *NOT* EDIT THIS FILE!
@ -18,14 +18,12 @@
#include <wx/colour.h>
#include <wx/settings.h>
#include <wx/textctrl.h>
#include <wx/choice.h>
#include <wx/sizer.h>
#include <wx/button.h>
#include <wx/dialog.h>
///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
/// Class WX_TEXT_ENTRY_DIALOG_BASE
///////////////////////////////////////////////////////////////////////////////
@ -37,8 +35,6 @@ class WX_TEXT_ENTRY_DIALOG_BASE : public DIALOG_SHIM
wxBoxSizer* m_mainSizer;
wxStaticText* m_label;
wxTextCtrl* m_textCtrl;
wxStaticText* m_choiceLabel;
wxChoice* m_choice;
wxStdDialogButtonSizer* m_sdbSizer1;
wxButton* m_sdbSizer1OK;
wxButton* m_sdbSizer1Cancel;

View File

@ -41,8 +41,7 @@ static int DEFAULT_COL_WIDTHS[] = { 200, 300 };
EDA_LIST_DIALOG::EDA_LIST_DIALOG( wxWindow* aParent, const wxString& aTitle,
const wxArrayString& aItemHeaders,
const std::vector<wxArrayString>& aItemList,
const wxString& aPreselectText, bool aSortList,
const std::vector<std::pair<wxString, bool*>>& aExtraCheckboxes ) :
const wxString& aPreselectText, bool aSortList ) :
EDA_LIST_DIALOG_BASE( aParent, wxID_ANY, aTitle ),
m_sortList( aSortList )
{
@ -63,19 +62,6 @@ EDA_LIST_DIALOG::EDA_LIST_DIALOG( wxWindow* aParent, const wxString& aTitle,
// columns, different column names, and column widths.
m_hash_key = TO_UTF8( aTitle );
if( !aExtraCheckboxes.empty() )
{
m_ExtrasSizer->AddSpacer( 5 );
for( const auto& [label, valuePtr] : aExtraCheckboxes )
{
wxCheckBox* cb = new wxCheckBox( this, wxID_ANY, label );
cb->SetValue( *valuePtr );
m_ExtrasSizer->Add( cb, 0, wxBOTTOM, 5 );
m_extraCheckboxMap[cb] = valuePtr;
}
}
SetupStandardButtons();
Layout();
@ -93,6 +79,22 @@ EDA_LIST_DIALOG::EDA_LIST_DIALOG( wxWindow* aParent, const wxString& aTitle, boo
}
void EDA_LIST_DIALOG::AddExtraCheckbox( const wxString& aLabel, bool* aValuePtr )
{
wxCHECK2_MSG( aValuePtr, return, wxT( "Null pointer for checkbox value." ) );
int flags = wxBOTTOM;
if( m_ExtrasSizer->GetItemCount() > 0 )
flags |= wxTOP;
wxCheckBox* cb = new wxCheckBox( this, wxID_ANY, aLabel );
cb->SetValue( *aValuePtr );
m_ExtrasSizer->Add( cb, 0, flags, 5 );
m_extraCheckboxMap[cb] = aValuePtr;
}
bool EDA_LIST_DIALOG::Show( bool show )
{
bool retVal = DIALOG_SHIM::Show( show );

View File

@ -26,6 +26,11 @@
#include <wx/log.h>
#include <wx/textctrl.h>
#include <wx/uri.h>
#include <wx/panel.h>
#include <wx/sizer.h>
#include <wx/button.h>
#include <wx/stattext.h>
#include <algorithm>
#include <string_utils.h>
#include <dialogs/html_message_box.h>
#include <build_version.h>
@ -38,6 +43,33 @@ HTML_MESSAGE_BOX::HTML_MESSAGE_BOX( wxWindow* aParent, const wxString& aTitle,
m_htmlWindow->SetLayoutDirection( wxLayout_LeftToRight );
ListClear();
m_searchPanel = new wxPanel( this );
wxBoxSizer* searchSizer = new wxBoxSizer( wxHORIZONTAL );
m_matchCount = new wxStaticText( m_searchPanel, wxID_ANY, wxEmptyString );
m_searchCtrl = new wxTextCtrl( m_searchPanel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_PROCESS_ENTER );
m_prevBtn = new wxButton( m_searchPanel, wxID_ANY, wxS( "" ), wxDefaultPosition, wxDefaultSize, wxBORDER_NONE );
m_nextBtn = new wxButton( m_searchPanel, wxID_ANY, wxS( "" ), wxDefaultPosition, wxDefaultSize, wxBORDER_NONE );
// Set minimum size for buttons to make them thinner
m_prevBtn->SetMinSize( wxSize( 25, -1 ) );
m_nextBtn->SetMinSize( wxSize( 25, -1 ) );
// Set minimum width for match count to ensure it's visible
m_matchCount->SetMinSize( wxSize( 60, -1 ) );
searchSizer->Add( m_matchCount, 0, wxALIGN_CENTER_VERTICAL|wxRIGHT, 5 );
searchSizer->Add( m_searchCtrl, 1, wxALIGN_CENTER_VERTICAL|wxRIGHT, 5 );
searchSizer->Add( m_prevBtn, 0, wxALIGN_CENTER_VERTICAL|wxRIGHT, 2 );
searchSizer->Add( m_nextBtn, 0, wxALIGN_CENTER_VERTICAL );
m_searchPanel->SetSizer( searchSizer );
m_searchPanel->Hide();
GetSizer()->Insert( 0, m_searchPanel, 0, wxALIGN_RIGHT|wxTOP|wxRIGHT, 5 );
m_searchCtrl->Bind( wxEVT_TEXT, &HTML_MESSAGE_BOX::OnSearchText, this );
m_searchCtrl->Bind( wxEVT_TEXT_ENTER, &HTML_MESSAGE_BOX::OnNext, this );
m_prevBtn->Bind( wxEVT_BUTTON, &HTML_MESSAGE_BOX::OnPrev, this );
m_nextBtn->Bind( wxEVT_BUTTON, &HTML_MESSAGE_BOX::OnNext, this );
// Gives a default logical size (the actual size depends on the display definition)
if( aSize != wxDefaultSize )
setSizeInDU( aSize.x, aSize.y );
@ -162,7 +194,46 @@ void HTML_MESSAGE_BOX::OnHTMLLinkClicked( wxHtmlLinkEvent& event )
void HTML_MESSAGE_BOX::OnCharHook( wxKeyEvent& aEvent )
{
// shift-return (Mac default) or Ctrl-Return (GTK) for OK
if( m_searchPanel->IsShown() )
{
if( aEvent.GetKeyCode() == WXK_ESCAPE )
{
HideSearchBar();
return;
}
else if( aEvent.GetKeyCode() == WXK_RETURN || aEvent.GetKeyCode() == WXK_NUMPAD_ENTER )
{
wxCommandEvent evt;
OnNext( evt );
return;
}
else if( aEvent.GetKeyCode() == WXK_BACK )
{
long from, to;
m_searchCtrl->GetSelection( &from, &to );
if( from == to )
m_searchCtrl->Remove( std::max( 0L, from - 1 ), from );
else
m_searchCtrl->Remove( from, to );
return;
}
else if( !aEvent.HasModifiers() && wxIsprint( aEvent.GetUnicodeKey() ) )
{
m_searchCtrl->AppendText( wxString( (wxChar) aEvent.GetUnicodeKey() ) );
return;
}
}
else if( !aEvent.HasModifiers() && wxIsprint( aEvent.GetUnicodeKey() ) )
{
ShowSearchBar();
m_searchCtrl->SetValue( wxString( (wxChar) aEvent.GetUnicodeKey() ) );
m_currentMatch = 0;
updateSearch();
return;
}
if( aEvent.GetKeyCode() == WXK_ESCAPE )
{
wxPostEvent( this, wxCommandEvent( wxEVT_COMMAND_BUTTON_CLICKED, wxID_OK ) );
@ -189,3 +260,195 @@ void HTML_MESSAGE_BOX::OnCharHook( wxKeyEvent& aEvent )
aEvent.Skip();
}
void HTML_MESSAGE_BOX::OnSearchText( wxCommandEvent& aEvent )
{
m_currentMatch = 0;
updateSearch();
}
void HTML_MESSAGE_BOX::OnNext( wxCommandEvent& aEvent )
{
if( !m_matchPos.empty() )
{
m_currentMatch = ( m_currentMatch + 1 ) % m_matchPos.size();
updateSearch();
}
}
void HTML_MESSAGE_BOX::OnPrev( wxCommandEvent& aEvent )
{
if( !m_matchPos.empty() )
{
m_currentMatch = ( m_currentMatch + m_matchPos.size() - 1 ) % m_matchPos.size();
updateSearch();
}
}
void HTML_MESSAGE_BOX::ShowSearchBar()
{
if( !m_searchPanel->IsShown() )
{
m_originalSource = m_source;
m_searchPanel->Show();
Layout();
m_searchCtrl->SetFocus();
}
}
void HTML_MESSAGE_BOX::HideSearchBar()
{
if( m_searchPanel->IsShown() )
{
m_searchPanel->Hide();
Layout();
m_source = m_originalSource;
reload();
// Refocus on the main HTML window so user can press Escape again to close the dialog
m_htmlWindow->SetFocus();
}
}
void HTML_MESSAGE_BOX::updateSearch()
{
wxString term = m_searchCtrl->GetValue();
if( term.IsEmpty() )
{
m_source = m_originalSource;
reload();
m_matchPos.clear();
m_matchCount->SetLabel( wxEmptyString );
return;
}
m_matchPos.clear();
// Search only in text content, not in HTML tags
wxString termLower = term.Lower();
size_t pos = 0;
bool insideTag = false;
while( pos < m_originalSource.length() )
{
wxChar ch = m_originalSource[pos];
if( ch == '<' )
{
insideTag = true;
}
else if( ch == '>' )
{
insideTag = false;
pos++;
continue;
}
// Only search for matches when we're not inside an HTML tag
if( !insideTag )
{
// Check if we have a match starting at this position
if( pos + termLower.length() <= m_originalSource.length() )
{
wxString candidate = m_originalSource.Mid( pos, termLower.length() ).Lower();
if( candidate == termLower )
{
// Verify that this match doesn't span into an HTML tag
bool validMatch = true;
for( size_t i = 0; i < termLower.length(); i++ )
{
if( pos + i < m_originalSource.length() && m_originalSource[pos + i] == '<' )
{
validMatch = false;
break;
}
}
if( validMatch )
{
m_matchPos.push_back( pos );
}
}
}
}
pos++;
}
if( m_matchPos.empty() )
{
m_source = m_originalSource;
reload();
m_matchCount->SetLabel( wxS( "0/0" ) );
return;
}
if( m_currentMatch >= (int) m_matchPos.size() )
m_currentMatch = 0;
wxString out;
size_t start = 0;
for( size_t i = 0; i < m_matchPos.size(); ++i )
{
size_t idx = m_matchPos[i];
out += m_originalSource.Mid( start, idx - start );
wxString matchStr = m_originalSource.Mid( idx, term.length() );
// HTML-escape the match string to prevent HTML parsing issues
wxString escapedMatchStr = matchStr;
escapedMatchStr.Replace( wxS( "&" ), wxS( "&amp;" ) );
escapedMatchStr.Replace( wxS( "<" ), wxS( "&lt;" ) );
escapedMatchStr.Replace( wxS( ">" ), wxS( "&gt;" ) );
escapedMatchStr.Replace( wxS( "\"" ), wxS( "&quot;" ) );
if( (int) i == m_currentMatch )
{
// Use a unique anchor name for each search to avoid conflicts
wxString anchorName = wxString::Format( wxS( "kicad_search_%d" ), m_currentMatch );
out += wxString::Format( wxS( "<a name=\"%s\"></a><span style=\"background-color:#DDAAFF;\">%s</span>" ),
anchorName, escapedMatchStr );
}
else
{
out += wxString::Format( wxS( "<span style=\"background-color:#FFFFAA;\">%s</span>" ), escapedMatchStr );
}
start = idx + term.length();
}
out += m_originalSource.Mid( start );
m_source = out;
reload();
// Use CallAfter to ensure the HTML is fully loaded before scrolling
// Only scroll if we have matches and a valid current match
if( !m_matchPos.empty() && m_currentMatch >= 0 && m_currentMatch < (int)m_matchPos.size() )
{
CallAfter( [this]()
{
// Try to scroll to the anchor, with fallback if it fails
wxString anchorName = wxString::Format( wxS( "kicad_search_%d" ), m_currentMatch );
if( !m_htmlWindow->ScrollToAnchor( anchorName ) )
{
// If anchor scrolling fails, try to scroll to approximate position
// Calculate approximate scroll position based on match location
if( !m_matchPos.empty() && m_currentMatch < (int)m_matchPos.size() )
{
size_t matchPos = m_matchPos[m_currentMatch];
size_t totalLength = m_originalSource.length();
if( totalLength > 0 )
{
// Scroll to approximate percentage of document
double ratio = (double)matchPos / (double)totalLength;
int scrollPos = (int)(ratio * m_htmlWindow->GetScrollRange( wxVERTICAL ));
m_htmlWindow->Scroll( 0, scrollPos );
}
}
}
} );
}
m_matchCount->SetLabel( wxString::Format( wxS( "%d/%zu" ), m_currentMatch + 1, m_matchPos.size() ) );
}

View File

@ -17,21 +17,19 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <widgets/gal_options_panel.h>
#include <dialogs/panel_gal_options.h>
#include <widgets/paged_dialog.h>
#include <dialogs/panel_gal_display_options.h>
#include <dialogs/panel_base_display_options.h>
PANEL_GAL_DISPLAY_OPTIONS::PANEL_GAL_DISPLAY_OPTIONS( wxWindow* aParent,
APP_SETTINGS_BASE* aAppSettings ) :
wxPanel( aParent, wxID_ANY )
PANEL_BASE_DISPLAY_OPTIONS::PANEL_BASE_DISPLAY_OPTIONS( wxWindow* aParent, APP_SETTINGS_BASE* aAppSettings ) :
wxPanel( aParent, wxID_ANY )
{
auto mainSizer = new wxBoxSizer( wxHORIZONTAL );
SetSizer( mainSizer );
// install GAL options pane
m_galOptsPanel = new GAL_OPTIONS_PANEL( this, aAppSettings );
m_galOptsPanel = new PANEL_GAL_OPTIONS( this, aAppSettings );
mainSizer->Add( m_galOptsPanel, 1, wxEXPAND | wxLEFT, 5 );
// a spacer to take up the other half of the width
@ -40,14 +38,14 @@ PANEL_GAL_DISPLAY_OPTIONS::PANEL_GAL_DISPLAY_OPTIONS( wxWindow* aParent,
}
bool PANEL_GAL_DISPLAY_OPTIONS::TransferDataToWindow()
bool PANEL_BASE_DISPLAY_OPTIONS::TransferDataToWindow()
{
m_galOptsPanel->TransferDataToWindow();
return true;
}
bool PANEL_GAL_DISPLAY_OPTIONS::TransferDataFromWindow()
bool PANEL_BASE_DISPLAY_OPTIONS::TransferDataFromWindow()
{
m_galOptsPanel->TransferDataFromWindow();
return true;

View File

@ -27,6 +27,8 @@
#include <bitmaps.h>
#include <class_draw_panel_gal.h>
#include <dpi_scaling_common.h>
#include <eda_draw_frame.h>
#include <gal/graphics_abstraction_layer.h>
#include <kiface_base.h>
#include <kiplatform/ui.h>
#include <pgm_base.h>
@ -105,6 +107,10 @@ PANEL_COMMON_SETTINGS::PANEL_COMMON_SETTINGS( wxWindow* aParent ) :
m_canvasScaleAuto->Show( false );
}
m_zoomCorrectionCtrl = new ZOOM_CORRECTION_CTRL( this,
Pgm().GetCommonSettings()->m_Appearance.zoom_correction_factor );
bLeftSizer->Add( m_zoomCorrectionCtrl, 1, wxEXPAND );
// Hide the option of icons in menus for platforms that do not support them
m_checkBoxIconsInMenus->Show( KIPLATFORM::UI::AllowIconsInMenus() );
@ -198,6 +204,8 @@ bool PANEL_COMMON_SETTINGS::TransferDataFromWindow()
commonSettings->m_Appearance.grid_striping = m_gridStriping->GetValue();
commonSettings->m_Appearance.zoom_correction_factor = m_zoomCorrectionCtrl->GetValue();
double dimmingPercent = 80;
m_highContrastCtrl->GetValue().ToDouble( &dimmingPercent );
commonSettings->m_Appearance.hicontrast_dimming_factor = dimmingPercent / 100.0f;
@ -288,6 +296,8 @@ void PANEL_COMMON_SETTINGS::applySettingsToPanel( COMMON_SETTINGS& aSettings )
m_gridStriping->SetValue( aSettings.m_Appearance.grid_striping );
m_zoomCorrectionCtrl->SetDisplayedValue( aSettings.m_Appearance.zoom_correction_factor );
double dimmingPercent = aSettings.m_Appearance.hicontrast_dimming_factor * 100.0f;
m_highContrastCtrl->SetValue( wxString::Format( "%.0f", dimmingPercent ) );

View File

@ -1,5 +1,5 @@
///////////////////////////////////////////////////////////////////////////
// C++ code generated with wxFormBuilder (version 4.2.1-0-g80c4cb6)
// C++ code generated with wxFormBuilder (version 4.2.1-0-g80c4cb6a-dirty)
// http://www.wxformbuilder.org/
//
// PLEASE DO *NOT* EDIT THIS FILE!
@ -16,7 +16,6 @@ PANEL_COMMON_SETTINGS_BASE::PANEL_COMMON_SETTINGS_BASE( wxWindow* parent, wxWind
wxBoxSizer* bPanelSizer;
bPanelSizer = new wxBoxSizer( wxHORIZONTAL );
wxBoxSizer* bLeftSizer;
bLeftSizer = new wxBoxSizer( wxVERTICAL );
m_staticText20 = new wxStaticText( this, wxID_ANY, _("Rendering Engine"), wxDefaultPosition, wxDefaultSize, 0 );
@ -292,6 +291,16 @@ PANEL_COMMON_SETTINGS_BASE::PANEL_COMMON_SETTINGS_BASE( wxWindow* parent, wxWind
bLeftSizer->Add( bUserInterfaceSizer, 0, wxTOP|wxLEFT|wxEXPAND, 5 );
bLeftSizer->Add( 0, 0, 0, 0, 5 );
m_staticText251 = new wxStaticText( this, wxID_ANY, _("Scaling"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticText251->Wrap( -1 );
bLeftSizer->Add( m_staticText251, 0, wxLEFT|wxRIGHT|wxTOP, 15 );
m_staticline7 = new wxStaticLine( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL );
bLeftSizer->Add( m_staticline7, 0, wxEXPAND | wxALL, 5 );
bPanelSizer->Add( bLeftSizer, 0, wxRIGHT, 35 );
wxBoxSizer* rightSizer;

View File

@ -68,12 +68,12 @@
<property name="minimum_size"></property>
<property name="name">bLeftSizer</property>
<property name="orient">wxVERTICAL</property>
<property name="permission">none</property>
<object class="sizeritem" expanded="true">
<property name="permission">protected</property>
<object class="sizeritem" expanded="false">
<property name="border">13</property>
<property name="flag">wxTOP|wxRIGHT|wxLEFT|wxEXPAND</property>
<property name="proportion">0</property>
<object class="wxStaticText" expanded="true">
<object class="wxStaticText" expanded="false">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
@ -131,11 +131,11 @@
<property name="wrap">-1</property>
</object>
</object>
<object class="sizeritem" expanded="true">
<object class="sizeritem" expanded="false">
<property name="border">2</property>
<property name="flag">wxEXPAND|wxTOP|wxBOTTOM</property>
<property name="proportion">0</property>
<object class="wxStaticLine" expanded="true">
<object class="wxStaticLine" expanded="false">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
@ -190,21 +190,21 @@
<property name="window_style"></property>
</object>
</object>
<object class="sizeritem" expanded="true">
<object class="sizeritem" expanded="false">
<property name="border">5</property>
<property name="flag"></property>
<property name="proportion">0</property>
<object class="spacer" expanded="true">
<object class="spacer" expanded="false">
<property name="height">3</property>
<property name="permission">protected</property>
<property name="width">0</property>
</object>
</object>
<object class="sizeritem" expanded="true">
<object class="sizeritem" expanded="false">
<property name="border">5</property>
<property name="flag">wxEXPAND|wxTOP|wxRIGHT|wxLEFT</property>
<property name="proportion">1</property>
<object class="wxFlexGridSizer" expanded="true">
<object class="wxFlexGridSizer" expanded="false">
<property name="cols">1</property>
<property name="flexible_direction">wxBOTH</property>
<property name="growablecols"></property>
@ -216,11 +216,11 @@
<property name="permission">protected</property>
<property name="rows">0</property>
<property name="vgap">4</property>
<object class="sizeritem" expanded="true">
<object class="sizeritem" expanded="false">
<property name="border">5</property>
<property name="flag">wxLEFT</property>
<property name="proportion">0</property>
<object class="wxRadioButton" expanded="true">
<object class="wxRadioButton" expanded="false">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
@ -281,11 +281,11 @@
<property name="window_style"></property>
</object>
</object>
<object class="sizeritem" expanded="true">
<object class="sizeritem" expanded="false">
<property name="border">5</property>
<property name="flag">wxLEFT</property>
<property name="proportion">0</property>
<object class="wxRadioButton" expanded="true">
<object class="wxRadioButton" expanded="false">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
@ -348,21 +348,21 @@
</object>
</object>
</object>
<object class="sizeritem" expanded="true">
<object class="sizeritem" expanded="false">
<property name="border">5</property>
<property name="flag"></property>
<property name="proportion">0</property>
<object class="spacer" expanded="true">
<object class="spacer" expanded="false">
<property name="height">3</property>
<property name="permission">protected</property>
<property name="width">0</property>
</object>
</object>
<object class="sizeritem" expanded="true">
<object class="sizeritem" expanded="false">
<property name="border">5</property>
<property name="flag">wxLEFT</property>
<property name="proportion">0</property>
<object class="wxGridBagSizer" expanded="true">
<object class="wxGridBagSizer" expanded="false">
<property name="empty_cell_size">-1,2</property>
<property name="flexible_direction">wxBOTH</property>
<property name="growablecols">1</property>
@ -438,7 +438,7 @@
<property name="wrap">-1</property>
</object>
</object>
<object class="gbsizeritem" expanded="true">
<object class="gbsizeritem" expanded="false">
<property name="border">5</property>
<property name="colspan">1</property>
<property name="column">1</property>
@ -508,32 +508,32 @@
</object>
</object>
</object>
<object class="sizeritem" expanded="true">
<object class="sizeritem" expanded="false">
<property name="border">5</property>
<property name="flag">wxTOP|wxLEFT|wxEXPAND</property>
<property name="proportion">0</property>
<object class="wxBoxSizer" expanded="true">
<object class="wxBoxSizer" expanded="false">
<property name="minimum_size"></property>
<property name="name">bAntialiasingSizer</property>
<property name="orient">wxVERTICAL</property>
<property name="permission">none</property>
</object>
</object>
<object class="sizeritem" expanded="true">
<object class="sizeritem" expanded="false">
<property name="border">5</property>
<property name="flag"></property>
<property name="proportion">0</property>
<object class="spacer" expanded="true">
<object class="spacer" expanded="false">
<property name="height">15</property>
<property name="permission">protected</property>
<property name="width">0</property>
</object>
</object>
<object class="sizeritem" expanded="true">
<object class="sizeritem" expanded="false">
<property name="border">13</property>
<property name="flag">wxTOP|wxRIGHT|wxLEFT</property>
<property name="proportion">0</property>
<object class="wxStaticText" expanded="true">
<object class="wxStaticText" expanded="false">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
@ -591,11 +591,11 @@
<property name="wrap">-1</property>
</object>
</object>
<object class="sizeritem" expanded="true">
<object class="sizeritem" expanded="false">
<property name="border">2</property>
<property name="flag">wxEXPAND|wxTOP|wxBOTTOM</property>
<property name="proportion">0</property>
<object class="wxStaticLine" expanded="true">
<object class="wxStaticLine" expanded="false">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
@ -650,11 +650,11 @@
<property name="window_style"></property>
</object>
</object>
<object class="sizeritem" expanded="true">
<object class="sizeritem" expanded="false">
<property name="border">5</property>
<property name="flag">wxTOP|wxLEFT|wxEXPAND</property>
<property name="proportion">0</property>
<object class="wxBoxSizer" expanded="true">
<object class="wxBoxSizer" expanded="false">
<property name="minimum_size"></property>
<property name="name">bHelperAppsSizer</property>
<property name="orient">wxVERTICAL</property>
@ -882,20 +882,20 @@
<property name="width">0</property>
</object>
</object>
<object class="sizeritem" expanded="true">
<object class="sizeritem" expanded="false">
<property name="border">5</property>
<property name="flag">wxEXPAND|wxRIGHT|wxTOP</property>
<property name="proportion">0</property>
<object class="wxBoxSizer" expanded="true">
<object class="wxBoxSizer" expanded="false">
<property name="minimum_size"></property>
<property name="name">bSizerFileManager</property>
<property name="orient">wxHORIZONTAL</property>
<property name="permission">protected</property>
<object class="sizeritem" expanded="true">
<object class="sizeritem" expanded="false">
<property name="border">5</property>
<property name="flag">wxALIGN_CENTER_VERTICAL|wxLEFT|wxRIGHT</property>
<property name="proportion">0</property>
<object class="wxStaticText" expanded="true">
<object class="wxStaticText" expanded="false">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
@ -953,11 +953,11 @@
<property name="wrap">-1</property>
</object>
</object>
<object class="sizeritem" expanded="true">
<object class="sizeritem" expanded="false">
<property name="border">5</property>
<property name="flag">wxALIGN_CENTER_VERTICAL</property>
<property name="proportion">1</property>
<object class="wxTextCtrl" expanded="true">
<object class="wxTextCtrl" expanded="false">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
@ -1020,17 +1020,17 @@
</object>
</object>
</object>
<object class="sizeritem" expanded="true">
<object class="sizeritem" expanded="false">
<property name="border">5</property>
<property name="flag">wxEXPAND</property>
<property name="proportion">1</property>
<object class="spacer" expanded="true">
<object class="spacer" expanded="false">
<property name="height">12</property>
<property name="permission">protected</property>
<property name="width">0</property>
</object>
</object>
<object class="sizeritem" expanded="true">
<object class="sizeritem" expanded="false">
<property name="border">2</property>
<property name="flag">wxBOTTOM|wxEXPAND</property>
<property name="proportion">0</property>
@ -1107,11 +1107,11 @@
</object>
</object>
</object>
<object class="sizeritem" expanded="true">
<object class="sizeritem" expanded="false">
<property name="border">5</property>
<property name="flag">wxBOTTOM|wxRIGHT|wxEXPAND</property>
<property name="proportion">0</property>
<object class="wxBoxSizer" expanded="true">
<object class="wxBoxSizer" expanded="false">
<property name="minimum_size"></property>
<property name="name">bSizer7</property>
<property name="orient">wxHORIZONTAL</property>
@ -1326,21 +1326,21 @@
</object>
</object>
</object>
<object class="sizeritem" expanded="true">
<object class="sizeritem" expanded="false">
<property name="border">5</property>
<property name="flag"></property>
<property name="proportion">0</property>
<object class="spacer" expanded="true">
<object class="spacer" expanded="false">
<property name="height">15</property>
<property name="permission">protected</property>
<property name="width">0</property>
</object>
</object>
<object class="sizeritem" expanded="true">
<object class="sizeritem" expanded="false">
<property name="border">13</property>
<property name="flag">wxTOP|wxRIGHT|wxLEFT</property>
<property name="proportion">0</property>
<object class="wxStaticText" expanded="true">
<object class="wxStaticText" expanded="false">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
@ -1398,11 +1398,11 @@
<property name="wrap">-1</property>
</object>
</object>
<object class="sizeritem" expanded="true">
<object class="sizeritem" expanded="false">
<property name="border">2</property>
<property name="flag">wxEXPAND|wxTOP|wxBOTTOM</property>
<property name="proportion">0</property>
<object class="wxStaticLine" expanded="true">
<object class="wxStaticLine" expanded="false">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
@ -1457,11 +1457,11 @@
<property name="window_style"></property>
</object>
</object>
<object class="sizeritem" expanded="true">
<object class="sizeritem" expanded="false">
<property name="border">5</property>
<property name="flag">wxTOP|wxLEFT|wxEXPAND</property>
<property name="proportion">0</property>
<object class="wxBoxSizer" expanded="true">
<object class="wxBoxSizer" expanded="false">
<property name="minimum_size"></property>
<property name="name">bUserInterfaceSizer</property>
<property name="orient">wxVERTICAL</property>
@ -2465,11 +2465,11 @@
<property name="wrap">-1</property>
</object>
</object>
<object class="sizeritem" expanded="true">
<object class="sizeritem" expanded="false">
<property name="border">5</property>
<property name="flag">wxEXPAND|wxTOP|wxBOTTOM|wxLEFT</property>
<property name="proportion">0</property>
<object class="wxGridBagSizer" expanded="true">
<object class="wxGridBagSizer" expanded="false">
<property name="empty_cell_size">-1,-1</property>
<property name="flexible_direction">wxVERTICAL</property>
<property name="growablecols"></property>
@ -2886,6 +2886,137 @@
</object>
</object>
</object>
<object class="sizeritem" expanded="true">
<property name="border">5</property>
<property name="flag"></property>
<property name="proportion">0</property>
<object class="spacer" expanded="true">
<property name="height">0</property>
<property name="permission">protected</property>
<property name="width">0</property>
</object>
</object>
<object class="sizeritem" expanded="true">
<property name="border">15</property>
<property name="flag">wxLEFT|wxRIGHT|wxTOP</property>
<property name="proportion">0</property>
<object class="wxStaticText" expanded="true">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
<property name="TopDockable">1</property>
<property name="aui_layer">0</property>
<property name="aui_name"></property>
<property name="aui_position">0</property>
<property name="aui_row">0</property>
<property name="best_size"></property>
<property name="bg"></property>
<property name="caption"></property>
<property name="caption_visible">1</property>
<property name="center_pane">0</property>
<property name="close_button">1</property>
<property name="context_help"></property>
<property name="context_menu">1</property>
<property name="default_pane">0</property>
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="drag_accept_files">0</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
<property name="font"></property>
<property name="gripper">0</property>
<property name="hidden">0</property>
<property name="id">wxID_ANY</property>
<property name="label">Scaling</property>
<property name="markup">0</property>
<property name="max_size"></property>
<property name="maximize_button">0</property>
<property name="maximum_size"></property>
<property name="min_size"></property>
<property name="minimize_button">0</property>
<property name="minimum_size"></property>
<property name="moveable">1</property>
<property name="name">m_staticText251</property>
<property name="pane_border">1</property>
<property name="pane_position"></property>
<property name="pane_size"></property>
<property name="permission">protected</property>
<property name="pin_button">1</property>
<property name="pos"></property>
<property name="resize">Resizable</property>
<property name="show">1</property>
<property name="size"></property>
<property name="style"></property>
<property name="subclass">; ; forward_declare</property>
<property name="toolbar_pane">0</property>
<property name="tooltip"></property>
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style"></property>
<property name="wrap">-1</property>
</object>
</object>
<object class="sizeritem" expanded="true">
<property name="border">5</property>
<property name="flag">wxEXPAND | wxALL</property>
<property name="proportion">0</property>
<object class="wxStaticLine" expanded="true">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
<property name="TopDockable">1</property>
<property name="aui_layer">0</property>
<property name="aui_name"></property>
<property name="aui_position">0</property>
<property name="aui_row">0</property>
<property name="best_size"></property>
<property name="bg"></property>
<property name="caption"></property>
<property name="caption_visible">1</property>
<property name="center_pane">0</property>
<property name="close_button">1</property>
<property name="context_help"></property>
<property name="context_menu">1</property>
<property name="default_pane">0</property>
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="drag_accept_files">0</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
<property name="font"></property>
<property name="gripper">0</property>
<property name="hidden">0</property>
<property name="id">wxID_ANY</property>
<property name="max_size"></property>
<property name="maximize_button">0</property>
<property name="maximum_size"></property>
<property name="min_size"></property>
<property name="minimize_button">0</property>
<property name="minimum_size"></property>
<property name="moveable">1</property>
<property name="name">m_staticline7</property>
<property name="pane_border">1</property>
<property name="pane_position"></property>
<property name="pane_size"></property>
<property name="permission">protected</property>
<property name="pin_button">1</property>
<property name="pos"></property>
<property name="resize">Resizable</property>
<property name="show">1</property>
<property name="size"></property>
<property name="style">wxLI_HORIZONTAL</property>
<property name="subclass">; ; forward_declare</property>
<property name="toolbar_pane">0</property>
<property name="tooltip"></property>
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style"></property>
</object>
</object>
</object>
</object>
<object class="sizeritem" expanded="true">

View File

@ -1,5 +1,5 @@
///////////////////////////////////////////////////////////////////////////
// C++ code generated with wxFormBuilder (version 4.2.1-0-g80c4cb6)
// C++ code generated with wxFormBuilder (version 4.2.1-0-g80c4cb6a-dirty)
// http://www.wxformbuilder.org/
//
// PLEASE DO *NOT* EDIT THIS FILE!
@ -44,6 +44,7 @@ class PANEL_COMMON_SETTINGS_BASE : public RESETTABLE_PANEL
private:
protected:
wxBoxSizer* bLeftSizer;
wxStaticText* m_staticText20;
wxStaticLine* m_staticline3;
wxFlexGridSizer* m_renderingSizer;
@ -85,6 +86,8 @@ class PANEL_COMMON_SETTINGS_BASE : public RESETTABLE_PANEL
wxStaticText* m_highContrastLabel;
wxTextCtrl* m_highContrastCtrl;
wxStaticText* m_highContrastUnits;
wxStaticText* m_staticText251;
wxStaticLine* m_staticline7;
wxStaticText* m_staticText23;
wxStaticLine* m_staticline6;
wxCheckBox* m_warpMouseOnMove;

View File

@ -167,9 +167,7 @@ void PANEL_EMBEDDED_FILES::resizeGrid()
bool PANEL_EMBEDDED_FILES::TransferDataToWindow()
{
m_files_grid->ClearGrid();
if( m_files_grid->GetNumberRows() > 0 )
m_files_grid->DeleteRows( 0, m_files_grid->GetNumberRows() );
m_files_grid->ClearRows();
int ii = 0;

View File

@ -21,7 +21,7 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include <widgets/gal_options_panel.h>
#include <dialogs/panel_gal_options.h>
#include <settings/app_settings.h>
#include <gal/gal_display_options.h>
#include <eda_draw_frame.h>
@ -57,8 +57,8 @@ static const UTIL::CFG_MAP<KIGFX::GRID_SNAPPING> gridSnapConfigVals =
};
GAL_OPTIONS_PANEL::GAL_OPTIONS_PANEL( wxWindow* aParent, APP_SETTINGS_BASE* aAppSettings ) :
GAL_OPTIONS_PANEL_BASE( aParent ),
PANEL_GAL_OPTIONS::PANEL_GAL_OPTIONS( wxWindow* aParent, APP_SETTINGS_BASE* aAppSettings ) :
PANEL_GAL_OPTIONS_BASE( aParent ),
m_cfg( aAppSettings )
{
// Grid settings subpanel
@ -80,7 +80,7 @@ GAL_OPTIONS_PANEL::GAL_OPTIONS_PANEL( wxWindow* aParent, APP_SETTINGS_BASE* aApp
}
bool GAL_OPTIONS_PANEL::TransferDataToWindow()
bool PANEL_GAL_OPTIONS::TransferDataToWindow()
{
m_gridSnapOptions->SetSelection( m_cfg->m_Window.grid.snap );
@ -106,7 +106,7 @@ bool GAL_OPTIONS_PANEL::TransferDataToWindow()
}
bool GAL_OPTIONS_PANEL::TransferDataFromWindow()
bool PANEL_GAL_OPTIONS::TransferDataFromWindow()
{
m_cfg->m_Window.grid.snap = m_gridSnapOptions->GetSelection();
@ -134,7 +134,7 @@ bool GAL_OPTIONS_PANEL::TransferDataFromWindow()
}
bool GAL_OPTIONS_PANEL::ResetPanel( APP_SETTINGS_BASE* aAppSettings )
bool PANEL_GAL_OPTIONS::ResetPanel( APP_SETTINGS_BASE* aAppSettings )
{
APP_SETTINGS_BASE* saved = m_cfg;

View File

@ -0,0 +1,128 @@
///////////////////////////////////////////////////////////////////////////
// C++ code generated with wxFormBuilder (version 4.2.1-0-g80c4cb6)
// http://www.wxformbuilder.org/
//
// PLEASE DO *NOT* EDIT THIS FILE!
///////////////////////////////////////////////////////////////////////////
#include "panel_gal_options_base.h"
///////////////////////////////////////////////////////////////////////////
PANEL_GAL_OPTIONS_BASE::PANEL_GAL_OPTIONS_BASE( wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style, const wxString& name ) : wxPanel( parent, id, pos, size, style, name )
{
wxBoxSizer* mainSizer;
mainSizer = new wxBoxSizer( wxVERTICAL );
m_staticText1 = new wxStaticText( this, wxID_ANY, _("Grid Display"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticText1->Wrap( -1 );
mainSizer->Add( m_staticText1, 0, wxTOP|wxRIGHT|wxLEFT, 13 );
m_staticline1 = new wxStaticLine( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL );
mainSizer->Add( m_staticline1, 0, wxEXPAND|wxTOP|wxBOTTOM, 2 );
wxBoxSizer* bSizerGridStyle;
bSizerGridStyle = new wxBoxSizer( wxHORIZONTAL );
m_gridStyleLabel = new wxStaticText( this, wxID_ANY, _("Style:"), wxDefaultPosition, wxDefaultSize, 0 );
m_gridStyleLabel->Wrap( -1 );
bSizerGridStyle->Add( m_gridStyleLabel, 0, wxALIGN_CENTER_VERTICAL|wxTOP|wxBOTTOM|wxLEFT, 5 );
m_rbDots = new wxRadioButton( this, wxID_ANY, _("Dots"), wxDefaultPosition, wxDefaultSize, wxRB_GROUP );
bSizerGridStyle->Add( m_rbDots, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
m_rbLines = new wxRadioButton( this, wxID_ANY, _("Lines"), wxDefaultPosition, wxDefaultSize, 0 );
bSizerGridStyle->Add( m_rbLines, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
m_rbCrosses = new wxRadioButton( this, wxID_ANY, _("Small crosses"), wxDefaultPosition, wxDefaultSize, 0 );
bSizerGridStyle->Add( m_rbCrosses, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 );
mainSizer->Add( bSizerGridStyle, 0, wxEXPAND|wxALL, 5 );
wxGridBagSizer* gbGridSettings;
gbGridSettings = new wxGridBagSizer( 5, 5 );
gbGridSettings->SetFlexibleDirection( wxHORIZONTAL );
gbGridSettings->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED );
l_gridLineWidth = new wxStaticText( this, wxID_ANY, _("Grid thickness:"), wxDefaultPosition, wxDefaultSize, 0 );
l_gridLineWidth->Wrap( -1 );
gbGridSettings->Add( l_gridLineWidth, wxGBPosition( 0, 0 ), wxGBSpan( 1, 1 ), wxALIGN_CENTER_VERTICAL|wxLEFT, 5 );
wxArrayString m_gridLineWidthChoices;
m_gridLineWidth = new wxChoice( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, m_gridLineWidthChoices, 0 );
m_gridLineWidth->SetSelection( 0 );
gbGridSettings->Add( m_gridLineWidth, wxGBPosition( 0, 1 ), wxGBSpan( 1, 1 ), wxALIGN_CENTER_VERTICAL|wxEXPAND, 5 );
l_gridLineWidthUnits = new wxStaticText( this, wxID_ANY, _("pixels"), wxDefaultPosition, wxDefaultSize, 0 );
l_gridLineWidthUnits->Wrap( -1 );
gbGridSettings->Add( l_gridLineWidthUnits, wxGBPosition( 0, 2 ), wxGBSpan( 1, 1 ), wxALIGN_CENTER_VERTICAL|wxRIGHT, 5 );
l_gridMinSpacing = new wxStaticText( this, wxID_ANY, _("Minimum grid spacing:"), wxDefaultPosition, wxDefaultSize, 0 );
l_gridMinSpacing->Wrap( -1 );
gbGridSettings->Add( l_gridMinSpacing, wxGBPosition( 1, 0 ), wxGBSpan( 1, 1 ), wxALIGN_CENTER_VERTICAL|wxLEFT, 5 );
m_gridMinSpacing = new wxSpinCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS, 5, 200, 10 );
gbGridSettings->Add( m_gridMinSpacing, wxGBPosition( 1, 1 ), wxGBSpan( 1, 1 ), wxALIGN_CENTER_VERTICAL|wxEXPAND, 5 );
l_gridMinSpacingUnits = new wxStaticText( this, wxID_ANY, _("pixels"), wxDefaultPosition, wxDefaultSize, 0 );
l_gridMinSpacingUnits->Wrap( -1 );
gbGridSettings->Add( l_gridMinSpacingUnits, wxGBPosition( 1, 2 ), wxGBSpan( 1, 1 ), wxALIGN_CENTER_VERTICAL|wxRIGHT, 5 );
l_gridSnapOptions = new wxStaticText( this, wxID_ANY, _("Snap to grid:"), wxDefaultPosition, wxDefaultSize, 0 );
l_gridSnapOptions->Wrap( -1 );
gbGridSettings->Add( l_gridSnapOptions, wxGBPosition( 2, 0 ), wxGBSpan( 1, 1 ), wxALIGN_CENTER_VERTICAL|wxLEFT, 5 );
wxString m_gridSnapOptionsChoices[] = { _("Always"), _("When grid shown"), _("Never") };
int m_gridSnapOptionsNChoices = sizeof( m_gridSnapOptionsChoices ) / sizeof( wxString );
m_gridSnapOptions = new wxChoice( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, m_gridSnapOptionsNChoices, m_gridSnapOptionsChoices, 0 );
m_gridSnapOptions->SetSelection( 0 );
gbGridSettings->Add( m_gridSnapOptions, wxGBPosition( 2, 1 ), wxGBSpan( 1, 2 ), wxALIGN_CENTER_VERTICAL|wxEXPAND|wxRIGHT, 5 );
gbGridSettings->AddGrowableCol( 1 );
mainSizer->Add( gbGridSettings, 0, wxEXPAND|wxALL, 5 );
mainSizer->Add( 0, 5, 0, 0, 5 );
m_stGridLabel = new wxStaticText( this, wxID_ANY, _("Cursor"), wxDefaultPosition, wxDefaultSize, 0 );
m_stGridLabel->Wrap( -1 );
mainSizer->Add( m_stGridLabel, 0, wxTOP|wxRIGHT|wxLEFT, 13 );
m_staticline2 = new wxStaticLine( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL );
mainSizer->Add( m_staticline2, 0, wxEXPAND|wxTOP|wxBOTTOM, 2 );
wxFlexGridSizer* fgSizer1;
fgSizer1 = new wxFlexGridSizer( 0, 1, 3, 0 );
fgSizer1->SetFlexibleDirection( wxBOTH );
fgSizer1->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED );
m_rbSmallCrosshairs = new wxRadioButton( this, wxID_ANY, _("Small crosshairs"), wxDefaultPosition, wxDefaultSize, wxRB_GROUP );
fgSizer1->Add( m_rbSmallCrosshairs, 0, wxTOP|wxLEFT, 5 );
m_rbFullWindowCrosshairs = new wxRadioButton( this, wxID_ANY, _("Full window crosshairs"), wxDefaultPosition, wxDefaultSize, 0 );
fgSizer1->Add( m_rbFullWindowCrosshairs, 0, wxLEFT, 5 );
m_rb45DegreeCrosshairs = new wxRadioButton( this, wxID_ANY, _("45 degree crosshairs"), wxDefaultPosition, wxDefaultSize, 0 );
fgSizer1->Add( m_rb45DegreeCrosshairs, 0, wxLEFT, 5 );
fgSizer1->Add( 0, 8, 0, wxEXPAND, 5 );
m_forceCursorDisplay = new wxCheckBox( this, wxID_ANY, _("Always show crosshairs"), wxDefaultPosition, wxDefaultSize, 0 );
fgSizer1->Add( m_forceCursorDisplay, 0, wxLEFT, 5 );
mainSizer->Add( fgSizer1, 1, wxEXPAND|wxTOP|wxRIGHT|wxLEFT, 5 );
this->SetSizer( mainSizer );
this->Layout();
mainSizer->Fit( this );
}
PANEL_GAL_OPTIONS_BASE::~PANEL_GAL_OPTIONS_BASE()
{
}

View File

@ -13,12 +13,12 @@
<property name="cpp_use_enum">0</property>
<property name="embedded_files_path">res</property>
<property name="encoding">UTF-8</property>
<property name="file">gal_options_panel_base</property>
<property name="file">panel_gal_options_base</property>
<property name="first_id">1000</property>
<property name="internationalize">1</property>
<property name="lua_skip_events">1</property>
<property name="lua_ui_table">UI</property>
<property name="name">GAL_OPTIONS_PANEL_BASE_PRJ</property>
<property name="name">PANEL_GAL_OPTIONS_BASE</property>
<property name="path">.</property>
<property name="php_disconnect_events">0</property>
<property name="php_disconnect_mode">source_name</property>
@ -46,7 +46,7 @@
<property name="id">wxID_ANY</property>
<property name="maximum_size"></property>
<property name="minimum_size"></property>
<property name="name">GAL_OPTIONS_PANEL_BASE</property>
<property name="name">PANEL_GAL_OPTIONS_BASE</property>
<property name="pos"></property>
<property name="size">-1,-1</property>
<property name="subclass">; ; forward_declare</property>
@ -1267,7 +1267,7 @@
<property name="value">0</property>
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style"></property>
<property name="window_style"></property>
</object>
</object>
<object class="sizeritem" expanded="true">

View File

@ -0,0 +1,66 @@
///////////////////////////////////////////////////////////////////////////
// C++ code generated with wxFormBuilder (version 4.2.1-0-g80c4cb6)
// http://www.wxformbuilder.org/
//
// PLEASE DO *NOT* EDIT THIS FILE!
///////////////////////////////////////////////////////////////////////////
#pragma once
#include <wx/artprov.h>
#include <wx/xrc/xmlres.h>
#include <wx/intl.h>
#include <wx/string.h>
#include <wx/stattext.h>
#include <wx/gdicmn.h>
#include <wx/font.h>
#include <wx/colour.h>
#include <wx/settings.h>
#include <wx/statline.h>
#include <wx/radiobut.h>
#include <wx/sizer.h>
#include <wx/choice.h>
#include <wx/spinctrl.h>
#include <wx/gbsizer.h>
#include <wx/checkbox.h>
#include <wx/panel.h>
///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
/// Class PANEL_GAL_OPTIONS_BASE
///////////////////////////////////////////////////////////////////////////////
class PANEL_GAL_OPTIONS_BASE : public wxPanel
{
private:
protected:
wxStaticText* m_staticText1;
wxStaticLine* m_staticline1;
wxStaticText* m_gridStyleLabel;
wxRadioButton* m_rbDots;
wxRadioButton* m_rbLines;
wxRadioButton* m_rbCrosses;
wxStaticText* l_gridLineWidth;
wxChoice* m_gridLineWidth;
wxStaticText* l_gridLineWidthUnits;
wxStaticText* l_gridMinSpacing;
wxSpinCtrl* m_gridMinSpacing;
wxStaticText* l_gridMinSpacingUnits;
wxStaticText* l_gridSnapOptions;
wxChoice* m_gridSnapOptions;
wxStaticText* m_stGridLabel;
wxStaticLine* m_staticline2;
wxRadioButton* m_rbSmallCrosshairs;
wxRadioButton* m_rbFullWindowCrosshairs;
wxRadioButton* m_rb45DegreeCrosshairs;
wxCheckBox* m_forceCursorDisplay;
public:
PANEL_GAL_OPTIONS_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_GAL_OPTIONS_BASE();
};

View File

@ -25,7 +25,6 @@
#include <gestfich.h>
#include <hotkeys_basic.h>
#include <kiway_player.h>
#include <locale_io.h>
#include <panel_hotkeys_editor.h>
#include <wildcards_and_files_ext.h>
#include <tool/tool_manager.h>

View File

@ -118,6 +118,26 @@ bool PANEL_IMAGE_EDITOR::TransferDataFromWindow()
}
double PANEL_IMAGE_EDITOR::GetScale() const
{
return m_scale.GetDoubleValue();
}
void PANEL_IMAGE_EDITOR::SetScale( double aScale )
{
m_scale.ChangeDoubleValue( aScale );
m_workingImage->SetScale( aScale );
m_panelDraw->Refresh();
}
VECTOR2I PANEL_IMAGE_EDITOR::GetImageSize() const
{
return m_workingImage->GetSize();
}
void PANEL_IMAGE_EDITOR::OnRedrawPanel( wxPaintEvent& event )
{
wxPaintDC dc( m_panelDraw );

View File

@ -87,6 +87,10 @@ EDA_DRAW_PANEL_GAL::EDA_DRAW_PANEL_GAL( wxWindow* aParentWindow, wxWindowID aWin
m_stealsFocus( true ),
m_statusPopup( nullptr )
{
#ifdef _WIN32
// need to fix broken cairo rendering on Windows with wx 3.3
SetDoubleBuffered( false );
#endif
m_PaintEventCounter = std::make_unique<PROF_COUNTER>( "Draw panel paint events" );
if( Pgm().GetCommonSettings()->m_Appearance.show_scrollbars )

View File

@ -333,10 +333,9 @@ bool DS_DRAW_ITEM_POLYPOLYGONS::HitTest( const BOX2I& aRect, bool aContained, in
}
wxString DS_DRAW_ITEM_POLYPOLYGONS::GetItemDescription( UNITS_PROVIDER* aUnitsProvider,
bool aFull ) const
wxString DS_DRAW_ITEM_POLYPOLYGONS::GetItemDescription( UNITS_PROVIDER* aUnitsProvider, bool aFull ) const
{
return _( "Imported Shape" );
return _( "Imported shape" );
}
@ -435,10 +434,9 @@ bool DS_DRAW_ITEM_RECT::HitTest( const BOX2I& aRect, bool aContained, int aAccur
wxString DS_DRAW_ITEM_RECT::GetItemDescription( UNITS_PROVIDER* aUnitsProvider, bool aFull ) const
{
return wxString::Format(
_( "Rectangle, width %s height %s" ),
aUnitsProvider->MessageTextFromValue( std::abs( GetStart().x - GetEnd().x ) ),
aUnitsProvider->MessageTextFromValue( std::abs( GetStart().y - GetEnd().y ) ) );
return wxString::Format( _( "Rectangle, width %s height %s" ),
aUnitsProvider->MessageTextFromValue( std::abs( GetStart().x - GetEnd().x ) ),
aUnitsProvider->MessageTextFromValue( std::abs( GetStart().y - GetEnd().y ) ) );
}
@ -527,7 +525,7 @@ wxString DS_DRAW_ITEM_BITMAP::GetItemDescription( UNITS_PROVIDER* aUnitsProvider
wxString DS_DRAW_ITEM_PAGE::GetItemDescription( UNITS_PROVIDER* aUnitsProvider, bool aFull ) const
{
return _( "Page Limits" );
return _( "Page limits" );
}

View File

@ -60,6 +60,7 @@ track_segment_length
version
via
via_count
via_dangling
via_diameter
warning
within_diff_pairs

View File

@ -22,7 +22,7 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include <charconv>
#include <fast_float/fast_float.h>
#include <cstdarg>
#include <cstdio>
#include <cstdlib> // bsearch()
@ -861,43 +861,13 @@ wxArrayString* DSNLEXER::ReadCommentLines()
double DSNLEXER::parseDouble()
{
// We try here to be locale independent to avoid the need to switch to a "C" locale
#if ( defined( __GNUC__ ) && __GNUC__ < 11 ) || ( defined( __clang__ ) && __clang_major__ < 13 )
// GCC older than 11 "supports" C++17 without supporting the C++17 std::from_chars for doubles
// clang is similar
// Use wxString::ToCDouble() which is designed to be locale independent
wxString tmp = CurStr();
double fval;
bool success = tmp.ToCDouble( &fval );
if( !success )
{
wxString error;
error.Printf( _( "Invalid floating point number in\nfile: '%s'\nline: %d\noffset: %d" ),
CurSource(), CurLineNumber(), CurOffset() );
THROW_IO_ERROR( error );
}
return fval;
#else
// Use std::from_chars which is designed to be locale independent and performance oriented
// for data interchange
// Use fast_float::from_chars which is designed to be locale independent and significantly
// faster than strtod and std::from_chars
const std::string& str = CurStr();
// Offset any leading whitespace, this is one thing from_chars does not handle
size_t woff = 0;
while( std::isspace( str[woff] ) && woff < str.length() )
{
woff++;
}
double dval{};
std::from_chars_result res =
std::from_chars( str.data() + woff, str.data() + str.size(), dval );
fast_float::from_chars_result res = fast_float::from_chars( str.data(), str.data() + str.size(), dval,
fast_float::chars_format::skip_white_space );
if( res.ec != std::errc() )
{
@ -906,5 +876,4 @@ double DSNLEXER::parseDouble()
}
return dval;
#endif
}

View File

@ -1059,32 +1059,35 @@ std::vector<wxWindow*> EDA_DRAW_FRAME::findDialogs()
}
void EDA_DRAW_FRAME::FocusOnLocation( const VECTOR2I& aPos )
void EDA_DRAW_FRAME::FocusOnLocation( const VECTOR2I& aPos, bool aAllowScroll )
{
bool centerView = false;
BOX2D r = GetCanvas()->GetView()->GetViewport();
// Center if we're off the current view, or within 10% of its edge
r.Inflate( - r.GetWidth() / 10.0 );
if( !r.Contains( aPos ) )
centerView = true;
bool centerView = false;
std::vector<BOX2D> dialogScreenRects;
for( wxWindow* dialog : findDialogs() )
if( aAllowScroll )
{
dialogScreenRects.emplace_back( ToVECTOR2D( GetCanvas()->ScreenToClient( dialog->GetScreenPosition() ) ),
ToVECTOR2D( dialog->GetSize() ) );
}
BOX2D r = GetCanvas()->GetView()->GetViewport();
// Center if we're behind an obscuring dialog, or within 10% of its edge
for( BOX2D rect : dialogScreenRects )
{
rect.Inflate( rect.GetWidth() / 10 );
// Center if we're off the current view, or within 10% of its edge
r.Inflate( - r.GetWidth() / 10.0 );
if( rect.Contains( GetCanvas()->GetView()->ToScreen( aPos ) ) )
if( !r.Contains( aPos ) )
centerView = true;
for( wxWindow* dialog : findDialogs() )
{
dialogScreenRects.emplace_back( ToVECTOR2D( GetCanvas()->ScreenToClient( dialog->GetScreenPosition() ) ),
ToVECTOR2D( dialog->GetSize() ) );
}
// Center if we're behind an obscuring dialog, or within 10% of its edge
for( BOX2D rect : dialogScreenRects )
{
rect.Inflate( rect.GetWidth() / 10 );
if( rect.Contains( GetCanvas()->GetView()->ToScreen( aPos ) ) )
centerView = true;
}
}
if( centerView )

View File

@ -143,8 +143,7 @@ INSPECT_RESULT EDA_ITEM::Visit( INSPECTOR inspector, void* testData,
wxString EDA_ITEM::GetItemDescription( UNITS_PROVIDER* aUnitsProvider, bool aFull ) const
{
wxFAIL_MSG( wxT( "GetItemDescription() was not overridden for schematic item type " ) +
GetClass() );
wxFAIL_MSG( wxT( "GetItemDescription() was not overridden for schematic item type " ) + GetClass() );
return wxString( wxT( "Undefined item description for " ) + GetClass() );
}
@ -434,6 +433,7 @@ static struct EDA_ITEM_DESC
.Map( PCB_DIM_RADIAL_T, _HKI( "Dimension" ) )
.Map( PCB_DIM_LEADER_T, _HKI( "Leader" ) )
.Map( PCB_TARGET_T, _HKI( "Target" ) )
.Map( PCB_POINT_T, _HKI( "Point" ) )
.Map( PCB_ZONE_T, _HKI( "Zone" ) )
.Map( PCB_ITEM_LIST_T, _HKI( "ItemList" ) )
.Map( PCB_NETINFO_T, _HKI( "NetInfo" ) )

View File

@ -35,8 +35,11 @@
#include <geometry/shape_simple.h>
#include <geometry/shape_segment.h>
#include <geometry/shape_rect.h>
#include <geometry/roundrect.h>
#include <geometry/geometry_utils.h>
#include <macros.h>
#include <algorithm>
#include <properties/property_validators.h>
#include <math/util.h> // for KiROUND
#include <eda_item.h>
#include <plotters/plotter.h>
@ -54,6 +57,7 @@ EDA_SHAPE::EDA_SHAPE( SHAPE_T aType, int aLineWidth, FILL_T aFill ) :
m_hatchingDirty( true ),
m_rectangleHeight( 0 ),
m_rectangleWidth( 0 ),
m_cornerRadius( 0 ),
m_segmentLength( 0 ),
m_editState( 0 ),
m_proxyItem( false )
@ -73,6 +77,7 @@ EDA_SHAPE::EDA_SHAPE( const SHAPE& aShape ) :
m_hatchingDirty( true ),
m_rectangleHeight( 0 ),
m_rectangleWidth( 0 ),
m_cornerRadius( 0 ),
m_segmentLength( 0 ),
m_editState( 0 ),
m_proxyItem( false )
@ -188,6 +193,7 @@ void EDA_SHAPE::Serialize( google::protobuf::Any &aContainer ) const
types::GraphicRectangleAttributes* rectangle = shape.mutable_rectangle();
PackVector2( *rectangle->mutable_top_left(), GetStart() );
PackVector2( *rectangle->mutable_bottom_right(), GetEnd() );
rectangle->mutable_corner_radius()->set_value_nm( GetCornerRadius() );
break;
}
@ -280,6 +286,7 @@ bool EDA_SHAPE::Deserialize( const google::protobuf::Any &aContainer )
SetShape( SHAPE_T::RECTANGLE );
SetStart( UnpackVector2( shape.rectangle().top_left() ) );
SetEnd( UnpackVector2( shape.rectangle().bottom_right() ) );
SetCornerRadius( shape.rectangle().corner_radius().value_nm() );
}
else if( shape.has_arc() )
{
@ -433,6 +440,29 @@ int EDA_SHAPE::GetRectangleWidth() const
}
int EDA_SHAPE::GetCornerRadius() const
{
return m_cornerRadius;
}
void EDA_SHAPE::SetCornerRadius( int aRadius )
{
if( m_shape == SHAPE_T::RECTANGLE )
{
int width = std::abs( GetRectangleWidth() );
int height = std::abs( GetRectangleHeight() );
int maxRadius = std::min( width, height ) / 2;
m_cornerRadius = std::clamp( aRadius, 0, maxRadius );
}
else
{
m_cornerRadius = aRadius;
}
}
void EDA_SHAPE::SetLength( const double& aLength )
{
switch( m_shape )
@ -604,11 +634,11 @@ void EDA_SHAPE::UpdateHatching() const
return;
case SHAPE_T::RECTANGLE:
shapeBuffer.NewOutline();
for( const VECTOR2I& pt : GetRectCorners() )
shapeBuffer.Append( pt );
{
ROUNDRECT rr( SHAPE_RECT( getPosition(), GetRectangleWidth(), GetRectangleHeight() ),
GetCornerRadius() );
rr.TransformToPolygon( shapeBuffer );
}
break;
case SHAPE_T::CIRCLE:
@ -644,8 +674,8 @@ void EDA_SHAPE::UpdateHatching() const
// Generate a grid of holes for a cross-hatch. This is about 3X the speed of the above
// algorithm, even when modified for the 45-degree fracture problem.
int gridsize = GetHatchLineSpacing();
int hole_size = gridsize - GetHatchLineWidth();
int gridsize = GetHatchLineSpacing();
int hole_size = gridsize - GetHatchLineWidth();
m_hatching = shapeBuffer.CloneDropTriangulation();
m_hatching.Rotate( -ANGLE_45 );
@ -748,16 +778,11 @@ void EDA_SHAPE::scale( double aScale )
case SHAPE_T::SEGMENT:
case SHAPE_T::RECTANGLE:
case SHAPE_T::CIRCLE:
scalePt( m_start );
scalePt( m_end );
break;
case SHAPE_T::CIRCLE: // ring or circle
scalePt( m_start );
m_end.x = m_start.x + KiROUND( GetRadius() * aScale );
m_end.y = m_start.y;
break;
case SHAPE_T::POLY: // polygon
{
std::vector<VECTOR2I> pts;
@ -974,10 +999,9 @@ void EDA_SHAPE::SetCenter( const VECTOR2I& aCenter )
VECTOR2I EDA_SHAPE::GetArcMid() const
{
// If none of the input data have changed since we loaded the arc,
// keep the original mid point data to minimize churn
if( m_arcMidData.start == m_start && m_arcMidData.end == m_end
&& m_arcMidData.center == m_arcCenter )
// If none of the input data have changed since we loaded the arc, keep the original mid point data
// to minimize churn
if( m_arcMidData.start == m_start && m_arcMidData.end == m_end && m_arcMidData.center == m_arcCenter )
return m_arcMidData.mid;
VECTOR2I mid = m_start;
@ -1179,21 +1203,17 @@ void EDA_SHAPE::ShapeGetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PA
break;
case SHAPE_T::RECTANGLE:
aList.emplace_back( _( "Width" ),
aFrame->MessageTextFromValue( std::abs( GetEnd().x - GetStart().x ) ) );
aList.emplace_back( _( "Height" ),
aFrame->MessageTextFromValue( std::abs( GetEnd().y - GetStart().y ) ) );
aList.emplace_back( _( "Width" ), aFrame->MessageTextFromValue( std::abs( GetEnd().x - GetStart().x ) ) );
aList.emplace_back( _( "Height" ), aFrame->MessageTextFromValue( std::abs( GetEnd().y - GetStart().y ) ) );
break;
case SHAPE_T::SEGMENT:
{
aList.emplace_back( _( "Length" ),
aFrame->MessageTextFromValue( GetStart().Distance( GetEnd() ) ));
aList.emplace_back( _( "Length" ), aFrame->MessageTextFromValue( GetStart().Distance( GetEnd() ) ));
// angle counter-clockwise from 3'o-clock
EDA_ANGLE angle( atan2( (double)( GetStart().y - GetEnd().y ),
(double)( GetEnd().x - GetStart().x ) ), RADIANS_T );
EDA_ANGLE angle( atan2( (double)( GetStart().y - GetEnd().y ), (double)( GetEnd().x - GetStart().x ) ),
RADIANS_T );
aList.emplace_back( _( "Angle" ), EDA_UNIT_UTILS::UI::MessageTextFromValue( angle ) );
break;
}
@ -1246,6 +1266,7 @@ const BOX2I EDA_SHAPE::getBoundingBox() const
// using the bounding box of the curve (not control!) points.
for( const VECTOR2I& pt : m_bezierPoints )
bbox.Merge( pt );
break;
default:
@ -1293,9 +1314,9 @@ bool EDA_SHAPE::hitTest( const VECTOR2I& aPosition, int aAccuracy ) const
if( aPosition.Distance( m_end ) <= maxdist )
return true;
double radius = GetRadius();
double radius = GetRadius();
VECTOR2D relPos( VECTOR2D( aPosition ) - getCenter() );
double dist = relPos.EuclideanNorm();
double dist = relPos.EuclideanNorm();
if( IsFilledForHitTesting() )
{
@ -1361,6 +1382,15 @@ bool EDA_SHAPE::hitTest( const VECTOR2I& aPosition, int aAccuracy ) const
return poly.Collide( aPosition, maxdist );
}
else if( m_cornerRadius > 0 )
{
ROUNDRECT rr( SHAPE_RECT( GetStart(), GetRectangleWidth(), GetRectangleHeight() ), m_cornerRadius );
SHAPE_POLY_SET poly;
rr.TransformToPolygon( poly );
if( poly.CollideEdge( aPosition, nullptr, maxdist ) )
return true;
}
else
{
std::vector<VECTOR2I> pts = GetRectCorners();
@ -1372,13 +1402,13 @@ bool EDA_SHAPE::hitTest( const VECTOR2I& aPosition, int aAccuracy ) const
{
return true;
}
if( IsHatchedFill() && GetHatching().Collide( aPosition, maxdist ) )
return true;
return false;
}
if( IsHatchedFill() && GetHatching().Collide( aPosition, maxdist ) )
return true;
return false;
case SHAPE_T::POLY:
if( IsFilledForHitTesting() )
{
@ -1420,6 +1450,40 @@ bool EDA_SHAPE::hitTest( const BOX2I& aRect, bool aContained, int aAccuracy ) co
BOX2I bbox = getBoundingBox();
auto checkOutline =
[&]( const SHAPE_LINE_CHAIN& outline )
{
int count = (int) outline.GetPointCount();
for( int ii = 0; ii < count; ii++ )
{
VECTOR2I vertex = outline.GetPoint( ii );
// Test if the point is within aRect
if( arect.Contains( vertex ) )
return true;
if( ii + 1 < count )
{
VECTOR2I vertexNext = outline.GetPoint( ii + 1 );
// Test if this edge intersects aRect
if( arect.Intersects( vertex, vertexNext ) )
return true;
}
else if( outline.IsClosed() )
{
VECTOR2I vertexNext = outline.GetPoint( 0 );
// Test if this edge intersects aRect
if( arect.Intersects( vertex, vertexNext ) )
return true;
}
}
return false;
};
switch( m_shape )
{
case SHAPE_T::CIRCLE:
@ -1466,6 +1530,17 @@ bool EDA_SHAPE::hitTest( const BOX2I& aRect, bool aContained, int aAccuracy ) co
{
return arect.Contains( bbox );
}
else if( m_cornerRadius > 0 )
{
ROUNDRECT rr( SHAPE_RECT( GetStart(), GetRectangleWidth(), GetRectangleHeight() ), m_cornerRadius );
SHAPE_POLY_SET poly;
rr.TransformToPolygon( poly );
// Account for the width of the line
arect.Inflate( GetWidth() / 2 );
return checkOutline( poly.Outline( 0 ) );
}
else
{
std::vector<VECTOR2I> pts = GetRectCorners();
@ -1507,34 +1582,8 @@ bool EDA_SHAPE::hitTest( const BOX2I& aRect, bool aContained, int aAccuracy ) co
for( int ii = 0; ii < m_poly.OutlineCount(); ++ii )
{
const SHAPE_LINE_CHAIN& poly = m_poly.Outline( ii );
int count = poly.GetPointCount();
for( int jj = 0; jj < count; jj++ )
{
VECTOR2I vertex = poly.GetPoint( jj );
// Test if the point is within aRect
if( arect.Contains( vertex ) )
return true;
if( jj + 1 < count )
{
VECTOR2I vertexNext = poly.GetPoint( jj + 1 );
// Test if this edge intersects aRect
if( arect.Intersects( vertex, vertexNext ) )
return true;
}
else if( poly.IsClosed() )
{
VECTOR2I vertexNext = poly.GetPoint( 0 );
// Test if this edge intersects aRect
if( arect.Intersects( vertex, vertexNext ) )
return true;
}
}
if( checkOutline( m_poly.Outline( ii ) ) )
return true;
}
return false;
@ -1805,17 +1854,42 @@ std::vector<SHAPE*> EDA_SHAPE::makeEffectiveShapes( bool aEdgeOnly, bool aLineCh
case SHAPE_T::RECTANGLE:
{
std::vector<VECTOR2I> pts = GetRectCorners();
if( solidFill )
effectiveShapes.emplace_back( new SHAPE_SIMPLE( pts ) );
if( width > 0 || !solidFill )
if( m_cornerRadius > 0 )
{
effectiveShapes.emplace_back( new SHAPE_SEGMENT( pts[0], pts[1], width ) );
effectiveShapes.emplace_back( new SHAPE_SEGMENT( pts[1], pts[2], width ) );
effectiveShapes.emplace_back( new SHAPE_SEGMENT( pts[2], pts[3], width ) );
effectiveShapes.emplace_back( new SHAPE_SEGMENT( pts[3], pts[0], width ) );
ROUNDRECT rr( SHAPE_RECT( GetStart(), GetRectangleWidth(), GetRectangleHeight() ), m_cornerRadius );
SHAPE_POLY_SET poly;
rr.TransformToPolygon( poly );
SHAPE_LINE_CHAIN outline = poly.Outline( 0 );
if( solidFill )
effectiveShapes.emplace_back( new SHAPE_SIMPLE( outline ) );
if( width > 0 || !solidFill )
{
for( int i = 0; i < outline.PointCount() - 1; ++i )
{
effectiveShapes.emplace_back( new SHAPE_SEGMENT( outline.CPoint( i ), outline.CPoint( i + 1 ),
width ) );
}
effectiveShapes.emplace_back( new SHAPE_SEGMENT( outline.CPoint( outline.PointCount() - 1 ),
outline.CPoint( 0 ), width ) );
}
}
else
{
std::vector<VECTOR2I> pts = GetRectCorners();
if( solidFill )
effectiveShapes.emplace_back( new SHAPE_SIMPLE( pts ) );
if( width > 0 || !solidFill )
{
effectiveShapes.emplace_back( new SHAPE_SEGMENT( pts[0], pts[1], width ) );
effectiveShapes.emplace_back( new SHAPE_SEGMENT( pts[1], pts[2], width ) );
effectiveShapes.emplace_back( new SHAPE_SEGMENT( pts[2], pts[3], width ) );
effectiveShapes.emplace_back( new SHAPE_SEGMENT( pts[3], pts[0], width ) );
}
}
break;
}
@ -1976,7 +2050,7 @@ bool EDA_SHAPE::continueEdit( const VECTOR2I& aPosition )
SHAPE_LINE_CHAIN& poly = m_poly.Outline( 0 );
// do not add zero-length segments
if( poly.CPoint( poly.GetPointCount() - 2 ) != poly.CLastPoint() )
if( poly.CPoint( (int) poly.GetPointCount() - 2 ) != poly.CLastPoint() )
poly.Append( aPosition, true );
}
return true;
@ -2010,12 +2084,19 @@ void EDA_SHAPE::calcEdit( const VECTOR2I& aPosition )
SetBezierC1( aPosition );
SetBezierC2( aPosition );
break;
case 1:
SetBezierC2( aPosition );
SetEnd( aPosition );
break;
case 2: SetBezierC1( aPosition ); break;
case 3: SetBezierC2( aPosition ); break;
case 2:
SetBezierC1( aPosition );
break;
case 3:
SetBezierC2( aPosition );
break;
}
RebuildBezierToSegmentsPointsList( getMaxError() );
@ -2066,16 +2147,16 @@ void EDA_SHAPE::calcEdit( const VECTOR2I& aPosition )
if( ratio != 0 )
radius = std::max( sqrt( sq( radius ) * ratio ), sqrt( chordAfter ) / 2 );
}
break;
}
case 4:
{
double radialA = m_start.Distance( aPosition );
double radialB = m_end.Distance( aPosition );
radius = ( radialA + radialB ) / 2.0;
}
break;
}
case 5:
SetArcGeometry( GetStart(), aPosition, GetEnd() );
@ -2129,8 +2210,9 @@ void EDA_SHAPE::calcEdit( const VECTOR2I& aPosition )
m_arcCenter = c1.Distance( aPosition ) < c2.Distance( aPosition ) ? c1 : c2;
break;
}
}
break;
}
case SHAPE_T::POLY:
m_poly.Outline( 0 ).SetPoint( m_poly.Outline( 0 ).GetPointCount() - 1, aPosition );
@ -2170,8 +2252,9 @@ void EDA_SHAPE::endEdit( bool aClosed )
poly.Remove( poly.GetPointCount() - 1 );
}
}
}
break;
}
default:
UNIMPLEMENTED_FOR( SHAPE_T_asString() );
@ -2194,6 +2277,7 @@ void EDA_SHAPE::SwapShape( EDA_SHAPE* aImage )
SWAPITEM( m_bezierC2 );
SWAPITEM( m_bezierPoints );
SWAPITEM( m_poly );
SWAPITEM( m_cornerRadius );
SWAPITEM( m_fill );
SWAPITEM( m_fillColor );
SWAPITEM( m_editState );
@ -2217,7 +2301,11 @@ int EDA_SHAPE::Compare( const EDA_SHAPE* aOther ) const
TEST( (int) m_shape, (int) aOther->m_shape );
if( m_shape == SHAPE_T::ARC )
if( m_shape == SHAPE_T::RECTANGLE )
{
TEST( m_cornerRadius, aOther->m_cornerRadius );
}
else if( m_shape == SHAPE_T::ARC )
{
TEST_PT( GetArcMid(), aOther->GetArcMid() );
}
@ -2246,8 +2334,7 @@ int EDA_SHAPE::Compare( const EDA_SHAPE* aOther ) const
void EDA_SHAPE::TransformShapeToPolygon( SHAPE_POLY_SET& aBuffer, int aClearance, int aError,
ERROR_LOC aErrorLoc, bool ignoreLineWidth,
bool includeFill ) const
ERROR_LOC aErrorLoc, bool ignoreLineWidth, bool includeFill ) const
{
bool solidFill = IsSolidFill() || ( IsHatchedFill() && !includeFill ) || IsProxyItem();
int width = ignoreLineWidth ? 0 : GetWidth();
@ -2270,23 +2357,53 @@ void EDA_SHAPE::TransformShapeToPolygon( SHAPE_POLY_SET& aBuffer, int aClearance
case SHAPE_T::RECTANGLE:
{
std::vector<VECTOR2I> pts = GetRectCorners();
if( solidFill )
if( GetCornerRadius() > 0 )
{
aBuffer.NewOutline();
// Use specialized function for rounded rectangles
VECTOR2I size( GetRectangleWidth(), GetRectangleHeight() );
VECTOR2I position = GetStart() + size / 2; // Center position
for( const VECTOR2I& pt : pts )
aBuffer.Append( pt );
if( solidFill )
{
TransformRoundChamferedRectToPolygon( aBuffer, position, size, ANGLE_0, GetCornerRadius(),
0.0, 0, width / 2, aError, aErrorLoc );
}
else
{
// Export outline as a set of thick segments:
SHAPE_POLY_SET poly;
TransformRoundChamferedRectToPolygon( poly, position, size, ANGLE_0, GetCornerRadius(),
0.0, 0, 0, aError, aErrorLoc );
SHAPE_LINE_CHAIN& outline = poly.Outline( 0 );
outline.SetClosed( true );
for( int ii = 0; ii < outline.PointCount(); ii++ )
{
TransformOvalToPolygon( aBuffer, outline.CPoint( ii ), outline.CPoint( ii+1 ), width,
aError, aErrorLoc );
}
}
}
if( width > 0 || !solidFill )
else
{
// Add in segments
TransformOvalToPolygon( aBuffer, pts[0], pts[1], width, aError, aErrorLoc );
TransformOvalToPolygon( aBuffer, pts[1], pts[2], width, aError, aErrorLoc );
TransformOvalToPolygon( aBuffer, pts[2], pts[3], width, aError, aErrorLoc );
TransformOvalToPolygon( aBuffer, pts[3], pts[0], width, aError, aErrorLoc );
std::vector<VECTOR2I> pts = GetRectCorners();
if( solidFill )
{
aBuffer.NewOutline();
for( const VECTOR2I& pt : pts )
aBuffer.Append( pt );
}
if( width > 0 || !solidFill )
{
// Add in segments
TransformOvalToPolygon( aBuffer, pts[0], pts[1], width, aError, aErrorLoc );
TransformOvalToPolygon( aBuffer, pts[1], pts[2], width, aError, aErrorLoc );
TransformOvalToPolygon( aBuffer, pts[2], pts[3], width, aError, aErrorLoc );
TransformOvalToPolygon( aBuffer, pts[3], pts[0], width, aError, aErrorLoc );
}
}
break;
@ -2648,6 +2765,37 @@ static struct EDA_SHAPE_DESC
shapeProps )
.SetAvailableFunc( isRectangle );
propMgr.AddProperty( new PROPERTY<EDA_SHAPE, int>( _HKI( "Corner Radius" ),
&EDA_SHAPE::SetCornerRadius, &EDA_SHAPE::GetCornerRadius,
PROPERTY_DISPLAY::PT_SIZE, ORIGIN_TRANSFORMS::NOT_A_COORD ),
shapeProps )
.SetAvailableFunc( isRectangle )
.SetValidator( []( const wxAny&& aValue, EDA_ITEM* aItem ) -> VALIDATOR_RESULT
{
wxASSERT_MSG( aValue.CheckType<int>(),
"Expecting int-containing value" );
int radius = aValue.As<int>();
EDA_SHAPE* prop_shape = dynamic_cast<EDA_SHAPE*>( aItem );
if( !prop_shape )
{
wxLogDebug( wxT( "Corner Radius Validator: Not an EDA_SHAPE" ) );
return std::nullopt;
}
int maxRadius = std::min( prop_shape->GetRectangleWidth(),
prop_shape->GetRectangleHeight() ) / 2;
if( radius > maxRadius )
return std::make_unique<VALIDATION_ERROR_TOO_LARGE<int>>( radius, maxRadius );
else if( radius < 0 )
return std::make_unique<VALIDATION_ERROR_TOO_SMALL<int>>( radius, 0 );
return std::nullopt;
} );
propMgr.AddProperty( new PROPERTY<EDA_SHAPE, int>( _HKI( "Line Width" ),
&EDA_SHAPE::SetWidth, &EDA_SHAPE::GetWidth, PROPERTY_DISPLAY::PT_SIZE ),
shapeProps );

View File

@ -35,6 +35,7 @@
#include <font/glyph.h>
#include <gr_text.h>
#include <string_utils.h> // for UnescapeString
#include <text_eval/text_eval_wrapper.h>
#include <math/util.h> // for KiROUND
#include <math/vector2d.h>
#include <core/kicad_algo.h>
@ -638,6 +639,14 @@ void EDA_TEXT::cacheShownText()
}
wxString EDA_TEXT::EvaluateText( const wxString& aText ) const
{
static EXPRESSION_EVALUATOR evaluator;
return evaluator.Evaluate( aText );
}
KIFONT::FONT* EDA_TEXT::GetDrawFont( const RENDER_SETTINGS* aSettings ) const
{
KIFONT::FONT* font = GetFont();
@ -1405,12 +1414,10 @@ static struct EDA_TEXT_DESC
PROPERTY_DISPLAY::PT_SIZE ),
textProps );
propMgr.AddProperty( new PROPERTY_ENUM<EDA_TEXT, GR_TEXT_H_ALIGN_T>(
_HKI( "Horizontal Justification" ),
propMgr.AddProperty( new PROPERTY_ENUM<EDA_TEXT, GR_TEXT_H_ALIGN_T>( _HKI( "Horizontal Justification" ),
&EDA_TEXT::SetHorizJustify, &EDA_TEXT::GetHorizJustify ),
textProps );
propMgr.AddProperty( new PROPERTY_ENUM<EDA_TEXT, GR_TEXT_V_ALIGN_T>(
_HKI( "Vertical Justification" ),
propMgr.AddProperty( new PROPERTY_ENUM<EDA_TEXT, GR_TEXT_V_ALIGN_T>( _HKI( "Vertical Justification" ),
&EDA_TEXT::SetVertJustify, &EDA_TEXT::GetVertJustify ),
textProps );

View File

@ -458,6 +458,28 @@ wxString EDA_UNIT_UTILS::UI::MessageTextFromValue( const EDA_IU_SCALE& aIuScale,
text.Printf( format, value );
// Check if the formatted value shows only zeros but the actual value is non-zero
// If so, use scientific notation instead
if( value != 0.0 )
{
bool showsOnlyZeros = true;
// Check if the text contains only zeros (allowing for decimal point, minus sign, etc.)
for( auto ch : text )
{
if( ch >= '1' && ch <= '9' )
{
showsOnlyZeros = false;
break;
}
}
if( showsOnlyZeros )
{
text.Printf( wxT( "%.3e" ), value );
}
}
// Trim to 2-1/2 digits after the decimal place for short-form mm
if( short_form && aUnits == EDA_UNITS::MM )
{

View File

@ -1364,6 +1364,11 @@ CAIRO_GAL::CAIRO_GAL( GAL_DISPLAY_OPTIONS& aDisplayOptions, wxWindow* aParent,
m_currentTarget = TARGET_NONCACHED;
SetTarget( TARGET_NONCACHED );
#ifdef _WIN32
// need to fix broken cairo rendering on Windows with wx 3.3
SetDoubleBuffered( false );
#endif
m_bitmapBuffer = nullptr;
m_wxOutput = nullptr;

View File

@ -25,7 +25,7 @@
*/
#include <wx/log.h>
#include <advanced_config.h>
#include <gal/graphics_abstraction_layer.h>
#include <gal/definitions.h>
#include <font/font.h>
@ -62,7 +62,7 @@ GAL::GAL( GAL_DISPLAY_OPTIONS& aDisplayOptions ) :
// wxDC::GetPPI() reports 96 DPI, but somehow this value
// is the closest match to the legacy renderer
SetScreenDPI( 91 );
SetScreenDPI( ADVANCED_CFG::GetCfg().m_ScreenDPI );
SetDepthRange( VECTOR2D( GAL::MIN_DEPTH, GAL::MAX_DEPTH ) );
SetLayerDepth( 0.0 );
SetFlip( false, false );

View File

@ -2700,6 +2700,10 @@ void OPENGL_GAL::blitCursor()
glLineWidth( 1.0 );
glColor4d( color.r, color.g, color.b, color.a );
glMatrixMode( GL_PROJECTION );
glPushMatrix();
glTranslated( 0, 0, -0.5 );
glBegin( GL_LINES );
if( m_crossHairMode == CROSS_HAIR_MODE::FULLSCREEN_DIAGONAL )
@ -2743,6 +2747,8 @@ void OPENGL_GAL::blitCursor()
glEnd();
glPopMatrix();
if( depthTestEnabled )
glEnable( GL_DEPTH_TEST );
}

View File

@ -22,16 +22,13 @@
*/
#include "git_add_to_index_handler.h"
#include <git/kicad_git_memory.h>
#include "git_backend.h"
#include <iterator>
#include <wx/string.h>
#include <wx/log.h>
GIT_ADD_TO_INDEX_HANDLER::GIT_ADD_TO_INDEX_HANDLER( git_repository* aRepository )
GIT_ADD_TO_INDEX_HANDLER::GIT_ADD_TO_INDEX_HANDLER( git_repository* aRepository ) :
KIGIT_COMMON( aRepository )
{
m_repository = aRepository;
m_filesToAdd.clear();
}
@ -43,66 +40,11 @@ GIT_ADD_TO_INDEX_HANDLER::~GIT_ADD_TO_INDEX_HANDLER()
bool GIT_ADD_TO_INDEX_HANDLER::AddToIndex( const wxString& aFilePath )
{
// Test if file is currently in the index
git_index* index = nullptr;
size_t at_pos = 0;
if( git_repository_index( &index, m_repository ) != 0 )
{
wxLogError( "Failed to get repository index" );
return false;
}
KIGIT::GitIndexPtr indexPtr( index );
if( git_index_find( &at_pos, index, aFilePath.ToUTF8().data() ) == GIT_OK )
{
wxLogError( "%s already in index", aFilePath );
return false;
}
// Add file to index if not already there
m_filesToAdd.push_back( aFilePath );
return true;
return GetGitBackend()->AddToIndex( this, aFilePath );
}
bool GIT_ADD_TO_INDEX_HANDLER::PerformAddToIndex()
{
git_index* index = nullptr;
m_filesFailedToAdd.clear();
if( git_repository_index( &index, m_repository ) != 0 )
{
wxLogError( "Failed to get repository index" );
std::copy( m_filesToAdd.begin(), m_filesToAdd.end(), std::back_inserter( m_filesFailedToAdd ) );
return false;
}
KIGIT::GitIndexPtr indexPtr( index );
for( auto& file : m_filesToAdd )
{
if( git_index_add_bypath( index, file.ToUTF8().data() ) != 0 )
{
wxLogError( "Failed to add %s to index", file );
m_filesFailedToAdd.push_back( file );
continue;
}
}
if( git_index_write( index ) != 0 )
{
wxLogError( "Failed to write index" );
m_filesFailedToAdd.clear();
std::copy( m_filesToAdd.begin(), m_filesToAdd.end(),
std::back_inserter( m_filesFailedToAdd ) );
return false;
}
return true;
return GetGitBackend()->PerformAddToIndex( this );
}

View File

@ -24,12 +24,13 @@
#ifndef GIT_ADD_TO_INDEX_HANDLER_H_
#define GIT_ADD_TO_INDEX_HANDLER_H_
#include <git2.h>
#include <git/kicad_git_common.h>
#include <vector>
#include <wx/string.h>
class wxString;
class LIBGIT_BACKEND;
class GIT_ADD_TO_INDEX_HANDLER
class GIT_ADD_TO_INDEX_HANDLER : public KIGIT_COMMON
{
public:
GIT_ADD_TO_INDEX_HANDLER( git_repository* aRepository );
@ -40,8 +41,7 @@ public:
bool PerformAddToIndex();
private:
git_repository* m_repository;
friend class LIBGIT_BACKEND;
std::vector<wxString> m_filesToAdd;
std::vector<wxString> m_filesFailedToAdd;
};

View File

@ -0,0 +1,36 @@
/*
* 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 "git_backend.h"
static GIT_BACKEND* s_backend = nullptr;
GIT_BACKEND* GetGitBackend()
{
return s_backend;
}
void SetGitBackend( GIT_BACKEND* aBackend )
{
s_backend = aBackend;
}

127
common/git/git_backend.h Normal file
View File

@ -0,0 +1,127 @@
/*
* 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
*/
#ifndef GIT_BACKEND_H_
#define GIT_BACKEND_H_
#include <map>
#include <set>
#include <vector>
#include <wx/string.h>
class GIT_CLONE_HANDLER;
class GIT_COMMIT_HANDLER;
class GIT_PUSH_HANDLER;
class GIT_STATUS_HANDLER;
class GIT_ADD_TO_INDEX_HANDLER;
class GIT_REMOVE_FROM_INDEX_HANDLER;
class GIT_CONFIG_HANDLER;
class GIT_INIT_HANDLER;
class GIT_BRANCH_HANDLER;
class GIT_PULL_HANDLER;
class GIT_REVERT_HANDLER;
struct RemoteConfig;
struct git_repository;
enum class InitResult;
enum class BranchResult;
enum class PullResult;
struct FileStatus;
enum class PushResult;
// Commit result shared across backend and handlers
enum class CommitResult
{
Success,
Error,
Cancelled
};
class GIT_BACKEND
{
public:
virtual ~GIT_BACKEND() = default;
virtual void Init() = 0;
virtual void Shutdown() = 0;
// Whether the libgit2 library is available/initialized enough for use
virtual bool IsLibraryAvailable() = 0;
virtual bool Clone( GIT_CLONE_HANDLER* aHandler ) = 0;
virtual CommitResult Commit( GIT_COMMIT_HANDLER* aHandler,
const std::vector<wxString>& aFiles,
const wxString& aMessage,
const wxString& aAuthorName,
const wxString& aAuthorEmail ) = 0;
virtual PushResult Push( GIT_PUSH_HANDLER* aHandler ) = 0;
virtual bool HasChangedFiles( GIT_STATUS_HANDLER* aHandler ) = 0;
virtual std::map<wxString, FileStatus> GetFileStatus( GIT_STATUS_HANDLER* aHandler,
const wxString& aPathspec ) = 0;
virtual wxString GetCurrentBranchName( GIT_STATUS_HANDLER* aHandler ) = 0;
virtual void UpdateRemoteStatus( GIT_STATUS_HANDLER* aHandler,
const std::set<wxString>& aLocalChanges,
const std::set<wxString>& aRemoteChanges,
std::map<wxString, FileStatus>& aFileStatus ) = 0;
virtual wxString GetWorkingDirectory( GIT_STATUS_HANDLER* aHandler ) = 0;
virtual wxString GetWorkingDirectory( GIT_CONFIG_HANDLER* aHandler ) = 0;
virtual bool GetConfigString( GIT_CONFIG_HANDLER* aHandler, const wxString& aKey,
wxString& aValue ) = 0;
virtual bool IsRepository( GIT_INIT_HANDLER* aHandler, const wxString& aPath ) = 0;
virtual InitResult InitializeRepository( GIT_INIT_HANDLER* aHandler, const wxString& aPath ) = 0;
virtual bool SetupRemote( GIT_INIT_HANDLER* aHandler, const RemoteConfig& aConfig ) = 0;
virtual BranchResult SwitchToBranch( GIT_BRANCH_HANDLER* aHandler, const wxString& aBranchName ) = 0;
virtual bool BranchExists( GIT_BRANCH_HANDLER* aHandler, const wxString& aBranchName ) = 0;
virtual bool PerformFetch( GIT_PULL_HANDLER* aHandler, bool aSkipLock ) = 0;
virtual PullResult PerformPull( GIT_PULL_HANDLER* aHandler ) = 0;
virtual void PerformRevert( GIT_REVERT_HANDLER* aHandler ) = 0;
virtual git_repository* GetRepositoryForFile( const char* aFilename ) = 0;
virtual int CreateBranch( git_repository* aRepo, const wxString& aBranchName ) = 0;
virtual bool RemoveVCS( git_repository*& aRepo, const wxString& aProjectPath,
bool aRemoveGitDir, wxString* aErrors ) = 0;
virtual bool AddToIndex( GIT_ADD_TO_INDEX_HANDLER* aHandler, const wxString& aFilePath ) = 0;
virtual bool PerformAddToIndex( GIT_ADD_TO_INDEX_HANDLER* aHandler ) = 0;
virtual bool RemoveFromIndex( GIT_REMOVE_FROM_INDEX_HANDLER* aHandler, const wxString& aFilePath ) = 0;
virtual void PerformRemoveFromIndex( GIT_REMOVE_FROM_INDEX_HANDLER* aHandler ) = 0;
};
GIT_BACKEND* GetGitBackend();
void SetGitBackend( GIT_BACKEND* aBackend );
#endif

View File

@ -22,6 +22,7 @@
*/
#include "git_branch_handler.h"
#include "git_backend.h"
#include <git/kicad_git_common.h>
#include <git/kicad_git_memory.h>
#include <trace_helpers.h>
@ -35,89 +36,12 @@ GIT_BRANCH_HANDLER::~GIT_BRANCH_HANDLER()
bool GIT_BRANCH_HANDLER::BranchExists( const wxString& aBranchName )
{
git_repository* repo = GetRepo();
if( !repo )
return false;
git_reference* branchRef = nullptr;
bool exists = LookupBranchReference( aBranchName, &branchRef );
if( branchRef )
git_reference_free( branchRef );
return exists;
}
bool GIT_BRANCH_HANDLER::LookupBranchReference( const wxString& aBranchName, git_reference** aReference )
{
git_repository* repo = GetRepo();
if( !repo )
return false;
// Try direct lookup first
if( git_reference_lookup( aReference, repo, aBranchName.mb_str() ) == GIT_OK )
return true;
// Try dwim (Do What I Mean) lookup for short branch names
if( git_reference_dwim( aReference, repo, aBranchName.mb_str() ) == GIT_OK )
return true;
return false;
return GetGitBackend()->BranchExists( this, aBranchName );
}
BranchResult GIT_BRANCH_HANDLER::SwitchToBranch( const wxString& aBranchName )
{
git_repository* repo = GetRepo();
if( !repo )
{
AddErrorString( _( "No repository available" ) );
return BranchResult::Error;
}
// Look up the branch reference
git_reference* branchRef = nullptr;
if( !LookupBranchReference( aBranchName, &branchRef ) )
{
AddErrorString( wxString::Format( _( "Failed to lookup branch '%s': %s" ),
aBranchName, KIGIT_COMMON::GetLastGitError() ) );
return BranchResult::BranchNotFound;
}
KIGIT::GitReferencePtr branchRefPtr( branchRef );
const char* branchRefName = git_reference_name( branchRef );
git_object* branchObj = nullptr;
if( git_revparse_single( &branchObj, repo, aBranchName.mb_str() ) != GIT_OK )
{
AddErrorString( wxString::Format( _( "Failed to find branch head for '%s': %s" ),
aBranchName, KIGIT_COMMON::GetLastGitError() ) );
return BranchResult::Error;
}
KIGIT::GitObjectPtr branchObjPtr( branchObj );
// Switch to the branch
if( git_checkout_tree( repo, branchObj, nullptr ) != GIT_OK )
{
AddErrorString( wxString::Format( _( "Failed to switch to branch '%s': %s" ),
aBranchName, KIGIT_COMMON::GetLastGitError() ) );
return BranchResult::CheckoutFailed;
}
// Update the HEAD reference
if( git_repository_set_head( repo, branchRefName ) != GIT_OK )
{
AddErrorString( wxString::Format( _( "Failed to update HEAD reference for branch '%s': %s" ),
aBranchName, KIGIT_COMMON::GetLastGitError() ) );
return BranchResult::Error;
}
wxLogTrace( traceGit, "Successfully switched to branch '%s'", aBranchName );
return BranchResult::Success;
return GetGitBackend()->SwitchToBranch( this, aBranchName );
}
void GIT_BRANCH_HANDLER::UpdateProgress( int aCurrent, int aTotal, const wxString& aMessage )

View File

@ -57,15 +57,6 @@ public:
bool BranchExists( const wxString& aBranchName );
void UpdateProgress( int aCurrent, int aTotal, const wxString& aMessage ) override;
private:
/**
* Look up a branch reference by name
* @param aBranchName Name of the branch
* @param aReference Output parameter for the reference
* @return True if successful, false otherwise
*/
bool LookupBranchReference( const wxString& aBranchName, git_reference** aReference );
};
#endif // GIT_BRANCH_HANDLER_H

View File

@ -23,13 +23,8 @@
#include "git_clone_handler.h"
#include <git/kicad_git_common.h>
#include <git/kicad_git_memory.h>
#include <trace_helpers.h>
#include <git2.h>
#include <wx/filename.h>
#include <wx/log.h>
#include "git_backend.h"
GIT_CLONE_HANDLER::GIT_CLONE_HANDLER( KIGIT_COMMON* aCommon ) : KIGIT_REPO_MIXIN( aCommon )
{}
@ -41,55 +36,7 @@ GIT_CLONE_HANDLER::~GIT_CLONE_HANDLER()
bool GIT_CLONE_HANDLER::PerformClone()
{
std::unique_lock<std::mutex> lock( GetCommon()->m_gitActionMutex, std::try_to_lock );
if( !lock.owns_lock() )
{
wxLogTrace( traceGit, "GIT_CLONE_HANDLER::PerformClone() could not lock" );
return false;
}
wxFileName clonePath( m_clonePath );
if( !clonePath.DirExists() )
{
if( !clonePath.Mkdir( wxS_DIR_DEFAULT, wxPATH_MKDIR_FULL ) )
{
AddErrorString( wxString::Format( _( "Could not create directory '%s'" ),
m_clonePath ) );
return false;
}
}
git_clone_options cloneOptions;
git_clone_init_options( &cloneOptions, GIT_CLONE_OPTIONS_VERSION );
cloneOptions.checkout_opts.checkout_strategy = GIT_CHECKOUT_SAFE;
cloneOptions.checkout_opts.progress_cb = clone_progress_cb;
cloneOptions.checkout_opts.progress_payload = this;
cloneOptions.fetch_opts.callbacks.transfer_progress = transfer_progress_cb;
cloneOptions.fetch_opts.callbacks.credentials = credentials_cb;
cloneOptions.fetch_opts.callbacks.payload = this;
TestedTypes() = 0;
ResetNextKey();
git_repository* newRepo = nullptr;
wxString remote = GetCommon()->m_remote;
if( git_clone( &newRepo, remote.mbc_str(), m_clonePath.mbc_str(),
&cloneOptions ) != 0 )
{
AddErrorString( wxString::Format( _( "Could not clone repository '%s'" ), remote ) );
return false;
}
GetCommon()->SetRepo( newRepo );
if( m_progressReporter )
m_progressReporter->Hide();
m_previousProgress = 0;
return true;
return GetGitBackend()->Clone( this );
}

View File

@ -22,8 +22,7 @@
*/
#include "git_commit_handler.h"
#include <git/kicad_git_memory.h>
#include <wx/log.h>
#include "git_backend.h"
GIT_COMMIT_HANDLER::GIT_COMMIT_HANDLER( git_repository* aRepo ) :
KIGIT_COMMON( aRepo )
@ -34,121 +33,13 @@ GIT_COMMIT_HANDLER::~GIT_COMMIT_HANDLER()
{}
GIT_COMMIT_HANDLER::CommitResult
CommitResult
GIT_COMMIT_HANDLER::PerformCommit( const std::vector<wxString>& aFiles,
const wxString& aMessage,
const wxString& aAuthorName,
const wxString& aAuthorEmail )
{
git_repository* repo = GetRepo();
if( !repo )
return CommitResult::Error;
git_index* index = nullptr;
if( git_repository_index( &index, repo ) != 0 )
{
AddErrorString( wxString::Format( _( "Failed to get repository index: %s" ),
KIGIT_COMMON::GetLastGitError() ) );
return CommitResult::Error;
}
KIGIT::GitIndexPtr indexPtr( index );
for( const wxString& file : aFiles )
{
if( git_index_add_bypath( index, file.mb_str() ) != 0 )
{
AddErrorString( wxString::Format( _( "Failed to add file to index: %s" ),
KIGIT_COMMON::GetLastGitError() ) );
return CommitResult::Error;
}
}
if( git_index_write( index ) != 0 )
{
AddErrorString( wxString::Format( _( "Failed to write index: %s" ),
KIGIT_COMMON::GetLastGitError() ) );
return CommitResult::Error;
}
git_oid tree_id;
if( git_index_write_tree( &tree_id, index ) != 0 )
{
AddErrorString( wxString::Format( _( "Failed to write tree: %s" ),
KIGIT_COMMON::GetLastGitError() ) );
return CommitResult::Error;
}
git_tree* tree = nullptr;
if( git_tree_lookup( &tree, repo, &tree_id ) != 0 )
{
AddErrorString( wxString::Format( _( "Failed to lookup tree: %s" ),
KIGIT_COMMON::GetLastGitError() ) );
return CommitResult::Error;
}
KIGIT::GitTreePtr treePtr( tree );
git_commit* parent = nullptr;
if( git_repository_head_unborn( repo ) == 0 )
{
git_reference* headRef = nullptr;
if( git_repository_head( &headRef, repo ) != 0 )
{
AddErrorString( wxString::Format( _( "Failed to get HEAD reference: %s" ),
KIGIT_COMMON::GetLastGitError() ) );
return CommitResult::Error;
}
KIGIT::GitReferencePtr headRefPtr( headRef );
if( git_reference_peel( (git_object**) &parent, headRef, GIT_OBJECT_COMMIT ) != 0 )
{
AddErrorString( wxString::Format( _( "Failed to get commit: %s" ),
KIGIT_COMMON::GetLastGitError() ) );
return CommitResult::Error;
}
}
KIGIT::GitCommitPtr parentPtr( parent );
git_signature* author = nullptr;
if( git_signature_now( &author, aAuthorName.mb_str(), aAuthorEmail.mb_str() ) != 0 )
{
AddErrorString( wxString::Format( _( "Failed to create author signature: %s" ),
KIGIT_COMMON::GetLastGitError() ) );
return CommitResult::Error;
}
KIGIT::GitSignaturePtr authorPtr( author );
git_oid oid;
size_t parentsCount = parent ? 1 : 0;
#if( LIBGIT2_VER_MAJOR == 1 && LIBGIT2_VER_MINOR == 8 \
&& ( LIBGIT2_VER_REVISION < 2 || LIBGIT2_VER_REVISION == 3 ) )
git_commit* const parents[1] = { parent };
git_commit** const parentsPtr = parent ? parents : nullptr;
#else
const git_commit* parents[1] = { parent };
const git_commit** parentsPtr = parent ? parents : nullptr;
#endif
if( git_commit_create( &oid, repo, "HEAD", author, author, nullptr,
aMessage.mb_str(), tree, parentsCount, parentsPtr ) != 0 )
{
AddErrorString( wxString::Format( _( "Failed to create commit: %s" ),
KIGIT_COMMON::GetLastGitError() ) );
return CommitResult::Error;
}
return CommitResult::Success;
return GetGitBackend()->Commit( this, aFiles, aMessage, aAuthorName, aAuthorEmail );
}

View File

@ -27,25 +27,20 @@
// Define a class to handle git commit operations
#include <git/kicad_git_common.h>
#include <git2.h>
#include "git_backend.h"
#include <string>
#include <vector>
#include <wx/string.h>
class LIBGIT_BACKEND;
class GIT_COMMIT_HANDLER : public KIGIT_COMMON
{
public:
GIT_COMMIT_HANDLER( git_repository* aRepo );
virtual ~GIT_COMMIT_HANDLER();
enum class CommitResult
{
Success,
Error,
Cancelled
};
CommitResult PerformCommit( const std::vector<wxString>& aFiles,
const wxString& aMessage,
const wxString& aAuthorName,
@ -54,6 +49,7 @@ public:
wxString GetErrorString() const;
private:
friend class LIBGIT_BACKEND;
void AddErrorString( const wxString& aErrorString );
wxString m_errorString;

View File

@ -22,6 +22,7 @@
*/
#include "git_config_handler.h"
#include "git_backend.h"
#include <git/kicad_git_common.h>
#include <git/kicad_git_memory.h>
#include <pgm_base.h>
@ -59,48 +60,12 @@ GitUserConfig GIT_CONFIG_HANDLER::GetUserConfig()
wxString GIT_CONFIG_HANDLER::GetWorkingDirectory()
{
git_repository* repo = GetRepo();
if( !repo )
return wxEmptyString;
const char* workdir = git_repository_workdir( repo );
if( !workdir )
return wxEmptyString;
return wxString( workdir );
return GetGitBackend()->GetWorkingDirectory( this );
}
bool GIT_CONFIG_HANDLER::GetConfigString( const wxString& aKey, wxString& aValue )
{
git_repository* repo = GetRepo();
if( !repo )
return false;
git_config* config = nullptr;
if( git_repository_config( &config, repo ) != GIT_OK )
{
wxLogTrace( traceGit, "Failed to get repository config: %s", KIGIT_COMMON::GetLastGitError() );
return false;
}
KIGIT::GitConfigPtr configPtr( config );
git_config_entry* entry = nullptr;
int result = git_config_get_entry( &entry, config, aKey.mb_str() );
KIGIT::GitConfigEntryPtr entryPtr( entry );
if( result != GIT_OK || entry == nullptr )
{
wxLogTrace( traceGit, "Config key '%s' not found", aKey );
return false;
}
aValue = wxString( entry->value );
return true;
return GetGitBackend()->GetConfigString( this, aKey, aValue );
}
void GIT_CONFIG_HANDLER::UpdateProgress( int aCurrent, int aTotal, const wxString& aMessage )

View File

@ -22,6 +22,7 @@
*/
#include "git_init_handler.h"
#include "git_backend.h"
#include <git/kicad_git_common.h>
#include <git/kicad_git_memory.h>
#include <trace_helpers.h>
@ -35,118 +36,17 @@ GIT_INIT_HANDLER::~GIT_INIT_HANDLER()
bool GIT_INIT_HANDLER::IsRepository( const wxString& aPath )
{
git_repository* repo = nullptr;
int error = git_repository_open( &repo, aPath.mb_str() );
if( error == 0 )
{
git_repository_free( repo );
return true;
}
return false;
return GetGitBackend()->IsRepository( this, aPath );
}
InitResult GIT_INIT_HANDLER::InitializeRepository( const wxString& aPath )
{
// Check if directory is already a git repository
if( IsRepository( aPath ) )
{
return InitResult::AlreadyExists;
}
git_repository* repo = nullptr;
if( git_repository_init( &repo, aPath.mb_str(), 0 ) != GIT_OK )
{
if( repo )
git_repository_free( repo );
AddErrorString( wxString::Format( _( "Failed to initialize Git repository: %s" ),
KIGIT_COMMON::GetLastGitError() ) );
return InitResult::Error;
}
// Update the common repository pointer
GetCommon()->SetRepo( repo );
wxLogTrace( traceGit, "Successfully initialized Git repository at %s", aPath );
return InitResult::Success;
return GetGitBackend()->InitializeRepository( this, aPath );
}
bool GIT_INIT_HANDLER::SetupRemote( const RemoteConfig& aConfig )
{
// This is an optional step
if( aConfig.url.IsEmpty() )
return true;
git_repository* repo = GetRepo();
if( !repo )
{
AddErrorString( _( "No repository available to set up remote" ) );
return false;
}
// Update connection settings in common
GetCommon()->SetUsername( aConfig.username );
GetCommon()->SetPassword( aConfig.password );
GetCommon()->SetSSHKey( aConfig.sshKey );
git_remote* remote = nullptr;
wxString fullURL;
// Build the full URL based on connection type
if( aConfig.connType == KIGIT_COMMON::GIT_CONN_TYPE::GIT_CONN_SSH )
{
fullURL = aConfig.username + "@" + aConfig.url;
}
else if( aConfig.connType == KIGIT_COMMON::GIT_CONN_TYPE::GIT_CONN_HTTPS )
{
fullURL = aConfig.url.StartsWith( "https" ) ? "https://" : "http://";
if( !aConfig.username.empty() )
{
fullURL.append( aConfig.username );
if( !aConfig.password.empty() )
{
fullURL.append( wxS( ":" ) );
fullURL.append( aConfig.password );
}
fullURL.append( wxS( "@" ) );
}
// Extract the bare URL (without protocol prefix)
wxString bareURL = aConfig.url;
if( bareURL.StartsWith( "https://" ) )
bareURL = bareURL.Mid( 8 );
else if( bareURL.StartsWith( "http://" ) )
bareURL = bareURL.Mid( 7 );
fullURL.append( bareURL );
}
else
{
fullURL = aConfig.url;
}
int error = git_remote_create_with_fetchspec( &remote, repo, "origin",
fullURL.ToStdString().c_str(),
"+refs/heads/*:refs/remotes/origin/*" );
KIGIT::GitRemotePtr remotePtr( remote );
if( error != GIT_OK )
{
AddErrorString( wxString::Format( _( "Failed to create remote: %s" ),
KIGIT_COMMON::GetLastGitError() ) );
return false;
}
wxLogTrace( traceGit, "Successfully set up remote origin" );
return true;
return GetGitBackend()->SetupRemote( this, aConfig );
}
void GIT_INIT_HANDLER::UpdateProgress( int aCurrent, int aTotal, const wxString& aMessage )

View File

@ -22,188 +22,22 @@
*/
#include "git_pull_handler.h"
#include <git/kicad_git_common.h>
#include <git/kicad_git_memory.h>
#include <trace_helpers.h>
#include <wx/log.h>
#include <iostream>
#include <time.h>
#include <memory>
#include "git_backend.h"
GIT_PULL_HANDLER::GIT_PULL_HANDLER( KIGIT_COMMON* aCommon ) : KIGIT_REPO_MIXIN( aCommon )
{
}
{}
GIT_PULL_HANDLER::~GIT_PULL_HANDLER()
{
}
{}
bool GIT_PULL_HANDLER::PerformFetch( bool aSkipLock )
{
if( !GetRepo() )
{
wxLogTrace( traceGit, "GIT_PULL_HANDLER::PerformFetch() - No repository found" );
return false;
}
std::unique_lock<std::mutex> lock( GetCommon()->m_gitActionMutex, std::try_to_lock );
if( !aSkipLock && !lock.owns_lock() )
{
wxLogTrace( traceGit, "GIT_PULL_HANDLER::PerformFetch() - Could not lock mutex" );
return false;
}
// Fetch updates from remote repository
git_remote* remote = nullptr;
if( git_remote_lookup( &remote, GetRepo(), "origin" ) != 0 )
{
wxLogTrace( traceGit, "GIT_PULL_HANDLER::PerformFetch() - Failed to lookup remote 'origin'" );
AddErrorString( wxString::Format( _( "Could not lookup remote '%s'" ), "origin" ) );
return false;
}
KIGIT::GitRemotePtr remotePtr( remote );
git_remote_callbacks remoteCallbacks;
git_remote_init_callbacks( &remoteCallbacks, GIT_REMOTE_CALLBACKS_VERSION );
remoteCallbacks.sideband_progress = progress_cb;
remoteCallbacks.transfer_progress = transfer_progress_cb;
remoteCallbacks.credentials = credentials_cb;
remoteCallbacks.payload = this;
GetCommon()->SetCancelled( false );
TestedTypes() = 0;
ResetNextKey();
if( git_remote_connect( remote, GIT_DIRECTION_FETCH, &remoteCallbacks, nullptr, nullptr ) )
{
wxString errorMsg = KIGIT_COMMON::GetLastGitError();
wxLogTrace( traceGit, "GIT_PULL_HANDLER::PerformFetch() - Failed to connect to remote: %s", errorMsg );
AddErrorString( wxString::Format( _( "Could not connect to remote '%s': %s" ), "origin", errorMsg ) );
return false;
}
git_fetch_options fetchOptions;
git_fetch_init_options( &fetchOptions, GIT_FETCH_OPTIONS_VERSION );
fetchOptions.callbacks = remoteCallbacks;
if( git_remote_fetch( remote, nullptr, &fetchOptions, nullptr ) )
{
wxString errorMsg = KIGIT_COMMON::GetLastGitError();
wxLogTrace( traceGit, "GIT_PULL_HANDLER::PerformFetch() - Failed to fetch from remote: %s", errorMsg );
AddErrorString( wxString::Format( _( "Could not fetch data from remote '%s': %s" ), "origin", errorMsg ) );
return false;
}
wxLogTrace( traceGit, "GIT_PULL_HANDLER::PerformFetch() - Fetch completed successfully" );
return true;
return GetGitBackend()->PerformFetch( this, aSkipLock );
}
PullResult GIT_PULL_HANDLER::PerformPull()
{
PullResult result = PullResult::Success;
std::unique_lock<std::mutex> lock( GetCommon()->m_gitActionMutex, std::try_to_lock );
if( !lock.owns_lock() )
{
wxLogTrace( traceGit, "GIT_PULL_HANDLER::PerformPull() - Could not lock mutex" );
return PullResult::Error;
}
if( !PerformFetch( true ) )
return PullResult::Error;
git_oid pull_merge_oid = {};
if( git_repository_fetchhead_foreach( GetRepo(), fetchhead_foreach_cb,
&pull_merge_oid ) )
{
AddErrorString( _( "Could not read 'FETCH_HEAD'" ) );
return PullResult::Error;
}
git_annotated_commit* fetchhead_commit;
if( git_annotated_commit_lookup( &fetchhead_commit, GetRepo(), &pull_merge_oid ) )
{
AddErrorString( _( "Could not lookup commit" ) );
return PullResult::Error;
}
KIGIT::GitAnnotatedCommitPtr fetchheadCommitPtr( fetchhead_commit );
const git_annotated_commit* merge_commits[] = { fetchhead_commit };
git_merge_analysis_t merge_analysis;
git_merge_preference_t merge_preference = GIT_MERGE_PREFERENCE_NONE;
if( git_merge_analysis( &merge_analysis, &merge_preference, GetRepo(), merge_commits, 1 ) )
{
AddErrorString( _( "Could not analyze merge" ) );
return PullResult::Error;
}
if( merge_analysis & GIT_MERGE_ANALYSIS_UNBORN )
{
AddErrorString( _( "Invalid HEAD. Cannot merge." ) );
return PullResult::MergeFailed;
}
// Nothing to do if the repository is up to date
if( merge_analysis & GIT_MERGE_ANALYSIS_UP_TO_DATE )
{
wxLogTrace( traceGit, "GIT_PULL_HANDLER::PerformPull() - Repository is up to date" );
git_repository_state_cleanup( GetRepo() );
return PullResult::UpToDate;
}
// Fast-forward is easy, just update the local reference
if( merge_analysis & GIT_MERGE_ANALYSIS_FASTFORWARD )
{
wxLogTrace( traceGit, "GIT_PULL_HANDLER::PerformPull() - Fast-forward merge" );
return handleFastForward();
}
if( merge_analysis & GIT_MERGE_ANALYSIS_NORMAL )
{
wxLogTrace( traceGit, "GIT_PULL_HANDLER::PerformPull() - Normal merge" );
// Check git config to determine if we should rebase or merge
git_config* config = nullptr;
if( git_repository_config( &config, GetRepo() ) != GIT_OK )
{
wxLogTrace( traceGit, "GIT_PULL_HANDLER::PerformPull() - Failed to get repository config" );
AddErrorString( _( "Could not access repository configuration" ) );
return PullResult::Error;
}
KIGIT::GitConfigPtr configPtr( config );
// Check for pull.rebase config
int rebase_value = 0;
int ret = git_config_get_bool( &rebase_value, config, "pull.rebase" );
// If pull.rebase is set to true, use rebase; otherwise use merge
if( ret == GIT_OK && rebase_value )
{
wxLogTrace( traceGit, "GIT_PULL_HANDLER::PerformPull() - Using rebase based on config" );
return handleRebase( merge_commits, 1 );
}
wxLogTrace( traceGit, "GIT_PULL_HANDLER::PerformPull() - Using merge based on config" );
return handleMerge( merge_commits, 1 );
}
wxLogTrace( traceGit, "GIT_PULL_HANDLER::PerformPull() - Merge needs resolution" );
//TODO: handle merges when they need to be resolved
return result;
return GetGitBackend()->PerformPull( this );
}
const std::vector<std::pair<std::string, std::vector<CommitDetails>>>&
@ -212,384 +46,7 @@ GIT_PULL_HANDLER::GetFetchResults() const
return m_fetchResults;
}
std::string GIT_PULL_HANDLER::getFirstLineFromCommitMessage( const std::string& aMessage )
{
if( aMessage.empty() )
return aMessage;
size_t firstLineEnd = aMessage.find_first_of( '\n' );
if( firstLineEnd != std::string::npos )
return aMessage.substr( 0, firstLineEnd );
return aMessage;
}
std::string GIT_PULL_HANDLER::getFormattedCommitDate( const git_time& aTime )
{
char dateBuffer[64];
time_t time = static_cast<time_t>( aTime.time );
struct tm timeInfo;
#ifdef _WIN32
localtime_s( &timeInfo, &time );
#else
gmtime_r( &time, &timeInfo );
#endif
strftime( dateBuffer, sizeof( dateBuffer ), "%Y-%b-%d %H:%M:%S", &timeInfo );
return dateBuffer;
}
PullResult GIT_PULL_HANDLER::handleFastForward()
{
git_reference* rawRef = nullptr;
// Get the current HEAD reference
if( git_repository_head( &rawRef, GetRepo() ) )
{
AddErrorString( _( "Could not get repository head" ) );
return PullResult::Error;
}
KIGIT::GitReferencePtr headRef( rawRef );
git_oid updatedRefOid;
const char* currentBranchName = git_reference_name( rawRef );
const char* branch_shorthand = git_reference_shorthand( rawRef );
wxString remote_name = GetRemotename();
wxString remoteBranchName = wxString::Format( "refs/remotes/%s/%s",
remote_name, branch_shorthand );
// Get the OID of the updated reference (remote-tracking branch)
if( git_reference_name_to_id( &updatedRefOid, GetRepo(), remoteBranchName.c_str() ) != GIT_OK )
{
AddErrorString( wxString::Format( _( "Could not get reference OID for reference '%s'" ),
remoteBranchName ) );
return PullResult::Error;
}
// Get the target commit object
git_commit* targetCommit = nullptr;
if( git_commit_lookup( &targetCommit, GetRepo(), &updatedRefOid ) != GIT_OK )
{
AddErrorString( _( "Could not look up target commit" ) );
return PullResult::Error;
}
KIGIT::GitCommitPtr targetCommitPtr( targetCommit );
// Get the tree from the target commit
git_tree* targetTree = nullptr;
if( git_commit_tree( &targetTree, targetCommit ) != GIT_OK )
{
git_commit_free( targetCommit );
AddErrorString( _( "Could not get tree from target commit" ) );
return PullResult::Error;
}
KIGIT::GitTreePtr targetTreePtr( targetTree );
// Perform a checkout to update the working directory
git_checkout_options checkoutOptions;
git_checkout_init_options( &checkoutOptions, GIT_CHECKOUT_OPTIONS_VERSION );
auto notify_cb = []( git_checkout_notify_t why, const char* path, const git_diff_file* baseline,
const git_diff_file* target, const git_diff_file* workdir, void* payload ) -> int
{
switch( why )
{
case GIT_CHECKOUT_NOTIFY_CONFLICT:
wxLogTrace( traceGit, "Checkout conflict: %s", path ? path : "unknown" );
break;
case GIT_CHECKOUT_NOTIFY_DIRTY:
wxLogTrace( traceGit, "Checkout dirty: %s", path ? path : "unknown" );
break;
case GIT_CHECKOUT_NOTIFY_UPDATED:
wxLogTrace( traceGit, "Checkout updated: %s", path ? path : "unknown" );
break;
case GIT_CHECKOUT_NOTIFY_UNTRACKED:
wxLogTrace( traceGit, "Checkout untracked: %s", path ? path : "unknown" );
break;
case GIT_CHECKOUT_NOTIFY_IGNORED:
wxLogTrace( traceGit, "Checkout ignored: %s", path ? path : "unknown" );
break;
default:
break;
}
return 0;
};
checkoutOptions.checkout_strategy = GIT_CHECKOUT_SAFE | GIT_CHECKOUT_ALLOW_CONFLICTS;
checkoutOptions.notify_flags = GIT_CHECKOUT_NOTIFY_ALL;
checkoutOptions.notify_cb = notify_cb;
if( git_checkout_tree( GetRepo(), reinterpret_cast<git_object*>( targetTree ), &checkoutOptions ) != GIT_OK )
{
AddErrorString( _( "Failed to perform checkout operation." ) );
return PullResult::Error;
}
git_reference* updatedRef = nullptr;
// Update the current branch to point to the new commit
if (git_reference_set_target(&updatedRef, rawRef, &updatedRefOid, nullptr) != GIT_OK)
{
AddErrorString( wxString::Format( _( "Failed to update reference '%s' to point to '%s'" ), currentBranchName,
git_oid_tostr_s( &updatedRefOid ) ) );
return PullResult::Error;
}
KIGIT::GitReferencePtr updatedRefPtr( updatedRef );
// Clean up the repository state
if( git_repository_state_cleanup( GetRepo() ) != GIT_OK )
{
AddErrorString( _( "Failed to clean up repository state after fast-forward." ) );
return PullResult::Error;
}
git_revwalk* revWalker = nullptr;
// Collect commit details for updated references
if( git_revwalk_new( &revWalker, GetRepo() ) != GIT_OK )
{
AddErrorString( _( "Failed to initialize revision walker." ) );
return PullResult::Error;
}
KIGIT::GitRevWalkPtr revWalkerPtr( revWalker );
git_revwalk_sorting( revWalker, GIT_SORT_TIME );
if( git_revwalk_push_glob( revWalker, currentBranchName ) != GIT_OK )
{
AddErrorString( _( "Failed to push reference to revision walker." ) );
return PullResult::Error;
}
std::pair<std::string, std::vector<CommitDetails>>& branchCommits = m_fetchResults.emplace_back();
branchCommits.first = currentBranchName;
git_oid commitOid;
while( git_revwalk_next( &commitOid, revWalker ) == GIT_OK )
{
git_commit* commit = nullptr;
if( git_commit_lookup( &commit, GetRepo(), &commitOid ) )
{
AddErrorString( wxString::Format( _( "Could not lookup commit '%s'" ),
git_oid_tostr_s( &commitOid ) ) );
return PullResult::Error;
}
KIGIT::GitCommitPtr commitPtr( commit );
CommitDetails details;
details.m_sha = git_oid_tostr_s( &commitOid );
details.m_firstLine = getFirstLineFromCommitMessage( git_commit_message( commit ) );
details.m_author = git_commit_author( commit )->name;
details.m_date = getFormattedCommitDate( git_commit_author( commit )->when );
branchCommits.second.push_back( details );
}
return PullResult::FastForward;
}
PullResult GIT_PULL_HANDLER::handleMerge( const git_annotated_commit** aMergeHeads,
size_t aMergeHeadsCount )
{
git_merge_options merge_opts;
git_merge_options_init( &merge_opts, GIT_MERGE_OPTIONS_VERSION );
git_checkout_options checkout_opts;
git_checkout_init_options( &checkout_opts, GIT_CHECKOUT_OPTIONS_VERSION );
checkout_opts.checkout_strategy = GIT_CHECKOUT_SAFE;
if( git_merge( GetRepo(), aMergeHeads, aMergeHeadsCount, &merge_opts, &checkout_opts ) )
{
AddErrorString( _( "Could not merge commits" ) );
return PullResult::Error;
}
// Get the repository index
git_index* index = nullptr;
if( git_repository_index( &index, GetRepo() ) )
{
AddErrorString( _( "Could not get repository index" ) );
return PullResult::Error;
}
KIGIT::GitIndexPtr indexPtr( index );
// Check for conflicts
git_index_conflict_iterator* conflicts = nullptr;
if( git_index_conflict_iterator_new( &conflicts, index ) )
{
AddErrorString( _( "Could not get conflict iterator" ) );
return PullResult::Error;
}
KIGIT::GitIndexConflictIteratorPtr conflictsPtr( conflicts );
const git_index_entry* ancestor = nullptr;
const git_index_entry* our = nullptr;
const git_index_entry* their = nullptr;
std::vector<ConflictData> conflict_data;
while( git_index_conflict_next( &ancestor, &our, &their, conflicts ) == 0 )
{
// Case 3: Both files have changed
if( ancestor && our && their )
{
ConflictData conflict_datum;
conflict_datum.filename = our->path;
conflict_datum.our_oid = our->id;
conflict_datum.their_oid = their->id;
conflict_datum.our_commit_time = our->mtime.seconds;
conflict_datum.their_commit_time = their->mtime.seconds;
conflict_datum.our_status = _( "Changed" );
conflict_datum.their_status = _( "Changed" );
conflict_datum.use_ours = true;
conflict_data.push_back( conflict_datum );
}
// Case 4: File added in both ours and theirs
else if( !ancestor && our && their )
{
ConflictData conflict_datum;
conflict_datum.filename = our->path;
conflict_datum.our_oid = our->id;
conflict_datum.their_oid = their->id;
conflict_datum.our_commit_time = our->mtime.seconds;
conflict_datum.their_commit_time = their->mtime.seconds;
conflict_datum.our_status = _( "Added" );
conflict_datum.their_status = _( "Added" );
conflict_datum.use_ours = true;
conflict_data.push_back( conflict_datum );
}
// Case 1: Remote file has changed or been added, local file has not
else if( their && !our )
{
// Accept their changes
git_index_add( index, their );
}
// Case 2: Local file has changed or been added, remote file has not
else if( our && !their )
{
// Accept our changes
git_index_add( index, our );
}
else
{
wxLogError( wxS( "Unexpected conflict state" ) );
}
}
if( conflict_data.empty() )
{
git_index_conflict_cleanup( index );
git_index_write( index );
}
return conflict_data.empty() ? PullResult::Success : PullResult::MergeFailed;
}
PullResult GIT_PULL_HANDLER::handleRebase( const git_annotated_commit** aMergeHeads, size_t aMergeHeadsCount )
{
// Get the current branch reference
git_reference* head_ref = nullptr;
if( git_repository_head( &head_ref, GetRepo() ) )
{
wxString errorMsg = KIGIT_COMMON::GetLastGitError();
wxLogTrace( traceGit, "GIT_PULL_HANDLER::handleRebase() - Failed to get HEAD: %s", errorMsg );
return PullResult::Error;
}
KIGIT::GitReferencePtr headRefPtr(head_ref);
// Initialize rebase operation
git_rebase* rebase = nullptr;
git_rebase_options rebase_opts = GIT_REBASE_OPTIONS_INIT;
rebase_opts.checkout_options.checkout_strategy = GIT_CHECKOUT_SAFE;
if( git_rebase_init( &rebase, GetRepo(), nullptr, nullptr, aMergeHeads[0], &rebase_opts ) )
{
wxString errorMsg = KIGIT_COMMON::GetLastGitError();
wxLogTrace( traceGit, "GIT_PULL_HANDLER::handleRebase() - Failed to initialize rebase: %s", errorMsg );
return PullResult::Error;
}
KIGIT::GitRebasePtr rebasePtr( rebase );
git_rebase_operation* operation = nullptr;
while( git_rebase_next( &operation, rebase ) != GIT_ITEROVER )
{
// Check for conflicts
git_index* index = nullptr;
if( git_repository_index( &index, GetRepo() ) )
{
wxLogTrace( traceGit, "GIT_PULL_HANDLER::handleRebase() - Failed to get index: %s",
KIGIT_COMMON::GetLastGitError() );
return PullResult::Error;
}
KIGIT::GitIndexPtr indexPtr( index );
if( git_index_has_conflicts( index ) )
{
// Abort the rebase if there are conflicts because we need to merge manually
git_rebase_abort( rebase );
AddErrorString( _( "Conflicts detected during rebase" ) );
return PullResult::MergeFailed;
}
git_oid commit_id;
git_signature* committer = nullptr;
if( git_signature_default( &committer, GetRepo() ) )
{
wxLogTrace( traceGit, "GIT_PULL_HANDLER::handleRebase() - Failed to create signature: %s",
KIGIT_COMMON::GetLastGitError() );
return PullResult::Error;
}
KIGIT::GitSignaturePtr committerPtr( committer );
if( git_rebase_commit( &commit_id, rebase, nullptr, committer, nullptr, nullptr ) != GIT_OK )
{
wxString errorMsg = KIGIT_COMMON::GetLastGitError();
wxLogTrace( traceGit, "GIT_PULL_HANDLER::handleRebase() - Failed to commit operation: %s", errorMsg );
git_rebase_abort( rebase );
return PullResult::Error;
}
}
// Finish the rebase
if( git_rebase_finish( rebase, nullptr ) )
{
wxLogTrace( traceGit, "GIT_PULL_HANDLER::handleRebase() - Failed to finish rebase: %s",
KIGIT_COMMON::GetLastGitError() );
return PullResult::Error;
}
wxLogTrace( traceGit, "GIT_PULL_HANDLER::handleRebase() - Rebase completed successfully" );
git_repository_state_cleanup( GetRepo() );
return PullResult::Success;
}
void GIT_PULL_HANDLER::UpdateProgress( int aCurrent, int aTotal, const wxString& aMessage )
{
ReportProgress( aCurrent, aTotal, aMessage );
}

View File

@ -29,7 +29,6 @@
#include <vector>
#include <string>
#include <wx/string.h>
#include <git2.h>
// Structure to store commit details
struct CommitDetails
@ -50,22 +49,12 @@ enum class PullResult : int
FastForward
};
struct ConflictData
{
std::string filename;
std::string our_status;
std::string their_status;
git_oid our_oid;
git_oid their_oid;
git_time_t our_commit_time;
git_time_t their_commit_time;
bool use_ours; // Flag indicating user's choice (true = ours, false = theirs)
};
class LIBGIT_BACKEND;
class GIT_PULL_HANDLER : public KIGIT_REPO_MIXIN
{
public:
friend class LIBGIT_BACKEND;
GIT_PULL_HANDLER( KIGIT_COMMON* aCommon );
~GIT_PULL_HANDLER();
@ -77,15 +66,8 @@ public:
// Implementation for progress updates
void UpdateProgress( int aCurrent, int aTotal, const wxString& aMessage ) override;
private:
std::vector<std::pair<std::string, std::vector<CommitDetails>>> m_fetchResults;
std::string getFirstLineFromCommitMessage( const std::string& aMessage );
std::string getFormattedCommitDate( const git_time& aTime );
PullResult handleFastForward();
PullResult handleMerge( const git_annotated_commit** aMergeHeads, size_t aMergeHeadsCount );
PullResult handleRebase( const git_annotated_commit** aMergeHeads, size_t aMergeHeadsCount );
};
#endif // _GIT_PULL_HANDLER_H_

View File

@ -22,13 +22,8 @@
*/
#include "git_push_handler.h"
#include <git/kicad_git_common.h>
#include <git/kicad_git_memory.h>
#include <trace_helpers.h>
#include <iostream>
#include <wx/log.h>
#include "git_backend.h"
GIT_PUSH_HANDLER::GIT_PUSH_HANDLER( KIGIT_COMMON* aRepo ) : KIGIT_REPO_MIXIN( aRepo )
{}
@ -38,79 +33,7 @@ GIT_PUSH_HANDLER::~GIT_PUSH_HANDLER()
PushResult GIT_PUSH_HANDLER::PerformPush()
{
std::unique_lock<std::mutex> lock( GetCommon()->m_gitActionMutex, std::try_to_lock );
if(!lock.owns_lock())
{
wxLogTrace(traceGit, "GIT_PUSH_HANDLER::PerformPush: Could not lock mutex");
return PushResult::Error;
}
PushResult result = PushResult::Success;
// Fetch updates from remote repository
git_remote* remote = nullptr;
if(git_remote_lookup(&remote, GetRepo(), "origin") != 0)
{
AddErrorString(_("Could not lookup remote"));
return PushResult::Error;
}
KIGIT::GitRemotePtr remotePtr(remote);
git_remote_callbacks remoteCallbacks;
git_remote_init_callbacks(&remoteCallbacks, GIT_REMOTE_CALLBACKS_VERSION);
remoteCallbacks.sideband_progress = progress_cb;
remoteCallbacks.transfer_progress = transfer_progress_cb;
remoteCallbacks.update_tips = update_cb;
remoteCallbacks.push_transfer_progress = push_transfer_progress_cb;
remoteCallbacks.credentials = credentials_cb;
remoteCallbacks.payload = this;
GetCommon()->SetCancelled( false );
TestedTypes() = 0;
ResetNextKey();
if( git_remote_connect( remote, GIT_DIRECTION_PUSH, &remoteCallbacks, nullptr, nullptr ) )
{
AddErrorString( wxString::Format( _( "Could not connect to remote: %s" ),
KIGIT_COMMON::GetLastGitError() ) );
return PushResult::Error;
}
git_push_options pushOptions;
git_push_init_options( &pushOptions, GIT_PUSH_OPTIONS_VERSION );
pushOptions.callbacks = remoteCallbacks;
// Get the current HEAD reference
git_reference* head = nullptr;
if( git_repository_head( &head, GetRepo() ) != 0 )
{
git_remote_disconnect( remote );
AddErrorString( _( "Could not get repository head" ) );
return PushResult::Error;
}
KIGIT::GitReferencePtr headPtr( head );
// Create refspec for current branch
const char* refs[1];
refs[0] = git_reference_name( head );
const git_strarray refspecs = { (char**) refs, 1 };
if( git_remote_push( remote, &refspecs, &pushOptions ) )
{
AddErrorString( wxString::Format( _( "Could not push to remote: %s" ),
KIGIT_COMMON::GetLastGitError() ) );
git_remote_disconnect( remote );
return PushResult::Error;
}
git_remote_disconnect( remote );
return result;
return GetGitBackend()->Push( this );
}

View File

@ -21,15 +21,14 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include <wx/string.h>
#include "git_remove_from_index_handler.h"
#include "git_backend.h"
#include <wx/log.h>
#include <git/kicad_git_memory.h>
#include "git_remove_from_index_handler.h"
GIT_REMOVE_FROM_INDEX_HANDLER::GIT_REMOVE_FROM_INDEX_HANDLER( git_repository* aRepository )
GIT_REMOVE_FROM_INDEX_HANDLER::GIT_REMOVE_FROM_INDEX_HANDLER( git_repository* aRepository ) :
KIGIT_COMMON( aRepository )
{
m_repository = aRepository;
m_filesToRemove.clear();
}
@ -41,61 +40,11 @@ GIT_REMOVE_FROM_INDEX_HANDLER::~GIT_REMOVE_FROM_INDEX_HANDLER()
bool GIT_REMOVE_FROM_INDEX_HANDLER::RemoveFromIndex( const wxString& aFilePath )
{
// Test if file is currently in the index
git_index* index = nullptr;
size_t at_pos = 0;
if( git_repository_index( &index, m_repository ) != 0 )
{
wxLogError( "Failed to get repository index" );
return false;
}
KIGIT::GitIndexPtr indexPtr( index );
if( git_index_find( &at_pos, index, aFilePath.ToUTF8().data() ) != 0 )
{
wxLogError( "Failed to find index entry for %s", aFilePath );
return false;
}
m_filesToRemove.push_back( aFilePath );
return true;
return GetGitBackend()->RemoveFromIndex( this, aFilePath );
}
void GIT_REMOVE_FROM_INDEX_HANDLER::PerformRemoveFromIndex()
{
for( auto& file : m_filesToRemove )
{
git_index* index = nullptr;
git_oid oid;
if( git_repository_index( &index, m_repository ) != 0 )
{
wxLogError( "Failed to get repository index" );
return;
}
KIGIT::GitIndexPtr indexPtr( index );
if( git_index_remove_bypath( index, file.ToUTF8().data() ) != 0 )
{
wxLogError( "Failed to remove index entry for %s", file );
return;
}
if( git_index_write( index ) != 0 )
{
wxLogError( "Failed to write index" );
return;
}
if( git_index_write_tree( &oid, index ) != 0 )
{
wxLogError( "Failed to write index tree" );
return;
}
}
GetGitBackend()->PerformRemoveFromIndex( this );
}

View File

@ -24,12 +24,13 @@
#ifndef GIT_REMOVE_FROM_INDEX_HANDLER_H_
#define GIT_REMOVE_FROM_INDEX_HANDLER_H_
#include <git2.h>
#include <git/kicad_git_common.h>
#include <vector>
#include <wx/string.h>
class wxString;
class LIBGIT_BACKEND;
class GIT_REMOVE_FROM_INDEX_HANDLER
class GIT_REMOVE_FROM_INDEX_HANDLER : public KIGIT_COMMON
{
public:
GIT_REMOVE_FROM_INDEX_HANDLER( git_repository* aRepository );
@ -41,7 +42,7 @@ public:
private:
git_repository* m_repository;
friend class LIBGIT_BACKEND;
std::vector<wxString> m_filesToRemove;
};

View File

@ -22,11 +22,7 @@
*/
#include "git_revert_handler.h"
#include <wx/log.h>
#include <wx/string.h>
#include <trace_helpers.h>
#include "git_backend.h"
GIT_REVERT_HANDLER::GIT_REVERT_HANDLER( git_repository* aRepository )
@ -46,74 +42,8 @@ bool GIT_REVERT_HANDLER::Revert( const wxString& aFilePath )
return true;
}
static void checkout_progress_cb( const char *path, size_t cur, size_t tot, void *payload )
{
wxLogTrace( traceGit, wxS( "checkout_progress_cb: %s %zu/%zu" ), path, cur, tot );
}
static int checkout_notify_cb( git_checkout_notify_t why, const char *path,
const git_diff_file *baseline,
const git_diff_file *target,
const git_diff_file *workdir, void *payload )
{
GIT_REVERT_HANDLER* handler = static_cast<GIT_REVERT_HANDLER*>(payload);
if( why & ( GIT_CHECKOUT_NOTIFY_CONFLICT | GIT_CHECKOUT_NOTIFY_IGNORED
| GIT_CHECKOUT_NOTIFY_UPDATED ) )
handler->PushFailedFile( path );
return 0;
}
void GIT_REVERT_HANDLER::PerformRevert()
{
git_object* head_commit = NULL;
git_checkout_options opts;
git_checkout_init_options( &opts, GIT_CHECKOUT_OPTIONS_VERSION );
// Get the HEAD commit
if( git_revparse_single( &head_commit, m_repository, "HEAD" ) != 0 )
{
// Handle error. If we cannot get the HEAD, then there's no point proceeding.
return;
}
opts.checkout_strategy = GIT_CHECKOUT_FORCE;
char** paths = new char*[m_filesToRevert.size()];
for( size_t ii = 0; ii < m_filesToRevert.size(); ii++ )
{
// Set paths to the specific file
paths[ii] = wxStrdup( m_filesToRevert[ii].ToUTF8() );
}
git_strarray arr = { paths, m_filesToRevert.size() };
opts.paths = arr;
opts.progress_cb = checkout_progress_cb;
opts.notify_cb = checkout_notify_cb;
opts.notify_payload = static_cast<void*>( this );
// Attempt to checkout the file(s)
if( git_checkout_tree(m_repository, head_commit, &opts ) != 0 )
{
const git_error *e = git_error_last();
if( e )
{
wxLogTrace( traceGit, wxS( "Checkout failed: %d: %s" ), e->klass, e->message );
}
}
// Free the HEAD commit
for( size_t ii = 0; ii < m_filesToRevert.size(); ii++ )
delete( paths[ii] );
delete[] paths;
git_object_free( head_commit );
GetGitBackend()->PerformRevert( this );
}

View File

@ -27,6 +27,10 @@
#include <git2.h>
#include <vector>
#include <wx/string.h>
// TEMPORARY HACKFIX INCLUDE FOR STD::VECTOR EXPORT OUT OF KICOMMON ON WINDOWS
#include <settings/parameters.h>
class LIBGIT_BACKEND;
class GIT_REVERT_HANDLER
{
@ -44,6 +48,7 @@ public:
}
private:
friend class LIBGIT_BACKEND;
git_repository* m_repository;
std::vector<wxString> m_filesToRevert;

View File

@ -22,10 +22,8 @@
*/
#include "git_status_handler.h"
#include <git/kicad_git_common.h>
#include <git/kicad_git_memory.h>
#include <trace_helpers.h>
#include <wx/log.h>
#include "git_backend.h"
GIT_STATUS_HANDLER::GIT_STATUS_HANDLER( KIGIT_COMMON* aCommon ) : KIGIT_REPO_MIXIN( aCommon )
{}
@ -35,171 +33,29 @@ GIT_STATUS_HANDLER::~GIT_STATUS_HANDLER()
bool GIT_STATUS_HANDLER::HasChangedFiles()
{
git_repository* repo = GetRepo();
if( !repo )
return false;
git_status_options opts;
git_status_init_options( &opts, GIT_STATUS_OPTIONS_VERSION );
opts.show = GIT_STATUS_SHOW_INDEX_AND_WORKDIR;
opts.flags = GIT_STATUS_OPT_INCLUDE_UNTRACKED | GIT_STATUS_OPT_RENAMES_HEAD_TO_INDEX
| GIT_STATUS_OPT_SORT_CASE_SENSITIVELY;
git_status_list* status_list = nullptr;
if( git_status_list_new( &status_list, repo, &opts ) != GIT_OK )
{
wxLogTrace( traceGit, "Failed to get status list: %s", KIGIT_COMMON::GetLastGitError() );
return false;
}
KIGIT::GitStatusListPtr status_list_ptr( status_list );
bool hasChanges = ( git_status_list_entrycount( status_list ) > 0 );
return hasChanges;
return GetGitBackend()->HasChangedFiles( this );
}
std::map<wxString, FileStatus> GIT_STATUS_HANDLER::GetFileStatus( const wxString& aPathspec )
{
std::map<wxString, FileStatus> fileStatusMap;
git_repository* repo = GetRepo();
if( !repo )
return fileStatusMap;
git_status_options status_options;
git_status_init_options( &status_options, GIT_STATUS_OPTIONS_VERSION );
status_options.show = GIT_STATUS_SHOW_INDEX_AND_WORKDIR;
status_options.flags = GIT_STATUS_OPT_INCLUDE_UNTRACKED | GIT_STATUS_OPT_INCLUDE_UNMODIFIED;
// Set up pathspec if provided
std::string pathspec_str;
std::vector<const char*> pathspec_ptrs;
if( !aPathspec.IsEmpty() )
{
pathspec_str = aPathspec.ToStdString();
pathspec_ptrs.push_back( pathspec_str.c_str() );
status_options.pathspec.strings = const_cast<char**>( pathspec_ptrs.data() );
status_options.pathspec.count = pathspec_ptrs.size();
}
git_status_list* status_list = nullptr;
if( git_status_list_new( &status_list, repo, &status_options ) != GIT_OK )
{
wxLogTrace( traceGit, "Failed to get git status list: %s", KIGIT_COMMON::GetLastGitError() );
return fileStatusMap;
}
KIGIT::GitStatusListPtr statusListPtr( status_list );
size_t count = git_status_list_entrycount( status_list );
wxString repoWorkDir( git_repository_workdir( repo ) );
for( size_t ii = 0; ii < count; ++ii )
{
const git_status_entry* entry = git_status_byindex( status_list, ii );
std::string path( entry->head_to_index ? entry->head_to_index->old_file.path
: entry->index_to_workdir->old_file.path );
wxString absPath = repoWorkDir + path;
FileStatus fileStatus;
fileStatus.filePath = absPath;
fileStatus.gitStatus = entry->status;
fileStatus.status = ConvertStatus( entry->status );
fileStatusMap[absPath] = fileStatus;
}
return fileStatusMap;
return GetGitBackend()->GetFileStatus( this, aPathspec );
}
wxString GIT_STATUS_HANDLER::GetCurrentBranchName()
{
git_repository* repo = GetRepo();
if( !repo )
return wxEmptyString;
git_reference* currentBranchReference = nullptr;
int rc = git_repository_head( &currentBranchReference, repo );
KIGIT::GitReferencePtr currentBranchReferencePtr( currentBranchReference );
if( currentBranchReference )
{
return git_reference_shorthand( currentBranchReference );
}
else if( rc == GIT_EUNBORNBRANCH )
{
// Unborn branch - could return empty or a default name
return wxEmptyString;
}
else
{
wxLogTrace( traceGit, "Failed to lookup current branch: %s", KIGIT_COMMON::GetLastGitError() );
return wxEmptyString;
}
return GetGitBackend()->GetCurrentBranchName( this );
}
void GIT_STATUS_HANDLER::UpdateRemoteStatus( const std::set<wxString>& aLocalChanges,
const std::set<wxString>& aRemoteChanges,
std::map<wxString, FileStatus>& aFileStatus )
const std::set<wxString>& aRemoteChanges,
std::map<wxString, FileStatus>& aFileStatus )
{
git_repository* repo = GetRepo();
if( !repo )
return;
wxString repoWorkDir( git_repository_workdir( repo ) );
// Update status based on local/remote changes
for( auto& [absPath, fileStatus] : aFileStatus )
{
// Convert absolute path to relative path for comparison
wxString relativePath = absPath;
if( relativePath.StartsWith( repoWorkDir ) )
{
relativePath = relativePath.Mid( repoWorkDir.length() );
#ifdef _WIN32
relativePath.Replace( wxS( "\\" ), wxS( "/" ) );
#endif
}
std::string relativePathStd = relativePath.ToStdString();
// Only update if the file is not already modified/added/deleted
if( fileStatus.status == KIGIT_COMMON::GIT_STATUS::GIT_STATUS_CURRENT )
{
if( aLocalChanges.count( relativePathStd ) )
{
fileStatus.status = KIGIT_COMMON::GIT_STATUS::GIT_STATUS_AHEAD;
}
else if( aRemoteChanges.count( relativePathStd ) )
{
fileStatus.status = KIGIT_COMMON::GIT_STATUS::GIT_STATUS_BEHIND;
}
}
}
GetGitBackend()->UpdateRemoteStatus( this, aLocalChanges, aRemoteChanges, aFileStatus );
}
wxString GIT_STATUS_HANDLER::GetWorkingDirectory()
{
git_repository* repo = GetRepo();
if( !repo )
return wxEmptyString;
const char* workdir = git_repository_workdir( repo );
if( !workdir )
return wxEmptyString;
return wxString( workdir );
return GetGitBackend()->GetWorkingDirectory( this );
}
KIGIT_COMMON::GIT_STATUS GIT_STATUS_HANDLER::ConvertStatus( unsigned int aGitStatus )

View File

@ -29,6 +29,8 @@
#include <map>
#include <set>
class LIBGIT_BACKEND;
struct FileStatus
{
wxString filePath;
@ -80,6 +82,7 @@ public:
void UpdateProgress( int aCurrent, int aTotal, const wxString& aMessage ) override;
private:
friend class LIBGIT_BACKEND;
/**
* Convert git status flags to KIGIT_COMMON::GIT_STATUS
* @param aGitStatus Raw git status flags

View File

@ -33,6 +33,8 @@
#include <wx/string.h>
class LIBGIT_BACKEND;
class KIGIT_COMMON
{
@ -174,6 +176,7 @@ protected:
friend class GIT_PUSH_HANDLER;
friend class GIT_PULL_HANDLER;
friend class GIT_CLONE_HANDLER;
friend class LIBGIT_BACKEND;
friend class PROJECT_TREE_PANE;
private:

File diff suppressed because it is too large Load Diff

100
common/git/libgit_backend.h Normal file
View File

@ -0,0 +1,100 @@
/*
* 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
*/
#ifndef LIBGIT_BACKEND_H_
#define LIBGIT_BACKEND_H_
#include "git_backend.h"
// Forward declarations to avoid exposing libgit2 headers
struct git_annotated_commit;
class LIBGIT_BACKEND : public GIT_BACKEND
{
public:
void Init() override;
void Shutdown() override;
bool IsLibraryAvailable() override;
bool Clone( GIT_CLONE_HANDLER* aHandler ) override;
CommitResult Commit( GIT_COMMIT_HANDLER* aHandler,
const std::vector<wxString>& aFiles,
const wxString& aMessage,
const wxString& aAuthorName,
const wxString& aAuthorEmail ) override;
PushResult Push( GIT_PUSH_HANDLER* aHandler ) override;
bool HasChangedFiles( GIT_STATUS_HANDLER* aHandler ) override;
std::map<wxString, FileStatus> GetFileStatus( GIT_STATUS_HANDLER* aHandler,
const wxString& aPathspec ) override;
wxString GetCurrentBranchName( GIT_STATUS_HANDLER* aHandler ) override;
void UpdateRemoteStatus( GIT_STATUS_HANDLER* aHandler,
const std::set<wxString>& aLocalChanges,
const std::set<wxString>& aRemoteChanges,
std::map<wxString, FileStatus>& aFileStatus ) override;
wxString GetWorkingDirectory( GIT_STATUS_HANDLER* aHandler ) override;
wxString GetWorkingDirectory( GIT_CONFIG_HANDLER* aHandler ) override;
bool GetConfigString( GIT_CONFIG_HANDLER* aHandler, const wxString& aKey,
wxString& aValue ) override;
bool IsRepository( GIT_INIT_HANDLER* aHandler, const wxString& aPath ) override;
InitResult InitializeRepository( GIT_INIT_HANDLER* aHandler, const wxString& aPath ) override;
bool SetupRemote( GIT_INIT_HANDLER* aHandler, const RemoteConfig& aConfig ) override;
BranchResult SwitchToBranch( GIT_BRANCH_HANDLER* aHandler, const wxString& aBranchName ) override;
bool BranchExists( GIT_BRANCH_HANDLER* aHandler, const wxString& aBranchName ) override;
bool PerformFetch( GIT_PULL_HANDLER* aHandler, bool aSkipLock ) override;
PullResult PerformPull( GIT_PULL_HANDLER* aHandler ) override;
void PerformRevert( GIT_REVERT_HANDLER* aHandler ) override;
git_repository* GetRepositoryForFile( const char* aFilename ) override;
int CreateBranch( git_repository* aRepo, const wxString& aBranchName ) override;
bool RemoveVCS( git_repository*& aRepo, const wxString& aProjectPath,
bool aRemoveGitDir, wxString* aErrors ) override;
bool AddToIndex( GIT_ADD_TO_INDEX_HANDLER* aHandler, const wxString& aFilePath ) override;
bool PerformAddToIndex( GIT_ADD_TO_INDEX_HANDLER* aHandler ) override;
bool RemoveFromIndex( GIT_REMOVE_FROM_INDEX_HANDLER* aHandler, const wxString& aFilePath ) override;
void PerformRemoveFromIndex( GIT_REMOVE_FROM_INDEX_HANDLER* aHandler ) override;
private:
PullResult handleFastForward( GIT_PULL_HANDLER* aHandler );
PullResult handleMerge( GIT_PULL_HANDLER* aHandler, const git_annotated_commit** aMergeHeads,
size_t aMergeHeadsCount );
PullResult handleRebase( GIT_PULL_HANDLER* aHandler, const git_annotated_commit** aMergeHeads,
size_t aMergeHeadsCount );
};
#endif

View File

@ -22,105 +22,25 @@
*/
#include "project_git_utils.h"
#include "kicad_git_common.h"
#include "kicad_git_memory.h"
#include <git/kicad_git_compat.h>
#include <trace_helpers.h>
#include <wx/log.h>
#include <wx/filename.h>
#include <gestfich.h>
#include "git_backend.h"
namespace KIGIT
{
git_repository* PROJECT_GIT_UTILS::GetRepositoryForFile( const char* aFilename )
{
git_repository* repo = nullptr;
git_buf repo_path = GIT_BUF_INIT;
if( git_repository_discover( &repo_path, aFilename, 0, nullptr ) != GIT_OK )
{
wxLogTrace( traceGit, "Can't repo discover %s: %s", aFilename,
KIGIT_COMMON::GetLastGitError() );
return nullptr;
}
KIGIT::GitBufPtr repo_path_ptr( &repo_path );
if( git_repository_open( &repo, repo_path.ptr ) != GIT_OK )
{
wxLogTrace( traceGit, "Can't open repo for %s: %s", repo_path.ptr,
KIGIT_COMMON::GetLastGitError() );
return nullptr;
}
return repo;
return GetGitBackend()->GetRepositoryForFile( aFilename );
}
int PROJECT_GIT_UTILS::CreateBranch( git_repository* aRepo, const wxString& aBranchName )
{
git_oid head_oid;
if( int error = git_reference_name_to_id( &head_oid, aRepo, "HEAD" ); error != GIT_OK )
{
wxLogTrace( traceGit, "Failed to lookup HEAD reference: %s",
KIGIT_COMMON::GetLastGitError() );
return error;
}
git_commit* commit = nullptr;
if( int error = git_commit_lookup( &commit, aRepo, &head_oid ); error != GIT_OK )
{
wxLogTrace( traceGit, "Failed to lookup commit: %s",
KIGIT_COMMON::GetLastGitError() );
return error;
}
KIGIT::GitCommitPtr commitPtr( commit );
git_reference* branchRef = nullptr;
if( int error = git_branch_create( &branchRef, aRepo, aBranchName.mb_str(), commit, 0 ); error != GIT_OK )
{
wxLogTrace( traceGit, "Failed to create branch: %s",
KIGIT_COMMON::GetLastGitError() );
return error;
}
git_reference_free( branchRef );
return 0;
return GetGitBackend()->CreateBranch( aRepo, aBranchName );
}
bool PROJECT_GIT_UTILS::RemoveVCS( git_repository*& aRepo, const wxString& aProjectPath,
bool aRemoveGitDir, wxString* aErrors )
{
if( aRepo )
{
git_repository_free( aRepo );
aRepo = nullptr;
}
if( aRemoveGitDir )
{
wxFileName gitDir( aProjectPath, wxEmptyString );
gitDir.AppendDir( ".git" );
if( gitDir.DirExists() )
{
wxString errors;
if( !RmDirRecursive( gitDir.GetPath(), &errors ) )
{
if( aErrors )
*aErrors = errors;
wxLogTrace( traceGit, "Failed to remove .git directory: %s", errors );
return false;
}
}
}
wxLogTrace( traceGit, "Successfully removed VCS from project" );
return true;
return GetGitBackend()->RemoveVCS( aRepo, aProjectPath, aRemoveGitDir, aErrors );
}
} // namespace KIGIT
} // namespace KIGIT

View File

@ -29,6 +29,7 @@
#include <trigo.h>
#include <math/util.h> // for KiROUND
#include <font/font.h>
#include <text_eval/text_eval_wrapper.h>
#include <callback_gal.h>
@ -100,8 +101,15 @@ int GRTextWidth( const wxString& aText, KIFONT::FONT* aFont, const VECTOR2I& aSi
{
if( !aFont )
aFont = KIFONT::FONT::GetFont();
wxString evaluated( aText );
return KiROUND( aFont->StringBoundaryLimits( aText, aSize, aThickness, aBold, aItalic,
if( evaluated.Contains( wxS( "@{" ) ) )
{
EXPRESSION_EVALUATOR evaluator;
evaluated = evaluator.Evaluate( evaluated );
}
return KiROUND( aFont->StringBoundaryLimits( evaluated, aSize, aThickness, aBold, aItalic,
aFontMetrics ).x );
}
@ -114,6 +122,13 @@ void GRPrintText( wxDC* aDC, const VECTOR2I& aPos, const COLOR4D& aColor, const
{
KIGFX::GAL_DISPLAY_OPTIONS empty_opts;
bool fill_mode = true;
wxString evaluatedText( aText );
if( evaluatedText.Contains( wxS( "@{" ) ) )
{
EXPRESSION_EVALUATOR evaluator;
evaluatedText = evaluator.Evaluate( evaluatedText );
}
if( !aFont )
aFont = KIFONT::FONT::GetFont();
@ -156,7 +171,7 @@ void GRPrintText( wxDC* aDC, const VECTOR2I& aPos, const COLOR4D& aColor, const
attributes.m_Valign = aV_justify;
attributes.m_Size = aSize;
aFont->Draw( &callback_gal, aText, aPos, attributes, aFontMetrics );
aFont->Draw( &callback_gal, evaluatedText, aPos, attributes, aFontMetrics );
}

View File

@ -40,6 +40,7 @@
#include <wx/txtstrm.h>
#include <wx/wfstream.h>
#include <tool/tool_action.h>
#include <tool/tool_event.h>
/*
@ -159,6 +160,10 @@ static struct hotkey_name_descr hotkeyNameList[] =
#define MODIFIER_CMD_MAC wxT( "Cmd+" )
#define MODIFIER_CTRL_BASE wxT( "Ctrl+" )
#define MODIFIER_SHIFT wxT( "Shift+" )
#define MODIFIER_META wxT( "Meta+" )
#define MODIFIER_WIN wxT( "Win+" )
#define MODIFIER_SUPER wxT( "Super+" )
#define MODIFIER_ALTGR wxT( "AltGr+" )
wxString KeyNameFromKeyCode( int aKeycode, bool* aIsFound )
@ -175,6 +180,14 @@ wxString KeyNameFromKeyCode( int aKeycode, bool* aIsFound )
return wxString( MODIFIER_SHIFT ).BeforeFirst( '+' );
else if( aKeycode == WXK_ALT )
return wxString( MODIFIER_ALT ).BeforeFirst( '+' );
#ifdef WXK_WINDOWS_LEFT
else if( aKeycode == WXK_WINDOWS_LEFT || aKeycode == WXK_WINDOWS_RIGHT )
return wxString( MODIFIER_WIN ).BeforeFirst( '+' );
#endif
#ifdef WXK_META
else if( aKeycode == WXK_META )
return wxString( MODIFIER_META ).BeforeFirst( '+' );
#endif
// Assume keycode of 0 is "unassigned"
if( (aKeycode & MD_CTRL) != 0 )
@ -186,7 +199,16 @@ wxString KeyNameFromKeyCode( int aKeycode, bool* aIsFound )
if( (aKeycode & MD_SHIFT) != 0 )
modifier << MODIFIER_SHIFT;
aKeycode &= ~( MD_CTRL | MD_ALT | MD_SHIFT );
if( (aKeycode & MD_META) != 0 )
modifier << MODIFIER_META;
if( (aKeycode & MD_SUPER) != 0 )
modifier << MODIFIER_WIN;
if( (aKeycode & MD_ALTGR) != 0 )
modifier << MODIFIER_ALTGR;
aKeycode &= ~MD_MODIFIER_MASK;
if( (aKeycode > ' ') && (aKeycode < 0x7F ) )
{
@ -262,7 +284,7 @@ int KeyCodeFromKeyName( const wxString& keyname )
{
int ii, keycode = KEY_NON_FOUND;
// Search for modifiers: Ctrl+ Alt+ and Shift+
// Search for modifiers: Ctrl+ Alt+ Shift+ and others
// Note: on Mac OSX, the Cmd key is equiv here to Ctrl
wxString key = keyname;
wxString prefix;
@ -292,6 +314,26 @@ int KeyCodeFromKeyName( const wxString& keyname )
modifier |= MD_SHIFT;
prefix = MODIFIER_SHIFT;
}
else if( key.StartsWith( MODIFIER_META ) )
{
modifier |= MD_META;
prefix = MODIFIER_META;
}
else if( key.StartsWith( MODIFIER_WIN ) )
{
modifier |= MD_SUPER;
prefix = MODIFIER_WIN;
}
else if( key.StartsWith( MODIFIER_SUPER ) )
{
modifier |= MD_SUPER;
prefix = MODIFIER_SUPER;
}
else if( key.StartsWith( MODIFIER_ALTGR ) )
{
modifier |= MD_ALTGR;
prefix = MODIFIER_ALTGR;
}
else
{
break;

View File

@ -40,8 +40,7 @@ JOB_EXPORT_SCH_BOM::JOB_EXPORT_SCH_BOM() :
m_sortField(),
m_sortAsc( true ),
m_filterString(),
m_excludeDNP( false ),
m_includeExcludedFromBOM( false )
m_excludeDNP( false )
{
m_params.emplace_back( new JOB_PARAM<wxString>( "field_delimiter",
&m_fieldDelimiter,
@ -70,13 +69,8 @@ JOB_EXPORT_SCH_BOM::JOB_EXPORT_SCH_BOM() :
m_fieldsGroupBy ) );
m_params.emplace_back( new JOB_PARAM<wxString>( "sort_field", &m_sortField, m_sortField ) );
m_params.emplace_back( new JOB_PARAM<bool>( "sort_asc", &m_sortAsc, m_sortAsc ) );
m_params.emplace_back( new JOB_PARAM<wxString>( "filter_string",
&m_filterString,
m_filterString ) );
m_params.emplace_back( new JOB_PARAM<wxString>( "filter_string", &m_filterString, m_filterString ) );
m_params.emplace_back( new JOB_PARAM<bool>( "exclude_dnp", &m_excludeDNP, m_excludeDNP ) );
m_params.emplace_back( new JOB_PARAM<bool>( "include_excluded_from_bom",
&m_includeExcludedFromBOM,
m_includeExcludedFromBOM ) );
m_params.emplace_back( new JOB_PARAM<wxString>( "bom_preset_name",
&m_bomPresetName,

View File

@ -55,7 +55,6 @@ public:
bool m_sortAsc;
wxString m_filterString;
bool m_excludeDNP;
bool m_includeExcludedFromBOM;
};
#endif

View File

@ -0,0 +1,27 @@
/*
* 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 <jobs/job_pcb_upgrade.h>
JOB_PCB_UPGRADE::JOB_PCB_UPGRADE() :
JOB( "upgrade", false ),
m_filename(),
m_force( false )
{
}

View File

@ -0,0 +1,35 @@
/*
* 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 JOB_PCB_UPGRADE_H
#define JOB_PCB_UPGRADE_H
#include <kicommon.h>
#include "job.h"
class KICOMMON_API JOB_PCB_UPGRADE : public JOB
{
public:
JOB_PCB_UPGRADE();
wxString m_filename;
bool m_force;
};
#endif

View File

@ -0,0 +1,27 @@
/*
* 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 <jobs/job_sch_upgrade.h>
JOB_SCH_UPGRADE::JOB_SCH_UPGRADE() :
JOB( "upgrade", false ),
m_filename(),
m_force( false )
{
}

View File

@ -0,0 +1,35 @@
/*
* 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 JOB_SCH_UPGRADE_H
#define JOB_SCH_UPGRADE_H
#include <kicommon.h>
#include "job.h"
class KICOMMON_API JOB_SCH_UPGRADE : public JOB
{
public:
JOB_SCH_UPGRADE();
wxString m_filename;
bool m_force;
};
#endif

View File

@ -142,6 +142,7 @@ wxString LayerName( int aLayer )
case LAYER_DRC_EXCLUSION: return _( "DRC exclusions" );
case LAYER_MARKER_SHADOWS: return _( "DRC marker shadows" );
case LAYER_ANCHOR: return _( "Anchors" );
case LAYER_POINTS: return _( "Points" );
case LAYER_DRAWINGSHEET: return _( "Drawing sheet" );
case LAYER_PAGE_LIMITS: return _( "Page limits" );
case LAYER_CURSOR: return _( "Cursor" );

View File

@ -19,11 +19,23 @@
#include "lib_table_grid_tricks.h"
#include "lib_table_grid.h"
#include <wx/clipbrd.h>
#include <wx/log.h>
LIB_TABLE_GRID_TRICKS::LIB_TABLE_GRID_TRICKS( WX_GRID* aGrid ) :
GRID_TRICKS( aGrid )
{
m_grid->Disconnect( wxEVT_CHAR_HOOK );
m_grid->Connect( wxEVT_CHAR_HOOK, wxCharEventHandler( LIB_TABLE_GRID_TRICKS::onCharHook ), nullptr, this );
}
LIB_TABLE_GRID_TRICKS::LIB_TABLE_GRID_TRICKS( WX_GRID* aGrid,
std::function<void( wxCommandEvent& )> aAddHandler ) :
GRID_TRICKS( aGrid, aAddHandler )
{
m_grid->Disconnect( wxEVT_CHAR_HOOK );
m_grid->Connect( wxEVT_CHAR_HOOK, wxCharEventHandler( LIB_TABLE_GRID_TRICKS::onCharHook ), nullptr, this );
}
@ -134,6 +146,61 @@ void LIB_TABLE_GRID_TRICKS::doPopupSelection( wxCommandEvent& event )
GRID_TRICKS::doPopupSelection( event );
}
}
void LIB_TABLE_GRID_TRICKS::onCharHook( wxKeyEvent& ev )
{
if( ev.GetModifiers() == wxMOD_CONTROL && ev.GetKeyCode() == 'V' && m_grid->IsCellEditControlShown() )
{
wxLogNull doNotLog;
if( wxTheClipboard->Open() )
{
if( wxTheClipboard->IsSupported( wxDF_TEXT ) || wxTheClipboard->IsSupported( wxDF_UNICODETEXT ) )
{
wxTextDataObject data;
wxTheClipboard->GetData( data );
wxString text = data.GetText();
if( !text.Contains( '\t' ) && text.Contains( ',' ) )
text.Replace( ',', '\t' );
if( text.Contains( '\t' ) || text.Contains( '\n' ) || text.Contains( '\r' ) )
{
m_grid->CancelPendingChanges();
int row = m_grid->GetGridCursorRow();
// Check if the current row already has data (has a nickname)
wxGridTableBase* table = m_grid->GetTable();
if( table && row >= 0 && row < table->GetNumberRows() )
{
// Check if the row has a nickname (indicating it has existing data)
wxString nickname = table->GetValue( row, COL_NICKNAME );
if( !nickname.IsEmpty() )
{
// Row already has data, don't allow pasting over it
wxTheClipboard->Close();
wxBell(); // Provide audio feedback
return;
}
}
m_grid->ClearSelection();
m_grid->SelectRow( row );
m_grid->SetGridCursor( row, 0 );
getSelectedArea();
paste_text( text );
wxTheClipboard->Close();
m_grid->ForceRefresh();
return;
}
}
wxTheClipboard->Close();
}
}
GRID_TRICKS::onCharHook( ev );
}
bool LIB_TABLE_GRID_TRICKS::handleDoubleClick( wxGridEvent& aEvent )

View File

@ -32,6 +32,7 @@
#include <wx/wupdlock.h>
#include <wx/settings.h>
#include <wx/dc.h>
#include <wx/log.h>
#include <string_utils.h>
@ -308,6 +309,15 @@ void LIB_TREE_MODEL_ADAPTER::UpdateSearchString( const wxString& aSearch, bool a
const LIB_TREE_NODE* firstMatch = ShowResults();
#ifdef __WXGTK__
// Ensure the control is repainted with the updated data. Without an explicit
// refresh the Gtk port can display stale rows until the user interacts with
// them, leading to mismatched tree contents.
m_widget->Refresh();
m_widget->Update();
wxYield();
#endif
if( firstMatch )
{
wxDataViewItem item = ToItem( firstMatch );

View File

@ -857,7 +857,12 @@ bool COMPILER::generateUCode( UCODE* aCode, CONTEXT* aPreflightContext )
case TR_OP_FUNC_CALL:
// Function call's uop was generated inside TR_STRUCT_REF
if( !node->uop )
reportError( CST_CODEGEN, _( "Unknown parent of function parameters" ), node->srcPos );
{
// This function call is bare so we don't know who to apply it to
// Set a safe default value to exit gracefully with an error
reportError( CST_CODEGEN, _( "Unknown parent of function parameters" ), node->srcPos );
node->SetUop( TR_UOP_PUSH_VALUE, 0.0, EDA_UNITS::UNSCALED );
}
node->isTerminal = true;
break;
@ -1095,7 +1100,6 @@ bool COMPILER::generateUCode( UCODE* aCode, CONTEXT* aPreflightContext )
{
stack.push_back( node->leaf[0] );
node->leaf[0]->isVisited = true;
continue;
}
else if( node->leaf[1] && !node->leaf[1]->isVisited )
{
@ -1156,7 +1160,9 @@ void UOP::Exec( CONTEXT* ctx )
return;
case TR_OP_METHOD_CALL:
m_func( ctx, m_ref.get() );
if( m_func )
m_func( ctx, m_ref.get() );
return;
default:
@ -1317,9 +1323,8 @@ VALUE* UCODE::Run( CONTEXT* ctx )
}
catch(...)
{
// rules which fail outright should not be fired
std::unique_ptr<VALUE> temp_false = std::make_unique<VALUE>( 0 );
return ctx->StoreValue( temp_false.get() );
// rules which fail outright should not be fired; return 0/false
return ctx->StoreValue( new VALUE( 0 ) );
}
if( ctx->SP() == 1 )
@ -1335,8 +1340,7 @@ VALUE* UCODE::Run( CONTEXT* ctx )
wxASSERT( ctx->SP() == 1 );
// non-well-formed rules should not be fired on a release build
std::unique_ptr<VALUE> temp_false = std::make_unique<VALUE>( 0 );
return ctx->StoreValue( temp_false.get() );
return ctx->StoreValue( new VALUE( 0 ) );
}
}

View File

@ -806,7 +806,8 @@ GAL_SET GAL_SET::DefaultVisible()
LAYER_FILLED_SHAPES,
LAYER_LOCKED_ITEM_SHADOW,
// LAYER_BOARD_OUTLINE_AREA, // currently hidden by default
LAYER_CONFLICTS_SHADOW
LAYER_CONFLICTS_SHADOW,
LAYER_POINTS
};
static const GAL_SET saved( visible, arrayDim( visible ) );

View File

@ -280,6 +280,7 @@ pintype
placed
placement
plus
point
polygon
portrait
precision

View File

@ -29,6 +29,7 @@
#include <macros.h>
#include <string_utils.h>
#include <convert_basic_shapes_to_polygon.h>
#include <geometry/shape_rect.h>
#include <trigo.h>
#include <fmt/core.h>
@ -446,10 +447,21 @@ void DXF_PLOTTER::SetColor( const COLOR4D& color )
}
void DXF_PLOTTER::Rect( const VECTOR2I& p1, const VECTOR2I& p2, FILL_T fill, int width )
void DXF_PLOTTER::Rect( const VECTOR2I& p1, const VECTOR2I& p2, FILL_T fill, int width,
int aCornerRadius )
{
wxASSERT( m_outputFile );
if( aCornerRadius > 0 )
{
BOX2I box( p1, VECTOR2I( p2.x - p1.x, p2.y - p1.y ) );
box.Normalize();
SHAPE_RECT rect( box );
rect.SetRadius( aCornerRadius );
PlotPoly( rect.Outline(), fill, width, nullptr );
return;
}
if( p1 != p2 )
{
MoveTo( p1 );
@ -605,6 +617,22 @@ void DXF_PLOTTER::PlotPoly( const std::vector<VECTOR2I>& aCornerList, FILL_T aFi
}
void DXF_PLOTTER::PlotPoly( const SHAPE_LINE_CHAIN& aCornerList, FILL_T aFill, int aWidth,
void* aData )
{
std::vector<VECTOR2I> cornerList;
cornerList.reserve( aCornerList.PointCount() );
for( int ii = 0; ii < aCornerList.PointCount(); ii++ )
cornerList.emplace_back( aCornerList.CPoint( ii ) );
if( aCornerList.IsClosed() && cornerList.front() != cornerList.back() )
cornerList.emplace_back( aCornerList.CPoint( 0 ) );
PlotPoly( cornerList, aFill, aWidth, aData );
}
void DXF_PLOTTER::PenTo( const VECTOR2I& pos, char plume )
{
wxASSERT( m_outputFile );
@ -735,17 +763,17 @@ void DXF_PLOTTER::ThickRect( const VECTOR2I& p1, const VECTOR2I& p2, int width,
{
VECTOR2I offsetp1( p1.x - width/2, p1.y - width/2 );
VECTOR2I offsetp2( p2.x + width/2, p2.y + width/2 );
Rect( offsetp1, offsetp2, FILL_T::NO_FILL, DXF_LINE_WIDTH );
Rect( offsetp1, offsetp2, FILL_T::NO_FILL, DXF_LINE_WIDTH, 0 );
offsetp1.x += width;
offsetp1.y += width;
offsetp2.x -= width;
offsetp2.y -= width;
Rect( offsetp1, offsetp2, FILL_T::NO_FILL, DXF_LINE_WIDTH );
Rect( offsetp1, offsetp2, FILL_T::NO_FILL, DXF_LINE_WIDTH, 0 );
}
else
{
Rect( p1, p2, FILL_T::NO_FILL, DXF_LINE_WIDTH );
Rect( p1, p2, FILL_T::NO_FILL, DXF_LINE_WIDTH, 0 );
}
}

View File

@ -25,6 +25,7 @@
#include <string_utils.h>
#include <convert_basic_shapes_to_polygon.h>
#include <geometry/shape_rect.h>
#include <macros.h>
#include <math/util.h> // for KiROUND
#include <trigo.h>
@ -846,8 +847,19 @@ void GERBER_PLOTTER::PenTo( const VECTOR2I& aPos, char plume )
}
void GERBER_PLOTTER::Rect( const VECTOR2I& p1, const VECTOR2I& p2, FILL_T fill, int width )
void GERBER_PLOTTER::Rect( const VECTOR2I& p1, const VECTOR2I& p2, FILL_T fill, int width,
int aCornerRadius )
{
if( aCornerRadius > 0 )
{
BOX2I box( p1, VECTOR2I( p2.x - p1.x, p2.y - p1.y ) );
box.Normalize();
SHAPE_RECT rect( box );
rect.SetRadius( aCornerRadius );
PlotPoly( rect.Outline(), fill, width, nullptr );
return;
}
std::vector<VECTOR2I> cornerList;
cornerList.reserve( 5 );

View File

@ -51,6 +51,7 @@
#include <fmt/ranges.h>
#include <plotters/plotters_pslike.h>
#include <geometry/shape_rect.h>
std::string PDF_PLOTTER::encodeStringForPlotter( const wxString& aText )
@ -227,7 +228,8 @@ void PDF_PLOTTER::SetDash( int aLineWidth, LINE_STYLE aLineStyle )
}
void PDF_PLOTTER::Rect( const VECTOR2I& p1, const VECTOR2I& p2, FILL_T fill, int width )
void PDF_PLOTTER::Rect( const VECTOR2I& p1, const VECTOR2I& p2, FILL_T fill, int width,
int aCornerRadius )
{
wxASSERT( m_workFile );
@ -236,6 +238,16 @@ void PDF_PLOTTER::Rect( const VECTOR2I& p1, const VECTOR2I& p2, FILL_T fill, int
SetCurrentLineWidth( width );
if( aCornerRadius > 0 )
{
BOX2I box( p1, VECTOR2I( p2.x - p1.x, p2.y - p1.y ) );
box.Normalize();
SHAPE_RECT rect( box );
rect.SetRadius( aCornerRadius );
PlotPoly( rect.Outline(), fill, width, nullptr );
return;
}
VECTOR2I size = p2 - p1;
if( size.x == 0 && size.y == 0 )
@ -429,6 +441,22 @@ void PDF_PLOTTER::PlotPoly( const std::vector<VECTOR2I>& aCornerList, FILL_T aFi
}
void PDF_PLOTTER::PlotPoly( const SHAPE_LINE_CHAIN& aCornerList, FILL_T aFill, int aWidth,
void* aData )
{
std::vector<VECTOR2I> cornerList;
cornerList.reserve( aCornerList.PointCount() );
for( int ii = 0; ii < aCornerList.PointCount(); ii++ )
cornerList.emplace_back( aCornerList.CPoint( ii ) );
if( aCornerList.IsClosed() && cornerList.front() != cornerList.back() )
cornerList.emplace_back( aCornerList.CPoint( 0 ) );
PlotPoly( cornerList, aFill, aWidth, aData );
}
void PDF_PLOTTER::PenTo( const VECTOR2I& pos, char plume )
{
wxASSERT( m_workFile );

View File

@ -30,6 +30,7 @@
#include <convert_basic_shapes_to_polygon.h>
#include <macros.h>
#include <math/util.h> // for KiROUND
#include <geometry/shape_rect.h>
#include <string_utils.h>
#include <trigo.h>
#include <fmt/format.h>
@ -457,13 +458,24 @@ void PS_PLOTTER::SetDash( int aLineWidth, LINE_STYLE aLineStyle )
}
void PS_PLOTTER::Rect( const VECTOR2I& p1, const VECTOR2I& p2, FILL_T fill, int width )
void PS_PLOTTER::Rect( const VECTOR2I& p1, const VECTOR2I& p2, FILL_T fill, int width,
int aCornerRadius )
{
SetCurrentLineWidth( width );
if( fill == FILL_T::NO_FILL && GetCurrentLineWidth() <= 0 )
return;
if( aCornerRadius > 0 )
{
BOX2I box( p1, VECTOR2I( p2.x - p1.x, p2.y - p1.y ) );
box.Normalize();
SHAPE_RECT rect( box );
rect.SetRadius( aCornerRadius );
PlotPoly( rect.Outline(), fill, width, nullptr );
return;
}
VECTOR2D p1_dev = userToDeviceCoordinates( p1 );
VECTOR2D p2_dev = userToDeviceCoordinates( p2 );
@ -556,6 +568,22 @@ void PS_PLOTTER::PlotPoly( const std::vector<VECTOR2I>& aCornerList, FILL_T aFil
}
void PS_PLOTTER::PlotPoly( const SHAPE_LINE_CHAIN& aCornerList, FILL_T aFill, int aWidth,
void* aData )
{
std::vector<VECTOR2I> cornerList;
cornerList.reserve( aCornerList.PointCount() );
for( int ii = 0; ii < aCornerList.PointCount(); ii++ )
cornerList.emplace_back( aCornerList.CPoint( ii ) );
if( aCornerList.IsClosed() && cornerList.front() != cornerList.back() )
cornerList.emplace_back( aCornerList.CPoint( 0 ) );
PlotPoly( cornerList, aFill, aWidth, aData );
}
void PS_PLOTTER::PlotImage( const wxImage& aImage, const VECTOR2I& aPos, double aScaleFactor )
{
VECTOR2I pix_size; // size of the bitmap in pixels

View File

@ -372,7 +372,8 @@ void SVG_PLOTTER::SetDash( int aLineWidth, LINE_STYLE aLineStyle )
}
void SVG_PLOTTER::Rect( const VECTOR2I& p1, const VECTOR2I& p2, FILL_T fill, int width )
void SVG_PLOTTER::Rect( const VECTOR2I& p1, const VECTOR2I& p2, FILL_T fill, int width,
int aCornerRadius )
{
BOX2I rect( p1, VECTOR2I( p2.x - p1.x, p2.y - p1.y ) );
rect.Normalize();
@ -412,7 +413,7 @@ void SVG_PLOTTER::Rect( const VECTOR2I& p1, const VECTOR2I& p2, FILL_T fill, int
rect_dev.GetPosition().y,
rect_dev.GetSize().x,
rect_dev.GetSize().y,
0.0 /* radius of rounded corners */ );
userToDeviceSize( aCornerRadius ) );
}
}

View File

@ -38,6 +38,7 @@
#include <trigo.h>
#include <plotters/plotter.h>
#include <text_eval/text_eval_wrapper.h>
#include <geometry/shape_line_chain.h>
#include <bezier_curves.h>
#include <callback_gal.h>
@ -267,7 +268,7 @@ void PLOTTER::PlotImage( const wxImage& aImage, const VECTOR2I& aPos, double aSc
end.x += size.x;
end.y += size.y;
Rect( start, end, FILL_T::NO_FILL, USE_DEFAULT_LINE_WIDTH );
Rect( start, end, FILL_T::NO_FILL, USE_DEFAULT_LINE_WIDTH, 0 );
}
@ -584,7 +585,7 @@ void PLOTTER::ThickArc( const EDA_SHAPE& aArcShape, void* aData, int aWidth )
void PLOTTER::ThickRect( const VECTOR2I& p1, const VECTOR2I& p2, int width, void* aData )
{
Rect( p1, p2, FILL_T::NO_FILL, width );
Rect( p1, p2, FILL_T::NO_FILL, width, 0 );
}
@ -637,6 +638,13 @@ void PLOTTER::Text( const VECTOR2I& aPos,
void* aData )
{
KIGFX::GAL_DISPLAY_OPTIONS empty_opts;
wxString text( aText );
if( text.Contains( wxS( "@{" ) ) )
{
EXPRESSION_EVALUATOR evaluator;
text = evaluator.Evaluate( text );
}
SetColor( aColor );
@ -680,7 +688,7 @@ void PLOTTER::Text( const VECTOR2I& aPos,
if( !aFont )
aFont = KIFONT::FONT::GetFont( m_renderSettings->GetDefaultFont() );
aFont->Draw( &callback_gal, aText, aPos, attributes, aFontMetrics );
aFont->Draw( &callback_gal, text, aPos, attributes, aFontMetrics );
}
@ -693,6 +701,13 @@ void PLOTTER::PlotText( const VECTOR2I& aPos,
void* aData )
{
KIGFX::GAL_DISPLAY_OPTIONS empty_opts;
wxString text( aText );
if( text.Contains( wxS( "@{" ) ) )
{
EXPRESSION_EVALUATOR evaluator;
text = evaluator.Evaluate( text );
}
TEXT_ATTRIBUTES attributes = aAttributes;
int penWidth = attributes.m_StrokeWidth;
@ -725,5 +740,5 @@ void PLOTTER::PlotText( const VECTOR2I& aPos,
if( !aFont )
aFont = KIFONT::FONT::GetFont( m_renderSettings->GetDefaultFont() );
aFont->Draw( &callback_gal, aText, aPos, attributes, aFontMetrics );
aFont->Draw( &callback_gal, text, aPos, attributes, aFontMetrics );
}

View File

@ -0,0 +1,208 @@
/*
* This program source code file is part of KICAD, a free EDA CAD application.
*
* Copyright (C) 2024 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 <preview_items/angle_item.h>
#include <tool/edit_points.h>
#include <gal/graphics_abstraction_layer.h>
#include <gal/painter.h>
#include <view/view.h>
#include <geometry/seg.h>
#include <preview_items/preview_utils.h>
#include <font/font.h>
#include <wx/string.h>
#include <algorithm>
#include <map>
using namespace KIGFX::PREVIEW;
ANGLE_ITEM::ANGLE_ITEM( EDIT_POINTS* aPoints ) :
SIMPLE_OVERLAY_ITEM(),
m_points( aPoints )
{
}
const BOX2I ANGLE_ITEM::ViewBBox() const
{
if( m_points )
return m_points->ViewBBox();
else
return BOX2I();
}
void ANGLE_ITEM::drawPreviewShape( KIGFX::VIEW* aView ) const
{
if( !m_points )
return;
KIGFX::GAL* gal = aView->GetGAL();
KIGFX::RENDER_SETTINGS* settings = aView->GetPainter()->GetSettings();
KIGFX::COLOR4D drawColor = settings->GetLayerColor( LAYER_AUX_ITEMS );
double size = aView->ToWorld( EDIT_POINT::POINT_SIZE ) / 2.0;
double borderSize = aView->ToWorld( EDIT_POINT::BORDER_SIZE );
double radius = size * 10.0;
gal->SetStrokeColor( drawColor );
gal->SetFillColor( drawColor );
gal->SetIsFill( false );
gal->SetLineWidth( borderSize * 2.0 );
gal->SetGlyphSize( VECTOR2I( radius / 2, radius / 2 ) );
std::vector<const EDIT_POINT*> anglePoints;
for( unsigned i = 0; i < m_points->PointsSize(); ++i )
{
const EDIT_POINT& point = m_points->Point( i );
if( point.IsActive() || point.IsHover() )
{
anglePoints.push_back( &point );
EDIT_POINT* prev = m_points->Previous( point );
EDIT_POINT* next = m_points->Next( point );
if( prev )
anglePoints.push_back( prev );
if( next )
anglePoints.push_back( next );
}
}
std::sort( anglePoints.begin(), anglePoints.end() );
anglePoints.erase( std::unique( anglePoints.begin(), anglePoints.end() ), anglePoints.end() );
// First pass: collect all angles and identify congruent ones
struct AngleInfo
{
const EDIT_POINT* point;
EDA_ANGLE angle;
VECTOR2D center;
VECTOR2D v1, v2;
EDA_ANGLE start;
EDA_ANGLE sweep;
EDA_ANGLE mid;
bool isRightAngle;
};
std::vector<AngleInfo> angles;
std::map<int, int> angleCount; // Map angle (in tenths of degree) to count
for( const EDIT_POINT* pt : anglePoints )
{
EDIT_POINT* prev = m_points->Previous( *pt );
EDIT_POINT* next = m_points->Next( *pt );
if( !( prev && next ) )
continue;
SEG seg1( pt->GetPosition(), prev->GetPosition() );
SEG seg2( pt->GetPosition(), next->GetPosition() );
// Calculate the interior angle (0-180 degrees) instead of the smallest angle
VECTOR2I c = pt->GetPosition();
VECTOR2I v1 = prev->GetPosition() - c;
VECTOR2I v2 = next->GetPosition() - c;
EDA_ANGLE angle = seg2.Angle( seg1 );
EDA_ANGLE start = EDA_ANGLE( VECTOR2D( v1 ) );
EDA_ANGLE sweep = ( EDA_ANGLE( VECTOR2D( v2 ) ) - start ).Normalize180();
EDA_ANGLE mid = start + sweep / 2.0;
VECTOR2D center( c );
AngleInfo info;
info.point = pt;
info.angle = angle;
info.center = center;
info.v1 = v1;
info.v2 = v2;
info.start = start;
info.sweep = sweep;
info.mid = mid;
info.isRightAngle = ( angle.AsTenthsOfADegree() == 900 );
angles.push_back( info );
angleCount[angle.AsTenthsOfADegree()]++;
}
// Second pass: draw the angles with congruence markings
for( const AngleInfo& angleInfo : angles )
{
bool isCongruent = angleCount[angleInfo.angle.AsTenthsOfADegree()] > 1;
if( angleInfo.isRightAngle )
{
VECTOR2D u1 = VECTOR2D( angleInfo.v1 ).Resize( radius );
VECTOR2D u2 = VECTOR2D( angleInfo.v2 ).Resize( radius );
VECTOR2D p1 = angleInfo.center + u1;
VECTOR2D p2 = angleInfo.center + u2;
VECTOR2D corner = angleInfo.center + u1 + u2;
// Draw the primary right angle marker
gal->DrawLine( p1, corner );
gal->DrawLine( p2, corner );
// Draw congruence marking for right angles
if( isCongruent )
{
double innerRadius = radius * 0.6;
VECTOR2D u1_inner = VECTOR2D( angleInfo.v1 ).Resize( innerRadius );
VECTOR2D u2_inner = VECTOR2D( angleInfo.v2 ).Resize( innerRadius );
VECTOR2D p1_inner = angleInfo.center + u1_inner;
VECTOR2D p2_inner = angleInfo.center + u2_inner;
VECTOR2D corner_inner = angleInfo.center + u1_inner + u2_inner;
gal->DrawLine( p1_inner, corner_inner );
gal->DrawLine( p2_inner, corner_inner );
}
}
else
{
// Draw the primary arc
gal->DrawArc( angleInfo.center, radius, angleInfo.start, angleInfo.sweep );
// Draw congruence marking for non-right angles
if( isCongruent )
{
double innerRadius = radius * 0.7;
gal->DrawArc( angleInfo.center, innerRadius, angleInfo.start, angleInfo.sweep );
}
}
VECTOR2D textDir( angleInfo.mid.Cos(), angleInfo.mid.Sin() );
wxString label = wxString::Format( wxT( "%.1f°" ), angleInfo.angle.AsDegrees() );
// Calculate actual text dimensions to ensure proper clearance
KIFONT::FONT* font = KIFONT::FONT::GetFont();
VECTOR2I textSize = font->StringBoundaryLimits( label, gal->GetGlyphSize(), 0, false, false,
KIFONT::METRICS::Default() );
// Calculate offset based on text direction - use width for horizontal, height for vertical
double absX = std::abs( textDir.x );
double absY = std::abs( textDir.y );
double textClearance = ( absX * textSize.x + absY * textSize.y ) / 2.0;
double textOffset = radius + borderSize + textClearance;
VECTOR2I textPos = angleInfo.center + VECTOR2I( textDir * textOffset );
gal->BitmapText( label, textPos, ANGLE_HORIZONTAL );
}
}

View File

@ -24,6 +24,16 @@
#include <properties/pg_properties.h>
#include <widgets/color_swatch.h>
#include <widgets/unit_binder.h>
#include <bitmaps.h>
#include <frame_type.h>
#include <kiway_player.h>
#include <kiway.h>
#include <wx/filedlg.h>
#include <wx/intl.h>
#include <eda_doc.h>
#include <wx/button.h>
#include <wx/bmpbuttn.h>
#include <wx/log.h>
@ -31,6 +41,8 @@ const wxString PG_UNIT_EDITOR::EDITOR_NAME = wxS( "KiCadUnitEditor" );
const wxString PG_CHECKBOX_EDITOR::EDITOR_NAME = wxS( "KiCadCheckboxEditor" );
const wxString PG_COLOR_EDITOR::EDITOR_NAME = wxS( "KiCadColorEditor" );
const wxString PG_RATIO_EDITOR::EDITOR_NAME = wxS( "KiCadRatioEditor" );
const wxString PG_FPID_EDITOR::EDITOR_NAME = wxS( "KiCadFpidEditor" );
const wxString PG_URL_EDITOR::EDITOR_NAME = wxS( "KiCadUrlEditor" );
PG_UNIT_EDITOR::PG_UNIT_EDITOR( EDA_DRAW_FRAME* aFrame ) :
@ -51,6 +63,9 @@ PG_UNIT_EDITOR::~PG_UNIT_EDITOR()
wxString PG_UNIT_EDITOR::BuildEditorName( EDA_DRAW_FRAME* aFrame )
{
if( !aFrame )
return EDITOR_NAME + "NoFrame";
return EDITOR_NAME + aFrame->GetName();
}
@ -458,3 +473,164 @@ void PG_RATIO_EDITOR::UpdateControl( wxPGProperty* aProperty, wxWindow* aCtrl )
"properties!" ) );
}
}
PG_FPID_EDITOR::PG_FPID_EDITOR( EDA_DRAW_FRAME* aFrame ) : m_frame( aFrame )
{
m_editorName = BuildEditorName( aFrame );
}
void PG_FPID_EDITOR::UpdateFrame( EDA_DRAW_FRAME* aFrame )
{
m_frame = aFrame;
m_editorName = BuildEditorName( aFrame );
}
wxString PG_FPID_EDITOR::BuildEditorName( EDA_DRAW_FRAME* aFrame )
{
if( !aFrame )
return EDITOR_NAME + "NoFrame";
return EDITOR_NAME + aFrame->GetName();
}
wxPGWindowList PG_FPID_EDITOR::CreateControls( wxPropertyGrid* aGrid, wxPGProperty* aProperty,
const wxPoint& aPos, const wxSize& aSize ) const
{
wxPGMultiButton* buttons = new wxPGMultiButton( aGrid, aSize );
buttons->Add( KiBitmap( BITMAPS::small_library ) );
buttons->Finalize( aGrid, aPos );
wxSize textSize = buttons->GetPrimarySize();
wxWindow* textCtrl = aGrid->GenerateEditorTextCtrl( aPos, textSize,
aProperty->GetValueAsString(), nullptr, 0,
aProperty->GetMaxLength() );
wxPGWindowList ret( textCtrl, buttons );
return ret;
}
bool PG_FPID_EDITOR::OnEvent( wxPropertyGrid* aGrid, wxPGProperty* aProperty, wxWindow* aCtrl,
wxEvent& aEvent ) const
{
if( aEvent.GetEventType() == wxEVT_BUTTON )
{
wxString fpid = aProperty->GetValue().GetString();
if( KIWAY_PLAYER* frame = m_frame->Kiway().Player( FRAME_FOOTPRINT_CHOOSER, true, m_frame ) )
{
if( frame->ShowModal( &fpid, m_frame ) )
aGrid->ChangePropertyValue( aProperty, fpid );
frame->Destroy();
}
return true;
}
return wxPGTextCtrlEditor::OnEvent( aGrid, aProperty, aCtrl, aEvent );
}
PG_URL_EDITOR::PG_URL_EDITOR( EDA_DRAW_FRAME* aFrame ) : m_frame( aFrame )
{
m_editorName = BuildEditorName( aFrame );
}
void PG_URL_EDITOR::UpdateFrame( EDA_DRAW_FRAME* aFrame )
{
m_frame = aFrame;
m_editorName = BuildEditorName( aFrame );
}
wxString PG_URL_EDITOR::BuildEditorName( EDA_DRAW_FRAME* aFrame )
{
if( !aFrame )
return EDITOR_NAME + "NoFrame";
return EDITOR_NAME + aFrame->GetName();
}
wxPGWindowList PG_URL_EDITOR::CreateControls( wxPropertyGrid* aGrid, wxPGProperty* aProperty,
const wxPoint& aPos, const wxSize& aSize ) const
{
wxPGMultiButton* buttons = new wxPGMultiButton( aGrid, aSize );
// Use a folder icon when no datasheet is set; otherwise use a globe icon.
wxString urlValue = aProperty->GetValueAsString();
bool hasUrl = !( urlValue.IsEmpty() || urlValue == wxS( "~" ) );
buttons->Add( KiBitmap( hasUrl ? BITMAPS::www : BITMAPS::small_folder ) );
buttons->Finalize( aGrid, aPos );
wxSize textSize = buttons->GetPrimarySize();
wxWindow* textCtrl = aGrid->GenerateEditorTextCtrl( aPos, textSize,
aProperty->GetValueAsString(), nullptr, 0,
aProperty->GetMaxLength() );
wxPGWindowList ret( textCtrl, buttons );
return ret;
}
bool PG_URL_EDITOR::OnEvent( wxPropertyGrid* aGrid, wxPGProperty* aProperty, wxWindow* aCtrl,
wxEvent& aEvent ) const
{
if( aEvent.GetEventType() == wxEVT_BUTTON )
{
wxString filename = aProperty->GetValue().GetString();
if( filename.IsEmpty() || filename == wxS( "~" ) )
{
wxFileDialog openFileDialog( m_frame, _( "Open file" ), wxS( "" ), wxS( "" ),
_( "All Files" ) + wxS( " (*.*)|*.*" ),
wxFD_OPEN | wxFD_FILE_MUST_EXIST );
if( openFileDialog.ShowModal() == wxID_OK )
{
filename = openFileDialog.GetPath();
aGrid->ChangePropertyValue( aProperty, wxString::Format( wxS( "file://%s" ),
filename ) );
}
}
else
{
GetAssociatedDocument( m_frame, filename, &m_frame->Prj() );
}
// Update the button icon to reflect presence/absence of URL
if( wxObject* src = aEvent.GetEventObject() )
{
wxString newUrl = aProperty->GetValueAsString();
bool hasUrl = !( newUrl.IsEmpty() || newUrl == wxS( "~" ) );
auto bmp = KiBitmap( hasUrl ? BITMAPS::www : BITMAPS::small_folder );
if( wxWindow* win = wxDynamicCast( src, wxWindow ) )
{
if( wxBitmapButton* bb = wxDynamicCast( win, wxBitmapButton ) )
{
bb->SetBitmap( bmp );
}
else if( wxButton* b = wxDynamicCast( win, wxButton ) )
{
b->SetBitmap( bmp );
}
else if( wxWindow* parent = win->GetParent() )
{
if( wxPGMultiButton* buttons = wxDynamicCast( parent, wxPGMultiButton ) )
{
wxWindow* btn0 = buttons->GetButton( 0 );
if( wxBitmapButton* bb0 = wxDynamicCast( btn0, wxBitmapButton ) )
bb0->SetBitmap( bmp );
else if( wxButton* b0 = wxDynamicCast( btn0, wxButton ) )
b0->SetBitmap( bmp );
}
}
}
}
return true;
}
return wxPGTextCtrlEditor::OnEvent( aGrid, aProperty, aCtrl, aEvent );
}

View File

@ -247,6 +247,10 @@ wxPGProperty* PGPropertyFactory( const PROPERTY_BASE* aProperty, EDA_DRAW_FRAME*
ret = new PGPROPERTY_RATIO();
break;
case PROPERTY_DISPLAY::PT_NET:
ret = new PGPROPERTY_NET( aProperty->Choices() );
break;
default:
wxFAIL;
KI_FALLTHROUGH;
@ -692,7 +696,9 @@ PGPROPERTY_COLOR4D::PGPROPERTY_COLOR4D( const wxString& aLabel, const wxString&
m_backgroundColor( aBackgroundColor )
{
SetEditor( PG_COLOR_EDITOR::EDITOR_NAME );
#if wxCHECK_VERSION( 3, 3, 0 )
#if wxCHECK_VERSION( 3, 3, 1 )
SetFlag( wxPGFlags::NoEditor );
#elif wxCHECK_VERSION( 3, 3, 0 )
SetFlag( wxPGPropertyFlags::NoEditor );
#else
SetFlag( wxPG_PROP_NOEDITOR );
@ -792,3 +798,19 @@ wxValidator* PGPROPERTY_TIME::DoGetValidator() const
{
return nullptr;
}
PGPROPERTY_NET::PGPROPERTY_NET( const wxPGChoices& aChoices ) :
wxEnumProperty( wxPG_LABEL, wxPG_LABEL, const_cast<wxPGChoices&>( aChoices ) )
{
SetEditor( wxS( "PG_NET_SELECTOR_EDITOR" ) );
}
const wxPGEditor* PGPROPERTY_NET::DoGetEditorClass() const
{
wxCHECK_MSG( m_customEditor, wxPGEditor_Choice,
wxT( "Make sure to RegisterEditorClass() for PGPROPERTY_NET!" ) );
return m_customEditor;
}

View File

@ -280,6 +280,9 @@ APP_SETTINGS_BASE::APP_SETTINGS_BASE( const std::string& aFilename, int aSchemaV
m_params.emplace_back( new PARAM<bool>( "cross_probing.auto_highlight",
&m_CrossProbing.auto_highlight, true ) );
m_params.emplace_back( new PARAM<bool>( "cross_probing.flash_selection",
&m_CrossProbing.flash_selection, false ) );
}

View File

@ -175,6 +175,7 @@ static const std::map<int, COLOR4D> s_defaultTheme =
{ NETNAMES_LAYER_ID_START, CSS_COLOR( 255, 255, 255, 0.7 ) },
{ LAYER_PAD_NETNAMES, CSS_COLOR( 255, 255, 255, 0.9 ) },
{ LAYER_VIA_NETNAMES, CSS_COLOR( 50, 50, 50, 0.9 ) },
{ LAYER_POINTS, CSS_COLOR( 255, 38, 226, 1 ) },
{ F_Cu, CSS_COLOR( 200, 52, 52, 1 ) },
{ In1_Cu, CSS_COLOR( 127, 200, 127, 1 ) },
@ -450,6 +451,7 @@ static const std::map<int, COLOR4D> s_classicTheme =
{ NETNAMES_LAYER_ID_START, CSS_COLOR( 255, 255, 255, 0.7 ) },
{ LAYER_PAD_NETNAMES, CSS_COLOR( 255, 255, 255, 0.9 ) },
{ LAYER_VIA_NETNAMES, CSS_COLOR( 50, 50, 50, 0.9 ) },
{ LAYER_POINTS, COLOR4D( BLUE ) },
{ F_Cu, COLOR4D( RED ) },
{ In1_Cu, COLOR4D( YELLOW ) },

View File

@ -142,6 +142,7 @@ COLOR_SETTINGS::COLOR_SETTINGS( const wxString& aFilename, bool aAbsolutePath )
CLR( "board.track_net_names", NETNAMES_LAYER_ID_START );
CLR( "board.pad_net_names", LAYER_PAD_NETNAMES );
CLR( "board.via_net_names", LAYER_VIA_NETNAMES );
CLR( "board.points", LAYER_POINTS );
CLR( "board.copper.f", F_Cu );
CLR( "board.copper.in1", In1_Cu );

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