Compare commits

...

153 Commits

Author SHA1 Message Date
Wayne Stambaugh ad43570ec0 Tag stable version 8.0.7. 2024-12-02 16:04:30 -05:00
Seth Hillbrand 5dd4718db0 Update translations 2024-12-01 17:25:35 -08:00
dsa-t ea70d8cf4c Translated using Weblate (Russian)
Currently translated at 100.0% (9198 of 9198 strings)

Translation: KiCad EDA/v8
Translate-URL: https://hosted.weblate.org/projects/kicad/v8/ru/
2024-12-02 02:25:06 +01:00
ZbeeGin cd2879880a Translated using Weblate (Polish)
Currently translated at 100.0% (9198 of 9198 strings)

Translation: KiCad EDA/v8
Translate-URL: https://hosted.weblate.org/projects/kicad/v8/pl/
2024-12-02 02:25:06 +01:00
Pferd O b51c8c1b3d Translated using Weblate (German)
Currently translated at 100.0% (9198 of 9198 strings)

Translation: KiCad EDA/v8
Translate-URL: https://hosted.weblate.org/projects/kicad/v8/de/
2024-12-02 02:25:06 +01:00
Wellington Terumi Uemura 5db1ee930f Translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (9198 of 9198 strings)

Translation: KiCad EDA/v8
Translate-URL: https://hosted.weblate.org/projects/kicad/v8/pt_BR/
2024-12-02 02:25:06 +01:00
2tama3 695dd57477 Translated using Weblate (Japanese)
Currently translated at 100.0% (9198 of 9198 strings)

Translation: KiCad EDA/v8
Translate-URL: https://hosted.weblate.org/projects/kicad/v8/ja/
2024-12-02 02:25:06 +01:00
Ettore Atalan 224c989072 Translated using Weblate (German)
Currently translated at 99.9% (9192 of 9198 strings)

Translation: KiCad EDA/v8
Translate-URL: https://hosted.weblate.org/projects/kicad/v8/de/
2024-12-02 02:25:05 +01:00
John Beard 80db7ff8cf Pcbnew: update DRC exclusions from DRC dialog
When excluding/re-including DRC violations, update the
BDS list immediately rather than waiting for the
BOARD::RecordDRCExclusions() to be called.

This was implemented in 8.99 in 0598ca0f90
(along with DRC exclusion comments).

Follow that commit's updates of the m_DrcExclusions
structures in an analogous way.

Fixes: https://gitlab.com/kicad/code/kicad/-/issues/19113
2024-11-29 03:04:43 +08:00
jean-pierre charras 6e6d3e9b03 Revert "Try to fix a link issue in Gerbview" and try another fix 2024-11-25 16:55:28 +01:00
jean-pierre charras c08dd172d6 Try to fix a link issue in Gerbview 2024-11-25 16:38:55 +01:00
Wayne Stambaugh 7972805d07 Tag stable version 8.0.7 release candidate 1. 2024-11-24 19:06:04 -05:00
Alex Shvartzkop a86147b4b1 Optimize ConvertImageToLibShapes for EasyEDA/LCEDA schematic import.
Don't sort all symbol draw items after adding each draw item.

-75% CPU usage on typical schematic imports.

(cherry picked from commit 5323c8587a)
2024-11-24 20:54:24 +03:00
Dhineshkumar S 335bb8792f Fix switching bold option on and off alters text thickness
Currently, unselecting the bold option resets the thickness to the
standard size instead of reverting to the original thickness.
To address this, the original thickness should be preserved so it
can be restored when bold is turned off.

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

(cherry picked from commit 43b1bc52db)
2024-11-24 07:46:40 -05:00
jean-pierre charras c8f7887cf8 Simulator: fix crash when deselecting the Probe Tool in some cases.
If a schematic item was selected, when activating the probe tool from the
simulator, and deactivating from the Select Item sch editor tool, a crash
happened.
From master branch

Fixes https://gitlab.com/kicad/code/kicad/-/issues/18547
2024-11-24 10:34:22 +01:00
John Beard 2fe5c28787 Fabmaster: catch illegal parses up front
Parsing an empty string as double/int produces uninitialised data.
That is likely to cause an undefined amout of chaos later on,
so catch it explicitly with a wxCHECK.

It's still something that shouldn't happen, and could still cause
chaos, but it's at least deterministic. It also avoids putting
gigantic numbers into things that don't expect them. For example
normalising an angle of 1e303 is functionally an infinite loop.

This happens at least in files with missing fields in rows,
like in #19174's file, line 4:

S!U2306!IC!!!!!!SOT_23_5!!!!!SGM2576/TT9107!!!

The file is still broken, but now it loads.

Relates-To: https://gitlab.com/kicad/code/kicad/-/issues/19174
(cherry picked from commit 4d2d70ce22)
2024-11-24 14:04:57 +08:00
John Beard 64365de9de Update font when needed on italic/bold change
When the italic or bold nature is changed, text using outline fonts may
need to change its font. Add this to the SetItalic/SetBold functions.

Also add a counterpart SetItalicFlag function (following SetBoldFlag)
when you only need to set the flag (e.g. when importing or changing
everything in the text properties dialog).

Fixes: https://gitlab.com/kicad/code/kicad/-/issues/18592
(cherry picked from commit b043f334de)
2024-11-24 09:51:54 +08:00
Alex Shvartzkop a950d55cb2 Show empty field for unconstrained length in length tuning properties.
Because it's confusing when the dialog shows last target value, but it
doesn't apply when you start tuning.

Also the last values are remembered in DRAWING_TOOL::PlaceTuningPattern
now, instead of global variables.

Related: https://gitlab.com/kicad/code/kicad/-/issues/18979
2024-11-23 18:11:25 +03:00
Alex Shvartzkop 3748a10ed5 Length tuning workflow improvements:
-Allow changing length tuning settings before tuning has been started
-Do not exit out of the length tuning tool after each placement
-Keep specified settings between pattern placements

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

(cherry picked from commit 78b2e53777)
2024-11-23 17:27:27 +03:00
Alex Shvartzkop 227bb76909 Don't modify m_selection while iterating over it in PCB editor.
This caused a fatal assert when selecting connected tracks with tuning patterns.

(cherry picked from commit fee8560079)
2024-11-23 17:27:16 +03:00
jean-pierre charras a20a6bb2a3 French translation update 2024-11-23 10:16:03 +01:00
jean-pierre charras 7c17aa5974 EEschema: fix crash when repeat an item (ins key), due to a null parent
A recent change set the parent member of a item put in the repeat list to
nullptr (this is OK) but the code to copy an item from this list did not
update this parent member.
From master branch, commit 8f348820
2024-11-23 10:07:38 +01:00
Dhineshkumar S 59795c81c5 Fix copy-paste issue for grids with checkboxes
Handle boolean value parsing during paste operation. The boolean value
was not being handled correctly in grid_tricks, which prevented the
boolean value from being pasted into the target row

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

(cherry picked from commit 07f96b83b7)
2024-11-21 11:37:47 -08:00
Mike Williams 84d00a7887 cli: accept multiple gerber layers for single layer plotting
Fixes: https://gitlab.com/kicad/code/kicad/-/issues/19089
(cherry picked from commit 325d6ff064)
2024-11-21 12:55:13 -05:00
John Beard 3774e31db8 Pcbnew: convert to lines should take the width of polygons if it can
Fixes: https://gitlab.com/kicad/code/kicad/-/issues/18713
(cherry picked from commit 81c1cd9af1)
2024-11-21 12:32:56 -05:00
Seth Hillbrand 69ac570658 Update translations 2024-11-21 09:29:00 -08:00
Pablo Bianchi 46ecb22ef5 Translated using Weblate (Spanish)
Currently translated at 98.5% (9055 of 9191 strings)

Translation: KiCad EDA/v8
Translate-URL: https://hosted.weblate.org/projects/kicad/v8/es/
2024-11-21 18:27:21 +01:00
Jan Straka ff7ea6eae0 Translated using Weblate (Czech)
Currently translated at 84.1% (7735 of 9191 strings)

Translation: KiCad EDA/v8
Translate-URL: https://hosted.weblate.org/projects/kicad/v8/cs/
2024-11-21 18:27:21 +01:00
Marco Ciampa 2f70ac171f Translated using Weblate (Italian)
Currently translated at 99.9% (9190 of 9191 strings)

Translation: KiCad EDA/v8
Translate-URL: https://hosted.weblate.org/projects/kicad/v8/it/
2024-11-21 18:27:20 +01:00
Marco Ciampa 360011e563 Translated using Weblate (Italian)
Currently translated at 99.9% (9190 of 9191 strings)

Translation: KiCad EDA/v8
Translate-URL: https://hosted.weblate.org/projects/kicad/v8/it/
2024-11-21 18:27:20 +01:00
CloverGit 2a0785d188 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 100.0% (9191 of 9191 strings)

Translation: KiCad EDA/v8
Translate-URL: https://hosted.weblate.org/projects/kicad/v8/zh_Hans/
2024-11-21 18:27:20 +01:00
Toni Laiho a480b1a5ba Translated using Weblate (Finnish)
Currently translated at 99.7% (9172 of 9191 strings)

Translation: KiCad EDA/v8
Translate-URL: https://hosted.weblate.org/projects/kicad/v8/fi/
2024-11-21 18:27:20 +01:00
Marco Ciampa 6f31e306a1 Translated using Weblate (Italian)
Currently translated at 99.9% (9190 of 9191 strings)

Translation: KiCad EDA/v8
Translate-URL: https://hosted.weblate.org/projects/kicad/v8/it/
2024-11-21 18:27:20 +01:00
Pferd O 5983815415 Translated using Weblate (German)
Currently translated at 100.0% (9191 of 9191 strings)

Translation: KiCad EDA/v8
Translate-URL: https://hosted.weblate.org/projects/kicad/v8/de/
2024-11-21 18:27:20 +01:00
Marco Ciampa 288050b6ec Translated using Weblate (Italian)
Currently translated at 99.9% (9190 of 9191 strings)

Translation: KiCad EDA/v8
Translate-URL: https://hosted.weblate.org/projects/kicad/v8/it/
2024-11-21 18:27:20 +01:00
co8 j 6d36363403 Translated using Weblate (Japanese)
Currently translated at 100.0% (9191 of 9191 strings)

Translation: KiCad EDA/v8
Translate-URL: https://hosted.weblate.org/projects/kicad/v8/ja/
2024-11-21 18:27:20 +01:00
Marco Ciampa 720c7d9fc4 Translated using Weblate (Italian)
Currently translated at 99.5% (9152 of 9191 strings)

Translation: KiCad EDA/v8
Translate-URL: https://hosted.weblate.org/projects/kicad/v8/it/
2024-11-21 18:27:20 +01:00
Wellington Terumi Uemura e009afd4a1 Translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (9191 of 9191 strings)

Translation: KiCad EDA/v8
Translate-URL: https://hosted.weblate.org/projects/kicad/v8/pt_BR/
2024-11-21 18:27:20 +01:00
ZbeeGin 9e13ff25d0 Translated using Weblate (Polish)
Currently translated at 99.9% (9190 of 9191 strings)

Translation: KiCad EDA/v8
Translate-URL: https://hosted.weblate.org/projects/kicad/v8/pl/
2024-11-21 18:27:20 +01:00
Pferd O af1899ddc3 Translated using Weblate (German)
Currently translated at 99.9% (9190 of 9191 strings)

Translation: KiCad EDA/v8
Translate-URL: https://hosted.weblate.org/projects/kicad/v8/de/
2024-11-21 18:27:20 +01:00
Ian McInerney beb30dd881 Use appropriate tunning pattern icon in menus for tunning pattern generators
(cherry picked from commit 2190c37cd6)
2024-11-21 12:22:38 -05:00
Alex Shvartzkop 6d09293b11 DXF import: scale text size too inside scaled blocks.
Fixes https://gitlab.com/kicad/code/kicad/-/issues/18525

(cherry picked from commit 37fb792411)
2024-11-21 12:19:31 -05:00
Alex Shvartzkop ca7378924c Make color picker dialog usable on hidpi monitors.
Fixes https://gitlab.com/kicad/code/kicad/-/issues/17860

(cherry picked from commit 894bf45480)
2024-11-21 11:55:54 -05:00
Ian McInerney 74316a62d3 Always use black text in PCB calculator E-series table
The white text in dark mode is too washed out on the cell colors to be
visible. Since we already purposely subdue the colors in dark mode, the
easiest fix is to just always use black text.

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

(cherry picked from commit c7d280dfa1)
2024-11-21 11:34:06 -05:00
Dhineshkumar S 3150f467bb Fix Courtyard layers disappeared
Currently, the used layers passed from parseLayers() do not include
mandatory layers if they are missing in the loaded board file.
To fix this, we can manually add the mandatory layers to ensure they
are always enabled.

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

(cherry picked from commit 6e2ed5666d)
2024-11-21 11:28:37 -05:00
Dhineshkumar S c033c364d4 Fixing Paste Issue in Library Table
Previously, when attempting to paste an entire row copied from the global
table into a project table, the value would be pasted from the cell where
the cursor was focused, rather than from the first cell. This issue
occurred because the first cell, a checkbox column, was not selectable.
To resolve this, the checkbox column should be enabled for selection
when the Left Mouse Button event is triggered

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

(cherry picked from commit 1fc8e65f7a)
2024-11-21 11:15:17 -05:00
Mike Williams 37c14a65ed net navigator: add sheet changes to navigation history
Fixes: https://gitlab.com/kicad/code/kicad/-/issues/18616
(cherry picked from commit 284c52845d)
2024-11-21 11:07:22 -05:00
Mathieu Pilato dbf64ac0cf Fix missing current scale in AC simulation
Fixes https://gitlab.com/kicad/code/kicad/-/issues/18313

(cherry picked from commit 10d23ada48)
2024-11-21 09:40:12 -05:00
jean-pierre charras 0eda576189 Gerbview: fix a link issue on msys2: round 2
Reverts commit 6ee9fb4027
Make fix only for mingw/msys2
2024-11-20 18:29:32 +01:00
jean-pierre charras 6ee9fb4027 Gerbview: fix a link issue on msys2
mingw/msys2 is picky about order of files to link.
2024-11-20 18:06:21 +01:00
Kamil Galik 64134cee92 ADDED: 3D Mouse support in places
Gerber Viewer, Drawing Sheet Editor and Footprint Properties 3D Model tab

Fixed https://gitlab.com/kicad/code/kicad/-/issues/14002
Fixes https://gitlab.com/kicad/code/kicad/-/issues/13306
2024-11-20 15:56:19 +00:00
Jeff Young fead0eb33b Manual cherry-pick of ee8d86390e. 2024-11-18 22:44:41 +00:00
jean-pierre charras ff71b324a1 EEschema: fix an issue in sheet cross-references of global labels.
Commit 5ca34147 (a cherry pick from master branch) broke these cross-references.
If was fixed later in master branch, but these changes cannot be cherry picked.
So the old code is reused in 2 functions to fix the issue.

Fixes https://gitlab.com/kicad/code/kicad/-/issues/18534
2024-11-17 13:11:23 +01:00
Seth Hillbrand b10ab478bd Fix 3D viewer omission of STEP models with relative path assignment
The project was not assigned to the board in the 3D viewer frame,
resulting in a failure to locate the relative path for STEP models.
To fix this, the current project should be assigned to the board in
the 3D viewer frame.

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


(cherry picked from commit d2e51fdb5f)

c824484c Fix 3D viewer omission of STEP models with relative path assignment

Co-authored-by: Dhineshkumar S <dhineshkumar@cgvakindia.com>
2024-11-17 07:21:14 +00:00
Wayne Stambaugh 710b6adb8c Warn user when template field names contain trailing/leading white space.
When loading a schematic that contains fields with trailing/leading white
space, show an infobar message.  When editing the template field names,
prompt the user to keep or remove any trailing or leading white space
characters from field names.

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

(cherry picked from commit d9d984d2c8)
2024-11-16 20:51:03 -06:00
Mark Roszko 6a01bdbabd Drop the first point of an arc when building an outline when there's a previous point that's being changed
Fixes https://gitlab.com/kicad/code/kicad/-/issues/18125


(cherry picked from commit 8b4253cda4)

Co-authored-by: Marek Roszko <mark.roszko@gmail.com>
2024-11-16 08:53:01 +00:00
Jeff Young 76e19c6dcf Import PCB into existing project.
Or, to be more direct: don't pull the project rug
out from under EESchema when importing in non-
stand-alone mode.

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

(cherry picked from commit a2f7edde2e)
2024-11-16 02:43:13 -06:00
Seth Hillbrand 8af289c33e Fix error in PointInside
If we are checking a point that is inline with multiple segments, we
were counting both the entry and exit as crossings, leading to points
inside a polygon being registered as outside.  Changing the conditional
to only catch one crossing as required.

Adds a QA check to ensure that this remains fixed

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

(cherry picked from commit 7916b1ddb8)
2024-11-16 02:38:49 -06:00
JamesJCode 35fa7db5c7 Don't reset sheet / screen file names if cancelling repeat insert
in recursive state

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

(cherry picked from commit c05dd18613)
2024-11-16 02:36:23 -06:00
Seth Hillbrand 67739ee3d1 Convert courtyards with error allowance
We convert arcs/circles to polygons with an allowable error.  This means
that the segments might end up being closer than we expect and we should
allow for this deviation when checking courtyards

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

(cherry picked from commit 3a8a5bb378)
2024-11-16 02:34:53 -06:00
Seth Hillbrand d8ba7284a8 Correct pad connections for 45° circular
When calculating the pad bbox, we need to only account for deflation of
zone min width.  Additionally, when calculating spokes for roughly
circular elements, we don't need to go to the bbox corners, so special
case it to rotate after the fact

Fixes https://gitlab.com/kicad/code/kicad/-/issues/18329
2024-11-16 02:34:25 -06:00
Seth Hillbrand fdc0309592 Simplify spoke generation
Sin/Cos are pre-caclulated for all multiples of 45° so we don't need to
short circuit them here.  Calculating the bbox intersection point allows
us to pick spoke sizes that are not overly large so as to miss the hit
point testing in the associated fill areas.

Fixes https://gitlab.com/kicad/code/kicad/-/issues/18329
2024-11-16 02:34:25 -06:00
Mike Williams 55d77f0dbb pcb: fix crash on routing many traces
Further improvements could be made to the behavior of the autoroute
functionality in this case, but not crashing is a good start.

Fixes: https://gitlab.com/kicad/code/kicad/-/issues/18328
(cherry picked from commit 04ff715945)
2024-11-16 02:32:33 -06:00
Seth Hillbrand 14fafebbc7 Handled unconnected nets
These nets may have only a single element in them (no connections), so
be sure to leave the node even without Features

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

(cherry picked from commit 14ccadd2a9)
2024-11-16 02:31:06 -06:00
Seth Hillbrand 7ca472deb8 Handle error when we don't have Eagle Board
This can also occur in libraries, so ensure we're not dereferencing a
null board pointer

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

(cherry picked from commit 89b9b13e21)
2024-11-16 02:30:36 -06:00
Seth Hillbrand fdb3612565 Some fixes for DXF import
In order to find elements, we need to have bbox correctly set.  ::min()
for doubles, just gives the smallest positive value.  So negative placed
graphics don't trigger the right bbox and they get nopped out of
existence.

Similarly, following the advice from @msteinbeck, we elevate the degree
of the spline before converting it to beziers in order to properly
represent in KiCad

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

(cherry picked from commit e0fc7b2b88)
2024-11-16 02:30:03 -06:00
Seth Hillbrand bf59a6305a Handle DXF files with out of bounds values
First, ensure that we calculate the bbox of the imported elements.

If the total BBOX is outside our allowed value, refused to import.  This
needs to be scaled or addressed in an external editor

If the bbox fits, then make sure that we clamp it such that the largest
element is still within our bounds

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

(cherry picked from commit a724b3d8b1)
2024-11-16 02:29:19 -06:00
Dhineshkumar S 17db770d92 Fix copy and paste issue in bus alias definition
Previously, creating a new member row by pasting text from the clipboard
did not trigger a cell value change which prevented the correct
association of the member value with the alias. To ensure this, we force
the member to be updated with the current alias before closing the dialog,
as well as with the previous alias when adding a new one

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

(cherry picked from commit cd40c6bbbf)
2024-11-16 02:27:26 -06:00
Dhineshkumar S b3004c9d96 Disable custom color selection when Fill Mode is Body Background Color
Currently, the system allows custom color selection for the Fill Color
property in the Properties toolbar even when Fill Mode is set to Body
Background Color via the Properties window. However, this does not update
the color to match the Body Background color. To fix this, custom color
selection for Fill Color will be disabled when Body Background Color is
chosen.

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

(cherry picked from commit cb41f39045)
2024-11-16 02:09:46 -06:00
Dhinesh c54ebdecd2 Fix missing text and graphics in PDFs generated by "Plot to PDF"
The "Plot to PDF" function was producing PDF files that lacked text and
graphic items in viewers like Adobe and Foxit. This issue was caused by
the use of the %g format specifier for floating-point numbers defined in
the PDF specification when writing text and drawing shapes in the PDF.
This incorrect format led to a "Too Few Operands" error during rendering.
To resolve this issue, all floating-point numbers must be specified in
fixed-point format according to the PDF specification wherever the issue
was generated.

Fixes #16465

(cherry picked from commit 8851cd77ab)
2024-11-16 02:08:50 -06:00
Ian McInerney 6fc15ed8df Make instance checker path globally writable
On Linux, this directory is shared between users, so a multi-user
machine needs to let the other users have access to the directory to
create their own lockfiles.

(cherry picked from commit 921358b096)
2024-11-16 01:43:18 -06:00
John Beard e7779d9b91 Exclude letter hotkeys from Shift fallback
From master branch

There is a fallback mechanism here designed to catch cases
where a hotkey is bound to a key that needs Shift to be
input (e.g. ? requires Shift on many non-US keyboards,
but the hotkey for that should be '?', not 'Shift+/'). For any key
where the two options are equally-valid "main" key (e.g. '6' and '^'
or '?' and '/' or ':' amd ';'), this is correct, as it allows
the hotkey to be simply the character in question.

Letters don't require this treatment - using this fallback
in the letter case means that a hotkey bound to 'B' will
also fire when 'Shift+B' is pressed, even when Shift+B is
bound to something else. In fact, it could even preempt the
real Shift+B hotkey.

Fixes: https://gitlab.com/kicad/code/kicad/-/issues/19093
2024-11-13 19:50:48 +01:00
jean-pierre charras 06a91637a7 3D viewer: Ensure the 3D display view is not modified after left clicking.
After opening a context menu and left clicking on the 3D canvas, the view
was modified because a drag event was generated, probably a wxWidgets bug.
From master branch.

Fixes https://gitlab.com/kicad/code/kicad/-/issues/17422
2024-11-11 17:11:07 +01:00
Alex Shvartzkop 08e9ce2828 Fix an "unreferenced local variable" warning, 2024-11-11 00:03:34 +03:00
Wayne Stambaugh 24f82ab87d Another attempt to fix Windows file URLs for PDF links.
Fixes https://gitlab.com/kicad/code/kicad/-/issues/14250

(cherry picked from commit 6cc5d89838)
2024-11-10 10:17:27 -05:00
Wayne Stambaugh bcf069699d Fix PDF plotter URI issues.
Add 'file:' URI JavaScript handlers.

Properly convert Windows file paths to valid URI syntax.

Use expanded variables for URI menu names.

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

(cherry picked from commit 930407fac8)
2024-11-08 14:55:40 -05:00
Wayne Stambaugh f8d694e4d0 Substitute variables in PDF plotter URI links and add file:// URI handler.
Fixes https://gitlab.com/kicad/code/kicad/-/issues/14250

(cherry picked from commit 43c3cd57eb)
2024-11-08 14:55:19 -05:00
John Beard b80334baa1 Libgit2: the const git_commit* saga continues
The change wasn't re-reverted in 1.8.3, it was just not
included. It was than _also_ reverted in 1.8.4, as it was for
1.8.2 (those two tags are on different branches - main and maint/v1.8).

Hopefully, this means that we're done here, and v1.8.5 will also be
const-y, whether it is based on main or maint/v1.8.

The current state of play:

* 1.7.0 and older: const
* 1.8.0, 1.8.1:    no const
* 1.8.2:           const
* 1.8.3:           no const
* 1.8.4:           const
Future:
* 1.8.5/1.9.0:     presumably/hopefully, const

This is currently breaking at least Arch and Fedora Rawhide

Fixes: https://gitlab.com/kicad/code/kicad/-/issues/19062
(cherry picked from commit 9f579f787b)
2024-11-08 08:24:59 +08:00
Jan Wichmann 6c359e2f06 Fix: Clear drill holes table before loading board file
From master branch
2024-11-07 16:56:18 +01:00
Jeff Young a3eff548b7 Even the orphaned net must obey the min board clearance.
(And other Default netclass constraints.)

(cherry picked from commit 5d656e3c8d)

Fixes: https://gitlab.com/kicad/code/kicad/-/issues/19051
2024-11-05 21:02:23 +08:00
Mark Roszko e33a732371 Bump vcpkg and wxwidgets for aui patch 2024-11-02 19:23:47 +00:00
Jon Evans 95d3200a3a Clear unknown keys from environment variable maps on save
Also fix the previous code for clearing unknown keys to use
a JSON pointer so that it functions correctly when the JSON path
is more than one level deep.

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


(cherry picked from commit 09652efec5)

Co-authored-by: Jon Evans <jon@craftyjon.com>
2024-11-02 18:54:12 +00:00
Jon Evans 5ee7ae4a45 Make sure to set modified bit when releasing nested settings
(cherry picked from commit 826794469d)
2024-11-02 10:26:03 -04:00
Jon Evans b13a9e231b Use a persistent flag to track JSON modifications
(cherry picked from commit eb6d85bacf)
2024-11-02 10:25:59 -04:00
Seth Hillbrand 1011f361fd Update translations 2024-11-01 16:27:28 -07:00
David Chorváth 288a08b9c2 Translated using Weblate (Slovak)
Currently translated at 65.0% (5974 of 9190 strings)

Translation: KiCad EDA/v8
Translate-URL: https://hosted.weblate.org/projects/kicad/v8/sk/
2024-11-02 00:26:56 +01:00
ZbeeGin cac1979f61 Translated using Weblate (Polish)
Currently translated at 100.0% (9190 of 9190 strings)

Translation: KiCad EDA/v8
Translate-URL: https://hosted.weblate.org/projects/kicad/v8/pl/
2024-11-02 00:26:56 +01:00
Pferd O 38a9477423 Translated using Weblate (German)
Currently translated at 100.0% (9190 of 9190 strings)

Translation: KiCad EDA/v8
Translate-URL: https://hosted.weblate.org/projects/kicad/v8/de/
2024-11-02 00:26:56 +01:00
David Chorváth 072446e79d Translated using Weblate (Slovak)
Currently translated at 64.8% (5961 of 9190 strings)

Translation: KiCad EDA/v8
Translate-URL: https://hosted.weblate.org/projects/kicad/v8/sk/
2024-11-02 00:26:56 +01:00
Pferd O 4fc528819d Translated using Weblate (German)
Currently translated at 99.9% (9187 of 9190 strings)

Translation: KiCad EDA/v8
Translate-URL: https://hosted.weblate.org/projects/kicad/v8/de/
2024-11-02 00:26:56 +01:00
CloverGit d5f52000ce Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 100.0% (9190 of 9190 strings)

Translation: KiCad EDA/v8
Translate-URL: https://hosted.weblate.org/projects/kicad/v8/zh_Hans/
2024-11-02 00:26:56 +01:00
Henrik Kauhanen 8e4d7da4ea Translated using Weblate (Swedish)
Currently translated at 99.9% (9189 of 9190 strings)

Translation: KiCad EDA/v8
Translate-URL: https://hosted.weblate.org/projects/kicad/v8/sv/
2024-11-02 00:26:55 +01:00
Henrik Kauhanen ea3f0bada4 Translated using Weblate (Swedish)
Currently translated at 99.9% (9189 of 9190 strings)

Translation: KiCad EDA/v8
Translate-URL: https://hosted.weblate.org/projects/kicad/v8/sv/
2024-11-02 00:26:55 +01:00
co8 j 3b33ce8bcc Translated using Weblate (Japanese)
Currently translated at 100.0% (9190 of 9190 strings)

Translation: KiCad EDA/v8
Translate-URL: https://hosted.weblate.org/projects/kicad/v8/ja/
2024-11-02 00:26:55 +01:00
Pferd O 74b42f1bb2 Translated using Weblate (German)
Currently translated at 99.9% (9187 of 9190 strings)

Translation: KiCad EDA/v8
Translate-URL: https://hosted.weblate.org/projects/kicad/v8/de/
2024-11-02 00:26:55 +01:00
Pferd O b455a4cd54 Translated using Weblate (German)
Currently translated at 99.9% (9187 of 9190 strings)

Translation: KiCad EDA/v8
Translate-URL: https://hosted.weblate.org/projects/kicad/v8/de/
2024-11-02 00:26:55 +01:00
co8 j 5021f6ee26 Translated using Weblate (Japanese)
Currently translated at 100.0% (9190 of 9190 strings)

Translation: KiCad EDA/v8
Translate-URL: https://hosted.weblate.org/projects/kicad/v8/ja/
2024-11-02 00:26:55 +01:00
sergio 0be2b88f5a Translated using Weblate (Russian)
Currently translated at 99.9% (9187 of 9190 strings)

Translation: KiCad EDA/v8
Translate-URL: https://hosted.weblate.org/projects/kicad/v8/ru/
2024-11-02 00:26:55 +01:00
Wellington Terumi Uemura f3a57cf763 Translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (9190 of 9190 strings)

Translation: KiCad EDA/v8
Translate-URL: https://hosted.weblate.org/projects/kicad/v8/pt_BR/
2024-11-02 00:26:55 +01:00
Pferd O ddd69019bc Translated using Weblate (German)
Currently translated at 99.9% (9187 of 9190 strings)

Translation: KiCad EDA/v8
Translate-URL: https://hosted.weblate.org/projects/kicad/v8/de/
2024-11-02 00:26:55 +01:00
109247019824 94e34cb1eb Translated using Weblate (Bulgarian)
Currently translated at 7.6% (706 of 9190 strings)

Translation: KiCad EDA/v8
Translate-URL: https://hosted.weblate.org/projects/kicad/v8/bg/
2024-11-02 00:26:55 +01:00
JamesJCode 6470212edd Fix missed rows when pasting to WX_GRID on macOS
Fixes https://gitlab.com/kicad/code/kicad/-/issues/18916

(cherry picked from commit 816af9562b)
2024-11-01 23:10:26 +00:00
Mike Williams 8c3bcade1c schematic: fix missing actions strings and hotkey conflict
Fixes: https://gitlab.com/kicad/code/kicad/-/issues/17694
(cherry picked from commit 5ed80a08b8)

Fixes https://gitlab.com/kicad/code/kicad/-/issues/18748
2024-11-01 13:37:53 -07:00
jean-pierre charras 70e99acce6 FP editor: fix possible crash when saving a footprint due to a null pointer
From master branch

Fixes https://gitlab.com/kicad/code/kicad/-/issues/19018
2024-11-01 20:56:42 +01:00
jean-pierre charras 25be138ac1 eeschema, DIALOG_SHEET_PROPERTIES: add test for valid sheet filename
From master branch

Fixes https://gitlab.com/kicad/code/kicad/-/issues/18981
2024-11-01 20:24:50 +01:00
Alex Shvartzkop 9f196d2e64 EasyEDA/LCEDA: import bezier curves in symbols.
See https://gitlab.com/kicad/code/kicad/-/issues/19034
2024-11-01 16:36:45 +03:00
Alex Shvartzkop b51fed4118 EasyEDA/LCEDA Pro: don't import empty but visible netlabels.
Fixes https://gitlab.com/kicad/code/kicad/-/issues/19034
2024-11-01 16:10:15 +03:00
JamesJCode a914f361d3 Fix libgit integration for version >= 1.8.3
The API continues to change...

(cherry picked from commit 75c2f17b42)
2024-10-31 18:48:10 +00:00
Alex Shvartzkop 846b634e0e EasyEDA/LCEDA import: take symbol/netport Name from device entry if empty in schematic.
Also fixes netport orientation if it's symbol is non-default.

Fixes https://gitlab.com/kicad/code/kicad/-/issues/19021
2024-10-30 18:33:42 +03:00
Alex Shvartzkop 08b54e205d Show failing strings in HTMLEscape test.
(cherry picked from commit 0581423d50)
2024-10-30 10:37:01 +03:00
Alex Shvartzkop 7cba1e1a55 Update field order in PCB_TUNING_PATTERN.
(cherry picked from commit d2c33e186e)
2024-10-30 10:36:53 +03:00
Alex Shvartzkop 6ae334a751 Fix/improve HTML unescape function.
Also adds some tests.
2024-10-30 08:22:38 +03:00
Alex Shvartzkop 61687e8499 QA: do not pass negative char values to isdigit in NUMERIC_EVALUATOR.
This causes an assert failure on MSVC when running qa_common.
2024-10-30 08:22:38 +03:00
Seth Hillbrand e014f2274f Fix display of broken fonts
TTF fonts are supposed to obey a specific winding.  But sometimes they
don't, especially with garbage windows font editing programs.  If the
outline with hole winding doesn't have an outline, it is probably an
outline itself

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

(cherry picked from commit a6b25d1ee1)
2024-10-29 11:02:26 -07:00
Jeff Young 7e0f05f991 Must check for implicit min separately from opt/max.
Fixes https://gitlab.com/kicad/code/kicad/-/issues/19012

(cherry picked from commit 7074c31374)
2024-10-29 17:01:45 +00:00
Jeff Young 1e21b41be5 Centralize ref-des error checking.
(cherry picked from commit 905eaa79a9)
2024-10-28 19:03:50 +00:00
Mark Roszko 4a7dcfdd1f Update vcpkg.json 2024-10-27 23:43:15 +00:00
Alex Shvartzkop d1684b8a72 Fix compatibility with LCEDA/EasyEDA v2.2.32
Now device attributes can contain numbers.

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

(cherry picked from commit 840b9aebba)
2024-10-27 04:30:59 +03:00
Troy Denton 8da026baff Fix URI environment variable expansion issue.
Fixes https://gitlab.com/kicad/code/kicad/-/issues/18918

(cherry picked from commit 0f33aebe48)
2024-10-24 11:53:41 -04:00
jean-pierre charras 89a3ead51e Pcbnew: fix text position when drawing PCB_TEXTs on non paired layers
For these texts, and when the view was "flip board view" option, these text
positions were incorrectly calculated for texts having a text rotation not 0.
From master branch

Fixes https://gitlab.com/kicad/code/kicad/-/issues/18980
2024-10-24 15:20:33 +02:00
jean-pierre charras 5064834716 French translation update 2024-10-24 14:09:49 +02:00
Seth Hillbrand 51a3859d7e Preserve pin numbering when duplicating
We renumber duplicated pins but the previous order was essentially
random.  This keeps the numeric order of the pins on the screen, falling
back to position if they are not numbered

(cherry picked from commit f4bec843d4)
2024-10-21 14:00:18 -07:00
Seth Hillbrand bf37bd8ed5 Fix DRC error with arcs
When two arcs only barely overlapped, we cannot predict the actual point
ends as they exist in the error margins.  Since arc tracks have
different radii by definition, rounding errors in calculating the
overlap angle led to some mistaken identification of parallel segments.

This adds an advanced config flag to set the preferred cutoff point
(currently 0.001°) for whether two arcs actually overlap in shared angle
space

(cherry picked from commit 6be6680d8c)
2024-10-21 13:41:25 -07:00
Dhineshkumar S 283fed83c3 Fix Focus Issue in Parent Window After Hiding the Search Panel
Previously, when the search panel was hidden, the focused search control
did not lose focus, causing an inability to focus on any items in the
parent window when using shortcut keys. This forces correct focus back to the edit window

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

(cherry picked from commit 2bee6f2549)
2024-10-21 13:36:29 -07:00
jean-pierre charras 48983dd31d Python script: Ensure image handlers are loaded before loading a board,.
because a board can include bitmap images using various formats, all
available image handlers must be loaded.
From master branch

Fixes https://gitlab.com/kicad/code/kicad/-/issues/18959
2024-10-21 17:33:14 +02:00
jean-pierre charras ccd4b0cf05 pagelayout_editor: lock panel update during widgets rebuild.
The rebuild is much faster.
From master branch
2024-10-21 17:21:04 +02:00
aris-kimi 154c755a1b Fix non working Esc when init Polyline Properties dialog.
Fixes: https://gitlab.com/kicad/code/kicad/-/issues/18850
(cherry picked from commit 36bac3f467)
2024-10-20 12:53:34 +01:00
Jeff Young 4157d3350e Limit fix to MacOS.
GTK definitely doesn't need it.  It's unlikely that
MSW needs it either.
2024-10-19 16:49:21 +01:00
Jeff Young 08ba185003 Make sure Paste can't leak through modal dialog.
Fixes https://gitlab.com/kicad/code/kicad/-/issues/18912

(cherry picked from commit f1ff75f969)
2024-10-19 16:49:21 +01:00
Jeff Young 7b0e5cd080 DRCEpsilon will appear on *both* sides of a zone neck.
Also don't hide modification of minWidth as a side-effect
of an if-statement.

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

(cherry picked from commit b342126ff3)
2024-10-19 16:49:21 +01:00
Jeff Young 66f50d0c0b A neck in a zone fill will be DRCEpsilon smaller on each side.
Fixes https://gitlab.com/kicad/code/kicad/-/issues/18921

(cherry picked from commit 4089735c28)
2024-10-19 16:49:21 +01:00
Jeff Young 973d2d6c03 Even the orphaned net must obey the min board clearance.
(And other Default netclass constraints.)

(cherry picked from commit 4601503660)
2024-10-19 16:49:21 +01:00
Jeff Young fa854b80da Don't ask about locking twice.
Fixes https://gitlab.com/kicad/code/kicad/-/issues/18679

(cherry picked from commit a9f79093be)
2024-10-19 16:49:21 +01:00
Jeff Young 05f8bc05ec Fix broken logic.
Fixes https://gitlab.com/kicad/code/kicad/-/issues/18580

(cherry picked from commit e5321f7401)
2024-10-19 16:49:21 +01:00
Jeff Young d9af68b910 Report implicit rule minimums as being from the board setup.
Fixes https://gitlab.com/kicad/code/kicad/-/issues/18642

(cherry picked from commit ed268c5701)
2024-10-19 16:49:21 +01:00
Seth Hillbrand 0c8172880f Prevent soldermask bridge DRC error with mask pad
We checked logical pad matching when looking at pad-based mask but we
should also do the same for aperture masks
2024-10-18 15:24:21 -07:00
Seth Hillbrand 45559cb809 Update translations 2024-10-16 15:32:27 -07:00
Ivan Chuba d3e1d94046 Translated using Weblate (Ukrainian)
Currently translated at 87.0% (7998 of 9190 strings)

Translation: KiCad EDA/v8
Translate-URL: https://hosted.weblate.org/projects/kicad/v8/uk/
2024-10-17 00:31:56 +02:00
Jan Straka 2c75396b80 Translated using Weblate (Czech)
Currently translated at 84.1% (7735 of 9190 strings)

Translation: KiCad EDA/v8
Translate-URL: https://hosted.weblate.org/projects/kicad/v8/cs/
2024-10-17 00:31:56 +02:00
Arnau Llovet Vidal 7aae0a9f65 Translated using Weblate (Catalan)
Currently translated at 47.4% (4365 of 9190 strings)

Translation: KiCad EDA/v8
Translate-URL: https://hosted.weblate.org/projects/kicad/v8/ca/
2024-10-17 00:31:56 +02:00
Flórián Fuszkó bfd6d96ffc Translated using Weblate (Hungarian)
Currently translated at 3.4% (320 of 9190 strings)

Translation: KiCad EDA/v8
Translate-URL: https://hosted.weblate.org/projects/kicad/v8/hu/
2024-10-17 00:31:56 +02:00
Pferd O f4efa47fe7 Translated using Weblate (German)
Currently translated at 99.9% (9187 of 9190 strings)

Translation: KiCad EDA/v8
Translate-URL: https://hosted.weblate.org/projects/kicad/v8/de/
2024-10-17 00:31:56 +02:00
co8 j d1fd8b18ad Translated using Weblate (Japanese)
Currently translated at 100.0% (9190 of 9190 strings)

Translation: KiCad EDA/v8
Translate-URL: https://hosted.weblate.org/projects/kicad/v8/ja/
2024-10-17 00:31:56 +02:00
Karl SCHUH 5ee1c0ab42 Translated using Weblate (German)
Currently translated at 99.9% (9187 of 9190 strings)

Translation: KiCad EDA/v8
Translate-URL: https://hosted.weblate.org/projects/kicad/v8/de/
2024-10-17 00:31:56 +02:00
co8 j 8d53326021 Translated using Weblate (Japanese)
Currently translated at 100.0% (9190 of 9190 strings)

Translation: KiCad EDA/v8
Translate-URL: https://hosted.weblate.org/projects/kicad/v8/ja/
2024-10-17 00:31:55 +02:00
CloverGit 246afee56e Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 100.0% (9190 of 9190 strings)

Translation: KiCad EDA/v8
Translate-URL: https://hosted.weblate.org/projects/kicad/v8/zh_Hans/
2024-10-17 00:31:55 +02:00
taotieren 352faf526f Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 99.9% (9187 of 9190 strings)

Translation: KiCad EDA/v8
Translate-URL: https://hosted.weblate.org/projects/kicad/v8/zh_Hans/
2024-10-17 00:31:55 +02:00
Wellington Terumi Uemura c183a63c50 Translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (9190 of 9190 strings)

Translation: KiCad EDA/v8
Translate-URL: https://hosted.weblate.org/projects/kicad/v8/pt_BR/
2024-10-17 00:31:55 +02:00
Pferd O 9c34432b99 Translated using Weblate (German)
Currently translated at 99.9% (9187 of 9190 strings)

Translation: KiCad EDA/v8
Translate-URL: https://hosted.weblate.org/projects/kicad/v8/de/
2024-10-17 00:31:55 +02:00
CloverGit 76bc0e27fc Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 99.9% (9187 of 9190 strings)

Translation: KiCad EDA/v8
Translate-URL: https://hosted.weblate.org/projects/kicad/v8/zh_Hans/
2024-10-17 00:31:55 +02:00
Petr Pazourek b2f6d341dd Translated using Weblate (Czech)
Currently translated at 84.1% (7735 of 9190 strings)

Translation: KiCad EDA/v8
Translate-URL: https://hosted.weblate.org/projects/kicad/v8/cs/
2024-10-17 00:31:55 +02:00
JamesJCode 7b5afe805e Drag NC markers attached to SCH_SHEET pins when SCH_SHEET is dragged
Fixes https://gitlab.com/kicad/code/kicad/-/issues/18854

(Cherry-picked from commit d726097a3f)
2024-10-14 00:02:05 +01:00
Wayne Stambaugh b77a591c45 Begin version 8.0.7 development. 2024-10-13 18:20:51 -04:00
201 changed files with 45013 additions and 39814 deletions
+5
View File
@@ -752,6 +752,11 @@ void EDA_3D_CANVAS::OnLeftDown( wxMouseEvent& event )
SetFocus();
stop_editingTimeOut_Timer();
// Ensure m_camera.m_lastPosition (current mouse position) is up to date for
// future drag events (can be not the case when left clicking after
// opening a context menu)
OnMouseMoveCamera( event );
if( !event.Dragging() && ( m_3d_render_raytracing != nullptr ) )
{
RAY mouseRay = getRayAtCurrentMousePosition();
+2
View File
@@ -1,6 +1,8 @@
add_library(3d-viewer_navlib STATIC
"nl_3d_viewer_plugin.cpp"
"nl_3d_viewer_plugin_impl.cpp"
"nl_footprint_properties_plugin.cpp"
"nl_footprint_properties_plugin_impl.cpp"
)
# 3d-viewer_navlib depends on make_lexer outputs in common
+3 -6
View File
@@ -25,20 +25,17 @@
NL_3D_VIEWER_PLUGIN::NL_3D_VIEWER_PLUGIN( EDA_3D_CANVAS* aViewport )
: m_impl( nullptr )
{
if( ADVANCED_CFG::GetCfg().m_Use3DConnexionDriver
&& KIPLATFORM::DRIVERS::Valid3DConnexionDriverVersion() )
{
m_impl = new NL_3D_VIEWER_PLUGIN_IMPL( aViewport );
m_impl = std::make_unique<NL_3D_VIEWER_PLUGIN_IMPL>( aViewport, "KiCAD 3D" );
m_impl->Connect();
}
}
NL_3D_VIEWER_PLUGIN::~NL_3D_VIEWER_PLUGIN()
{
delete m_impl;
}
NL_3D_VIEWER_PLUGIN::~NL_3D_VIEWER_PLUGIN() = default;
void NL_3D_VIEWER_PLUGIN::SetFocus( bool focus )
+3 -1
View File
@@ -26,6 +26,8 @@
#ifndef NL_3D_VIEWER_PLUGIN_H_
#define NL_3D_VIEWER_PLUGIN_H_
#include <memory>
// Forward declarations.
class EDA_3D_CANVAS;
class NL_3D_VIEWER_PLUGIN_IMPL;
@@ -54,7 +56,7 @@ public:
void SetFocus( bool aFocus = true );
private:
NL_3D_VIEWER_PLUGIN_IMPL* m_impl;
std::unique_ptr<NL_3D_VIEWER_PLUGIN_IMPL> m_impl;
};
#endif // NL_3D_VIEWER_PLUGIN_H_
@@ -1,8 +1,8 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2021 3Dconnexion
* Copyright (C) 2021 KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 2024 3Dconnexion
* Copyright (C) 2024 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
@@ -27,6 +27,7 @@
// KiCAD includes
#include <tool/action_manager.h>
#include <tool/tool_manager.h>
#include <tool/tools_holder.h>
// stdlib
#include <map>
@@ -72,7 +73,7 @@ bool equals( glm::mat<L, C, T, Q> const& aFirst, glm::mat<L, C, T, Q> const& aSe
}
NL_3D_VIEWER_PLUGIN_IMPL::NL_3D_VIEWER_PLUGIN_IMPL( EDA_3D_CANVAS* aCanvas ) :
NL_3D_VIEWER_PLUGIN_IMPL::NL_3D_VIEWER_PLUGIN_IMPL( EDA_3D_CANVAS* aCanvas, const std::string& aProfileHint ) :
NAV_3D( false, false ),
m_canvas( aCanvas ),
m_capIsMoving( false ),
@@ -80,12 +81,7 @@ NL_3D_VIEWER_PLUGIN_IMPL::NL_3D_VIEWER_PLUGIN_IMPL( EDA_3D_CANVAS* aCanvas ) :
{
m_camera = dynamic_cast<TRACK_BALL*>( m_canvas->GetCamera() );
PutProfileHint( "KiCAD 3D" );
EnableNavigation( true );
PutFrameTimingSource( TimingSource::SpaceMouse );
exportCommandsAndImages();
PutProfileHint( aProfileHint );
}
@@ -101,8 +97,19 @@ void NL_3D_VIEWER_PLUGIN_IMPL::SetFocus( bool aFocus )
NAV_3D::Write( navlib::focus_k, aFocus );
}
// temporary store for the categories
typedef std::map<std::string, TDx::CCommandTreeNode*> CATEGORY_STORE;
EDA_3D_CANVAS* NL_3D_VIEWER_PLUGIN_IMPL::GetCanvas() const
{
return m_canvas;
}
void NL_3D_VIEWER_PLUGIN_IMPL::Connect()
{
EnableNavigation(true);
PutFrameTimingSource(TimingSource::SpaceMouse);
exportCommandsAndImages();
}
/**
* Add a category to the store.
@@ -571,7 +578,7 @@ long NL_3D_VIEWER_PLUGIN_IMPL::SetActiveCommand( std::string commandId )
if( parent->IsEnabled() )
{
TOOL_MANAGER* tool_manager = static_cast<PCB_BASE_FRAME*>( parent )->GetToolManager();
TOOL_MANAGER* tool_manager = dynamic_cast<TOOLS_HOLDER*>( parent )->GetToolManager();
if( tool_manager == nullptr )
{
+21 -4
View File
@@ -1,8 +1,8 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2021 3Dconnexion
* Copyright (C) 2021 KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 2024 3Dconnexion
* Copyright (C) 2024 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
@@ -42,6 +42,11 @@
class EDA_3D_CANVAS;
class TRACK_BALL;
// temporary store for the categories
typedef std::map<std::string, TDx::CCommandTreeNode*> CATEGORY_STORE;
CATEGORY_STORE::iterator add_category( std::string aCategoryPath, CATEGORY_STORE& aCategoryStore );
// Convenience typedef.
typedef TDx::SpaceMouse::Navigation3D::CNavigation3D NAV_3D;
@@ -56,8 +61,9 @@ public:
* Initializes a new instance of the NL_3DVIEWER_PLUGIN.
*
* @param aCanvas is the viewport to be navigated.
* @param aProfileHint tells the 3DConnexion UI which profile to use.
*/
NL_3D_VIEWER_PLUGIN_IMPL( EDA_3D_CANVAS* aCanvas );
NL_3D_VIEWER_PLUGIN_IMPL( EDA_3D_CANVAS* aCanvas, const std::string& aProfileHint );
virtual ~NL_3D_VIEWER_PLUGIN_IMPL();
@@ -69,11 +75,21 @@ public:
*/
void SetFocus( bool aFocus = true );
/**
* Get the m_canvas pointer.
*/
EDA_3D_CANVAS* GetCanvas() const;
/**
* Connect plugin implementation to the driver.
*/
void Connect();
private:
/**
* Export the invocable actions and images to the 3Dconnexion UI.
*/
void exportCommandsAndImages();
virtual void exportCommandsAndImages();
long GetCameraMatrix( navlib::matrix_t& aMatrix ) const override;
long GetPointerPosition( navlib::point_t& aPosition ) const override;
@@ -111,6 +127,7 @@ private:
long GetCoordinateSystem( navlib::matrix_t& aMatrix ) const override;
long GetIsViewRotatable( navlib::bool_t& isRotatable ) const override;
private:
EDA_3D_CANVAS* m_canvas;
TRACK_BALL* m_camera;
@@ -0,0 +1,45 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2024 3Dconnexion
* Copyright (C) 2024 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "nl_footprint_properties_plugin.h"
#include "nl_footprint_properties_plugin_impl.h"
#include <advanced_config.h>
#include <kiplatform/drivers.h>
NL_FOOTPRINT_PROPERTIES_PLUGIN::NL_FOOTPRINT_PROPERTIES_PLUGIN( EDA_3D_CANVAS* aViewport )
{
if( ADVANCED_CFG::GetCfg().m_Use3DConnexionDriver
&& KIPLATFORM::DRIVERS::Valid3DConnexionDriverVersion() )
{
m_impl = std::make_unique<NL_FOOTPRINT_PROPERTIES_PLUGIN_IMPL>( aViewport );
m_impl->Connect();
}
}
NL_FOOTPRINT_PROPERTIES_PLUGIN::~NL_FOOTPRINT_PROPERTIES_PLUGIN() = default;
void NL_FOOTPRINT_PROPERTIES_PLUGIN::SetFocus( bool focus )
{
if( m_impl )
m_impl->SetFocus( focus );
}
@@ -0,0 +1,62 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2024 3Dconnexion
* Copyright (C) 2024 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @file nl_footprint_properties_plugin.h
* @brief declaration of the nl_footprint_properties_plugin class
*/
#ifndef NL_FOOTPRINT_PROPERTIES_PLUGIN_H_
#define NL_FOOTPRINT_PROPERTIES_PLUGIN_H_
#include <memory>
// Forward declarations.
class EDA_3D_CANVAS;
class NL_FOOTPRINT_PROPERTIES_PLUGIN_IMPL;
/**
* The class that implements the public interface to the SpaceMouse plug-in.
*/
class NL_FOOTPRINT_PROPERTIES_PLUGIN
{
public:
/**
* Initializes a new instance of the NL_FOOTPRINT_PROPERTIES_PLUGIN.
*
* @param aViewport is the viewport to be navigated.
*/
NL_FOOTPRINT_PROPERTIES_PLUGIN( EDA_3D_CANVAS* aViewport );
virtual ~NL_FOOTPRINT_PROPERTIES_PLUGIN();
/**
* Set the connection to the 3Dconnexion driver to the focus state so that
* 3DMouse data is routed here.
*
* @param aFocus is true to set the connection active.
*/
void SetFocus( bool aFocus = true );
private:
std::unique_ptr<NL_FOOTPRINT_PROPERTIES_PLUGIN_IMPL> m_impl;
};
#endif // NL_FOOTPRINT_PROPERTIES_PLUGIN_H_
@@ -0,0 +1,162 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2024 3Dconnexion
* Copyright (C) 2024 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "nl_footprint_properties_plugin_impl.h"
#include <3d-viewer/3d_canvas/eda_3d_canvas.h>
// KiCAD includes
#include <tool/action_manager.h>
#include <tool/tool_manager.h>
#include <tool/tools_holder.h>
#include <wx/mstream.h>
#define BOUNDING_BOX_SCALE_FACTOR 1.3f
/**
* Flag to enable the NL_FOOTPRINT_PROPERTIES_PLUGIN debug tracing.
*
* Use "KI_TRACE_NL_FOOTPRINT_PROPERTIES_PLUGIN" to enable.
*
* @ingroup trace_env_vars
*/
const wxChar* NL_FOOTPRINT_PROPERTIES_PLUGIN_IMPL::m_logTrace =
wxT( "KI_TRACE_NL_FOOTPRINT_PROPERTIES_PLUGIN" );
NL_FOOTPRINT_PROPERTIES_PLUGIN_IMPL::NL_FOOTPRINT_PROPERTIES_PLUGIN_IMPL(EDA_3D_CANVAS* aCanvas) :
NL_3D_VIEWER_PLUGIN_IMPL(aCanvas, "KiCAD Footprint Properties")
{}
long NL_FOOTPRINT_PROPERTIES_PLUGIN_IMPL::GetModelExtents( navlib::box_t& extents ) const
{
SFVEC3F min = NL_3D_VIEWER_PLUGIN_IMPL::GetCanvas()->GetBoardAdapter().GetBBox().Min();
SFVEC3F max = NL_3D_VIEWER_PLUGIN_IMPL::GetCanvas()->GetBoardAdapter().GetBBox().Max();
SFVEC3F diff = ( BOUNDING_BOX_SCALE_FACTOR - 1.f ) / 2.f * ( max - min );
min -= diff;
max += diff;
extents = { min.x, min.y, min.z, max.x, max.y, max.z };
return 0;
}
void NL_FOOTPRINT_PROPERTIES_PLUGIN_IMPL::exportCommandsAndImages()
{
std::list<TOOL_ACTION*> actions = ACTION_MANAGER::GetActionList();
if( actions.size() == 0 )
{
return;
}
using TDx::SpaceMouse::CCommand;
using TDx::SpaceMouse::CCommandSet;
// The root action set node
CCommandSet commandSet( "EDA_3D_CANVAS", "3D Viewer" );
// Activate the command set
NAV_3D::PutActiveCommands( commandSet.GetId() );
// temporary store for the categories
CATEGORY_STORE categoryStore;
std::vector<TDx::CImage> vImages;
// add the action set to the category_store
categoryStore.insert( categoryStore.end(), CATEGORY_STORE::value_type( ".", &commandSet ) );
std::list<TOOL_ACTION*>::const_iterator it;
for( it = actions.begin(); it != actions.end(); ++it )
{
const TOOL_ACTION* action = *it;
std::string label = action->GetMenuLabel().ToStdString();
if( label.empty() )
{
continue;
}
std::string name = action->GetName();
// Do no export commands for the pcbnew app.
if( name.rfind( "pcbnew.", 0 ) == 0 )
{
continue;
}
// Exclude commands which can't be used in the footprint properties.
if( name.rfind( "3DViewer.Control.pivotCenter", 0 ) == 0
|| name.rfind( "3DViewer.Control.material", 0 ) == 0
|| name.rfind( "3DViewer.Control.attribute", 0 ) == 0
|| name.rfind( "3DViewer.Control.show", 0 ) == 0 )
{
continue;
}
std::string strCategory = action->GetToolName();
CATEGORY_STORE::iterator iter = categoryStore.find( strCategory );
if( iter == categoryStore.end() )
{
iter = add_category( std::move( strCategory ), categoryStore );
}
std::string description = action->GetDescription().ToStdString();
// Arbitrary 8-bit data stream
wxMemoryOutputStream imageStream;
if( action->GetIcon() != BITMAPS::INVALID_BITMAP )
{
wxImage image = KiBitmap( action->GetIcon() ).ConvertToImage();
image.SaveFile( imageStream, wxBitmapType::wxBITMAP_TYPE_PNG );
image.Destroy();
if( imageStream.GetSize() )
{
wxStreamBuffer* streamBuffer = imageStream.GetOutputStreamBuffer();
TDx::CImage tdxImage = TDx::CImage::FromData( "", 0, name.c_str() );
tdxImage.AssignImage( std::string( reinterpret_cast<const char*>(
streamBuffer->GetBufferStart() ),
streamBuffer->GetBufferSize() ),
0 );
wxLogTrace( m_logTrace, wxT( "Adding image for : %s" ), name );
vImages.push_back( std::move( tdxImage ) );
}
}
wxLogTrace( m_logTrace, wxT( "Inserting command: %s, description: %s, in category: %s" ),
name, description, iter->first );
iter->second->push_back(
CCommand( std::move( name ), std::move( label ), std::move( description ) ) );
}
NAV_3D::AddCommandSet( commandSet );
NAV_3D::AddImages( vImages );
}
@@ -0,0 +1,68 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2024 3Dconnexion
* Copyright (C) 2024 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @file nl_footprint_properties_plugin_impl.h
* @brief declaration of the nl_footprint_properties_plugin_impl class
*/
#ifndef NL_FOOTPRINT_PROPERTIES_PLUGIN_IMPL_H_
#define NL_FOOTPRINT_PROPERTIES_PLUGIN_IMPL_H_
#include "nl_3d_viewer_plugin_impl.h"
// TDxWare SDK.
#include <SpaceMouse/CNavigation3D.hpp>
/**
* The class that adjusts NL_3D_VIEWER_PLUGIN_IMPL implementation for 3D Model preview in footprint properties dialog.
*/
class NL_FOOTPRINT_PROPERTIES_PLUGIN_IMPL : public NL_3D_VIEWER_PLUGIN_IMPL
{
public:
/**
* Initializes a new instance of the NL_FOOTPRINT_PROPERTIES_PLUGIN.
*
* @param aCanvas is the viewport to be navigated.
*/
NL_FOOTPRINT_PROPERTIES_PLUGIN_IMPL( EDA_3D_CANVAS* aCanvas );
private:
/**
* Get Footprint 3D Model extents.
*
* @param extents is the box around the 3D model.
*/
long GetModelExtents( navlib::box_t& extents ) const override;
/**
* Export the invocable actions and images to the 3Dconnexion UI.
*/
void exportCommandsAndImages() override;
private:
/**
* Trace mask used to enable or disable the trace output of this class.
* The debug output can be turned on by setting the WXTRACE environment variable to
* "KI_TRACE_NL_FOOTPRINT_PROPERTIES_PLUGIN". See the wxWidgets documentation on wxLogTrace for
* more information.
*/
static const wxChar* m_logTrace;
};
#endif // NL_FOOTPRINT_PROPERTIES_PLUGIN_IMPL_H_
@@ -570,6 +570,9 @@ void EDA_3D_VIEWER_FRAME::LoadSettings( APP_SETTINGS_BASE *aCfg )
{
applySettings( cfg );
if( !GetBoard()->GetProject() )
GetBoard()->SetProject( &Prj() );
m_boardAdapter.SetBoard( GetBoard() );
// When opening the 3D viewer, we use the OpenGL mode, never the ray tracing engine
@@ -44,6 +44,8 @@
#include <eda_3d_viewer_settings.h>
#include <board_design_settings.h>
#include <3d_navlib/nl_footprint_properties_plugin.h>
PANEL_PREVIEW_3D_MODEL::PANEL_PREVIEW_3D_MODEL( wxWindow* aParent, PCB_BASE_FRAME* aFrame,
FOOTPRINT* aFootprint,
std::vector<FP_3DMODEL>* aParentModelList ) :
@@ -125,6 +127,9 @@ PANEL_PREVIEW_3D_MODEL::PANEL_PREVIEW_3D_MODEL( wxWindow* aParent, PCB_BASE_FRAM
OGL_ATT_LIST::GetAttributesList( ANTIALIASING_MODE::AA_8X ),
m_boardAdapter, m_currentCamera, PROJECT_PCB::Get3DCacheManager( &aFrame->Prj() ) );
m_spaceMouse = new NL_FOOTPRINT_PROPERTIES_PLUGIN( m_previewPane );
m_spaceMouse->SetFocus( true );
m_boardAdapter.SetBoard( m_dummyBoard );
m_boardAdapter.m_IsBoardView = false;
m_boardAdapter.m_IsPreviewer = true; // Force display 3D models, regardless the 3D viewer options
@@ -162,6 +167,8 @@ PANEL_PREVIEW_3D_MODEL::PANEL_PREVIEW_3D_MODEL( wxWindow* aParent, PCB_BASE_FRAM
wxCommandEventHandler( PANEL_PREVIEW_3D_MODEL::onUnitsChanged ),
nullptr, this );
Bind( wxCUSTOM_PANEL_SHOWN_EVENT, &PANEL_PREVIEW_3D_MODEL::onPanelShownEvent, this );
#ifdef __WXOSX__
// Call layout once to get the proper button sizes after the bitmaps have been set
Layout();
@@ -190,6 +197,7 @@ PANEL_PREVIEW_3D_MODEL::~PANEL_PREVIEW_3D_MODEL()
if( m_boardAdapter.m_Cfg )
m_boardAdapter.m_Cfg->m_Render = m_initialRender;
delete m_spaceMouse;
delete m_dummyBoard;
delete m_previewPane;
}
@@ -620,6 +628,17 @@ void PANEL_PREVIEW_3D_MODEL::onUnitsChanged( wxCommandEvent& aEvent )
}
void PANEL_PREVIEW_3D_MODEL::onPanelShownEvent( wxCommandEvent& aEvent )
{
if( m_spaceMouse != nullptr )
{
m_spaceMouse->SetFocus( static_cast<bool>( aEvent.GetInt() ) );
}
aEvent.Skip();
}
void PANEL_PREVIEW_3D_MODEL::UpdateDummyFootprint( bool aReloadRequired )
{
m_dummyFootprint->Models().clear();
@@ -34,6 +34,7 @@
#include <3d_canvas/eda_3d_canvas.h>
#include <3d_viewer_id.h>
#include <3d_rendering/track_ball.h>
#include <wx/event.h>
// Define min and max parameter values
#define MAX_SCALE 10000.0
@@ -52,6 +53,7 @@
#define OFFSET_INCREMENT_MIL 25.0
#define OFFSET_INCREMENT_MIL_FINE 5.0
wxDECLARE_EVENT( wxCUSTOM_PANEL_SHOWN_EVENT, wxCommandEvent );
// Declared classes to create pointers
class WX_INFOBAR;
@@ -60,6 +62,7 @@ class FILENAME_RESOLVER;
class BOARD;
class BOARD_ADAPTER;
class FOOTPRINT;
class NL_FOOTPRINT_PROPERTIES_PLUGIN;
class PANEL_PREVIEW_3D_MODEL: public EDA_3D_BOARD_HOLDER, public TOOLS_HOLDER, public PANEL_PREVIEW_3D_MODEL_BASE
{
@@ -139,6 +142,7 @@ private:
void doIncrementOffset( wxSpinEvent& aEvent, double aSign );
void onUnitsChanged( wxCommandEvent& aEvent );
void onPanelShownEvent( wxCommandEvent& aEvent );
wxString formatScaleValue( double aValue );
wxString formatRotationValue( double aValue );
@@ -211,6 +215,8 @@ private:
bool m_bodyStyleShowAll; /// true if the board body is show
/// The 3d viewer Render initial settings (must be saved and restored)
EDA_3D_VIEWER_SETTINGS::RENDER_SETTINGS m_initialRender;
NL_FOOTPRINT_PROPERTIES_PLUGIN* m_spaceMouse;
};
#endif // PANEL_PREVIEW_3D_MODEL_H
+1 -1
View File
@@ -37,7 +37,7 @@
# KiCad.
#
# Note: This version string should follow the semantic versioning system
set( KICAD_SEMANTIC_VERSION "8.0.6" )
set( KICAD_SEMANTIC_VERSION "8.0.7" )
# Default the version to the semantic version.
# This is overridden by the git repository tag though (if using git)
+7
View File
@@ -109,6 +109,7 @@ static const wxChar OcePluginAngularDeflection[] = wxT( "OcePluginAngularDeflect
static const wxChar TriangulateSimplificationLevel[] = wxT( "TriangulateSimplificationLevel" );
static const wxChar TriangulateMinimumArea[] = wxT( "TriangulateMinimumArea" );
static const wxChar EnableCacheFriendlyFracture[] = wxT( "EnableCacheFriendlyFracture" );
static const wxChar MinParallelAngle[] = wxT( "MinParallelAngle" );
} // namespace KEYS
@@ -261,6 +262,8 @@ ADVANCED_CFG::ADVANCED_CFG()
m_EnableCacheFriendlyFracture = true;
m_MinParallelAngle = 0.001;
loadFromConfigFile();
}
@@ -477,6 +480,10 @@ void ADVANCED_CFG::loadSettings( wxConfigBase& aCfg )
&m_EnableCacheFriendlyFracture,
m_EnableCacheFriendlyFracture ) );
configParams.push_back( new PARAM_CFG_DOUBLE( true, AC_KEYS::MinParallelAngle,
&m_MinParallelAngle, m_MinParallelAngle,
0.0, 45.0 ) );
// Special case for trace mask setting...we just grab them and set them immediately
// Because we even use wxLogTrace inside of advanced config
wxString traceMasks;
+3
View File
@@ -162,6 +162,9 @@ void COMMIT::makeEntry( EDA_ITEM* aItem, CHANGE_TYPE aType, EDA_ITEM* aCopy, BAS
ent.m_copy = aCopy;
ent.m_screen = aScreen;
// N.B. Do not throw an assertion for multiple changed items. An item can be changed multiple times
// in a single commit such as when importing graphics and grouping them.
m_changedItems.insert( aItem );
m_changes.push_back( ent );
}
+3 -10
View File
@@ -3,7 +3,7 @@
*
* Copyright (C) 2014-2020 Jean-Pierre Charras, jp.charras at wanadoo.fr
* Copyright (C) 2008 Wayne Stambaugh <stambaughw@gmail.com>
* Copyright (C) 1992-2023 KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 1992-2023, 2024 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -347,18 +347,11 @@ const wxString ExpandEnvVarSubstitutions( const wxString& aString, const PROJECT
}
const wxString ResolveUriByEnvVars( const wxString& aUri, PROJECT* aProject )
const wxString ResolveUriByEnvVars( const wxString& aUri, const PROJECT* aProject )
{
wxString uri = ExpandTextVars( aUri, aProject );
// URL-like URI: return as is.
wxURL url( uri );
if( url.GetError() == wxURL_NOERR )
return uri;
// Otherwise, the path points to a local file. Resolve environment variables if any.
return ExpandEnvVarSubstitutions( aUri, aProject );
return ExpandEnvVarSubstitutions( uri, aProject );
}
+33 -8
View File
@@ -1,7 +1,7 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2018-2022 KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 2018-2024 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
@@ -28,6 +28,7 @@
#include <wx/dcmemory.h>
#define ALPHA_MAX 100 // the max value returned by the alpha (opacity) slider
#define SLOPE_AXIS ( bmsize.y / 5.28 ) // was 50 at 264 size
using KIGFX::COLOR4D;
@@ -52,13 +53,17 @@ DIALOG_COLOR_PICKER::DIALOG_COLOR_PICKER( wxWindow* aParent, const COLOR4D& aCur
m_allowOpacityCtrl = aAllowOpacityControl;
m_previousColor4D = aCurrentColor;
m_newColor4D = aCurrentColor;
m_cursorsSize = 8; // Size of square cursors drawn on color bitmaps
m_newColor4D.ToHSV( m_hue, m_sat, m_val, true );
m_bitmapRGB = nullptr;
m_bitmapHSV = nullptr;
m_selectedCursor = nullptr;
m_defaultColor = aDefaultColor;
updateHandleSize();
m_OldColorRect->SetMinSize( FromDIP( wxSize( 24, 24 ) ) );
m_NewColorRect->SetMinSize( FromDIP( wxSize( 24, 24 ) ) );
if( !m_allowOpacityCtrl )
{
m_SizerTransparency->Show( false );
@@ -121,16 +126,15 @@ void DIALOG_COLOR_PICKER::updatePreview( wxStaticBitmap* aStaticBitmap, COLOR4D&
wxBitmap newBm = COLOR_SWATCH::MakeBitmap( aColor4D, COLOR4D::WHITE, aStaticBitmap->GetSize(),
ConvertDialogToPixels( CHECKERBOARD_SIZE_DU ),
aStaticBitmap->GetParent()->GetBackgroundColour() );
newBm.SetScaleFactor( GetDPIScaleFactor() );
aStaticBitmap->SetBitmap( newBm );
}
bool DIALOG_COLOR_PICKER::TransferDataToWindow()
{
// Draw all bitmaps, with colors according to the color 4D
updatePreview( m_OldColorRect, m_previousColor4D );
SetEditVals( ALL_CHANGED, false );
drawAll();
// Configure the spin control sizes
configureSpinCtrl( m_spinCtrlGreen );
@@ -144,6 +148,10 @@ bool DIALOG_COLOR_PICKER::TransferDataToWindow()
finishDialogSettings();
// Draw all bitmaps, with colors according to the color 4D
updatePreview( m_OldColorRect, m_previousColor4D );
drawAll();
return true;
}
@@ -171,6 +179,8 @@ void DIALOG_COLOR_PICKER::initDefinedColors( CUSTOM_COLORS_LIST* aPredefinedColo
{
wxBitmap bm = COLOR_SWATCH::MakeBitmap( aColor, COLOR4D::WHITE, swatchSize,
checkerboardSize, checkboardBackground );
bm.SetScaleFactor( GetDPIScaleFactor() );
wxStaticBitmap* swatch = new wxStaticBitmap( m_panelDefinedColors, aId, bm );
m_fgridColor->Add( swatch, 0, wxALIGN_CENTER_VERTICAL, 5 );
@@ -245,7 +255,6 @@ void DIALOG_COLOR_PICKER::createRGBBitmap()
// Red blue area in X Z 3d axis
double inc = 255.0 / half_size;
#define SLOPE_AXIS 50.0
double slope = SLOPE_AXIS/half_size;
color.g = 0.0;
@@ -315,6 +324,7 @@ void DIALOG_COLOR_PICKER::createRGBBitmap()
delete m_bitmapRGB;
m_bitmapRGB = new wxBitmap( img, 24 );
m_bitmapRGB->SetScaleFactor( m_RgbBitmap->GetDPIScaleFactor() );
m_RgbBitmap->SetBitmap( *m_bitmapRGB );
}
@@ -379,6 +389,7 @@ void DIALOG_COLOR_PICKER::createHSVBitmap()
delete m_bitmapHSV;
m_bitmapHSV = new wxBitmap( img, 24 );
m_bitmapHSV->SetScaleFactor( m_HsvBitmap->GetDPIScaleFactor() );
m_HsvBitmap->SetBitmap( *m_bitmapHSV );
}
@@ -413,8 +424,7 @@ void DIALOG_COLOR_PICKER::drawRGBPalette()
bitmapDC.SetBrush( brush );
int half_csize = m_cursorsSize / 2;
#define SLOPE_AXIS 50.0
double slope = SLOPE_AXIS / half_size;
double slope = SLOPE_AXIS / ( half_size );
// Red axis cursor (Z 3Daxis):
m_cursorBitmapRed.x = 0;
@@ -539,8 +549,15 @@ void DIALOG_COLOR_PICKER::SetEditVals( CHANGED_COLOR aChanged, bool aCheckTransp
}
void DIALOG_COLOR_PICKER::updateHandleSize()
{
m_cursorsSize = FromDIP( 8 ); // Size of square cursors drawn on color bitmaps
}
void DIALOG_COLOR_PICKER::drawAll()
{
updateHandleSize();
m_NewColorRect->Freeze(); // Avoid flicker
m_HsvBitmap->Freeze();
m_RgbBitmap->Freeze();
@@ -699,6 +716,14 @@ void DIALOG_COLOR_PICKER::onHSVMouseDrag( wxMouseEvent& event )
}
void DIALOG_COLOR_PICKER::onSize( wxSizeEvent& event )
{
drawAll();
event.Skip();
}
void DIALOG_COLOR_PICKER::OnColorValueText( wxCommandEvent& event )
{
if( m_newColor4D.SetFromHexString( m_colorValue->GetValue() ) )
+25 -29
View File
@@ -1,5 +1,5 @@
///////////////////////////////////////////////////////////////////////////
// C++ code generated with wxFormBuilder (version 3.10.1-0-g8feb16b)
// C++ code generated with wxFormBuilder (version 4.1.0-0-g733bf3d)
// http://www.wxformbuilder.org/
//
// PLEASE DO *NOT* EDIT THIS FILE!
@@ -33,7 +33,10 @@ DIALOG_COLOR_PICKER_BASE::DIALOG_COLOR_PICKER_BASE( wxWindow* parent, wxWindowID
m_RgbBitmap = new wxStaticBitmap( sbSizerViewRGB->GetStaticBox(), wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 264,264 ), 0 );
m_RgbBitmap->SetMinSize( wxSize( 264,264 ) );
sbSizerViewRGB->Add( m_RgbBitmap, 0, wxALL|wxALIGN_CENTER_HORIZONTAL, 5 );
sbSizerViewRGB->Add( m_RgbBitmap, 0, wxALIGN_CENTER_HORIZONTAL|wxALL|wxEXPAND|wxSHAPED, 5 );
sbSizerViewRGB->Add( 0, 0, 1, wxEXPAND, 5 );
wxFlexGridSizer* fgSizerRGB;
fgSizerRGB = new wxFlexGridSizer( 0, 3, 0, 0 );
@@ -68,18 +71,18 @@ DIALOG_COLOR_PICKER_BASE::DIALOG_COLOR_PICKER_BASE( wxWindow* parent, wxWindowID
sbSizerViewRGB->Add( fgSizerRGB, 0, wxEXPAND, 5 );
bSizerPanels->Add( sbSizerViewRGB, 0, wxEXPAND|wxBOTTOM|wxRIGHT|wxLEFT, 5 );
bSizerPanels->Add( sbSizerViewRGB, 1, wxBOTTOM|wxEXPAND|wxLEFT|wxRIGHT, 5 );
wxStaticBoxSizer* sbSizerViewHSV;
sbSizerViewHSV = new wxStaticBoxSizer( new wxStaticBox( m_panelFreeColors, wxID_ANY, _("HSV") ), wxHORIZONTAL );
wxBoxSizer* bSizer10;
bSizer10 = new wxBoxSizer( wxVERTICAL );
sbSizerViewHSV = new wxStaticBoxSizer( new wxStaticBox( m_panelFreeColors, wxID_ANY, _("HSV") ), wxVERTICAL );
m_HsvBitmap = new wxStaticBitmap( sbSizerViewHSV->GetStaticBox(), wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 264,264 ), 0 );
m_HsvBitmap->SetMinSize( wxSize( 264,264 ) );
bSizer10->Add( m_HsvBitmap, 0, wxALL|wxALIGN_CENTER_HORIZONTAL, 5 );
sbSizerViewHSV->Add( m_HsvBitmap, 0, wxALIGN_CENTER_HORIZONTAL|wxALL|wxEXPAND|wxSHAPED, 5 );
sbSizerViewHSV->Add( 0, 0, 1, wxEXPAND, 5 );
wxFlexGridSizer* fgSizerHSV;
fgSizerHSV = new wxFlexGridSizer( 0, 2, 0, 0 );
@@ -103,26 +106,23 @@ DIALOG_COLOR_PICKER_BASE::DIALOG_COLOR_PICKER_BASE( wxWindow* parent, wxWindowID
fgSizerHSV->Add( m_spinCtrlSaturation, 0, wxEXPAND|wxBOTTOM|wxRIGHT|wxLEFT, 5 );
bSizer10->Add( fgSizerHSV, 0, wxEXPAND, 5 );
sbSizerViewHSV->Add( fgSizerHSV, 0, wxEXPAND, 5 );
sbSizerViewHSV->Add( bSizer10, 0, wxEXPAND, 5 );
bSizerPanels->Add( sbSizerViewHSV, 1, wxEXPAND|wxBOTTOM|wxRIGHT|wxLEFT, 5 );
wxBoxSizer* bSizerBright;
bSizerBright = new wxBoxSizer( wxVERTICAL );
m_staticTextBright = new wxStaticText( sbSizerViewHSV->GetStaticBox(), wxID_ANY, _("Value:"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticTextBright = new wxStaticText( m_panelFreeColors, wxID_ANY, _("Value:"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticTextBright->Wrap( -1 );
bSizerBright->Add( m_staticTextBright, 0, wxALL|wxALIGN_CENTER_HORIZONTAL, 5 );
m_sliderBrightness = new wxSlider( sbSizerViewHSV->GetStaticBox(), wxID_ANY, 255, 0, 255, wxDefaultPosition, wxDefaultSize, wxSL_INVERSE|wxSL_LABELS|wxSL_LEFT|wxSL_VERTICAL );
m_sliderBrightness = new wxSlider( m_panelFreeColors, wxID_ANY, 255, 0, 255, wxDefaultPosition, wxDefaultSize, wxSL_INVERSE|wxSL_LABELS|wxSL_LEFT|wxSL_VERTICAL );
bSizerBright->Add( m_sliderBrightness, 1, wxALIGN_CENTER_HORIZONTAL|wxRIGHT|wxTOP, 5 );
sbSizerViewHSV->Add( bSizerBright, 0, wxEXPAND, 5 );
bSizerPanels->Add( sbSizerViewHSV, 0, wxEXPAND|wxBOTTOM|wxRIGHT, 5 );
bSizerPanels->Add( bSizerBright, 0, wxALL|wxEXPAND, 5 );
bSizerUpperFreeColors->Add( bSizerPanels, 1, wxEXPAND, 5 );
@@ -153,7 +153,7 @@ DIALOG_COLOR_PICKER_BASE::DIALOG_COLOR_PICKER_BASE( wxWindow* parent, wxWindowID
m_SizerDefinedColors->Fit( m_panelDefinedColors );
m_notebook->AddPage( m_panelDefinedColors, _("Defined Colors"), false );
bSizerUpperMain->Add( m_notebook, 0, wxEXPAND | wxALL, 5 );
bSizerUpperMain->Add( m_notebook, 1, wxEXPAND | wxALL, 5 );
m_SizerTransparency = new wxBoxSizer( wxVERTICAL );
@@ -171,35 +171,29 @@ DIALOG_COLOR_PICKER_BASE::DIALOG_COLOR_PICKER_BASE( wxWindow* parent, wxWindowID
bSizerUpperMain->Add( m_SizerTransparency, 0, wxEXPAND|wxRIGHT|wxLEFT, 5 );
bSizerUpperMain->Add( 0, 0, 1, wxEXPAND|wxRIGHT|wxLEFT, 5 );
bSizerMain->Add( bSizerUpperMain, 0, wxEXPAND, 5 );
bSizerMain->Add( bSizerUpperMain, 1, wxEXPAND, 5 );
wxBoxSizer* bButtonsSizer;
bButtonsSizer = new wxBoxSizer( wxHORIZONTAL );
m_staticTextOldColor = new wxStaticText( this, wxID_ANY, _("Preview (old/new):"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticTextOldColor->Wrap( -1 );
bButtonsSizer->Add( m_staticTextOldColor, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT, 5 );
bButtonsSizer->Add( m_staticTextOldColor, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL|wxLEFT|wxRIGHT, 5 );
m_OldColorRect = new wxStaticBitmap( this, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1,-1 ), 0 );
m_OldColorRect->SetMinSize( wxSize( 24,24 ) );
bButtonsSizer->Add( m_OldColorRect, 0, wxALIGN_CENTER_VERTICAL|wxLEFT, 5 );
bButtonsSizer->Add( m_OldColorRect, 0, wxALIGN_CENTER_VERTICAL|wxSHAPED, 5 );
m_NewColorRect = new wxStaticBitmap( this, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1,-1 ), 0 );
m_NewColorRect->SetMinSize( wxSize( 24,24 ) );
bButtonsSizer->Add( m_NewColorRect, 0, wxALIGN_CENTER_VERTICAL, 5 );
bButtonsSizer->Add( 10, 0, 0, wxEXPAND, 5 );
bButtonsSizer->Add( m_NewColorRect, 0, wxALIGN_CENTER_VERTICAL|wxSHAPED, 5 );
m_colorValue = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
m_colorValue->SetMinSize( wxSize( 176,-1 ) );
bButtonsSizer->Add( m_colorValue, 0, wxALIGN_CENTER_VERTICAL, 5 );
bButtonsSizer->Add( m_colorValue, 0, wxALIGN_CENTER_VERTICAL|wxLEFT, 5 );
bButtonsSizer->Add( 20, 0, 0, wxEXPAND, 5 );
@@ -217,7 +211,7 @@ DIALOG_COLOR_PICKER_BASE::DIALOG_COLOR_PICKER_BASE( wxWindow* parent, wxWindowID
bButtonsSizer->Add( m_sdbSizer, 1, wxALL, 5 );
bSizerMain->Add( bButtonsSizer, 1, wxEXPAND|wxLEFT, 10 );
bSizerMain->Add( bButtonsSizer, 0, wxEXPAND|wxLEFT, 10 );
this->SetSizer( bSizerMain );
@@ -234,6 +228,7 @@ DIALOG_COLOR_PICKER_BASE::DIALOG_COLOR_PICKER_BASE( wxWindow* parent, wxWindowID
m_spinCtrlBlue->Connect( wxEVT_COMMAND_SPINCTRL_UPDATED, wxSpinEventHandler( DIALOG_COLOR_PICKER_BASE::OnChangeEditBlue ), NULL, this );
m_HsvBitmap->Connect( wxEVT_LEFT_DOWN, wxMouseEventHandler( DIALOG_COLOR_PICKER_BASE::onHSVMouseClick ), NULL, this );
m_HsvBitmap->Connect( wxEVT_MOTION, wxMouseEventHandler( DIALOG_COLOR_PICKER_BASE::onHSVMouseDrag ), NULL, this );
m_HsvBitmap->Connect( wxEVT_SIZE, wxSizeEventHandler( DIALOG_COLOR_PICKER_BASE::onSize ), NULL, this );
m_spinCtrlHue->Connect( wxEVT_COMMAND_SPINCTRL_UPDATED, wxSpinEventHandler( DIALOG_COLOR_PICKER_BASE::OnChangeEditHue ), NULL, this );
m_spinCtrlSaturation->Connect( wxEVT_COMMAND_SPINCTRL_UPDATED, wxSpinEventHandler( DIALOG_COLOR_PICKER_BASE::OnChangeEditSat ), NULL, this );
m_sliderBrightness->Connect( wxEVT_SCROLL_TOP, wxScrollEventHandler( DIALOG_COLOR_PICKER_BASE::OnChangeBrightness ), NULL, this );
@@ -268,6 +263,7 @@ DIALOG_COLOR_PICKER_BASE::~DIALOG_COLOR_PICKER_BASE()
m_spinCtrlBlue->Disconnect( wxEVT_COMMAND_SPINCTRL_UPDATED, wxSpinEventHandler( DIALOG_COLOR_PICKER_BASE::OnChangeEditBlue ), NULL, this );
m_HsvBitmap->Disconnect( wxEVT_LEFT_DOWN, wxMouseEventHandler( DIALOG_COLOR_PICKER_BASE::onHSVMouseClick ), NULL, this );
m_HsvBitmap->Disconnect( wxEVT_MOTION, wxMouseEventHandler( DIALOG_COLOR_PICKER_BASE::onHSVMouseDrag ), NULL, this );
m_HsvBitmap->Disconnect( wxEVT_SIZE, wxSizeEventHandler( DIALOG_COLOR_PICKER_BASE::onSize ), NULL, this );
m_spinCtrlHue->Disconnect( wxEVT_COMMAND_SPINCTRL_UPDATED, wxSpinEventHandler( DIALOG_COLOR_PICKER_BASE::OnChangeEditHue ), NULL, this );
m_spinCtrlSaturation->Disconnect( wxEVT_COMMAND_SPINCTRL_UPDATED, wxSpinEventHandler( DIALOG_COLOR_PICKER_BASE::OnChangeEditSat ), NULL, this );
m_sliderBrightness->Disconnect( wxEVT_SCROLL_TOP, wxScrollEventHandler( DIALOG_COLOR_PICKER_BASE::OnChangeBrightness ), NULL, this );
File diff suppressed because it is too large Load Diff
+2 -1
View File
@@ -1,5 +1,5 @@
///////////////////////////////////////////////////////////////////////////
// C++ code generated with wxFormBuilder (version 3.10.1-0-g8feb16b)
// C++ code generated with wxFormBuilder (version 4.1.0-0-g733bf3d)
// http://www.wxformbuilder.org/
//
// PLEASE DO *NOT* EDIT THIS FILE!
@@ -81,6 +81,7 @@ class DIALOG_COLOR_PICKER_BASE : public DIALOG_SHIM
virtual void OnChangeEditBlue( wxSpinEvent& event ) { event.Skip(); }
virtual void onHSVMouseClick( wxMouseEvent& event ) { event.Skip(); }
virtual void onHSVMouseDrag( wxMouseEvent& event ) { event.Skip(); }
virtual void onSize( wxSizeEvent& event ) { event.Skip(); }
virtual void OnChangeEditHue( wxSpinEvent& event ) { event.Skip(); }
virtual void OnChangeEditSat( wxSpinEvent& event ) { event.Skip(); }
virtual void OnChangeBrightness( wxScrollEvent& event ) { event.Skip(); }
+11 -3
View File
@@ -2070,9 +2070,17 @@ static struct EDA_SHAPE_DESC
shapeProps )
.SetAvailableFunc( fillAvailable );
propMgr.AddProperty( new PROPERTY<EDA_SHAPE, COLOR4D>( _HKI( "Fill Color" ),
&EDA_SHAPE::SetFillColor, &EDA_SHAPE::GetFillColor ),
shapeProps )
auto fillColor = new PROPERTY<EDA_SHAPE, COLOR4D>( _HKI( "Fill Color" ),
&EDA_SHAPE::SetFillColor, &EDA_SHAPE::GetFillColor );
fillColor->SetWriteableFunc(
[=]( INSPECTABLE* aItem ) -> bool
{
if( EDA_SHAPE* edaShape = dynamic_cast<EDA_SHAPE*>( aItem ) )
return edaShape->GetFillMode() == FILL_T::FILLED_WITH_COLOR;
return true;
} );
propMgr.AddProperty( fillColor, shapeProps )
.SetAvailableFunc( fillAvailable )
.SetIsHiddenFromRulesEditor();
}
+50 -4
View File
@@ -212,6 +212,26 @@ void EDA_TEXT::SetTextAngle( const EDA_ANGLE& aAngle )
void EDA_TEXT::SetItalic( bool aItalic )
{
if( m_attributes.m_Italic != aItalic )
{
const KIFONT::FONT* font = GetFont();
if( !font || font->IsStroke() )
{
// For stroke fonts, just need to set the attribute.
}
else
{
// For outline fonts, italic-ness is determined by the font itself.
SetFont( KIFONT::FONT::GetFont( font->GetName(), IsBold(), aItalic ) );
}
}
SetItalicFlag( aItalic );
}
void EDA_TEXT::SetItalicFlag( bool aItalic )
{
m_attributes.m_Italic = aItalic;
ClearRenderCache();
@@ -223,12 +243,38 @@ void EDA_TEXT::SetBold( bool aBold )
{
if( m_attributes.m_Bold != aBold )
{
int size = std::min( m_attributes.m_Size.x, m_attributes.m_Size.y );
const KIFONT::FONT* font = GetFont();
if( aBold )
m_attributes.m_StrokeWidth = GetPenSizeForBold( size );
if( !font || font->IsStroke() )
{
// For stroke fonts, boldness is determined by the pen size.
const int size = std::min( m_attributes.m_Size.x, m_attributes.m_Size.y );
if( aBold )
{
m_attributes.m_StoredStrokeWidth = m_attributes.m_StrokeWidth;
m_attributes.m_StrokeWidth = GetPenSizeForBold( size );
}
else
{
// Restore the original stroke width from `m_StoredStrokeWidth` if it was previously stored,
// resetting the width after unbolding.
if( m_attributes.m_StoredStrokeWidth )
m_attributes.m_StrokeWidth = m_attributes.m_StoredStrokeWidth;
else
{
m_attributes.m_StrokeWidth = GetPenSizeForNormal( size );
// Sets `m_StrokeWidth` to the normal pen size and stores it in `m_StoredStrokeWidth`
// as the default, but only if the bold option was applied before this feature was implemented.
m_attributes.m_StoredStrokeWidth = m_attributes.m_StrokeWidth;
}
}
}
else
m_attributes.m_StrokeWidth = GetPenSizeForNormal( size );
{
// For outline fonts, boldness is determined by the font itself.
SetFont( KIFONT::FONT::GetFont( font->GetName(), aBold, IsItalic() ) );
}
}
SetBoldFlag( aBold );
+8
View File
@@ -452,6 +452,8 @@ VECTOR2I OUTLINE_FONT::getTextAsGlyphsUnlocked( BOX2I* aBBox,
for( SHAPE_LINE_CHAIN& hole : holes )
{
bool added_hole = false;
if( hole.PointCount() )
{
for( int ii = 0; ii < glyph->OutlineCount(); ++ii )
@@ -459,9 +461,15 @@ VECTOR2I OUTLINE_FONT::getTextAsGlyphsUnlocked( BOX2I* aBBox,
if( glyph->Outline( ii ).PointInside( hole.GetPoint( 0 ) ) )
{
glyph->AddHole( std::move( hole ), ii );
added_hole = true;
break;
}
}
// Some lovely TTF fonts decided that winding didn't matter for outlines that
// don't have holes, so holes that don't fit in any outline are added as outlines
if( !added_hole )
glyph->AddOutline( std::move( hole ) );
}
}
+2 -1
View File
@@ -35,7 +35,8 @@ TEXT_ATTRIBUTES::TEXT_ATTRIBUTES( KIFONT::FONT* aFont ) :
m_Visible( true ),
m_Mirrored( false ),
m_Multiline( true ),
m_KeepUpright( false )
m_KeepUpright( false ),
m_StoredStrokeWidth( 0 )
{
}
+16 -1
View File
@@ -693,7 +693,14 @@ void GRID_TRICKS::paste_clipboard()
wxTheClipboard->GetData( data );
paste_text( data.GetText() );
wxString text = data.GetText();
#ifdef __WXMAC__
// Some editors use windows linefeeds (\r\n), which wx re-writes to \n\n
text.Replace( "\n\n", "\n" );
#endif
paste_text( text );
}
wxTheClipboard->Close();
@@ -802,6 +809,14 @@ void GRID_TRICKS::paste_text( const wxString& cb_text )
{
tbl->SetValue( row, col, cellTxt );
wxGridEvent evt( m_grid->GetId(), wxEVT_GRID_CELL_CHANGED, m_grid, row, col );
m_grid->GetEventHandler()->ProcessEvent( evt );
}
// Allow paste to any cell that can accept a boolean value
else if( tbl->CanSetValueAs( row, col, wxGRID_VALUE_BOOL ) )
{
tbl->SetValueAsBool( row, col, cellTxt == wxT( "1" ) );
wxGridEvent evt( m_grid->GetId(), wxEVT_GRID_CELL_CHANGED, m_grid, row, col );
m_grid->GetEventHandler()->ProcessEvent( evt );
}
+12 -9
View File
@@ -98,7 +98,7 @@ DXF_IMPORT_PLUGIN::DXF_IMPORT_PLUGIN() : DL_CreationAdapter()
m_brdLayer = Dwgs_User; // The default import layer
m_importAsFPShapes = true;
m_minX = m_minY = std::numeric_limits<double>::max();
m_maxX = m_maxY = std::numeric_limits<double>::min();
m_maxX = m_maxY = std::numeric_limits<double>::lowest();
m_currentUnit = DXF_IMPORT_UNITS::DEFAULT;
m_importCoordinatePrecision = 4; // initial value per dxf spec
@@ -131,7 +131,7 @@ bool DXF_IMPORT_PLUGIN::Load( const wxString& aFileName )
m_internalImporter.ClearShapes();
reportMsg( _( "Memory was exhausted trying to load the DXF, it may be too large." ) );
ReportMsg( _( "Memory was exhausted trying to load the DXF, it may be too large." ) );
return false;
}
}
@@ -151,7 +151,7 @@ bool DXF_IMPORT_PLUGIN::LoadFromMemory( const wxMemoryBuffer& aMemBuffer )
m_internalImporter.ClearShapes();
reportMsg( _( "Memory was exhausted trying to load the DXF, it may be too large." ) );
ReportMsg( _( "Memory was exhausted trying to load the DXF, it may be too large." ) );
return false;
}
}
@@ -247,7 +247,7 @@ bool DXF_IMPORT_PLUGIN::ImportDxfFile( const wxMemoryBuffer& aMemBuffer )
}
void DXF_IMPORT_PLUGIN::reportMsg( const wxString& aMessage )
void DXF_IMPORT_PLUGIN::ReportMsg( const wxString& aMessage )
{
// Add message to keep trace of not handled dxf entities
m_messages += aMessage;
@@ -1411,8 +1411,8 @@ void DXF_IMPORT_PLUGIN::insertSpline( double aWidth )
ctrlp.push_back( m_curr_entity.m_SplineControlPointList[ii].m_y );
}
std::vector<double> coords;
tinyspline::BSpline beziers;
std::vector<double> coords;
try
{
@@ -1421,15 +1421,18 @@ void DXF_IMPORT_PLUGIN::insertSpline( double aWidth )
dxfspline.setControlPoints( ctrlp );
dxfspline.setKnots( m_curr_entity.m_SplineKnotsList );
beziers = tinyspline::BSpline( dxfspline.toBeziers() );
if( dxfspline.degree() < 3 )
dxfspline = dxfspline.elevateDegree( 3 - dxfspline.degree() );
beziers = dxfspline.toBeziers();
coords = beziers.controlPoints();
}
catch( const std::runtime_error& ) // tinyspline throws everything including data validation
// as runtime errors
{
// invalid spline definition, drop this block
reportMsg( _( "Invalid spline definition encountered" ) );
ReportMsg( _( "Invalid spline definition encountered" ) );
return;
}
@@ -1446,14 +1449,14 @@ void DXF_IMPORT_PLUGIN::insertSpline( double aWidth )
// not sure why this happens, but it seems to sometimes slip degree on the final bezier
VECTOR2D bezierControl2;
if( ii + 4 >= coords.size() )
if( ii + 5 >= coords.size() )
bezierControl2 = bezierControl1;
else
bezierControl2 = VECTOR2D( mapX( coords[ii + 4] ), mapY( coords[ii + 5] ) );
VECTOR2D end;
if( ii + 6 >= coords.size() )
if( ii + 7 >= coords.size() )
end = bezierControl2;
else
end = VECTOR2D( mapX( coords[ii + 6] ), mapY( coords[ii + 7] ) );
+18 -18
View File
@@ -320,10 +320,10 @@ public:
{
return m_messages;
}
// report message to keep trace of not supported dxf entities:
void ReportMsg( const wxString& aMessage ) override;
private:
// report message to keep trace of not supported dxf entities:
void reportMsg( const wxString& aMessage );
// coordinate conversions from dxf file to mm
double mapX( double aDxfCoordX );
@@ -455,77 +455,77 @@ private:
// Not yet handled DXF entities:
virtual void addXLine( const DL_XLineData& ) override
{
reportMsg( _( "DXF construction lines not currently supported." ) );
ReportMsg( _( "DXF construction lines not currently supported." ) );
}
virtual void addRay( const DL_RayData& ) override
{
reportMsg( _( "DXF construction lines not currently supported." ) );
ReportMsg( _( "DXF construction lines not currently supported." ) );
}
virtual void addArcAlignedText( const DL_ArcAlignedTextData& ) override
{
reportMsg( _( "DXF arc-aligned text not currently supported." ) );
ReportMsg( _( "DXF arc-aligned text not currently supported." ) );
}
virtual void addDimAlign( const DL_DimensionData&, const DL_DimAlignedData& ) override
{
reportMsg( _( "DXF dimensions not currently supported." ) );
ReportMsg( _( "DXF dimensions not currently supported." ) );
}
virtual void addDimLinear( const DL_DimensionData&, const DL_DimLinearData& ) override
{
reportMsg( _( "DXF dimensions not currently supported." ) );
ReportMsg( _( "DXF dimensions not currently supported." ) );
}
virtual void addDimRadial( const DL_DimensionData&, const DL_DimRadialData& ) override
{
reportMsg( _( "DXF dimensions not currently supported." ) );
ReportMsg( _( "DXF dimensions not currently supported." ) );
}
virtual void addDimDiametric( const DL_DimensionData&, const DL_DimDiametricData& ) override
{
reportMsg( _( "DXF dimensions not currently supported." ) );
ReportMsg( _( "DXF dimensions not currently supported." ) );
}
virtual void addDimAngular( const DL_DimensionData&, const DL_DimAngular2LData& ) override
{
reportMsg( _( "DXF dimensions not currently supported." ) );
ReportMsg( _( "DXF dimensions not currently supported." ) );
}
virtual void addDimAngular3P( const DL_DimensionData&, const DL_DimAngular3PData& ) override
{
reportMsg( _( "DXF dimensions not currently supported." ) );
ReportMsg( _( "DXF dimensions not currently supported." ) );
}
virtual void addDimOrdinate( const DL_DimensionData&, const DL_DimOrdinateData& ) override
{
reportMsg( _( "DXF dimensions not currently supported." ) );
ReportMsg( _( "DXF dimensions not currently supported." ) );
}
virtual void addLeader( const DL_LeaderData& ) override
{
reportMsg( _( "DXF dimensions not currently supported." ) );
ReportMsg( _( "DXF dimensions not currently supported." ) );
}
virtual void addLeaderVertex( const DL_LeaderVertexData& ) override { }
virtual void addHatch( const DL_HatchData& ) override
{
reportMsg( _( "DXF hatches not currently supported." ) );
ReportMsg( _( "DXF hatches not currently supported." ) );
}
virtual void addHatchLoop( const DL_HatchLoopData& ) override { }
virtual void addHatchEdge( const DL_HatchEdgeData& ) override { }
virtual void addTrace( const DL_TraceData& ) override
{
reportMsg( _( "DXF traces not currently supported." ) );
ReportMsg( _( "DXF traces not currently supported." ) );
}
virtual void add3dFace( const DL_3dFaceData& ) override
{
reportMsg( _( "DXF 3dfaces not currently supported." ) );
ReportMsg( _( "DXF 3dfaces not currently supported." ) );
}
virtual void addSolid( const DL_SolidData& ) override
{
reportMsg( _( "DXF solids not currently supported." ) );
ReportMsg( _( "DXF solids not currently supported." ) );
}
virtual void addImage( const DL_ImageData& ) override
{
reportMsg( _( "DXF images not currently supported." ) );
ReportMsg( _( "DXF images not currently supported." ) );
}
virtual void linkImage( const DL_ImageDefData& ) override {}
@@ -131,6 +131,8 @@ public:
*/
const virtual wxString& GetMessages() const = 0;
virtual void ReportMsg( const wxString& aMessage ) = 0;
protected:
///< Importer used to create objects representing the imported shapes.
GRAPHICS_IMPORTER* m_importer;
+5
View File
@@ -125,6 +125,11 @@ public:
return m_plugin->GetMessages();
}
void ReportMsg( const wxString& aMessage )
{
m_plugin->ReportMsg( aMessage );
}
/**
* Get original image Width.
*
@@ -98,6 +98,89 @@ void GRAPHICS_IMPORTER_BUFFER::AddShape( std::unique_ptr<IMPORTED_SHAPE>& aShape
void GRAPHICS_IMPORTER_BUFFER::ImportTo( GRAPHICS_IMPORTER& aImporter )
{
BOX2D boundingBox;
for( std::unique_ptr<IMPORTED_SHAPE>& shape : m_shapes )
{
BOX2D box = shape->GetBoundingBox();
if( box.IsValid() )
boundingBox.Merge( box );
}
boundingBox.SetOrigin( boundingBox.GetPosition().x * aImporter.GetScale().x,
boundingBox.GetPosition().y * aImporter.GetScale().y );
boundingBox.SetSize( boundingBox.GetSize().x * aImporter.GetScale().x,
boundingBox.GetSize().y * aImporter.GetScale().y );
// Check that the scaled graphics fit in the KiCad numeric limits
if( boundingBox.GetSize().x * aImporter.GetMillimeterToIuFactor() > std::numeric_limits<int>::max() ||
boundingBox.GetSize().y * aImporter.GetMillimeterToIuFactor() > std::numeric_limits<int>::max() )
{
double scale_factor = std::numeric_limits<int>::max() / ( aImporter.GetMillimeterToIuFactor() + 100 );
double max_scale = std::max( scale_factor / boundingBox.GetSize().x,
scale_factor / boundingBox.GetSize().y );
aImporter.ReportMsg( wxString::Format( _( "Imported graphic is too large. Maximum scale is %f" ),
max_scale ) );
return;
}
// They haven't set the import offset, so we set it to the bounding box origin to keep the graphics
// in the KiCad drawing area
else if( aImporter.GetImportOffsetMM() == VECTOR2D( 0, 0 ) )
{
VECTOR2D offset = boundingBox.GetOrigin();
aImporter.SetImportOffsetMM( -offset );
}
else
{
VECTOR2D bbox_origin = boundingBox.GetOrigin();
aImporter.SetImportOffsetMM( -bbox_origin + aImporter.GetImportOffsetMM() );
double total_scale_x = aImporter.GetScale().x * aImporter.GetMillimeterToIuFactor();
double total_scale_y = aImporter.GetScale().y * aImporter.GetMillimeterToIuFactor();
double max_offset_x =
( aImporter.GetImportOffsetMM().x + boundingBox.GetRight() ) * total_scale_x;
double max_offset_y =
( aImporter.GetImportOffsetMM().y + boundingBox.GetBottom() ) * total_scale_y;
double min_offset_x =
( aImporter.GetImportOffsetMM().x + boundingBox.GetLeft() ) * total_scale_x;
double min_offset_y =
( aImporter.GetImportOffsetMM().y + boundingBox.GetTop() ) * total_scale_y;
VECTOR2D newOffset = aImporter.GetImportOffsetMM();
bool needsAdjustment = false;
if( max_offset_x >= std::numeric_limits<int>::max() )
{
newOffset.x -= ( max_offset_x - std::numeric_limits<int>::max() + 100.0 ) / total_scale_x;
needsAdjustment = true;
}
else if( min_offset_x <= std::numeric_limits<int>::min() )
{
newOffset.x -= ( min_offset_x - std::numeric_limits<int>::min() - 100 ) / total_scale_x;
needsAdjustment = true;
}
if( max_offset_y >= std::numeric_limits<int>::max() )
{
newOffset.y -= ( max_offset_y - std::numeric_limits<int>::max() + 100 ) / total_scale_y;
needsAdjustment = true;
}
else if( min_offset_y <= std::numeric_limits<int>::min() )
{
newOffset.y -= ( min_offset_y - std::numeric_limits<int>::min() - 100 ) / total_scale_y;
needsAdjustment = true;
}
if( needsAdjustment )
{
aImporter.ReportMsg( wxString::Format( _( "Import offset adjusted to (%f, %f) to fit within numeric limits" ),
newOffset.x, newOffset.y ) );
aImporter.SetImportOffsetMM( newOffset );
}
}
for( std::unique_ptr<IMPORTED_SHAPE>& shape : m_shapes )
shape->ImportTo( aImporter );
}
@@ -30,6 +30,7 @@
#include "graphics_importer.h"
#include <math/matrix3x3.h>
#include <math/box2.h>
#include <list>
@@ -46,6 +47,8 @@ public:
void SetParentShapeIndex( int aIndex ) { m_parentShapeIndex = aIndex; }
int GetParentShapeIndex() const { return m_parentShapeIndex; }
virtual BOX2D GetBoundingBox() const = 0;
protected:
int m_parentShapeIndex = -1;
};
@@ -75,6 +78,14 @@ public:
m_end = aTransform * m_end + aTranslation;
}
BOX2D GetBoundingBox() const override
{
BOX2D box;
box.Merge( m_start );
box.Merge( m_end );
return box;
}
private:
VECTOR2D m_start;
VECTOR2D m_end;
@@ -113,6 +124,14 @@ public:
m_radius = newRadius.EuclideanNorm();
}
BOX2D GetBoundingBox() const override
{
BOX2D box;
box.Merge( m_center - VECTOR2D( m_radius, m_radius ) );
box.Merge( m_center + VECTOR2D( m_radius, m_radius ) );
return box;
}
private:
VECTOR2D m_center;
double m_radius;
@@ -148,6 +167,26 @@ public:
m_center = aTransform * m_center + aTranslation;
}
BOX2D GetBoundingBox() const override
{
BOX2D box;
box.Merge( m_start + m_stroke.GetWidth() );
box.Merge( m_start - m_stroke.GetWidth() );
for( double angle = 0; angle < m_angle.AsDegrees(); angle += 5 )
{
EDA_ANGLE ang = EDA_ANGLE( angle );
VECTOR2D start = m_center + m_start;
VECTOR2D pt = {start.x * ang.Cos() + start.y * ang.Sin(),
start.x * ang.Sin() - start.y * ang.Cos()};
box.Merge( pt );
}
return box;
}
private:
VECTOR2D m_center;
VECTOR2D m_start;
@@ -192,6 +231,16 @@ public:
const IMPORTED_STROKE& GetStroke() const { return m_stroke; }
BOX2D GetBoundingBox() const override
{
BOX2D box;
for( const VECTOR2D& vert : m_vertices )
box.Merge( vert );
return box;
}
private:
std::vector<VECTOR2D> m_vertices;
IMPORTED_STROKE m_stroke;
@@ -227,6 +276,19 @@ public:
void Transform( const MATRIX3x3D& aTransform, const VECTOR2D& aTranslation ) override
{
m_origin = aTransform * m_origin + aTranslation;
VECTOR2D textSize = aTransform * VECTOR2D( m_width, m_height );
m_width = textSize.x;
m_height = textSize.y;
}
BOX2D GetBoundingBox() const override
{
BOX2D box;
box.Merge( m_origin );
box.Merge( m_origin + VECTOR2D( m_width * m_text.length(), m_height ) );
return box;
}
private:
@@ -272,6 +334,14 @@ public:
m_end = aTransform * m_end + aTranslation;
}
BOX2D GetBoundingBox() const override
{
BOX2D box;
box.Merge( m_start );
box.Merge( m_end );
return box;
}
private:
VECTOR2D m_start;
VECTOR2D m_bezierControl1;
+8
View File
@@ -426,3 +426,11 @@ static float distanceFromPointToLine( const VECTOR2D& aPoint, const VECTOR2D& aL
return fabs( distance );
}
void SVG_IMPORT_PLUGIN::ReportMsg( const wxString& aMessage )
{
// Add message to keep trace of not handled svg entities
m_messages += aMessage;
m_messages += '\n';
}
+2
View File
@@ -62,6 +62,8 @@ public:
return m_messages;
}
void ReportMsg( const wxString& aMessage ) override;
bool Import() override;
bool Load( const wxString& aFileName ) override;
bool LoadFromMemory( const wxMemoryBuffer& aMemBuffer ) override;
@@ -307,3 +307,20 @@ EASYEDAPRO::ParseJsonLinesWithSeparation( wxInputStream& aInput, const wxString&
return lineBlocks;
}
std::map<wxString, wxString>
EASYEDAPRO::AnyMapToStringMap( const std::map<wxString, nlohmann::json>& aInput )
{
std::map<wxString, wxString> stringMap;
for( auto& [key, value] : aInput )
{
if( value.is_string() )
stringMap[key] = value.get<wxString>();
else if( value.is_number() )
stringMap[key] = wxString::FromCDouble( value.get<double>() );
}
return stringMap;
}
@@ -63,6 +63,8 @@ std::vector<nlohmann::json> ParseJsonLines( wxInputStream& aInput, const wxStrin
std::vector<std::vector<nlohmann::json>> ParseJsonLinesWithSeparation( wxInputStream& aInput,
const wxString& aSource );
std::map<wxString, wxString> AnyMapToStringMap( const std::map<wxString, nlohmann::json>& aInput );
} // namespace EASYEDAPRO
+2 -1
View File
@@ -29,6 +29,7 @@
#include <nlohmann/json.hpp>
#include <core/json_serializers.h>
#include <string_utils.h>
#include <io/easyedapro/easyedapro_import_utils.h>
void EASYEDAPRO::from_json( const nlohmann::json& j, EASYEDAPRO::SCH_ATTR& d )
@@ -273,7 +274,7 @@ void EASYEDAPRO::from_json( const nlohmann::json& j, EASYEDAPRO::PRJ_DEVICE& d )
d.custom_tags = j.at( "custom_tags" );
if( j.at( "attributes" ).is_object() )
d.attributes = j.at( "attributes" );
d.attributes = AnyMapToStringMap( j.at( "attributes" ) );
}
void EASYEDAPRO::from_json( const nlohmann::json& j, EASYEDAPRO::BLOB& d )
+2 -2
View File
@@ -273,7 +273,7 @@ NUMERIC_EVALUATOR::Token NUMERIC_EVALUATOR::getToken()
}
ch = m_token.input[ ++m_token.pos ];
} while( isdigit( ch ) || isDecimalSeparator( ch ) );
} while( isdigit( (unsigned char) ch ) || isDecimalSeparator( ch ) );
m_token.token[ idx ] = 0;
};
@@ -373,7 +373,7 @@ NUMERIC_EVALUATOR::Token NUMERIC_EVALUATOR::getToken()
{
/* End of input */
}
else if( isdigit( ch ) || isDecimalSeparator( ch ) )
else if( isdigit( (unsigned char) ch ) || isDecimalSeparator( ch ) )
{
// VALUE
extractNumber( &siScaler );
+7
View File
@@ -491,8 +491,15 @@ bool PGM_BASE::InitPgm( bool aHeadless, bool aSkipPyInit, bool aIsUnitTest )
}
#endif
// Ensure the instance checker directory exists
// It should be globally writable because it is shared between all users on Linux, and so on a
// multi-user machine, other need to be able to access it to check for the lock files or make
// their own lock files.
wxString instanceCheckerDir = PATHS::GetInstanceCheckerPath();
PATHS::EnsurePathExists( instanceCheckerDir );
wxChmod( instanceCheckerDir, wxPOSIX_USER_READ | wxPOSIX_USER_WRITE | wxPOSIX_USER_EXECUTE |
wxPOSIX_GROUP_READ | wxPOSIX_GROUP_WRITE | wxPOSIX_GROUP_EXECUTE |
wxPOSIX_OTHERS_READ | wxPOSIX_OTHERS_WRITE | wxPOSIX_OTHERS_EXECUTE );
wxString instanceCheckerName = wxString::Format( wxS( "%s-%s" ), pgm_name,
GetMajorMinorVersion() );
+42 -12
View File
@@ -7,7 +7,7 @@
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 1992-2012 Lorenzo Marcantonio, l.marcantonio@logossrl.com
* Copyright (C) 1992-2023 KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 1992-2023, 2024 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -37,7 +37,8 @@
#include <wx/datstrm.h>
#include <advanced_config.h>
#include <eda_text.h> // for IsGotoPageHref
#include <common.h> // ResolveUriByEnvVars
#include <eda_text.h> // for IsGotoPageHref
#include <font/font.h>
#include <core/ignore.h>
#include <macros.h>
@@ -400,12 +401,12 @@ void PDF_PLOTTER::PlotPoly( const std::vector<VECTOR2I>& aCornerList, FILL_T aFi
SetCurrentLineWidth( aWidth );
VECTOR2D pos = userToDeviceCoordinates( aCornerList[0] );
fprintf( m_workFile, "%g %g m\n", pos.x, pos.y );
fprintf( m_workFile, "%f %f m\n", pos.x, pos.y );
for( unsigned ii = 1; ii < aCornerList.size(); ii++ )
{
pos = userToDeviceCoordinates( aCornerList[ii] );
fprintf( m_workFile, "%g %g l\n", pos.x, pos.y );
fprintf( m_workFile, "%f %f l\n", pos.x, pos.y );
}
// Close path and stroke and/or fill
@@ -438,7 +439,7 @@ void PDF_PLOTTER::PenTo( const VECTOR2I& pos, char plume )
if( m_penState != plume || pos != m_penLastpos )
{
VECTOR2D pos_dev = userToDeviceCoordinates( pos );
fprintf( m_workFile, "%g %g %c\n",
fprintf( m_workFile, "%f %f %c\n",
pos_dev.x, pos_dev.y,
( plume=='D' ) ? 'l' : 'm' );
}
@@ -1332,16 +1333,35 @@ bool PDF_PLOTTER::EndPlot()
{
wxString href = property.substr( property.Find( "http:" ) );
if( m_project )
href = ResolveUriByEnvVars( href, m_project );
js += wxString::Format( wxT( "[\"%s\", \"%s\"],\n" ),
EscapeString( property, CTX_JS_STR ),
EscapeString( href, CTX_JS_STR ),
EscapeString( href, CTX_JS_STR ) );
}
else if( property.Find( "https:" ) >= 0 )
{
wxString href = property.substr( property.Find( "https:" ) );
if( m_project )
href = ResolveUriByEnvVars( href, m_project );
js += wxString::Format( wxT( "[\"%s\", \"%s\"],\n" ),
EscapeString( property, CTX_JS_STR ),
EscapeString( href, CTX_JS_STR ),
EscapeString( href, CTX_JS_STR ) );
}
else if( property.Find( "file:" ) >= 0 )
{
wxString href = property.substr( property.Find( "file:" ) );
if( m_project )
href = ResolveUriByEnvVars( href, m_project );
href = NormalizeFileUri( href );
js += wxString::Format( wxT( "[\"%s\", \"%s\"],\n" ),
EscapeString( href, CTX_JS_STR ),
EscapeString( href, CTX_JS_STR ) );
}
else
@@ -1367,13 +1387,22 @@ bool PDF_PLOTTER::EndPlot()
}
}
}
else if( url.StartsWith( "http:" ) || url.StartsWith( "https:" ) )
else if( url.StartsWith( "http:" ) || url.StartsWith( "https:" )
|| url.StartsWith( "file:" ) )
{
wxString menuText = wxString::Format( _( "Open %s" ), url );
wxString href = url;
if( m_project )
href = ResolveUriByEnvVars( url, m_project );
if( url.StartsWith( "file:" ) )
href = NormalizeFileUri( href );
wxString menuText = wxString::Format( _( "Open %s" ), href );
js += wxString::Format( wxT( "[\"%s\", \"%s\"],\n" ),
EscapeString( menuText, CTX_JS_STR ),
EscapeString( url, CTX_JS_STR ) );
EscapeString( href, CTX_JS_STR ),
EscapeString( href, CTX_JS_STR ) );
}
}
@@ -1413,6 +1442,7 @@ function ShM(aEntries) {
var cChoice = app.popUpMenuEx.apply(app, aParams);
if (cChoice != null && cChoice.substring(0, 1) == '#') this.pageNum = parseInt(cChoice.slice(1));
else if (cChoice != null && cChoice.substring(0, 4) == 'http') app.launchURL(cChoice);
else if (cChoice != null && cChoice.substring(0, 4) == 'file') app.openDoc(cChoice.substring(7));
}
)JS";
@@ -1634,7 +1664,7 @@ void PDF_PLOTTER::Text( const VECTOR2I& aPos,
coordinate system will be used for the overlining. Also the %f
for the trig part of the matrix to avoid %g going in exponential
format (which is not supported) */
fprintf( m_workFile, "q %f %f %f %f %g %g cm BT %s %g Tf %d Tr %g Tz ",
fprintf( m_workFile, "q %f %f %f %f %f %f cm BT %s %g Tf %d Tr %g Tz ",
ctm_a, ctm_b, ctm_c, ctm_d, ctm_e, ctm_f,
fontname, heightFactor, render_mode, wideningFactor * 100 );
+2 -1
View File
@@ -162,7 +162,8 @@ static wxString XmlEsc( const wxString& aStr, bool isAttribute = false )
}
SVG_PLOTTER::SVG_PLOTTER()
SVG_PLOTTER::SVG_PLOTTER( const PROJECT* aProject ) :
PSLIKE_PLOTTER( aProject )
{
m_graphics_changed = true;
SetTextMode( PLOT_TEXT_MODE::STROKE );
+3 -2
View File
@@ -2,7 +2,7 @@
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2017 Jean-Pierre Charras, jp.charras at wanadoo.fr
* Copyright (C) 2017-2023 KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 2017-2023, 2024 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -44,7 +44,8 @@
#include <callback_gal.h>
#include <math/util.h> // for KiROUND
PLOTTER::PLOTTER( )
PLOTTER::PLOTTER( const PROJECT* aProject ) :
m_project( aProject )
{
m_plotScale = 1;
m_currentPenWidth = -1; // To-be-set marker
+2 -1
View File
@@ -116,7 +116,7 @@ COMMON_SETTINGS::COMMON_SETTINGS() :
m_params.emplace_back( new PARAM<int>( "auto_backup.min_interval",
&m_Backup.min_interval, 300 ) );
m_params.emplace_back( new PARAM_LAMBDA<nlohmann::json>( "environment.vars",
auto envVarsParam = m_params.emplace_back( new PARAM_LAMBDA<nlohmann::json>( "environment.vars",
[&]() -> nlohmann::json
{
nlohmann::json ret = {};
@@ -212,6 +212,7 @@ COMMON_SETTINGS::COMMON_SETTINGS() :
}
},
{} ) );
envVarsParam->SetClearUnknownKeys();
m_params.emplace_back( new PARAM<bool>( "input.focus_follow_sch_pcb",
&m_Input.focus_follow_sch_pcb, false ) );
+14 -8
View File
@@ -75,6 +75,7 @@ JSON_SETTINGS::JSON_SETTINGS( const wxString& aFilename, SETTINGS_LOC aLocation,
m_createIfMissing( aCreateIfMissing ),
m_createIfDefault( aCreateIfDefault ),
m_writeFile( aWriteFile ),
m_modified( false ),
m_deleteLegacyAfterMigration( true ),
m_resetParamsIfMissing( true ),
m_schemaVersion( aSchemaVersion ),
@@ -353,6 +354,8 @@ bool JSON_SETTINGS::LoadFromFile( const wxString& aDirectory )
wxLogTrace( traceSettings, wxT( "Loaded <%s> with schema %d" ), GetFullFilename(),
m_schemaVersion );
m_modified = false;
// If we migrated, clean up the legacy file (with no extension)
if( m_writeFile && ( legacy_migrated || migrated ) )
{
@@ -373,15 +376,13 @@ bool JSON_SETTINGS::LoadFromFile( const wxString& aDirectory )
bool JSON_SETTINGS::Store()
{
bool modified = false;
for( PARAM_BASE* param : m_params )
{
modified |= !param->MatchesFile( this );
m_modified |= !param->MatchesFile( this );
param->Store( this );
}
return modified;
return m_modified;
}
@@ -469,10 +470,12 @@ bool JSON_SETTINGS::SaveToFile( const wxString& aDirectory, bool aForce )
for( PARAM_BASE* param : m_params )
{
if( PARAM_WXSTRING_MAP* stringMap = dynamic_cast<PARAM_WXSTRING_MAP*>( param ) )
if( param->ClearUnknownKeys() )
{
if( stringMap->ClearUnknownKeys() )
toSave[ stringMap->GetJsonPath() ] = nlohmann::json( {} );
nlohmann::json_pointer p
= JSON_SETTINGS_INTERNALS::PointerFromString( param->GetJsonPath() );
toSave[p] = nlohmann::json( {} );
}
}
@@ -504,6 +507,9 @@ bool JSON_SETTINGS::SaveToFile( const wxString& aDirectory, bool aForce )
success = false;
}
if( success )
m_modified = false;
return success;
}
@@ -858,7 +864,7 @@ void JSON_SETTINGS::ReleaseNestedSettings( NESTED_SETTINGS* aSettings )
if( it != m_nested_settings.end() )
{
wxLogTrace( traceSettings, wxT( "Flush and release %s" ), ( *it )->GetFilename() );
( *it )->SaveToFile();
m_modified |= ( *it )->SaveToFile();
m_nested_settings.erase( it );
}
+91 -14
View File
@@ -28,11 +28,15 @@
#include <clocale>
#include <cmath>
#include <map>
#include <core/map_helpers.h>
#include <fmt/core.h>
#include <macros.h>
#include <richio.h> // StrPrintf
#include <string_utils.h>
#include <wx_filename.h>
#include <fmt/chrono.h>
#include <wx/log.h>
#include <wx/regex.h>
#include "locale_io.h"
@@ -45,6 +49,34 @@
static const char illegalFileNameChars[] = "\\/:\"<>|*?";
// Checks if a full filename is valid, i.e. does not contains illegal chars
bool IsFullFileNameValid( const wxString& aFullFilename )
{
// Test for forbidden chars in aFullFilename.
// '\'and '/' are allowed here because aFullFilename can be a full path, and
// ':' is allowed on Windows as second char in string.
// So remove allowed separators from string to test
wxString filtered_fullpath = aFullFilename;
#ifdef __WINDOWS__
// On MSW, the list returned by wxFileName::GetForbiddenChars() contains separators
// '\'and '/'
filtered_fullpath.Replace( "/", "_" );
filtered_fullpath.Replace( "\\", "_" );
// A disk identifier is allowed, and therefore remove its separator
if( filtered_fullpath.Length() > 1 && filtered_fullpath[1] == ':' )
filtered_fullpath[1] = ' ';
#endif
if( wxString::npos != filtered_fullpath.find_first_of( wxFileName::GetForbiddenChars() ) )
return false;
return true;
}
wxString ConvertToNewOverbarNotation( const wxString& aOldStr )
{
wxString newStr;
@@ -540,22 +572,32 @@ wxString UnescapeHTML( const wxString& aString )
{
wxString converted = aString;
converted.Replace( wxS( "&quot;" ), wxS( "\"" ) );
converted.Replace( wxS( "&apos;" ), wxS( "'" ) );
converted.Replace( wxS( "&amp;" ), wxS( "&" ) );
converted.Replace( wxS( "&lt;" ), wxS( "<" ) );
converted.Replace( wxS( "&gt;" ), wxS( ">" ) );
// clang-format off
static const std::map<wxString, wxString> c_replacements = {
{ wxS( "quot" ), wxS( "\"" ) },
{ wxS( "apos" ), wxS( "'" ) },
{ wxS( "amp" ), wxS( "&" ) },
{ wxS( "lt" ), wxS( "<" ) },
{ wxS( "gt" ), wxS( ">" ) }
};
// clang-format on
// Yes, &amp;#123; is going to give unexpected results.
// Construct regex
wxString regexStr = "&(#(\\d*)|#x([a-zA-Z0-9]{4})";
wxString result;
for( auto& [key, value] : c_replacements )
regexStr << '|' << key;
wxRegEx regex( "&#(\\d*);" );
regexStr << ");";
wxRegEx regex( regexStr );
// Process matches
size_t start = 0;
size_t len = 0;
wxString str = aString;
wxString result;
wxString str = converted;
while( regex.Matches( str ) )
{
@@ -564,12 +606,26 @@ wxString UnescapeHTML( const wxString& aString )
result << str.Left( start );
unsigned long codeVal = 0;
wxString code = regex.GetMatch( str, 1 );
code.ToCULong( &codeVal );
wxString code = regex.GetMatch( str, 1 );
wxString codeDec = regex.GetMatch( str, 2 );
wxString codeHex = regex.GetMatch( str, 3 );
if( codeVal != 0 )
result << wxUniChar( codeVal );
if( !codeDec.IsEmpty() || !codeHex.IsEmpty() )
{
unsigned long codeVal = 0;
if( !codeDec.IsEmpty() )
codeDec.ToCULong( &codeVal );
else if( !codeHex.IsEmpty() )
codeHex.ToCULong( &codeVal, 16 );
if( codeVal != 0 )
result << wxUniChar( codeVal );
}
else if( auto val = get_opt( c_replacements, code ) )
{
result << *val;
}
str = str.Mid( start + len );
}
@@ -1400,3 +1456,24 @@ wxString From_UTF8( const std::string& aString )
return line;
}
wxString NormalizeFileUri( const wxString& aFileUri )
{
wxString uriPathAndFileName;
wxCHECK( aFileUri.StartsWith( wxS( "file://" ), &uriPathAndFileName ), aFileUri );
wxString tmp = uriPathAndFileName;
wxString retv = wxS( "file://" );
tmp.Replace( wxS( "\\" ), wxS( "/" ) );
tmp.Replace( wxS( ":" ), wxS( "" ) );
if( !tmp.IsEmpty() && tmp[0] != '/' )
tmp = wxS( "/" ) + tmp;
retv += tmp;
return retv;
}
+8 -6
View File
@@ -48,7 +48,7 @@ ACTION_MANAGER::ACTION_MANAGER( TOOL_MANAGER* aToolManager ) :
std::string groupName = "none";
std::optional<TOOL_ACTION_GROUP> group = action->GetActionGroup();
if( group.has_value() )
{
groupID = group.value().GetGroupID();
@@ -152,19 +152,21 @@ bool ACTION_MANAGER::RunHotKey( int aHotKey ) const
// If no luck, try without Shift, to handle keys that require it
// e.g. to get ? you need to press Shift+/ without US keyboard layout
// Hardcoding ? as Shift+/ is a bad idea, as on another layout you may need to press a
// different combination
if( it == m_actionHotKeys.end() )
// different combination.
// This doesn't apply for letters, as we already handled case normalisation.
if( it == m_actionHotKeys.end() && !std::isalpha( key ) )
{
wxLogTrace( kicadTraceToolStack,
wxS( "ACTION_MANAGER::RunHotKey No actions found, searching with key: %s" ),
KeyNameFromKeyCode( key | ( mod & ~MD_SHIFT ) ) );
it = m_actionHotKeys.find( key | ( mod & ~MD_SHIFT ) );
if( it == m_actionHotKeys.end() )
return false; // no appropriate action found for the hotkey
}
// Still no luck, we're done without a match
if( it == m_actionHotKeys.end() )
return false; // no appropriate action found for the hotkey
const std::list<TOOL_ACTION*>& actions = it->second;
// Choose the action that has the highest priority on the active tools stack
+18 -5
View File
@@ -38,6 +38,8 @@
#include <wx/textentry.h>
#include <wx/log.h>
#include <wx/combo.h>
#include <wx/msgdlg.h>
#include <refdes_utils.h>
FOOTPRINT_NAME_VALIDATOR::FOOTPRINT_NAME_VALIDATOR( wxString* aValue ) :
@@ -355,18 +357,24 @@ bool FIELD_VALIDATOR::Validate( wxWindow* aParent )
return false;
wxString val( text->GetValue() );
return DoValidate( val, aParent );
}
bool FIELD_VALIDATOR::DoValidate( const wxString& aValue, wxWindow* aParent )
{
wxString msg;
if( HasFlag( wxFILTER_EMPTY ) && val.empty() )
if( HasFlag( wxFILTER_EMPTY ) && aValue.empty() )
msg.Printf( _( "The value of the field cannot be empty." ) );
if( HasFlag( wxFILTER_EXCLUDE_CHAR_LIST ) && ContainsExcludedCharacters( val ) )
if( HasFlag( wxFILTER_EXCLUDE_CHAR_LIST ) && ContainsExcludedCharacters( aValue ) )
{
wxArrayString badCharsFound;
for( const wxUniCharRef& excludeChar : GetCharExcludes() )
{
if( val.Find( excludeChar ) != wxNOT_FOUND )
if( aValue.Find( excludeChar ) != wxNOT_FOUND )
{
if( excludeChar == '\r' )
badCharsFound.Add( _( "carriage return" ) );
@@ -434,14 +442,19 @@ bool FIELD_VALIDATOR::Validate( wxWindow* aParent )
break;
};
}
else if( m_fieldId == REFERENCE_FIELD && val.Contains( wxT( "${" ) ) )
else if( m_fieldId == REFERENCE_FIELD && aValue.Contains( wxT( "${" ) ) )
{
msg.Printf( _( "The reference designator cannot contain text variable references" ) );
}
else if( m_fieldId == REFERENCE_FIELD && UTIL::GetRefDesPrefix( aValue ).IsEmpty() )
{
msg.Printf( _( "References must start with a letter." ) );
}
if( !msg.empty() )
{
m_validatorWindow->SetFocus();
if( m_validatorWindow )
m_validatorWindow->SetFocus();
wxMessageBox( msg, _( "Field Validation Error" ), wxOK | wxICON_EXCLAMATION, aParent );
+1 -12
View File
@@ -353,19 +353,8 @@ bool DIALOG_FIELD_PROPERTIES::TransferDataFromWindow()
else if( m_StyledTextCtrl->IsShown() )
m_text = UnescapeString( m_StyledTextCtrl->GetValue() );
if( m_fieldId == REFERENCE_FIELD )
{
// Test if the reference string is valid:
if( !SCH_SYMBOL::IsReferenceStringValid( m_text ) )
{
DisplayError( this, _( "Illegal reference designator value!" ) );
return false;
}
}
else if( m_fieldId == SHEETFILENAME_V )
{
if( m_fieldId == SHEETFILENAME_V )
m_text = EnsureFileExtension( m_text, FILEEXT::KiCadSchematicFileExtension );
}
m_position = VECTOR2I( m_posX.GetValue(), m_posY.GetValue() );
m_size = m_textSize.GetValue();
@@ -35,7 +35,7 @@
#include <widgets/std_bitmap_button.h>
#include <string_utils.h>
#include <project_sch.h>
#include <refdes_utils.h>
#include <dialog_sim_model.h>
#include <dialog_lib_symbol_properties.h>
@@ -238,8 +238,8 @@ bool DIALOG_LIB_SYMBOL_PROPERTIES::Validate()
return false;
// Alias symbol reference can be empty because it inherits from the parent symbol.
if( m_libEntry->IsRoot() &&
!SCH_SYMBOL::IsReferenceStringValid( m_fields->at( REFERENCE_FIELD ).GetText() ) )
if( m_libEntry->IsRoot()
&& UTIL::GetRefDesPrefix( m_fields->at( REFERENCE_FIELD ).GetText() ).IsEmpty() )
{
if( m_NoteBook->GetSelection() != 0 )
m_NoteBook->SetSelection( 0 );
@@ -44,6 +44,7 @@
#include <trace_helpers.h>
#include "panel_eeschema_color_settings.h"
#include "wx/dcclient.h"
#include "string_utils.h"
DIALOG_SHEET_PROPERTIES::DIALOG_SHEET_PROPERTIES( SCH_EDIT_FRAME* aParent, SCH_SHEET* aSheet,
bool* aClearAnnotationNewItems,
@@ -286,7 +287,15 @@ bool DIALOG_SHEET_PROPERTIES::TransferDataFromWindow()
// but unedited data from existing files can be bad.)
sheetFileName = EnsureFileExtension( sheetFileName, FILEEXT::KiCadSchematicFileExtension );
// Ensure sheetFileName is legal
if( !IsFullFileNameValid( sheetFileName ) )
{
DisplayError( this, _( "A sheet must have a valid file name." ) );
return false;
}
wxFileName fn( sheetFileName );
wxString newRelativeFilename = fn.GetFullPath();
// Inside Eeschema, filenames are stored using unix notation
@@ -634,17 +634,6 @@ bool DIALOG_SYMBOL_PROPERTIES::Validate()
if( !m_fieldsGrid->CommitPendingChanges() || !m_fieldsGrid->Validate() )
return false;
if( !SCH_SYMBOL::IsReferenceStringValid( m_fields->at( REFERENCE_FIELD ).GetText() ) )
{
DisplayErrorMessage( this, _( "References must start with a letter." ) );
wxCommandEvent *evt = new wxCommandEvent( SYMBOL_DELAY_FOCUS );
evt->SetClientData( new VECTOR2I( REFERENCE_FIELD, FDC_VALUE ) );
QueueEvent( evt );
return false;
}
// Check for missing field names.
for( size_t i = MANDATORY_FIELDS; i < m_fields->size(); ++i )
{
+59 -2
View File
@@ -26,6 +26,7 @@
#include <schematic.h>
#include <dialogs/panel_setup_buses.h>
#include "grid_tricks.h"
#include <wx/clipbrd.h>
PANEL_SETUP_BUSES::PANEL_SETUP_BUSES( wxWindow* aWindow, SCH_EDIT_FRAME* aFrame ) :
PANEL_SETUP_BUSES_BASE( aWindow ),
@@ -147,6 +148,9 @@ bool PANEL_SETUP_BUSES::TransferDataFromWindow()
for( int ii = 0; ii < m_aliasesGrid->GetNumberRows(); ++ii )
m_aliases[ii]->SetName( m_aliasesGrid->GetCellValue( ii, 0 ) );
// Associate the respective members with the last alias that is active.
updateAliasMembers( m_lastAlias );
SCH_SCREENS screens( m_frame->Schematic().Root() );
for( SCH_SCREEN* screen = screens.GetFirst(); screen != nullptr; screen = screens.GetNext() )
@@ -168,6 +172,12 @@ void PANEL_SETUP_BUSES::OnAddAlias( wxCommandEvent& aEvent )
m_aliases.push_back( std::make_shared<BUS_ALIAS>( m_frame->GetScreen() ) );
int row = m_aliasesGrid->GetNumberRows();
// Associate the respective members with the previous alias. This ensures that the association starts
// correctly when adding more than one row
if( row > 0 )
updateAliasMembers( row - 1 );
m_aliasesGrid->AppendRows();
m_aliasesGrid->MakeCellVisible( row, 0 );
@@ -216,8 +226,35 @@ void PANEL_SETUP_BUSES::OnAddMember( wxCommandEvent& aEvent )
m_membersGrid->MakeCellVisible( row, 0 );
m_membersGrid->SetGridCursor( row, 0 );
m_membersGrid->EnableCellEditControl( true );
m_membersGrid->ShowCellEditControl();
/*
* Check if the clipboard contains text data.
*
* - If `clipboardHasText` is true, select the specified row in the members grid to allow our custom
* conext menu to paste the clipbaord .
* - Otherwise, enable and display the cell edit control, allowing the user to manually edit the cell.
*/
bool clipboardHasText = false;
if( wxTheClipboard->Open() )
{
if( wxTheClipboard->IsSupported( wxDF_TEXT )
|| wxTheClipboard->IsSupported( wxDF_UNICODETEXT ) )
{
clipboardHasText = true;
}
wxTheClipboard->Close();
}
if( clipboardHasText )
{
m_membersGrid->SelectRow( row );
}
else
{
m_membersGrid->EnableCellEditControl( true );
m_membersGrid->ShowCellEditControl();
}
}
@@ -459,3 +496,23 @@ void PANEL_SETUP_BUSES::OnUpdateUI( wxUpdateUIEvent& event )
}
void PANEL_SETUP_BUSES::updateAliasMembers( int aAliasIndex )
{
if( !m_aliases.empty() && m_membersGrid->GetNumberRows() > 0 && aAliasIndex >= 0
&& aAliasIndex < m_aliases.size() )
{
const std::shared_ptr<BUS_ALIAS>& alias = m_aliases[aAliasIndex];
alias->Members().clear();
for( int ii = 0; ii < m_membersGrid->GetNumberRows(); ++ii )
{
wxString memberValue = m_membersGrid->GetCellValue( ii, 0 );
if( !memberValue.empty() )
{
alias->Members().push_back( memberValue );
}
}
}
}
+10
View File
@@ -54,6 +54,16 @@ protected:
void doReloadMembersGrid();
/*
* When rows are created programmatically by pasting values from the clipboard,
* the cell change event may not be triggered. This can prevent members from
* being automatically added to the corresponding alias.
*
* To ensure that members are correctly associated with the alias,
* we manually update the members for the needed alias.
*/
void updateAliasMembers( int aAliasIndex );
private:
SCH_EDIT_FRAME* m_frame;
wxString m_membersLabelTemplate;
+35 -2
View File
@@ -346,12 +346,14 @@ PANEL_SYM_LIB_TABLE::PANEL_SYM_LIB_TABLE( DIALOG_EDIT_LIBRARY_TABLES* aParent, P
aGrid->SelectRow( 0 );
};
setupGrid( m_global_grid );
setupGrid( m_global_grid );
m_global_grid->Bind( wxEVT_GRID_CELL_LEFT_CLICK, &PANEL_SYM_LIB_TABLE::onGridCellLeftClickHandler, this );
if( m_projectTable )
{
m_project_grid->SetTable( new SYMBOL_LIB_TABLE_GRID( *m_projectTable ), true );
setupGrid( m_project_grid );
m_project_grid->Bind( wxEVT_GRID_CELL_LEFT_CLICK, &PANEL_SYM_LIB_TABLE::onGridCellLeftClickHandler, this );
}
else
{
@@ -389,9 +391,13 @@ PANEL_SYM_LIB_TABLE::~PANEL_SYM_LIB_TABLE()
// Delete the GRID_TRICKS.
// Any additional event handlers should be popped before the window is deleted.
m_global_grid->PopEventHandler( true );
m_global_grid->Unbind( wxEVT_GRID_CELL_LEFT_CLICK, &PANEL_SYM_LIB_TABLE::onGridCellLeftClickHandler, this );
if( m_project_grid )
{
m_project_grid->PopEventHandler( true );
m_project_grid->Unbind( wxEVT_GRID_CELL_LEFT_CLICK, &PANEL_SYM_LIB_TABLE::onGridCellLeftClickHandler, this );
}
m_path_subs_grid->PopEventHandler( true );
}
@@ -1072,6 +1078,33 @@ SYMBOL_LIB_TABLE_GRID* PANEL_SYM_LIB_TABLE::cur_model() const
}
void PANEL_SYM_LIB_TABLE::onGridCellLeftClickHandler( wxGridEvent& event )
{
// Get the grid object that triggered the event
wxGrid* grid = dynamic_cast<wxGrid*>( event.GetEventObject() );
// If the event object is a wxGrid, proceed with the handling
if( grid )
{
int row = event.GetRow();
int col = event.GetCol();
// Get the cell renderer for the clicked cell
wxGridCellRenderer* renderer = grid->GetCellRenderer( row, col );
// Check if the renderer is a wxGridCellBoolRenderer using dynamic_cast
if( dynamic_cast<wxGridCellBoolRenderer*>( renderer ) )
{
// Set the grid cursor to the clicked boolean cell
grid->SetGridCursor( row, col );
}
}
// Allow the default behavior to continue (toggle the bool)
event.Skip();
}
size_t PANEL_SYM_LIB_TABLE::m_pageNdx = 0;
@@ -1163,4 +1196,4 @@ void InvokeSchEditSymbolLibTable( KIWAY* aKiway, wxWindow *aParent )
aKiway->ExpressMail( FRAME_SCH, MAIL_RELOAD_LIB, payload );
aKiway->ExpressMail( FRAME_SCH_SYMBOL_EDITOR, MAIL_RELOAD_LIB, payload );
aKiway->ExpressMail( FRAME_SCH_VIEWER, MAIL_RELOAD_LIB, payload );
}
}
+1
View File
@@ -58,6 +58,7 @@ private:
void onSizeGrid( wxSizeEvent& event ) override;
void adjustPathSubsGridColumns( int aWidth );
void onConvertLegacyLibraries( wxCommandEvent& event ) override;
void onGridCellLeftClickHandler( wxGridEvent& event );
bool TransferDataFromWindow() override;
+34 -1
View File
@@ -22,6 +22,8 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include <wx/msgdlg.h>
#include <pgm_base.h>
#include <settings/settings_manager.h>
#include <eeschema_settings.h>
@@ -186,10 +188,41 @@ bool PANEL_TEMPLATE_FIELDNAMES::TransferDataFromWindow()
m_templateMgr->DeleteAllFieldNameTemplates( m_global );
for( const TEMPLATE_FIELDNAME& field : m_fields )
for( TEMPLATE_FIELDNAME& field : m_fields )
{
if( !field.m_Name.IsEmpty() )
{
wxString trimmedName = field.m_Name;
trimmedName.Trim();
trimmedName.Trim( false );
// Check if the field name contains leading and/or trailing white space.
if( field.m_Name != trimmedName )
{
wxString msg;
msg.Printf( _( "The field name \"%s\" contains trailing and/or leading white"
"space." ), field.m_Name );
wxMessageDialog dlg( this, msg, _( "Warning" ),
wxOK | wxCANCEL | wxCENTER | wxICON_WARNING );
dlg.SetExtendedMessage( _( "This may result in what appears to be duplicate field "
"names but are actually unique names differing only by "
"white space characters. Removing the white space "
"characters will have no effect on existing symbol "
"field names." ) );
dlg.SetOKCancelLabels( wxMessageDialog::ButtonLabel( _( "Remove White Space" ) ),
wxMessageDialog::ButtonLabel( _( "Keep White Space" ) ) );
if( dlg.ShowModal() == wxID_OK )
field.m_Name = trimmedName;
}
m_templateMgr->AddTemplateFieldName( field, m_global );
}
}
if( m_global )
+9 -2
View File
@@ -533,6 +533,13 @@ bool SCH_EDIT_FRAME::OpenProjectFiles( const std::vector<wxString>& aFileSet, in
SCH_COMMIT dummy( this );
RecalculateConnections( &dummy, GLOBAL_CLEANUP );
if( schematic.HasSymbolFieldNamesWithWhiteSpace() )
{
m_infoBar->QueueShowMessage( _( "This schematic contains symbols that have leading "
"and/or trailing white space field names." ),
wxICON_WARNING );
}
}
// Load any exclusions from the project file
@@ -1404,8 +1411,8 @@ bool SCH_EDIT_FRAME::importFile( const wxString& aFileName, int aFileType,
pi->SetProgressReporter( &progressReporter );
SCH_SHEET* loadedSheet =
pi->LoadSchematicFile( aFileName, &Schematic(), nullptr, aProperties );
SCH_SHEET* loadedSheet = pi->LoadSchematicFile( aFileName, &Schematic(), nullptr,
aProperties );
if( loadedSheet )
{
+3 -1
View File
@@ -136,9 +136,11 @@ void ConvertImageToLibShapes( LIB_SYMBOL* aSymbol, int unit, wxImage img, VECTOR
shape->Offset( offset );
aSymbol->AddDrawItem( shape.release() );
aSymbol->AddDrawItem( shape.release(), false );
}
}
aSymbol->GetDrawItems().sort();
}
+2 -2
View File
@@ -372,8 +372,8 @@ void SCH_EDIT_FRAME::onNetNavigatorSelection( wxTreeEvent& aEvent )
if( GetCurrentSheet() != itemData->GetSheetPath() )
{
Schematic().SetCurrentSheet( itemData->GetSheetPath() );
DisplayCurrentSheet();
GetToolManager()->RunAction<SCH_SHEET_PATH*>( EE_ACTIONS::changeSheet,
&itemData->GetSheetPath() );
}
// Do not focus on item when a sheet tree node is selected.
+2 -1
View File
@@ -769,8 +769,9 @@ void SCH_EDIT_FRAME::AddCopyForRepeatItem( const SCH_ITEM* aItem )
{
std::unique_ptr<SCH_ITEM> repeatItem( static_cast<SCH_ITEM*>( aItem->Duplicate() ) );
// Clone() preserves the flags, we want 'em cleared.
// Clone() preserves the flags & parent, we want 'em cleared.
repeatItem->ClearFlags();
repeatItem->SetParent( nullptr );
m_items_to_repeat.emplace_back( std::move( repeatItem ) );
}
@@ -505,6 +505,32 @@ SCH_EASYEDAPRO_PARSER::ParseSymbol( const std::vector<nlohmann::json>& aLines,
ksymbol->AddDrawItem( shape.release() );
}
else if( type == wxS( "BEZIER" ) )
{
std::vector<double> points = line.at( 2 );
wxString styleStr = line.at( 3 );
std::unique_ptr<LIB_SHAPE> shape =
std::make_unique<LIB_SHAPE>( ksymbol, SHAPE_T::BEZIER );
for( size_t i = 1; i < points.size(); i += 2 )
{
VECTOR2I pt = ScalePosSym( VECTOR2D( points[i - 1], points[i] ) );
switch( i )
{
case 1: shape->SetStart( pt ); break;
case 3: shape->SetBezierC1( pt ); break;
case 5: shape->SetBezierC2( pt ); break;
case 7: shape->SetEnd( pt ); break;
}
}
shape->SetUnit( currentUnit );
ApplyLineStyle( lineStyles, shape, styleStr );
ksymbol->AddDrawItem( shape.release() );
}
else if( type == wxS( "POLY" ) )
{
std::vector<double> points = line.at( 2 );
@@ -1148,8 +1174,8 @@ void SCH_EASYEDAPRO_PARSER::ParseSchematic( SCHEMATIC* aSchematic, SCH_SHEET* aR
if( !deviceAttr )
continue;
std::map<wxString, wxString> compAttrs =
aProject.at( "devices" ).at( deviceAttr->value ).at( "attributes" );
std::map<wxString, wxString> compAttrs = EASYEDAPRO::AnyMapToStringMap(
aProject.at( "devices" ).at( deviceAttr->value ).at( "attributes" ) );
wxString symbolId;
@@ -1210,39 +1236,60 @@ void SCH_EASYEDAPRO_PARSER::ParseSchematic( SCHEMATIC* aSchematic, SCH_SHEET* aR
{
auto nameAttr = get_opt( attributes, "Name" );
wxString netName;
if( nameAttr && !nameAttr->value.IsEmpty() )
netName = nameAttr->value;
else
netName = compAttrs.at( "Name" );
std::unique_ptr<SCH_GLOBALLABEL> label = std::make_unique<SCH_GLOBALLABEL>(
ScalePos( component->position ), netName );
std::vector<SCH_PIN*> pins = schSym->GetPins( &aSchematic->CurrentSheet() );
if( pins.size() > 0 )
{
switch( pins[0]->GetType() )
{
case ELECTRICAL_PINTYPE::PT_INPUT:
label->SetShape( LABEL_FLAG_SHAPE::L_INPUT );
break;
case ELECTRICAL_PINTYPE::PT_OUTPUT:
label->SetShape( LABEL_FLAG_SHAPE::L_OUTPUT );
break;
case ELECTRICAL_PINTYPE::PT_BIDI:
label->SetShape( LABEL_FLAG_SHAPE::L_BIDI );
break;
default: break;
}
}
BOX2I bbox = schSym->GetBodyAndPinsBoundingBox();
bbox.Offset( -schSym->GetPosition() );
VECTOR2I bboxCenter = bbox.GetCenter();
SPIN_STYLE spin = SPIN_STYLE::LEFT;
if( std::abs( bboxCenter.x ) >= std::abs( bboxCenter.y ) )
{
if( bboxCenter.x >= 0 )
spin = SPIN_STYLE::RIGHT;
else
spin = SPIN_STYLE::LEFT;
}
else
{
if( bboxCenter.y >= 0 )
spin = SPIN_STYLE::BOTTOM;
else
spin = SPIN_STYLE::UP;
}
label->SetSpinStyle( spin );
if( nameAttr )
{
std::unique_ptr<SCH_GLOBALLABEL> label = std::make_unique<SCH_GLOBALLABEL>(
ScalePos( component->position ), nameAttr->value );
SPIN_STYLE spin = SPIN_STYLE::LEFT;
if( esymInfo.symbolAttr )
{
wxString symStr = esymInfo.symbolAttr->value;
if( symStr == wxS( "Netport-IN" ) )
{
spin = SPIN_STYLE::LEFT;
label->SetShape( LABEL_FLAG_SHAPE::L_INPUT );
}
if( symStr == wxS( "Netport-OUT" ) )
{
spin = SPIN_STYLE::RIGHT;
label->SetShape( LABEL_FLAG_SHAPE::L_OUTPUT );
}
if( symStr == wxS( "Netport-BI" ) )
{
spin = SPIN_STYLE::RIGHT;
label->SetShape( LABEL_FLAG_SHAPE::L_BIDI );
}
}
for( double i = component->rotation; i > 0; i -= 90 )
spin = spin.RotateCCW();
label->SetSpinStyle( spin );
nlohmann::json style = fontStyles[nameAttr->fontStyle];
if( !style.is_null() && style.at( 5 ).is_number() )
@@ -1250,10 +1297,10 @@ void SCH_EASYEDAPRO_PARSER::ParseSchematic( SCHEMATIC* aSchematic, SCH_SHEET* aR
double size = style.at( 5 ).get<double>() * 0.5;
label->SetTextSize( VECTOR2I( ScaleSize( size ), ScaleSize( size ) ) );
}
createdItems.push_back( std::move( label ) );
}
createdItems.push_back( std::move( label ) );
continue;
}
else
@@ -1285,6 +1332,12 @@ void SCH_EASYEDAPRO_PARSER::ParseSchematic( SCHEMATIC* aSchematic, SCH_SHEET* aR
auto nameAttr = get_opt( attributes, "Name" );
auto valueAttr = get_opt( attributes, "Value" );
if( valueAttr && valueAttr->value.empty() )
valueAttr->value = get_def( compAttrs, "Value", wxString() );
if( nameAttr && nameAttr->value.empty() )
nameAttr->value = get_def( compAttrs, "Name", wxString() );
std::optional<EASYEDAPRO::SCH_ATTR> targetValueAttr;
if( valueAttr && !valueAttr->value.empty() && valueAttr->valVisible )
@@ -1412,7 +1465,7 @@ void SCH_EASYEDAPRO_PARSER::ParseSchematic( SCHEMATIC* aSchematic, SCH_SHEET* aR
if( netAttr )
{
if( !netAttr->valVisible )
if( !netAttr->valVisible || netAttr->value.IsEmpty() )
continue;
VECTOR2I kpos = ScalePos( *netAttr->position );
@@ -1075,7 +1075,7 @@ SCH_TEXT* SCH_IO_KICAD_LEGACY::loadText( LINE_READER& aReader )
if( m_version > 2 || *line >= ' ' )
{
if( strCompare( "Italic", line, &line ) )
text->SetItalic( true );
text->SetItalicFlag( true );
else if( !strCompare( "~", line, &line ) )
SCH_PARSE_ERROR( _( "expected 'Italics' or '~'" ), aReader, line );
}
@@ -1359,7 +1359,7 @@ SCH_SYMBOL* SCH_IO_KICAD_LEGACY::loadSymbol( LINE_READER& aReader )
if( textAttrs[1] == 'I' )
{
field.SetItalic( true );
field.SetItalicFlag( true );
}
else if( textAttrs[1] != 'N' )
{
@@ -647,7 +647,7 @@ void SCH_IO_KICAD_LEGACY_LIB_CACHE::loadField( std::unique_ptr<LIB_SYMBOL>& aSym
wxChar attr_2 = attributes[2];
if( attr_1 == 'I' ) // Italic
field->SetItalic( true );
field->SetItalicFlag( true );
else if( attr_1 != 'N' ) // No italics is default, check for error.
SCH_PARSE_ERROR( "invalid field text italic parameter", aReader, line );
@@ -1015,7 +1015,7 @@ LIB_TEXT* SCH_IO_KICAD_LEGACY_LIB_CACHE::loadText( std::unique_ptr<LIB_SYMBOL>&
&& !is_eol( *line ) )
{
if( strCompare( "Italic", line, &line ) )
text->SetItalic( true );
text->SetItalicFlag( true );
else if( !strCompare( "Normal", line, &line ) )
SCH_PARSE_ERROR( "invalid text stype, expected 'Normal' or 'Italic'", aReader, line );
@@ -744,7 +744,7 @@ void SCH_IO_KICAD_SEXPR_PARSER::parseEDA_TEXT( EDA_TEXT* aText, bool aConvertOve
case T_italic:
{
bool italic = parseMaybeAbsentBool( true );
aText->SetItalic( italic );
aText->SetItalicFlag( italic );
break;
}
+2 -2
View File
@@ -89,8 +89,8 @@ public:
bool CanConnect( const SCH_ITEM* aItem ) const override
{
return ( aItem->Type() == SCH_LINE_T && aItem->GetLayer() == LAYER_WIRE ) ||
aItem->Type() == SCH_SYMBOL_T;
return ( aItem->Type() == SCH_LINE_T && aItem->GetLayer() == LAYER_WIRE )
|| aItem->Type() == SCH_SYMBOL_T || aItem->Type() == SCH_SHEET_T;
}
std::vector<VECTOR2I> GetConnectionPoints() const override;
+4 -2
View File
@@ -4,7 +4,7 @@
* Copyright (C) 1992-2018 Jean-Pierre Charras jp.charras at wanadoo.fr
* Copyright (C) 1992-2010 Lorenzo Marcantonio
* Copyright (C) 2011 Wayne Stambaugh <stambaughw@gmail.com>
* Copyright (C) 1992-2023 KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 1992-2023, 2024 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -132,8 +132,10 @@ void SCH_PLOTTER::createPDFFile( const SCH_PLOT_SETTINGS& aPlotSettings,
sheetList.push_back( m_schematic->CurrentSheet() );
}
wxCHECK( m_schematic, /* void */ );
// Allocate the plotter and set the job level parameter
PDF_PLOTTER* plotter = new PDF_PLOTTER();
PDF_PLOTTER* plotter = new PDF_PLOTTER( &m_schematic->Prj() );
plotter->SetRenderSettings( aRenderSettings );
plotter->SetColorMode( !aPlotSettings.m_blackAndWhite );
plotter->SetCreator( wxT( "Eeschema-PDF" ) );
+1 -1
View File
@@ -4,7 +4,7 @@
* Copyright (C) 1992-2018 Jean-Pierre Charras jp.charras at wanadoo.fr
* Copyright (C) 1992-2010 Lorenzo Marcantonio
* Copyright (C) 2011 Wayne Stambaugh <stambaughw@gmail.com>
* Copyright (C) 1992-2023 KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 1992-2023, 2024 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
+37
View File
@@ -1743,6 +1743,31 @@ void SCH_SCREEN::PruneOrphanedSheetInstances( const wxString& aProjectName,
}
bool SCH_SCREEN::HasSymbolFieldNamesWithWhiteSpace() const
{
wxString trimmedFieldName;
for( const SCH_ITEM* item : Items().OfType( SCH_SYMBOL_T ) )
{
const SCH_SYMBOL* symbol = static_cast<const SCH_SYMBOL*>( item );
wxCHECK2( symbol, continue );
for( const SCH_FIELD& field : symbol->GetFields() )
{
trimmedFieldName = field.GetName();
trimmedFieldName.Trim();
trimmedFieldName.Trim( false );
if( field.GetName() != trimmedFieldName )
return true;
}
}
return false;
}
#if defined(DEBUG)
void SCH_SCREEN::Show( int nestLevel, std::ostream& os ) const
{
@@ -2161,3 +2186,15 @@ void SCH_SCREENS::PruneOrphanedSheetInstances( const wxString& aProjectName,
for( SCH_SCREEN* screen = GetFirst(); screen; screen = GetNext() )
screen->PruneOrphanedSheetInstances( aProjectName, aValidSheetPaths );
}
bool SCH_SCREENS::HasSymbolFieldNamesWithWhiteSpace() const
{
for( const SCH_SCREEN* screen : m_screens )
{
if( screen->HasSymbolFieldNamesWithWhiteSpace() )
return true;
}
return false;
}
+4
View File
@@ -542,6 +542,8 @@ public:
*/
bool AllSymbolDefaultInstancesNotSet();
bool HasSymbolFieldNamesWithWhiteSpace() const;
#if defined(DEBUG)
void Show( int nestLevel, std::ostream& os ) const override;
#endif
@@ -829,6 +831,8 @@ public:
void PruneOrphanedSheetInstances( const wxString& aProjectName,
const SCH_SHEET_LIST& aValidSheetPaths );
bool HasSymbolFieldNamesWithWhiteSpace() const;
private:
void addScreenToList( SCH_SCREEN* aScreen, SCH_SHEET* aSheet );
void buildScreenList( SCH_SHEET* aSheet);
+6 -2
View File
@@ -45,6 +45,7 @@
#include <string_utils.h>
#include <utility>
#include <validators.h>
std::unordered_map<TRANSFORM, int> SCH_SYMBOL::s_transformToOrientationCache;
@@ -783,9 +784,12 @@ const wxString SCH_SYMBOL::GetRef( const SCH_SHEET_PATH* sheet, bool aIncludeUni
}
bool SCH_SYMBOL::IsReferenceStringValid( const wxString& aReferenceString )
void SCH_SYMBOL::SetRefProp( const wxString& aRef )
{
return !UTIL::GetRefDesPrefix( aReferenceString ).IsEmpty();
FIELD_VALIDATOR validator( REFERENCE_FIELD );
if( validator.DoValidate( aRef, nullptr ) )
SetRef( &Schematic()->CurrentSheet(), aRef );
}
+1 -14
View File
@@ -556,10 +556,7 @@ public:
{
return GetRef( &Schematic()->CurrentSheet() );
}
void SetRefProp( const wxString aRef )
{
SetRef( &Schematic()->CurrentSheet(), aRef );
}
void SetRefProp( const wxString& aRef );
wxString GetValueProp() const
{
return GetValueFieldText( false, &Schematic()->CurrentSheet(), false );
@@ -677,16 +674,6 @@ public:
void SwapData( SCH_ITEM* aItem ) override;
/**
* Test for an acceptable reference string.
*
* An acceptable reference string must support unannotation i.e starts by letter
*
* @param aReferenceString is the reference string to validate
* @return true if reference string is valid.
*/
static bool IsReferenceStringValid( const wxString& aReferenceString );
/**
* Return the reference for the given sheet path.
*
+2 -2
View File
@@ -453,7 +453,7 @@ std::map<int, wxString> SCHEMATIC::GetVirtualPageToSheetNamesMap() const
{
std::map<int, wxString> namesMap;
for( const SCH_SHEET_PATH& sheet : GetUnorderedSheets() )
for( const SCH_SHEET_PATH& sheet : GetSheets() )
{
if( sheet.size() == 1 )
namesMap[sheet.GetVirtualPageNumber()] = _( "<root sheet>" );
@@ -469,7 +469,7 @@ std::map<int, wxString> SCHEMATIC::GetVirtualPageToSheetPagesMap() const
{
std::map<int, wxString> pagesMap;
for( const SCH_SHEET_PATH& sheet : GetUnorderedSheets() )
for( const SCH_SHEET_PATH& sheet : GetSheets() )
pagesMap[sheet.GetVirtualPageNumber()] = sheet.GetPageNumber();
return pagesMap;
+9 -1
View File
@@ -922,12 +922,20 @@ void SIM_PLOT_TAB::SetTraceData( TRACE* trace, std::vector<double>& aX, std::vec
trace->SetSweepCount( aSweepCount );
trace->SetSweepSize( aSweepSize );
if( ( trace->GetType() & SPT_AC_PHASE ) || ( trace->GetType() & SPT_CURRENT ) )
// Phase and currents on second Y axis, except for AC currents, those use the same axis as voltage
if( ( trace->GetType() & SPT_AC_PHASE )
|| ( ( GetSimType() != ST_AC ) && ( trace->GetType() & SPT_CURRENT ) ) )
{
trace->SetScale( m_axis_x, m_axis_y2 );
}
else if( trace->GetType() & SPT_POWER )
{
trace->SetScale( m_axis_x, m_axis_y3 );
}
else
{
trace->SetScale( m_axis_x, m_axis_y1 );
}
for( auto& [ cursorId, cursor ] : trace->GetCursors() )
{
+1 -1
View File
@@ -111,7 +111,7 @@ TOOL_ACTION EE_ACTIONS::selectNode( TOOL_ACTION_ARGS()
TOOL_ACTION EE_ACTIONS::selectConnection( TOOL_ACTION_ARGS()
.Name( "eeschema.InteractiveSelection.SelectConnection" )
.Scope( AS_GLOBAL )
.DefaultHotkey( MD_ALT + '4' )
.DefaultHotkey( MD_CTRL + '4' )
.LegacyHotkeyName( "Select Connection" )
.FriendlyName( _( "Select Connection" ) )
.Tooltip( _( "Select a complete connection" ) )
+13
View File
@@ -1256,6 +1256,10 @@ int SCH_EDIT_TOOL::RepeatDrawItem( const TOOL_EVENT& aEvent )
EESCHEMA_SETTINGS* cfg = Pgm().GetSettingsManager().GetAppSettings<EESCHEMA_SETTINGS>();
bool restore_state = false;
// Ensure newItem has a suitable parent: the current screen, because an item from
// a list of items to repeat must be attached to this current screen
newItem->SetParent( m_frame->GetScreen() );
if( SCH_LABEL_BASE* label = dynamic_cast<SCH_LABEL_BASE*>( newItem ) )
{
// If incrementing tries to go below zero, tell user why the value is repeated
@@ -1285,9 +1289,18 @@ int SCH_EDIT_TOOL::RepeatDrawItem( const TOOL_EVENT& aEvent )
if( m_frame->CheckSheetForRecursion( sheet, currentSheet ) )
{
// Clear out the filename so that the user can pick a new one
const wxString originalFileName = sheet->GetFileName();
const wxString originalScreenFileName = sheet->GetScreen()->GetFileName();
sheet->SetFileName( wxEmptyString );
sheet->GetScreen()->SetFileName( wxEmptyString );
restore_state = !m_frame->EditSheetProperties( sheet, currentSheet, nullptr );
if( restore_state )
{
sheet->SetFileName( originalFileName );
sheet->GetScreen()->SetFileName( originalScreenFileName );
}
}
}
+9
View File
@@ -555,6 +555,11 @@ int SCH_EDITOR_CONTROL::SimProbe( const TOOL_EVENT& aEvent )
[this, simFrame]( const VECTOR2D& aPosition )
{
EE_SELECTION_TOOL* selTool = m_toolMgr->GetTool<EE_SELECTION_TOOL>();
// We do not really want to keep an item selected in schematic,
// so clear the current selection
selTool->ClearSelection();
EDA_ITEM* item = selTool->GetNode( aPosition );
SCH_SHEET_PATH& sheet = m_frame->GetCurrentSheet();
@@ -684,6 +689,10 @@ int SCH_EDITOR_CONTROL::SimProbe( const TOOL_EVENT& aEvent )
}
// Wake the selection tool after exiting to ensure the cursor gets updated
// and deselect previous selection from simulator to avoid any issue
// ( avoid crash in some cases when the SimProbe tool is deselected )
EE_SELECTION_TOOL* selectionTool = m_toolMgr->GetTool<EE_SELECTION_TOOL>();
selectionTool->ClearSelection();
m_toolMgr->PostAction( EE_ACTIONS::selectionActivate );
} );
+35 -4
View File
@@ -878,12 +878,43 @@ int SYMBOL_EDITOR_EDIT_TOOL::Duplicate( const TOOL_EVENT& aEvent )
commit.Modify( symbol, m_frame->GetScreen() );
EDA_ITEMS newItems;
std::vector<EDA_ITEM*> oldItems;
std::vector<EDA_ITEM*> newItems;
for( unsigned ii = 0; ii < selection.GetSize(); ++ii )
std::copy( selection.begin(), selection.end(), std::back_inserter( oldItems ) );
std::sort( oldItems.begin(), oldItems.end(), []( EDA_ITEM* a, EDA_ITEM* b )
{
LIB_ITEM* oldItem = static_cast<LIB_ITEM*>( selection.GetItem( ii ) );
LIB_ITEM* newItem = static_cast<LIB_ITEM*>( oldItem->Duplicate() );
int cmp;
if( a->Type() != b->Type() )
return a->Type() < b->Type();
// Create the new pins in the same order as the old pins
if( a->Type() == SCH_PIN_T )
{
const wxString& aNum = static_cast<SCH_PIN*>( a )->GetNumber();
const wxString& bNum = static_cast<SCH_PIN*>( b )->GetNumber();
cmp = StrNumCmp( aNum, bNum );
// If the pin numbers are not numeric, then just number them by their position
// on the screen.
if( aNum.IsNumber() && bNum.IsNumber() && cmp != 0 )
return cmp < 0;
}
cmp = LexicographicalCompare( a->GetPosition(), b->GetPosition() );
if( cmp != 0 )
return cmp > 0;
return a->m_Uuid < b->m_Uuid;
} );
for( EDA_ITEM* item : oldItems )
{
LIB_ITEM* oldItem = static_cast<LIB_ITEM*>( item );
LIB_ITEM* newItem = oldItem->Duplicate();
if( newItem->Type() == LIB_PIN_T )
{
+11
View File
@@ -144,6 +144,15 @@ target_link_libraries( gerbview_kiface_objects
core
)
message( STATUS "Including 3Dconnexion SpaceMouse navigation support in gerbview" )
add_subdirectory( navlib )
if( NOT MINGW )
target_link_libraries( gerbview_kiface_objects PUBLIC gerbview_navlib)
endif()
add_dependencies( gerbview_kiface_objects gerbview_navlib )
# the main gerbview program, in DSO form.
add_library( gerbview_kiface MODULE )
@@ -163,6 +172,8 @@ target_link_libraries( gerbview_kiface
${wxWidgets_LIBRARIES}
)
target_link_libraries( gerbview_kiface PUBLIC gerbview_navlib)
set_source_files_properties( gerbview.cpp PROPERTIES
# The KIFACE is in gerbview.cpp, export it:
COMPILE_DEFINITIONS "BUILD_KIWAY_DLL;COMPILING_DLL"
+40 -10
View File
@@ -57,19 +57,21 @@
#include <dialog_draw_layers_settings.h>
#include <zoom_defines.h>
#include <navlib/nl_gerbview_plugin.h>
#include <wx/log.h>
GERBVIEW_FRAME::GERBVIEW_FRAME( KIWAY* aKiway, wxWindow* aParent )
: EDA_DRAW_FRAME( aKiway, aParent, FRAME_GERBER, wxT( "GerbView" ), wxDefaultPosition,
GERBVIEW_FRAME::GERBVIEW_FRAME( KIWAY* aKiway, wxWindow* aParent ) :
EDA_DRAW_FRAME( aKiway, aParent, FRAME_GERBER, wxT( "GerbView" ), wxDefaultPosition,
wxDefaultSize, KICAD_DEFAULT_DRAWFRAME_STYLE, GERBVIEW_FRAME_NAME,
gerbIUScale ),
m_TextInfo( nullptr ),
m_zipFileHistory( DEFAULT_FILE_HISTORY_SIZE, ID_GERBVIEW_ZIP_FILE1,
ID_GERBVIEW_ZIP_FILE_LIST_CLEAR, _( "Clear Recent Zip Files" ) ),
m_drillFileHistory( DEFAULT_FILE_HISTORY_SIZE, ID_GERBVIEW_DRILL_FILE1,
ID_GERBVIEW_DRILL_FILE_LIST_CLEAR, _( "Clear Recent Drill Files" ) ),
m_jobFileHistory( DEFAULT_FILE_HISTORY_SIZE, ID_GERBVIEW_JOB_FILE1,
ID_GERBVIEW_JOB_FILE_LIST_CLEAR, _( "Clear Recent Job Files" ) ),
m_activeLayer( 0 )
m_TextInfo( nullptr ),
m_zipFileHistory( DEFAULT_FILE_HISTORY_SIZE, ID_GERBVIEW_ZIP_FILE1,
ID_GERBVIEW_ZIP_FILE_LIST_CLEAR, _( "Clear Recent Zip Files" ) ),
m_drillFileHistory( DEFAULT_FILE_HISTORY_SIZE, ID_GERBVIEW_DRILL_FILE1,
ID_GERBVIEW_DRILL_FILE_LIST_CLEAR, _( "Clear Recent Drill Files" ) ),
m_jobFileHistory( DEFAULT_FILE_HISTORY_SIZE, ID_GERBVIEW_JOB_FILE1,
ID_GERBVIEW_JOB_FILE_LIST_CLEAR, _( "Clear Recent Job Files" ) ),
m_activeLayer( 0 )
{
m_maximizeByDefault = true;
m_gerberLayout = nullptr;
@@ -1069,6 +1071,18 @@ void GERBVIEW_FRAME::ActivateGalCanvas()
ReCreateOptToolbar();
ReCreateMenuBar();
try
{
if( !m_spaceMouse )
m_spaceMouse = std::make_unique<NL_GERBVIEW_PLUGIN>();
m_spaceMouse->SetCanvas( galCanvas );
}
catch( const std::system_error& e )
{
wxLogTrace( wxT( "KI_TRACE_NAVLIB" ), e.what() );
}
}
@@ -1236,3 +1250,19 @@ void GERBVIEW_FRAME::ToggleLayerManager()
m_auimgr.GetPane( "LayersManager" ).Show( m_show_layer_manager_tools );
m_auimgr.Update();
}
void GERBVIEW_FRAME::handleActivateEvent( wxActivateEvent& aEvent )
{
EDA_DRAW_FRAME::handleActivateEvent(aEvent);
if( m_spaceMouse )
m_spaceMouse->SetFocus( aEvent.GetActive() );
}
void GERBVIEW_FRAME::handleIconizeEvent( wxIconizeEvent& aEvent )
{
EDA_DRAW_FRAME::handleIconizeEvent(aEvent);
if( m_spaceMouse )
m_spaceMouse->SetFocus( false );
}
+8
View File
@@ -30,6 +30,8 @@
#include <page_info.h>
#include <gbr_display_options.h>
#include <memory>
#define NO_AVAILABLE_LAYERS UNDEFINED_LAYER
class DCODE_SELECTION_BOX;
@@ -42,6 +44,7 @@ class GERBVIEW_SETTINGS;
class REPORTER;
class SELECTION;
class wxStaticText;
class NL_GERBVIEW_PLUGIN;
/**
@@ -477,6 +480,9 @@ protected:
void setupUIConditions() override;
void doReCreateMenuBar() override;
void handleActivateEvent( wxActivateEvent& aEvent ) override;
void handleIconizeEvent( wxIconizeEvent& aEvent ) override;
private:
void updateComponentListSelectBox();
void updateNetnameListSelectBox();
@@ -556,6 +562,8 @@ private:
// relative to the m_SelAperAttributesBox
wxStaticText* m_dcodeText; // a message on the auxiliary toolbar,
// relative to the m_DCodeSelector
std::unique_ptr<NL_GERBVIEW_PLUGIN> m_spaceMouse;
};
#endif /* WX_GERBER_STRUCT_H */
+25
View File
@@ -0,0 +1,25 @@
add_library(gerbview_navlib STATIC
"nl_gerbview_plugin.cpp"
"nl_gerbview_plugin_impl.cpp"
)
# gerbview_navlib depends on make_lexer outputs in common
add_dependencies( gerbview_navlib common )
# Find the 3DxWare SDK component 3DxWare::NlClient
# find_package(TDxWare_SDK 4.0 REQUIRED COMPONENTS 3DxWare::Navlib)
target_compile_definitions(gerbview_navlib PRIVATE
$<TARGET_PROPERTY:3DxWare::Navlib,INTERFACE_COMPILE_DEFINITIONS>
)
target_compile_options(gerbview_navlib PRIVATE
$<TARGET_PROPERTY:3DxWare::Navlib,INTERFACE_COMPILE_OPTIONS>
)
target_include_directories(gerbview_navlib PRIVATE
$<TARGET_PROPERTY:3DxWare::Navlib,INTERFACE_INCLUDE_DIRECTORIES>
$<TARGET_PROPERTY:gerbview_kiface_objects,INCLUDE_DIRECTORIES>
)
target_link_libraries(gerbview_navlib
$<TARGET_PROPERTY:3DxWare::Navlib,INTERFACE_LINK_LIBRARIES>
3DxWare::Navlib
)
+52
View File
@@ -0,0 +1,52 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2024 3Dconnexion
* Copyright (C) 2022 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License 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 "nl_gerbview_plugin.h"
#include "nl_gerbview_plugin_impl.h"
#include <advanced_config.h>
#include <kiplatform/drivers.h>
NL_GERBVIEW_PLUGIN::NL_GERBVIEW_PLUGIN()
{
if( ADVANCED_CFG::GetCfg().m_Use3DConnexionDriver
&& KIPLATFORM::DRIVERS::Valid3DConnexionDriverVersion() )
{
m_impl = std::make_unique<NL_GERBVIEW_PLUGIN_IMPL>();
}
}
NL_GERBVIEW_PLUGIN::~NL_GERBVIEW_PLUGIN() = default;
void NL_GERBVIEW_PLUGIN::SetFocus( bool focus )
{
if( m_impl )
m_impl->SetFocus( focus );
}
void NL_GERBVIEW_PLUGIN::SetCanvas( EDA_DRAW_PANEL_GAL* aViewport )
{
if( m_impl )
m_impl->SetCanvas( aViewport );
}
+69
View File
@@ -0,0 +1,69 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2024 3Dconnexion
* Copyright (C) 2022 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License 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/>.
*/
/**
* @file nl_gerbview_plugin.h
* @brief Declaration of the NL_GERBVIEW_PLUGIN class
*/
#ifndef NL_GERBVIEW_PLUGIN_H_
#define NL_GERBVIEW_PLUGIN_H_
#include <memory>
// Forward declarations.
class EDA_DRAW_PANEL_GAL;
class NL_GERBVIEW_PLUGIN_IMPL;
/**
* The class that implements the public interface to the SpaceMouse plug-in.
*/
class NL_GERBVIEW_PLUGIN
{
public:
/**
* Initializes a new instance of the NL_GERBVIEW_PLUGIN.
*/
NL_GERBVIEW_PLUGIN();
virtual ~NL_GERBVIEW_PLUGIN();
/**
* Sets the viewport controlled by the SpaceMouse.
*
* @param aViewport is the viewport to be navigated.
*/
void SetCanvas( EDA_DRAW_PANEL_GAL* aViewport );
/**
* Set the connection to the 3Dconnexion driver to the focus state so that
* 3DMouse data is routed to this connexion.
*
* @param aFocus is true to set the connexion active.
*/
void SetFocus( bool aFocus );
private:
std::unique_ptr<NL_GERBVIEW_PLUGIN_IMPL> m_impl;
};
#endif // NL_GERBVIEW_PLUGIN_H_
+598
View File
@@ -0,0 +1,598 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2024 3Dconnexion
* Copyright (C) 2022 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License 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 "nl_gerbview_plugin_impl.h"
// KiCAD includes
#include <gal/graphics_abstraction_layer.h>
#include <gerbview_frame.h>
#include <bitmaps.h>
#include <class_draw_panel_gal.h>
#include <view/view.h>
#include <view/wx_view_controls.h>
#include <tool/action_manager.h>
#include <tool/tool_action.h>
#include <tool/tool_manager.h>
// stdlib
#include <list>
#include <map>
#include <memory>
#include <utility>
#include <vector>
#include <cfloat>
#include <wx/log.h>
#include <wx/mstream.h>
/**
* Flag to enable the NL_GERBVIEW_PLUGIN debug tracing.
*
* Use "KI_TRACE_NL_GERBVIEW_PLUGIN" to enable.
*
* @ingroup trace_env_vars
*/
const wxChar* NL_GERBVIEW_PLUGIN_IMPL::m_logTrace = wxT( "KI_TRACE_NL_GERBVIEW_PLUGIN" );
NL_GERBVIEW_PLUGIN_IMPL::NL_GERBVIEW_PLUGIN_IMPL() : CNavigation3D( false, false )
{
PutProfileHint( "KiCAD Gerbview" );
}
NL_GERBVIEW_PLUGIN_IMPL::~NL_GERBVIEW_PLUGIN_IMPL()
{
std::error_code m_errCode;
EnableNavigation( false, m_errCode );
if( m_errCode.value() != 0 )
{
wxLogTrace( wxT( "KI_TRACE_NAVLIB" ),
wxT( "Error occured when calling EnableNavigation. Error code: %d" ),
m_errCode.value() );
}
}
void NL_GERBVIEW_PLUGIN_IMPL::SetCanvas( EDA_DRAW_PANEL_GAL* aViewport )
{
m_viewport2D = aViewport;
if( m_viewport2D == nullptr )
{
return;
}
m_view = m_viewport2D->GetView();
if( m_view == nullptr )
{
return;
}
m_viewportWidth = m_view->GetBoundary().GetWidth();
if( !IsEnabled() )
{
// Use the default settings for the connexion to the 3DMouse navigation
// They are use a single-threaded threading model and row vectors.
EnableNavigation( true );
// Use the SpaceMouse internal timing source for the frame rate.
PutFrameTimingSource( TimingSource::SpaceMouse );
exportCommandsAndImages();
}
}
void NL_GERBVIEW_PLUGIN_IMPL::SetFocus( bool aFocus )
{
wxLogTrace( m_logTrace, wxT( "NL_GERBVIEW_PLUGIN_IMPL::SetFocus %d" ), aFocus );
NAV_3D::Write( navlib::focus_k, aFocus );
}
// temporary store for the command categories
using CATEGORY_STORE = std::map<std::string, TDx::CCommandTreeNode*, std::less<>>;
/**
* Add a category to the store.
*
* The function adds category paths of the format "A.B" where B is a sub-category of A.
*
* @param aCategoryPath is the std::string representation of the category.
* @param aCategoryStore is the CATEGORY_STORE instance to add to.
*/
static void add_category( const std::string& aCategoryPath, CATEGORY_STORE& aCategoryStore )
{
using TDx::SpaceMouse::CCategory;
auto parent_iter = aCategoryStore.begin();
std::string::size_type pos = aCategoryPath.find_last_of( '.' );
if( pos != std::string::npos )
{
std::string parentPath = aCategoryPath.substr( 0, pos );
if( aCategoryStore.find( parentPath ) == aCategoryStore.end() )
{
add_category( parentPath, aCategoryStore );
parent_iter = aCategoryStore.find( parentPath );
}
}
std::string name = aCategoryPath.substr( pos + 1 );
auto categoryNode = std::make_unique<CCategory>( aCategoryPath.c_str(), name.c_str() );
aCategoryStore.try_emplace( aCategoryStore.end(), aCategoryPath, categoryNode.get() );
parent_iter->second->push_back( std::move( categoryNode ) );
}
/**
* add_category wrapper.
*
* Function checks if path exists in the category and adds it if it doesn't.
*
* @param aCategoryPath is the std::string representation of the category.
* @param aCategoryStore is the CATEGORY_STORE instance to add to.
*/
static void try_add_category( const std::string& aCategoryPath, CATEGORY_STORE& aCategoryStore )
{
if( aCategoryStore.find( aCategoryPath ) == aCategoryStore.end() )
{
add_category( aCategoryPath, aCategoryStore );
}
}
void NL_GERBVIEW_PLUGIN_IMPL::exportCommandsAndImages()
{
wxLogTrace( m_logTrace, wxT( "NL_GERBVIEW_PLUGIN_IMPL::exportCommandsAndImages" ) );
std::list<TOOL_ACTION*> actions = ACTION_MANAGER::GetActionList();
if( actions.empty() )
return;
using TDx::SpaceMouse::CCommand;
using TDx::SpaceMouse::CCommandSet;
// The root action set node
CCommandSet commandSet( "GERBER_EDITOR", "Gerber Viewer" );
// Activate the command set
NAV_3D::PutActiveCommands( commandSet.GetId() );
// temporary store for the categories initialized with action set
CATEGORY_STORE categoryStore{ CATEGORY_STORE::value_type( ".", &commandSet ) };
std::vector<TDx::CImage> vImages;
for( const auto action : actions )
{
std::string label = action->GetMenuLabel().ToStdString();
if( label.empty() )
continue;
std::string name = action->GetName();
// Do no export commands for the 3DViewer app.
if( name.rfind( "3DViewer.", 0 ) == 0 )
continue;
std::string strCategory = action->GetToolName();
std::string description = action->GetDescription().ToStdString();
try_add_category( strCategory, categoryStore );
CATEGORY_STORE::iterator iter = categoryStore.find( strCategory );
// Arbitrary 8-bit data stream
wxMemoryOutputStream imageStream;
if( action->GetIcon() != BITMAPS::INVALID_BITMAP )
{
wxImage image = KiBitmap( action->GetIcon() ).ConvertToImage();
image.SaveFile( imageStream, wxBitmapType::wxBITMAP_TYPE_PNG );
image.Destroy();
if( imageStream.GetSize() )
{
const wxStreamBuffer* streamBuffer = imageStream.GetOutputStreamBuffer();
TDx::CImage tdxImage = TDx::CImage::FromData( "", 0, name.c_str() );
tdxImage.AssignImage(
std::string( static_cast<const char*>( streamBuffer->GetBufferStart() ),
streamBuffer->GetBufferSize() ),
0 );
wxLogTrace( m_logTrace, wxT( "Adding image for : %s" ), name );
vImages.push_back( std::move( tdxImage ) );
}
}
wxLogTrace( m_logTrace, wxT( "Inserting command: %s, description: %s, in category: %s" ),
name, description, iter->first );
iter->second->push_back(
CCommand( std::move( name ), std::move( label ), std::move( description ) ) );
}
NAV_3D::AddCommandSet( commandSet );
NAV_3D::AddImages( vImages );
}
long NL_GERBVIEW_PLUGIN_IMPL::GetCameraMatrix( navlib::matrix_t& matrix ) const
{
if( m_view == nullptr )
return navlib::make_result_code( navlib::navlib_errc::no_data_available );
m_viewPosition = m_view->GetCenter();
double x = m_view->IsMirroredX() ? -1 : 1;
double y = m_view->IsMirroredY() ? 1 : -1;
// x * y * z = 1 for a right-handed coordinate system.
double z = x * y;
// Note: the connexion has been configured as row vectors, the coordinate system is defined in
// NL_GERBVIEW_PLUGIN_IMPL::GetCoordinateSystem and the front view in NL_GERBVIEW_PLUGIN_IMPL::GetFrontView.
matrix = { { { x, 0, 0, 0, 0, y, 0, 0, 0, 0, z, 0, m_viewPosition.x, m_viewPosition.y, 0,
1 } } };
return 0;
}
long NL_GERBVIEW_PLUGIN_IMPL::GetPointerPosition( navlib::point_t& position ) const
{
if( m_view == nullptr )
return navlib::make_result_code( navlib::navlib_errc::no_data_available );
VECTOR2D mouse_pointer = m_viewport2D->GetViewControls()->GetMousePosition();
position.x = mouse_pointer.x;
position.y = mouse_pointer.y;
position.z = 0;
return 0;
}
long NL_GERBVIEW_PLUGIN_IMPL::GetViewExtents( navlib::box_t& extents ) const
{
if( m_view == nullptr )
return navlib::make_result_code( navlib::navlib_errc::no_data_available );
double scale = m_viewport2D->GetGAL()->GetWorldScale();
BOX2D box = m_view->GetViewport();
m_viewportWidth = box.GetWidth();
extents.min_x = -box.GetWidth() / 2.0;
extents.min_y = -box.GetHeight() / 2.0;
extents.min_z = m_viewport2D->GetGAL()->GetMinDepth() / scale;
extents.max_x = box.GetWidth() / 2.0;
extents.max_y = box.GetHeight() / 2.0;
extents.max_z = m_viewport2D->GetGAL()->GetMaxDepth() / scale;
return 0;
}
long NL_GERBVIEW_PLUGIN_IMPL::GetIsViewPerspective( navlib::bool_t& perspective ) const
{
perspective = false;
return 0;
}
long NL_GERBVIEW_PLUGIN_IMPL::SetCameraMatrix( const navlib::matrix_t& matrix )
{
if( m_view == nullptr )
return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
long result = 0;
VECTOR2D viewPos( matrix.m4x4[3][0], matrix.m4x4[3][1] );
if( !equals( m_view->GetCenter(), m_viewPosition,
static_cast<VECTOR2D::coord_type>( FLT_EPSILON ) ) )
{
m_view->SetCenter( viewPos + m_view->GetCenter() - m_viewPosition );
result = navlib::make_result_code( navlib::navlib_errc::error );
}
else
{
m_view->SetCenter( viewPos );
}
m_viewPosition = viewPos;
return result;
}
long NL_GERBVIEW_PLUGIN_IMPL::SetViewExtents( const navlib::box_t& extents )
{
if( m_view == nullptr )
return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
long result = 0;
if( m_viewportWidth != m_view->GetViewport().GetWidth() )
result = navlib::make_result_code( navlib::navlib_errc::error );
double width = m_viewportWidth;
m_viewportWidth = extents.max_x - extents.min_x;
double scale = width / m_viewportWidth * m_view->GetScale();
m_view->SetScale( scale, m_view->GetCenter() );
if( !equals( m_view->GetScale(), scale, static_cast<double>( FLT_EPSILON ) ) )
result = navlib::make_result_code( navlib::navlib_errc::error );
return result;
}
long NL_GERBVIEW_PLUGIN_IMPL::SetViewFOV( double fov )
{
return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
}
long NL_GERBVIEW_PLUGIN_IMPL::SetViewFrustum( const navlib::frustum_t& frustum )
{
return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
}
long NL_GERBVIEW_PLUGIN_IMPL::GetModelExtents( navlib::box_t& extents ) const
{
if( m_view == nullptr )
return navlib::make_result_code( navlib::navlib_errc::no_data_available );
BOX2I box = static_cast<GERBVIEW_FRAME*>( m_viewport2D->GetParent() )->GetDocumentExtents();
box.Normalize();
double half_depth = 0.1 / m_viewport2D->GetGAL()->GetWorldScale();
if( box.GetWidth() == 0 && box.GetHeight() == 0 )
half_depth = 0;
extents.min_x = static_cast<double>( box.GetOrigin().x );
extents.min_y = static_cast<double>( box.GetOrigin().y );
extents.min_z = -half_depth;
extents.max_x = static_cast<double>( box.GetEnd().x );
extents.max_y = static_cast<double>( box.GetEnd().y );
extents.max_z = half_depth;
return 0;
}
long NL_GERBVIEW_PLUGIN_IMPL::GetCoordinateSystem( navlib::matrix_t& matrix ) const
{
// The coordinate system is defined as x to the right, y down and z into the screen.
matrix = { { { 1, 0, 0, 0, 0, -1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 1 } } };
return 0;
}
long NL_GERBVIEW_PLUGIN_IMPL::GetFrontView( navlib::matrix_t& matrix ) const
{
matrix = { { { 1, 0, 0, 0, 0, -1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 1 } } };
return 0;
}
long NL_GERBVIEW_PLUGIN_IMPL::GetIsSelectionEmpty( navlib::bool_t& empty ) const
{
empty = true;
return 0;
}
long NL_GERBVIEW_PLUGIN_IMPL::GetIsViewRotatable( navlib::bool_t& isRotatable ) const
{
isRotatable = false;
return 0;
}
long NL_GERBVIEW_PLUGIN_IMPL::SetActiveCommand( std::string commandId )
{
if( commandId.empty() )
return 0;
if(m_viewport2D == nullptr)
{
return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
}
wxWindow* parent = m_viewport2D->GetParent();
// Only allow command execution if the window is enabled. i.e. there is not a modal dialog
// currently active.
if( parent == nullptr || !parent->IsEnabled() )
{
return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
}
TOOL_MANAGER* tool_manager = dynamic_cast<TOOLS_HOLDER*>( parent )->GetToolManager();
// Only allow for command execution if the tool manager is accessible.
if( tool_manager == nullptr )
{
return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
}
std::list<TOOL_ACTION*> actions = ACTION_MANAGER::GetActionList();
for( const auto action : actions )
{
if( action == nullptr )
{
continue;
}
if( commandId == action->GetName() )
{
// Get the selection to use to test if the action is enabled
const SELECTION& sel = tool_manager->GetToolHolder()->GetCurrentSelection();
const ACTION_CONDITIONS* aCond =
tool_manager->GetActionManager()->GetCondition( *action );
if( aCond == nullptr )
{
return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
}
aCond->enableCondition( sel );
tool_manager->RunAction( *action );
break;
}
}
return 0;
}
long NL_GERBVIEW_PLUGIN_IMPL::SetSettingsChanged( long change )
{
return 0;
}
long NL_GERBVIEW_PLUGIN_IMPL::SetMotionFlag( bool value )
{
m_isMoving = value;
return 0;
}
long NL_GERBVIEW_PLUGIN_IMPL::SetTransaction( long value )
{
if( value == 0L )
m_viewport2D->ForceRefresh();
return 0;
}
long NL_GERBVIEW_PLUGIN_IMPL::GetViewFOV( double& fov ) const
{
return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
}
long NL_GERBVIEW_PLUGIN_IMPL::GetViewFrustum( navlib::frustum_t& frustum ) const
{
return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
}
long NL_GERBVIEW_PLUGIN_IMPL::GetSelectionExtents( navlib::box_t& extents ) const
{
return navlib::make_result_code( navlib::navlib_errc::no_data_available );
}
long NL_GERBVIEW_PLUGIN_IMPL::GetSelectionTransform( navlib::matrix_t& transform ) const
{
return navlib::make_result_code( navlib::navlib_errc::no_data_available );
}
long NL_GERBVIEW_PLUGIN_IMPL::SetSelectionTransform( const navlib::matrix_t& matrix )
{
return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
}
long NL_GERBVIEW_PLUGIN_IMPL::GetPivotPosition( navlib::point_t& position ) const
{
return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
}
long NL_GERBVIEW_PLUGIN_IMPL::IsUserPivot( navlib::bool_t& userPivot ) const
{
return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
}
long NL_GERBVIEW_PLUGIN_IMPL::SetPivotPosition( const navlib::point_t& position )
{
return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
}
long NL_GERBVIEW_PLUGIN_IMPL::GetPivotVisible( navlib::bool_t& visible ) const
{
return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
}
long NL_GERBVIEW_PLUGIN_IMPL::SetPivotVisible( bool visible )
{
return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
}
long NL_GERBVIEW_PLUGIN_IMPL::GetHitLookAt( navlib::point_t& position ) const
{
return navlib::make_result_code( navlib::navlib_errc::no_data_available );
}
long NL_GERBVIEW_PLUGIN_IMPL::SetHitAperture( double aperture )
{
return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
}
long NL_GERBVIEW_PLUGIN_IMPL::SetHitDirection( const navlib::vector_t& direction )
{
return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
}
long NL_GERBVIEW_PLUGIN_IMPL::SetHitLookFrom( const navlib::point_t& eye )
{
return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
}
long NL_GERBVIEW_PLUGIN_IMPL::SetHitSelectionOnly( bool onlySelection )
{
return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
}
long NL_GERBVIEW_PLUGIN_IMPL::SetCameraTarget( const navlib::point_t& position )
{
return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
}
+147
View File
@@ -0,0 +1,147 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2024 3Dconnexion
* Copyright (C) 2022 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License 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/>.
*/
/**
* @file nl_gerbview_plugin_impl.h
* @brief Declaration of the NL_GERBVIEW_PLUGIN_IMPL class
*/
#ifndef NL_GERBVIEW_PLUGIN_IMPL_H_
#define NL_GERBVIEW_PLUGIN_IMPL_H_
#if _WIN32
#ifndef _WIN32_WINNT
#define _WIN32_WINNT 0x0603
#endif
#endif
// TDxWare SDK.
#include <SpaceMouse/CNavigation3D.hpp>
// wx
#include <wx/chartype.h>
// KiCAD
#include <math/vector2d.h>
// stdlib
#include <string>
// Forward declarations.
class EDA_DRAW_PANEL_GAL;
namespace KIGFX
{
class VIEW;
}
// Convenience typedef.
typedef TDx::SpaceMouse::Navigation3D::CNavigation3D NAV_3D;
/**
* The class that implements the accessors and mutators required for
* 3D navigation in an PCB_DRAW_PANEL_GAL using a SpaceMouse.
*/
class NL_GERBVIEW_PLUGIN_IMPL : public NAV_3D
{
public:
/**
* Initializes a new instance of the NL_GERBVIEW_PLUGIN_IMPL.
*/
NL_GERBVIEW_PLUGIN_IMPL();
virtual ~NL_GERBVIEW_PLUGIN_IMPL();
/**
* Sets the viewport controlled by the SpaceMouse.
*
* @param aViewport is the viewport to be navigated.
*/
void SetCanvas( EDA_DRAW_PANEL_GAL* aViewport );
/**
* Set the connection to the 3Dconnexion driver to the focus state so that
* 3DMouse data is routed here.
*
* @param aFocus is true to set the connection active.
*/
void SetFocus( bool aFocus );
private:
/**
* Export the invocable actions and images to the 3Dconnexion UI.
*/
void exportCommandsAndImages();
long GetCameraMatrix( navlib::matrix_t& aMatrix ) const override;
long GetPointerPosition( navlib::point_t& aPosition ) const override;
long GetViewExtents( navlib::box_t& aExtents ) const override;
long GetViewFOV( double& aFov ) const override;
long GetViewFrustum( navlib::frustum_t& aFrustum ) const override;
long GetIsViewPerspective( navlib::bool_t& aPerspective ) const override;
long SetCameraMatrix( const navlib::matrix_t& aMatrix ) override;
long SetViewExtents( const navlib::box_t& aExtents ) override;
long SetViewFOV( double aFov ) override;
long SetViewFrustum( const navlib::frustum_t& aFrustum ) override;
long GetModelExtents( navlib::box_t& aExtents ) const override;
long GetSelectionExtents( navlib::box_t& aExtents ) const override;
long GetSelectionTransform( navlib::matrix_t& aTransform ) const override;
long GetIsSelectionEmpty( navlib::bool_t& aEmpty ) const override;
long SetSelectionTransform( const navlib::matrix_t& aMatrix ) override;
long GetPivotPosition( navlib::point_t& aPosition ) const override;
long IsUserPivot( navlib::bool_t& aUserPivot ) const override;
long SetPivotPosition( const navlib::point_t& aPosition ) override;
long GetPivotVisible( navlib::bool_t& aVisible ) const override;
long SetPivotVisible( bool aVisible ) override;
long GetHitLookAt( navlib::point_t& aPosition ) const override;
long SetHitAperture( double aAperture ) override;
long SetHitDirection( const navlib::vector_t& aDirection ) override;
long SetHitLookFrom( const navlib::point_t& aPosition ) override;
long SetHitSelectionOnly( bool aSelectionOnly ) override;
long SetActiveCommand( std::string aCommandId ) override;
long SetSettingsChanged( long aChangeNumber ) override;
long SetMotionFlag( bool aValue ) override;
long SetTransaction( long aValue ) override;
long SetCameraTarget( const navlib::point_t& aPosition ) override;
long GetFrontView( navlib::matrix_t& aMatrix ) const override;
long GetCoordinateSystem( navlib::matrix_t& aMatrix ) const override;
long GetIsViewRotatable( navlib::bool_t& isRotatable ) const override;
private:
EDA_DRAW_PANEL_GAL* m_viewport2D = nullptr;
KIGFX::VIEW* m_view = nullptr;
bool m_isMoving = false;
mutable double m_viewportWidth = 0.0;
mutable VECTOR2D m_viewPosition;
/**
* Trace mask used to enable or disable the trace output of this class.
* The debug output can be turned on by setting the WXTRACE environment variable to
* "KI_TRACE_NL_GERBVIEW_PLUGIN". See the wxWidgets documentation on wxLogTrace for
* more information.
*/
static const wxChar* m_logTrace;
};
#endif // NL_GERBVIEW_PLUGIN_IMPL
+10 -1
View File
@@ -567,8 +567,17 @@ public:
*/
bool m_EnableCacheFriendlyFracture;
///@}
/**
* Minimum overlapping angle for which an arc is considered to be parallel
* to its paired arc.
*
* Setting name: "MinParallelAngle"
* Valid values: 0 to 45
* Default value: 0.001
*/
double m_MinParallelAngle;
///@}
private:
ADVANCED_CFG();
+3 -5
View File
@@ -4,7 +4,7 @@
* Copyright (C) 2014-2020 Jean-Pierre Charras, jp.charras at wanadoo.fr
* Copyright (C) 2007-2015 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
* Copyright (C) 2008 Wayne Stambaugh <stambaughw@gmail.com>
* Copyright (C) 1992-2023 KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 1992-2023, 2024 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -102,11 +102,9 @@ wxString GetTextVars( const wxString& aSource );
bool IsTextVar( const wxString& aSource );
/**
* Replace any environment and/or text variables in file-path uris (leaving network-path URIs
* alone).
* Replace any environment and/or text variables in URIs
*/
const wxString ResolveUriByEnvVars( const wxString& aUri, PROJECT* aProject );
const wxString ResolveUriByEnvVars( const wxString& aUri, const PROJECT* aProject );
long long TimestampDir( const wxString& aDirPath, const wxString& aFilespec );
+5 -1
View File
@@ -1,7 +1,7 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2018-2021 KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 2018-2024 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
@@ -156,6 +156,8 @@ private:
void onHSVMouseClick( wxMouseEvent& event ) override;
void onHSVMouseDrag( wxMouseEvent& event ) override;
void onSize( wxSizeEvent& event ) override;
void OnColorValueText( wxCommandEvent& event ) override;
///< Event handler for the reset button press
@@ -187,6 +189,8 @@ private:
*/
void initDefinedColors( CUSTOM_COLORS_LIST* aPredefinedColors );
void updateHandleSize();
// convert double value 0 ... 1 to int 0 ... aValMax
int normalizeToInt( double aValue, int aValMax = 255 )
{
+23
View File
@@ -136,10 +136,33 @@ public:
}
double GetTextAngleDegrees() const { return m_attributes.m_Angle.AsDegrees(); }
/**
* Set the text to be italic - this will also update the font if needed.
*
* This is the properties system interface.
*/
void SetItalic( bool aItalic );
/**
* Set only the italic flag, without changing the font.
*
* Used when bulk-changing text attributes (e.g. from a dialog or import).
*/
void SetItalicFlag( bool aItalic );
bool IsItalic() const { return m_attributes.m_Italic; }
/**
* Set the text to be bold - this will also update the font if needed.
*
* This is the properties system interface.
*/
void SetBold( bool aBold );
/**
* Set only the italic flag, without changing the font.
*
* Used when bulk-changing text attributes (e.g. from a dialog or import).
*/
void SetBoldFlag( bool aBold );
bool IsBold() const { return m_attributes.m_Bold; }
+1
View File
@@ -85,6 +85,7 @@ public:
// If true, keep rotation angle between -90...90 degrees for readability
bool m_KeepUpright;
int m_StoredStrokeWidth;
};
+17
View File
@@ -81,6 +81,23 @@ public:
return wxEmptyString;
}
bool CanGetValueAs( int aRow, int aCol, const wxString& aTypeName ) override
{
if( aRow < (int) size() )
{
switch( aCol )
{
case COL_ENABLED:
case COL_VISIBLE:
return aTypeName == wxGRID_VALUE_BOOL;
default:
return aTypeName == wxGRID_VALUE_STRING;
}
}
return false;
}
bool GetValueAsBool( int aRow, int aCol ) override
{
if( aRow < (int) size() && aCol == COL_ENABLED )
+4 -2
View File
@@ -2,7 +2,7 @@
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2016 Jean-Pierre Charras, jp.charras at wanadoo.fr
* Copyright (C) 2016-2023 KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 2016-2023, 2024 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -107,7 +107,7 @@ public:
static const int DO_NOT_SET_LINE_WIDTH = -2; // Skip selection
static const int USE_DEFAULT_LINE_WIDTH = -1; // use the default pen
PLOTTER();
PLOTTER( const PROJECT* aProject = nullptr );
virtual ~PLOTTER();
@@ -675,6 +675,8 @@ protected: // variables used in most of plotters:
wxArrayString m_headerExtraLines; // a set of string to print in header file
RENDER_SETTINGS* m_renderSettings;
const PROJECT* m_project;
};
+8 -5
View File
@@ -1,7 +1,7 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2016-2023 KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 2016-2023, 2024 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
@@ -35,7 +35,8 @@
class PSLIKE_PLOTTER : public PLOTTER
{
public:
PSLIKE_PLOTTER() :
PSLIKE_PLOTTER( const PROJECT* aProject = nullptr) :
PLOTTER( aProject ),
plotScaleAdjX( 1 ),
plotScaleAdjY( 1 ),
m_textMode( PLOT_TEXT_MODE::PHANTOM )
@@ -143,7 +144,8 @@ protected:
class PS_PLOTTER : public PSLIKE_PLOTTER
{
public:
PS_PLOTTER()
PS_PLOTTER( const PROJECT* aProject = nullptr ) :
PSLIKE_PLOTTER( aProject )
{
// The phantom plot in postscript is an hack and reportedly
// crashes Adobe's own postscript interpreter!
@@ -238,7 +240,8 @@ protected:
class PDF_PLOTTER : public PSLIKE_PLOTTER
{
public:
PDF_PLOTTER() :
PDF_PLOTTER( const PROJECT* aProject = nullptr ) :
PSLIKE_PLOTTER( aProject ),
m_pageTreeHandle( 0 ),
m_fontResDictHandle( 0 ),
m_imgResDictHandle( 0 ),
@@ -518,7 +521,7 @@ protected:
class SVG_PLOTTER : public PSLIKE_PLOTTER
{
public:
SVG_PLOTTER();
SVG_PLOTTER( const PROJECT* aProject = nullptr );
static wxString GetDefaultFileExtension()
{
+4 -1
View File
@@ -102,7 +102,7 @@ public:
/**
* Stores the current parameters into the JSON document represented by this object
* Note: this doesn't do any writing to disk; that's handled by SETTINGS_MANAGER
* @return true if any part of the JSON document was updated
* @return true if any part of the JSON document has been updated since the last save to disk
*/
virtual bool Store();
@@ -320,6 +320,9 @@ protected:
/// Whether or not the backing store file should be written
bool m_writeFile;
/// True if the JSON data store has been written to since the last file write
bool m_modified;
/// Whether or not to delete legacy file after migration
bool m_deleteLegacyAfterMigration;
+2
View File
@@ -75,6 +75,8 @@ public:
*/
bool ClearUnknownKeys() const { return m_clearUnknownKeys; }
void SetClearUnknownKeys( bool aSet = true ) { m_clearUnknownKeys = aSet; }
protected:
std::string m_path; ///< Address of the param in the json files
bool m_readOnly; ///< Indicates param pointer should never be overwritten
+26 -2
View File
@@ -1,7 +1,7 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2004-2021 KiCad Developers, see change_log.txt for contributors.
* Copyright (C) 2004-2021, 2024 KiCad Developers, see change_log.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
@@ -231,6 +231,13 @@ KICOMMON_API int GetTrailingInt( const wxString& aStr );
*/
KICOMMON_API wxString GetIllegalFileNameWxChars();
/**
* Checks if a full filename is valid, i.e. does not contains illegal chars
* path separators are allowed
* @return true if OK.
*/
KICOMMON_API bool IsFullFileNameValid( const wxString& aFullFilename );
/**
* Checks \a aName for illegal file name characters.
*
@@ -392,10 +399,27 @@ KICOMMON_API std::string FormatDouble2Str( double aValue );
/**
* Convert an expected UTF8 encoded std::string to a wxString.
* If fails, tray to convert using current locale
* If fails, try to convert using current locale
* If still fails, return the initial string (can be already a converted string)
*/
KICOMMON_API wxString From_UTF8( const std::string& aString );
KICOMMON_API wxString From_UTF8( const char* cstring );
/**
* Normalize file path \a aFileUri to URI convention.
*
* Unfortunately none of the wxWidgets objects results in acceptable file URIs which breaks
* PDF plotting URI links. This is an attempt to normalize Windows local file paths to a
* URI that PDF readers that can run JavaScript can handle.
*
* @note This does not expand environment or user variables. Variable expansion should be
* performed before calling. If \a aFileUri does not begin with 'file://', \a aFileUri
* returned unchanged.
*
* @param aFileUri is the string to be normalized.
* @return the normalized string.
*/
KICOMMON_API wxString NormalizeFileUri( const wxString& aFileUri );
#endif // STRING_UTILS_H
+2
View File
@@ -235,6 +235,8 @@ public:
*/
virtual bool Validate( wxWindow* aParent ) override;
bool DoValidate( const wxString& aValue, wxWindow* aParent );
private:
int m_fieldId;
};
+6 -6
View File
@@ -48,8 +48,8 @@ public:
*/
void Insert( VIEW_ITEM* aItem, const BOX2I& bbox )
{
const int mmin[2] = { bbox.GetX(), bbox.GetY() };
const int mmax[2] = { bbox.GetRight(), bbox.GetBottom() };
const int mmin[2] = { std::min( bbox.GetX(), bbox.GetRight() ), std::min( bbox.GetY(), bbox.GetBottom() ) };
const int mmax[2] = { std::max( bbox.GetX(), bbox.GetRight() ), std::max( bbox.GetY(), bbox.GetBottom() ) };
VIEW_RTREE_BASE::Insert( mmin, mmax, aItem );
}
@@ -65,8 +65,8 @@ public:
if( aBbox )
{
const int mmin[2] = { aBbox->GetX(), aBbox->GetY() };
const int mmax[2] = { aBbox->GetRight(), aBbox->GetBottom() };
const int mmin[2] = { std::min( aBbox->GetX(), aBbox->GetRight() ), std::min( aBbox->GetY(), aBbox->GetBottom() ) };
const int mmax[2] = { std::max( aBbox->GetX(), aBbox->GetRight() ), std::max( aBbox->GetY(), aBbox->GetBottom() ) };
VIEW_RTREE_BASE::Remove( mmin, mmax, aItem );
return;
}
@@ -85,8 +85,8 @@ public:
template <class Visitor>
void Query( const BOX2I& aBounds, Visitor& aVisitor ) const
{
int mmin[2] = { aBounds.GetX(), aBounds.GetY() };
int mmax[2] = { aBounds.GetRight(), aBounds.GetBottom() };
int mmin[2] = { std::min( aBounds.GetX(), aBounds.GetRight() ), std::min( aBounds.GetY(), aBounds.GetBottom() ) };
int mmax[2] = { std::max( aBounds.GetX(), aBounds.GetRight() ), std::max( aBounds.GetY(), aBounds.GetBottom() ) };
// We frequently use the maximum bounding box to recache all items
// or for any item that overflows the integer width limits of BBOX2I
+21 -4
View File
@@ -2241,12 +2241,29 @@ void PROJECT_TREE_PANE::onGitCommit( wxCommandEvent& aEvent )
git_oid oid;
#if( LIBGIT2_VER_MAJOR == 1 && LIBGIT2_VER_MINOR == 8 && LIBGIT2_VER_REVISION < 2 )
// For libgit2 versions 1.8.0, 1.8.1.
// This change was reverted for 1.8.2+
#if( LIBGIT2_VER_MAJOR == 1 && LIBGIT2_VER_MINOR == 8 \
&& ( LIBGIT2_VER_REVISION < 2 || LIBGIT2_VER_REVISION == 3 ) )
/*
* For libgit2 versions 1.8.0, 1.8.1. (cf19ddc52)
* This change was reverted for 1.8.2 (49d3fadfc, main branch)
* The revert for 1.8.2 was not included for 1.8.3 (which is on the maint/v1.8 branch, not main)
* This change was also reverted for 1.8.4 (94ba816f6, also maint/v1.8 branch)
*
* As of 1.8.4, the history is like this:
*
* * 3f4182d15 (tag: v1.8.4, maint/v1.8)
* * 94ba816f6 Revert "commit: fix const declaration" [puts const back]
* * 3353f78e8 (tag: v1.8.3)
* | * 4ce872a0f (tag: v1.8.2-rc1, tag: v1.8.2)
* | * 49d3fadfc Revert "commit: fix const declaration" [puts const back]
* |/
* * 36f7e21ad (tag: v1.8.1)
* * d74d49148 (tag: v1.8.0)
* * cf19ddc52 commit: fix const declaration [removes const]
*/
git_commit* const parents[1] = { parent };
#else
// For libgit2 versions older than 1.8.0
// For libgit2 versions older than 1.8.0, or equal to 1.8.2, or 1.8.4+
const git_commit* parents[1] = { parent };
#endif

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