Compare commits
256 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f67945aae9 | |||
| f74e4fa73e | |||
| efaa3b5ca8 | |||
| 0ad919d043 | |||
| dc2b87aa75 | |||
| b65d3c80a3 | |||
| 12e03b0fcf | |||
| e964ccb6b5 | |||
| 994cabf4c0 | |||
| 5f9f31605f | |||
| db2b94e1c6 | |||
| a37ffabd27 | |||
| de8b22ac10 | |||
| 30f6135ad6 | |||
| 9e50e37fdd | |||
| 50d8178482 | |||
| e4cf45edce | |||
| b6b85fa652 | |||
| dad2e485da | |||
| 63999f25fa | |||
| f23f43961f | |||
| 16594a65a2 | |||
| de32417df1 | |||
| bb779c87f3 | |||
| 3dedd899f7 | |||
| 5eb265080f | |||
| 3329affc12 | |||
| fce66a0372 | |||
| 780df7262b | |||
| 8a3a11e2f8 | |||
| 5878ac5aaf | |||
| 22cebd8e71 | |||
| 0f2f953476 | |||
| 205db57971 | |||
| d607249e81 | |||
| 5b9b49cf2b | |||
| 045b00bac7 | |||
| c297a4e2b3 | |||
| 4c9273206a | |||
| 8530b71833 | |||
| 67cca8db25 | |||
| 84cc67c9df | |||
| 044a7ca39e | |||
| 1d09917e3e | |||
| b5658962be | |||
| 0a1d209255 | |||
| dbf0150cec | |||
| 8871b0385d | |||
| 9f20816b24 | |||
| f3566a987d | |||
| a6210da126 | |||
| ebad7dfc0d | |||
| ab82dc5839 | |||
| cfc1f14282 | |||
| 479b3e6c72 | |||
| 27c573ca42 | |||
| e28381841a | |||
| 37ac2ee0a3 | |||
| 42397a6ce1 | |||
| e29131f265 | |||
| b4d03e2eeb | |||
| 5bd565211b | |||
| dd654ddd9a | |||
| 303a90eb65 | |||
| 7be9021ba3 | |||
| 843d01f27b | |||
| bdc1cbda27 | |||
| 51e094eb34 | |||
| ccec31da71 | |||
| fe3bbee807 | |||
| 12cb6fc043 | |||
| 1c3efdf212 | |||
| 5d4f66a613 | |||
| 711184ef62 | |||
| 9b4809e10f | |||
| 9109c4cd27 | |||
| 20c68f9c8d | |||
| 9950d046cb | |||
| ff44242682 | |||
| f671f4db51 | |||
| 406e7acaac | |||
| a3eca13ad3 | |||
| 73053a2177 | |||
| 5992d7331a | |||
| 9767a083cc | |||
| 07c9aee1ea | |||
| fc0911f55e | |||
| b74fef1b10 | |||
| 127874a7b9 | |||
| ecce28a472 | |||
| e93dacb788 | |||
| 6c4734c370 | |||
| 93a63a61ec | |||
| 57b9c1bdaf | |||
| b166e866e0 | |||
| 9fa2549d7a | |||
| f9cb5a26a3 | |||
| cbd40cb5e4 | |||
| 352672f8bf | |||
| 6dc5c2b24a | |||
| fa63bd24f4 | |||
| 10750bc460 | |||
| afb4b1411d | |||
| 74d7711e37 | |||
| 585693f0b3 | |||
| 186f5e65a7 | |||
| 1fd1cde3bf | |||
| dcadff46b7 | |||
| 62bb553460 | |||
| 0f32217cf0 | |||
| 0ec479c17f | |||
| 4ede3b3f2b | |||
| 22feba7bbf | |||
| b6eef921a4 | |||
| 567d0dca95 | |||
| 7a869fc503 | |||
| 8b6274af16 | |||
| 581715f7aa | |||
| 1c7a64b0ea | |||
| 8fb25f5577 | |||
| 88ae436249 | |||
| bf6bcba7bb | |||
| 10205bb432 | |||
| aa1fc43048 | |||
| 9c12ba60aa | |||
| 3c21938295 | |||
| 8d9e254e0c | |||
| e52dafcaaf | |||
| 676b7d1739 | |||
| 490d3152ab | |||
| 1b68a4f98e | |||
| 58fac19a5c | |||
| 65850682a8 | |||
| 6c4df9aca9 | |||
| b110861ba1 | |||
| 13fcb571f7 | |||
| 9738a71922 | |||
| f45e3ca339 | |||
| c579e11db4 | |||
| 819f75e17c | |||
| 0828ee3b10 | |||
| 35094a786d | |||
| add2215e5a | |||
| efa99b1e71 | |||
| 1ebc66b9e2 | |||
| c852055ae1 | |||
| 8fb2cecd64 | |||
| 5d2952cd24 | |||
| 4a1fe267ca | |||
| 694b37b852 | |||
| 253f7deb62 | |||
| 3e62bbf561 | |||
| 0f9c75749d | |||
| 9c7f1d261f | |||
| 44a4800383 | |||
| 2e6f01b871 | |||
| 41bb627ef2 | |||
| b2fa06b5f5 | |||
| 69e9aa917a | |||
| 507bebda80 | |||
| e4a66c8a11 | |||
| ecdee78368 | |||
| 763ee75856 | |||
| 07fb0804ac | |||
| ced1c742c8 | |||
| 029b0e709a | |||
| 43ffccc67f | |||
| 23e9b733ee | |||
| f4ffa8123b | |||
| fd9e976346 | |||
| 85db61b8d3 | |||
| a2e1ac3972 | |||
| 0c3f2fd4b4 | |||
| b71f32e1b4 | |||
| f478643411 | |||
| 39cf1fea22 | |||
| f967d6ab43 | |||
| 448da01cea | |||
| a25888b4ba | |||
| 7f3508b8b3 | |||
| 1d880cdcf6 | |||
| c855702918 | |||
| 51023a1ae4 | |||
| 35364bd8ad | |||
| 0f715223e9 | |||
| 9ceace2a47 | |||
| 6e93c08ff2 | |||
| 3744cfd987 | |||
| 245abd5f16 | |||
| f559b49f44 | |||
| 8e9f50f465 | |||
| ae39cfb1be | |||
| 259c34d12b | |||
| fbeeadfd0f | |||
| 9ed89a324b | |||
| 49c17a0ce5 | |||
| a11211ecd1 | |||
| 8d2c04b287 | |||
| 7834fc9214 | |||
| 6bebfdc65d | |||
| c35f4a0988 | |||
| 86660d055c | |||
| 59dae982d4 | |||
| 8a3bf672e7 | |||
| cc05e9d8fb | |||
| ada4f107e7 | |||
| 3db58c533b | |||
| 480e4290a0 | |||
| 89c96d50ef | |||
| dfc3a7bf5c | |||
| 10f0fa65f3 | |||
| d23a449d57 | |||
| 753c7ae666 | |||
| ac7fa777a6 | |||
| 2b63d9f175 | |||
| 744a3463b2 | |||
| f70fdad9ae | |||
| 42df6cbca2 | |||
| c2e39cbc5d | |||
| ed0046fcd0 | |||
| 5e2f979f36 | |||
| 0b1065ff55 | |||
| 7db48b81b6 | |||
| f0ce3167c0 | |||
| ace6439758 | |||
| e38b948f0b | |||
| 2f74d1466e | |||
| 85c324b5d7 | |||
| edddf8a660 | |||
| 193e7f894d | |||
| 32cc486d89 | |||
| 0aec789659 | |||
| f92cedab9a | |||
| f84f93b167 | |||
| d33fbd8e47 | |||
| 3ab23201b4 | |||
| 39236ae68f | |||
| 5ee89b41ac | |||
| ec0ff4ffc2 | |||
| 1b6b2d7896 | |||
| 036241c819 | |||
| 2dc81999ef | |||
| 3f8a5874e6 | |||
| 838674c4a7 | |||
| 98a8781d70 | |||
| 85f4ab3944 | |||
| 25db3032ee | |||
| d638f4cad0 | |||
| 32fe612045 | |||
| 76d463dcc8 | |||
| 2daa432261 | |||
| d7b2c81db5 | |||
| b597a4559f | |||
| 18e3227c9a | |||
| 41b847b3c9 | |||
| ae2aea8fc0 |
@@ -208,12 +208,6 @@ public:
|
||||
m_3dmousePivotPos = aPos;
|
||||
}
|
||||
|
||||
private:
|
||||
/**
|
||||
* Called by a wxPaintEvent event
|
||||
*/
|
||||
void OnPaint( wxPaintEvent& aEvent );
|
||||
|
||||
/**
|
||||
* The actual function to repaint the canvas.
|
||||
*
|
||||
@@ -222,6 +216,10 @@ private:
|
||||
*/
|
||||
void DoRePaint();
|
||||
|
||||
private:
|
||||
// The wxPaintEvent event. mainly calls DoRePaint()
|
||||
void OnPaint( wxPaintEvent& aEvent );
|
||||
|
||||
void OnEraseBackground( wxEraseEvent& event );
|
||||
|
||||
void OnRefreshRequest( wxEvent& aEvent );
|
||||
|
||||
@@ -794,8 +794,13 @@ void EDA_3D_VIEWER_FRAME::takeScreenshot( wxCommandEvent& event )
|
||||
}
|
||||
|
||||
// Be sure we have the latest 3D view (remember 3D view is buffered)
|
||||
m_canvas->Request_refresh( true );
|
||||
wxYield();
|
||||
// Also ensure any highlighted item is not highlighted when creating screen shot
|
||||
EDA_3D_VIEWER_SETTINGS::RENDER_SETTINGS& cfg = m_boardAdapter.m_Cfg->m_Render;
|
||||
bool allow_highlight = cfg.opengl_highlight_on_rollover;
|
||||
cfg.opengl_highlight_on_rollover = false;
|
||||
|
||||
m_canvas->DoRePaint(); // init first buffer
|
||||
m_canvas->DoRePaint(); // init second buffer
|
||||
|
||||
// Build image from the 3D buffer
|
||||
wxWindowUpdateLocker noUpdates( this );
|
||||
@@ -805,6 +810,8 @@ void EDA_3D_VIEWER_FRAME::takeScreenshot( wxCommandEvent& event )
|
||||
if( m_canvas )
|
||||
m_canvas->GetScreenshot( screenshotImage );
|
||||
|
||||
cfg.opengl_highlight_on_rollover = allow_highlight;
|
||||
|
||||
if( event.GetId() == ID_TOOL_SCREENCOPY_TOCLIBBOARD )
|
||||
{
|
||||
wxBitmap bitmap( screenshotImage );
|
||||
|
||||
@@ -167,7 +167,11 @@ BM2CMP_FRAME::BM2CMP_FRAME( KIWAY* aKiway, wxWindow* aParent ) :
|
||||
wxIcon icon;
|
||||
wxIconBundle icon_bundle;
|
||||
|
||||
icon.CopyFromBitmap( KiBitmap( BITMAPS::icon_bitmap2component ) );
|
||||
icon.CopyFromBitmap( KiBitmap( BITMAPS::icon_bitmap2component, 48 ) );
|
||||
icon_bundle.AddIcon( icon );
|
||||
icon.CopyFromBitmap( KiBitmap( BITMAPS::icon_bitmap2component, 128 ) );
|
||||
icon_bundle.AddIcon( icon );
|
||||
icon.CopyFromBitmap( KiBitmap( BITMAPS::icon_bitmap2component, 256 ) );
|
||||
icon_bundle.AddIcon( icon );
|
||||
icon.CopyFromBitmap( KiBitmap( BITMAPS::icon_bitmap2component_32 ) );
|
||||
icon_bundle.AddIcon( icon );
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
# KiCad.
|
||||
#
|
||||
# Note: This version string should follow the semantic versioning system
|
||||
set( KICAD_SEMANTIC_VERSION "7.0.10" )
|
||||
set( KICAD_SEMANTIC_VERSION "7.0.11" )
|
||||
|
||||
# Default the version to the semantic version.
|
||||
# This is overridden by the git repository tag though (if using git)
|
||||
|
||||
@@ -1013,6 +1013,28 @@ void BuildBitmapInfo( std::unordered_map<BITMAPS, std::vector<BITMAP_INFO>>& aBi
|
||||
aBitmapInfoCache[BITMAPS::icon_pagelayout_editor].emplace_back( BITMAPS::icon_pagelayout_editor, wxT( "icon_pagelayout_editor_dark_128.png" ), 128, wxT( "dark" ) );
|
||||
aBitmapInfoCache[BITMAPS::icon_bitmap2component].emplace_back( BITMAPS::icon_bitmap2component, wxT( "icon_bitmap2component_dark_128.png" ), 128, wxT( "dark" ) );
|
||||
aBitmapInfoCache[BITMAPS::icon_pcbcalculator].emplace_back( BITMAPS::icon_pcbcalculator, wxT( "icon_pcbcalculator_dark_128.png" ), 128, wxT( "dark" ) );
|
||||
aBitmapInfoCache[BITMAPS::icon_cvpcb].emplace_back( BITMAPS::icon_cvpcb, wxT( "icon_cvpcb_256.png" ), 256, wxT( "light" ) );
|
||||
aBitmapInfoCache[BITMAPS::icon_eeschema].emplace_back( BITMAPS::icon_eeschema, wxT( "icon_eeschema_256.png" ), 256, wxT( "light" ) );
|
||||
aBitmapInfoCache[BITMAPS::icon_gerbview].emplace_back( BITMAPS::icon_gerbview, wxT( "icon_gerbview_256.png" ), 256, wxT( "light" ) );
|
||||
aBitmapInfoCache[BITMAPS::icon_kicad].emplace_back( BITMAPS::icon_kicad, wxT( "icon_kicad_256.png" ), 256, wxT( "light" ) );
|
||||
aBitmapInfoCache[BITMAPS::icon_kicad_nightly].emplace_back( BITMAPS::icon_kicad_nightly, wxT( "icon_kicad_nightly_256.png" ), 256, wxT( "light" ) );
|
||||
aBitmapInfoCache[BITMAPS::icon_libedit].emplace_back( BITMAPS::icon_libedit, wxT( "icon_libedit_256.png" ), 256, wxT( "light" ) );
|
||||
aBitmapInfoCache[BITMAPS::icon_modedit].emplace_back( BITMAPS::icon_modedit, wxT( "icon_modedit_256.png" ), 256, wxT( "light" ) );
|
||||
aBitmapInfoCache[BITMAPS::icon_pcbnew].emplace_back( BITMAPS::icon_pcbnew, wxT( "icon_pcbnew_256.png" ), 256, wxT( "light" ) );
|
||||
aBitmapInfoCache[BITMAPS::icon_pagelayout_editor].emplace_back( BITMAPS::icon_pagelayout_editor, wxT( "icon_pagelayout_editor_256.png" ), 256, wxT( "light" ) );
|
||||
aBitmapInfoCache[BITMAPS::icon_bitmap2component].emplace_back( BITMAPS::icon_bitmap2component, wxT( "icon_bitmap2component_256.png" ), 256, wxT( "light" ) );
|
||||
aBitmapInfoCache[BITMAPS::icon_pcbcalculator].emplace_back( BITMAPS::icon_pcbcalculator, wxT( "icon_pcbcalculator_256.png" ), 256, wxT( "light" ) );
|
||||
aBitmapInfoCache[BITMAPS::icon_cvpcb].emplace_back( BITMAPS::icon_cvpcb, wxT( "icon_cvpcb_dark_256.png" ), 256, wxT( "dark" ) );
|
||||
aBitmapInfoCache[BITMAPS::icon_eeschema].emplace_back( BITMAPS::icon_eeschema, wxT( "icon_eeschema_dark_256.png" ), 256, wxT( "dark" ) );
|
||||
aBitmapInfoCache[BITMAPS::icon_gerbview].emplace_back( BITMAPS::icon_gerbview, wxT( "icon_gerbview_dark_256.png" ), 256, wxT( "dark" ) );
|
||||
aBitmapInfoCache[BITMAPS::icon_kicad].emplace_back( BITMAPS::icon_kicad, wxT( "icon_kicad_dark_256.png" ), 256, wxT( "dark" ) );
|
||||
aBitmapInfoCache[BITMAPS::icon_kicad_nightly].emplace_back( BITMAPS::icon_kicad_nightly, wxT( "icon_kicad_nightly_dark_256.png" ), 256, wxT( "dark" ) );
|
||||
aBitmapInfoCache[BITMAPS::icon_libedit].emplace_back( BITMAPS::icon_libedit, wxT( "icon_libedit_dark_256.png" ), 256, wxT( "dark" ) );
|
||||
aBitmapInfoCache[BITMAPS::icon_modedit].emplace_back( BITMAPS::icon_modedit, wxT( "icon_modedit_dark_256.png" ), 256, wxT( "dark" ) );
|
||||
aBitmapInfoCache[BITMAPS::icon_pcbnew].emplace_back( BITMAPS::icon_pcbnew, wxT( "icon_pcbnew_dark_256.png" ), 256, wxT( "dark" ) );
|
||||
aBitmapInfoCache[BITMAPS::icon_pagelayout_editor].emplace_back( BITMAPS::icon_pagelayout_editor, wxT( "icon_pagelayout_editor_dark_256.png" ), 256, wxT( "dark" ) );
|
||||
aBitmapInfoCache[BITMAPS::icon_bitmap2component].emplace_back( BITMAPS::icon_bitmap2component, wxT( "icon_bitmap2component_dark_256.png" ), 256, wxT( "dark" ) );
|
||||
aBitmapInfoCache[BITMAPS::icon_pcbcalculator].emplace_back( BITMAPS::icon_pcbcalculator, wxT( "icon_pcbcalculator_dark_256.png" ), 256, wxT( "dark" ) );
|
||||
aBitmapInfoCache[BITMAPS::dialog_warning].emplace_back( BITMAPS::dialog_warning, wxT( "dialog_warning_48.png" ), 48, wxT( "light" ) );
|
||||
aBitmapInfoCache[BITMAPS::icon_3d].emplace_back( BITMAPS::icon_3d, wxT( "icon_3d_48.png" ), 48, wxT( "light" ) );
|
||||
aBitmapInfoCache[BITMAPS::icon_cvpcb].emplace_back( BITMAPS::icon_cvpcb, wxT( "icon_cvpcb_48.png" ), 48, wxT( "light" ) );
|
||||
|
||||
@@ -113,7 +113,7 @@ void DS_DRAW_ITEM_LIST::GetTextVars( wxArrayString* aVars )
|
||||
wxString DS_DRAW_ITEM_LIST::BuildFullText( const wxString& aTextbase )
|
||||
{
|
||||
std::function<bool( wxString* )> wsResolver =
|
||||
[ this ]( wxString* token ) -> bool
|
||||
[&]( wxString* token ) -> bool
|
||||
{
|
||||
bool tokenUpdated = false;
|
||||
|
||||
@@ -166,10 +166,24 @@ wxString DS_DRAW_ITEM_LIST::BuildFullText( const wxString& aTextbase )
|
||||
}
|
||||
else if( m_titleBlock )
|
||||
{
|
||||
// no need for tokenUpdated; TITLE_BLOCK::TextVarResolver() does a full
|
||||
// resolve
|
||||
if( m_titleBlock->TextVarResolver( token, m_project ) )
|
||||
{
|
||||
// No need for tokenUpdated; TITLE_BLOCK::TextVarResolver() already goes
|
||||
// up to the project.
|
||||
//
|
||||
// However, the title block may have variables in it itself, so we need
|
||||
// to run the worksheet resolver again.
|
||||
//
|
||||
const TITLE_BLOCK* savedTitleBlock = m_titleBlock;
|
||||
|
||||
m_titleBlock = nullptr;
|
||||
{
|
||||
*token = ExpandTextVars( *token, &wsResolver );
|
||||
}
|
||||
m_titleBlock = savedTitleBlock;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if( m_properties && m_properties->count( *token ) )
|
||||
{
|
||||
|
||||
@@ -26,9 +26,15 @@
|
||||
#include <macros.h>
|
||||
#include <font/fontconfig.h>
|
||||
|
||||
#ifdef __WIN32__
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
using namespace fontconfig;
|
||||
|
||||
static FONTCONFIG* g_config = nullptr;
|
||||
static bool g_fcInitSuccess = false;
|
||||
|
||||
/**
|
||||
* A simple wrapper to avoid exporing fontconfig in the header
|
||||
@@ -50,11 +56,41 @@ FONTCONFIG::FONTCONFIG()
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* This is simply a wrapper to call FcInit() with SEH for Windows
|
||||
* SEH on Windows can only be used in functions without objects that might be unwinded
|
||||
* (basically objects with destructors)
|
||||
* For example, new FONTCONFIG() in Fontconfig() is creating a object with a destructor
|
||||
* that *might* need to be unwinded. MSVC catches this and throws a compile error
|
||||
*/
|
||||
static void bootstrapFc()
|
||||
{
|
||||
#if defined( _MSC_VER )
|
||||
__try
|
||||
{
|
||||
#endif
|
||||
FcInit();
|
||||
g_fcInitSuccess = true;
|
||||
#if defined( _MSC_VER )
|
||||
}
|
||||
__except( GetExceptionCode() == STATUS_IN_PAGE_ERROR ? EXCEPTION_EXECUTE_HANDLER
|
||||
: EXCEPTION_CONTINUE_SEARCH )
|
||||
{
|
||||
g_fcInitSuccess = false;
|
||||
// We have documented cases that fontconfig while trying to cache fonts
|
||||
// ends up using freetype to try and get font info
|
||||
// freetype itself reads fonts through memory mapping instead of normal file APIs
|
||||
// there are crashes reading fonts sometimes as a result that return STATUS_IN_PAGE_ERROR
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
FONTCONFIG* Fontconfig()
|
||||
{
|
||||
if( !g_config )
|
||||
{
|
||||
FcInit();
|
||||
bootstrapFc();
|
||||
g_config = new FONTCONFIG();
|
||||
}
|
||||
|
||||
@@ -154,6 +190,10 @@ FONTCONFIG::FF_RESULT FONTCONFIG::FindFont( const wxString &aFontName, wxString
|
||||
int& aFaceIndex, bool aBold, bool aItalic )
|
||||
{
|
||||
FF_RESULT retval = FF_RESULT::FF_ERROR;
|
||||
|
||||
if( !g_fcInitSuccess )
|
||||
return retval;
|
||||
|
||||
wxString qualifiedFontName = aFontName;
|
||||
|
||||
wxScopedCharBuffer const fcBuffer = qualifiedFontName.ToUTF8();
|
||||
@@ -271,6 +311,9 @@ FONTCONFIG::FF_RESULT FONTCONFIG::FindFont( const wxString &aFontName, wxString
|
||||
|
||||
void FONTCONFIG::ListFonts( std::vector<std::string>& aFonts, const std::string& aDesiredLang )
|
||||
{
|
||||
if( !g_fcInitSuccess )
|
||||
return;
|
||||
|
||||
// be sure to cache bust if the language changed
|
||||
if( m_fontInfoCache.empty() || m_fontCacheLastLang != aDesiredLang )
|
||||
{
|
||||
|
||||
+11
-1
@@ -183,6 +183,17 @@ wxString PATHS::GetStockDataPath( bool aRespectRunFromBuildDir )
|
||||
}
|
||||
|
||||
|
||||
#ifdef __WXMSW__
|
||||
/**
|
||||
* Gets the stock (install) data path, which is the base path for things like scripting, etc
|
||||
*/
|
||||
wxString PATHS::GetWindowsBaseSharePath()
|
||||
{
|
||||
return getWindowsKiCadRoot() + wxT( "share\\" );
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
wxString PATHS::GetStockEDALibraryPath()
|
||||
{
|
||||
wxString path;
|
||||
@@ -388,7 +399,6 @@ void PATHS::EnsureUserPathsExist()
|
||||
{
|
||||
EnsurePathExists( GetUserCachePath() );
|
||||
EnsurePathExists( GetUserPluginsPath() );
|
||||
EnsurePathExists( GetUserPlugins3DPath() );
|
||||
EnsurePathExists( GetUserScriptingPath() );
|
||||
EnsurePathExists( GetUserTemplatesPath() );
|
||||
EnsurePathExists( GetDefaultUserProjectsPath() );
|
||||
|
||||
@@ -814,6 +814,10 @@ wxString PGM_BASE::GetLanguageTag()
|
||||
|
||||
void PGM_BASE::SetLanguagePath()
|
||||
{
|
||||
#ifdef _MSC_VER
|
||||
wxLocale::AddCatalogLookupPathPrefix( PATHS::GetWindowsBaseSharePath()
|
||||
+ wxT( "locale" ) );
|
||||
#endif
|
||||
wxLocale::AddCatalogLookupPathPrefix( PATHS::GetLocaleDataPath() );
|
||||
|
||||
if( wxGetEnv( wxT( "KICAD_RUN_FROM_BUILD_DIR" ), nullptr ) )
|
||||
|
||||
@@ -357,7 +357,7 @@ void SVG_PLOTTER::emitSetRGBColor( double r, double g, double b, double a )
|
||||
int blue = (int) ( 255.0 * b );
|
||||
long rgb_color = (red << 16) | (green << 8) | blue;
|
||||
|
||||
if( m_pen_rgb_color != rgb_color )
|
||||
if( m_pen_rgb_color != rgb_color || m_brush_alpha != a )
|
||||
{
|
||||
m_graphics_changed = true;
|
||||
m_pen_rgb_color = rgb_color;
|
||||
|
||||
@@ -30,9 +30,10 @@
|
||||
|
||||
LIB_ID AltiumToKiCadLibID( const wxString& aLibName, const wxString& aLibReference )
|
||||
{
|
||||
wxString libName = LIB_ID::FixIllegalChars( aLibName, true );
|
||||
wxString libReference = EscapeString( aLibReference, CTX_LIBID );
|
||||
|
||||
wxString key = !aLibName.empty() ? ( aLibName + ":" + libReference ) : libReference;
|
||||
wxString key = !libName.empty() ? ( libName + ":" + libReference ) : libReference;
|
||||
|
||||
LIB_ID libId;
|
||||
libId.Parse( key, true );
|
||||
|
||||
@@ -41,8 +41,12 @@ bool EDIT_POINT::WithinPoint( const VECTOR2I& aPoint, unsigned int aSize ) const
|
||||
}
|
||||
|
||||
|
||||
EDIT_POINTS::EDIT_POINTS( EDA_ITEM* aParent )
|
||||
: EDA_ITEM( NOT_USED ), m_parent( aParent ), m_allowPoints( true )
|
||||
EDIT_POINTS::EDIT_POINTS( EDA_ITEM* aParent ) :
|
||||
EDA_ITEM( NOT_USED ),
|
||||
m_parent( aParent ),
|
||||
m_swapX( false ),
|
||||
m_swapY( false ),
|
||||
m_allowPoints( true )
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -538,6 +538,23 @@ void TOOL_DISPATCHER::DispatchWxEvent( wxEvent& aEvent )
|
||||
}
|
||||
else if( type == wxEVT_MENU_OPEN || type == wxEVT_MENU_CLOSE || type == wxEVT_MENU_HIGHLIGHT )
|
||||
{
|
||||
wxMenuEvent* tmp = dynamic_cast<wxMenuEvent*>( &aEvent );
|
||||
|
||||
// Something is amiss if the event has these types and isn't a menu event, so bail out on
|
||||
// its processing
|
||||
if( !tmp )
|
||||
{
|
||||
aEvent.Skip();
|
||||
return;
|
||||
}
|
||||
|
||||
wxMenuEvent& menuEvent = *tmp;
|
||||
|
||||
#if wxCHECK_VERSION( 3, 2, 0 )
|
||||
// Forward the event to the menu for processing
|
||||
if( ACTION_MENU* currentMenu = dynamic_cast<ACTION_MENU*>( menuEvent.GetMenu() ) )
|
||||
currentMenu->OnMenuEvent( menuEvent );
|
||||
#else
|
||||
//
|
||||
// wxWidgets has several issues that we have to work around:
|
||||
//
|
||||
@@ -546,16 +563,13 @@ void TOOL_DISPATCHER::DispatchWxEvent( wxEvent& aEvent )
|
||||
// (FWIW, this one is fixed in wxWidgets 3.1.x.)
|
||||
//
|
||||
// 2) wxWidgets doesn't pass the menu pointer for wxEVT_MENU_HIGHLIGHT events. So we
|
||||
// store the menu pointer from the wxEVT_MENU_OPEN call.
|
||||
// store the menu pointer from the wxEVT_MENU_OPEN call (fixed in 3.1.3).
|
||||
//
|
||||
// 3) wxWidgets has no way to tell whether a command is from a menu selection or a
|
||||
// hotkey. So we keep track of menu highlighting so we can differentiate.
|
||||
//
|
||||
|
||||
static ACTION_MENU* currentMenu;
|
||||
|
||||
wxMenuEvent& menuEvent = *dynamic_cast<wxMenuEvent*>( &aEvent );
|
||||
|
||||
if( type == wxEVT_MENU_OPEN )
|
||||
{
|
||||
currentMenu = dynamic_cast<ACTION_MENU*>( menuEvent.GetMenu() );
|
||||
@@ -575,6 +589,7 @@ void TOOL_DISPATCHER::DispatchWxEvent( wxEvent& aEvent )
|
||||
|
||||
currentMenu = nullptr;
|
||||
}
|
||||
#endif
|
||||
|
||||
aEvent.Skip();
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
*
|
||||
* Copyright (C) 2018 jp.charras at wanadoo.fr
|
||||
* Copyright (C) 2011 Wayne Stambaugh <stambaughw@gmail.com>
|
||||
* Copyright (C) 2021-2022 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
* Copyright (C) 2021-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
|
||||
@@ -96,6 +96,22 @@ bool PICKED_ITEMS_LIST::ContainsItem( const EDA_ITEM* aItem ) const
|
||||
}
|
||||
|
||||
|
||||
bool PICKED_ITEMS_LIST::ContainsItemType( KICAD_T aItemType ) const
|
||||
{
|
||||
for( const ITEM_PICKER& picker : m_ItemsList )
|
||||
{
|
||||
const EDA_ITEM* item = picker.GetItem();
|
||||
|
||||
wxCHECK2( item, continue );
|
||||
|
||||
if( item->Type() == aItemType )
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
int PICKED_ITEMS_LIST::FindItem( const EDA_ITEM* aItem ) const
|
||||
{
|
||||
for( size_t i = 0; i < m_ItemsList.size(); i++ )
|
||||
|
||||
@@ -184,6 +184,9 @@ bool IFACE::OnKifaceStart( PGM_BASE* aProgram, int aCtlBits )
|
||||
}
|
||||
catch( const IO_ERROR& ioe )
|
||||
{
|
||||
// we didnt get anywhere deregister the settings
|
||||
aProgram->GetSettingsManager().FlushAndRelease( KifaceSettings(), false );
|
||||
|
||||
DisplayErrorMessage( nullptr, _( "An error occurred attempting to load the global "
|
||||
"footprint library table." ),
|
||||
ioe.What() );
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2018 CERN
|
||||
* Copyright (C) 2021-2022 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
* Copyright (C) 2021-2024 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* @author Jon Evans <jon@craftyjon.com>
|
||||
*
|
||||
@@ -2997,6 +2997,7 @@ bool CONNECTION_GRAPH::ercCheckBusToNetConflicts( const CONNECTION_SUBGRAPH* aSu
|
||||
if( net_item && bus_item )
|
||||
{
|
||||
std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( ERCE_BUS_TO_NET_CONFLICT );
|
||||
ercItem->SetSheetSpecificPath( sheet );
|
||||
ercItem->SetItems( net_item, bus_item );
|
||||
|
||||
SCH_MARKER* marker = new SCH_MARKER( ercItem, net_item->GetPosition() );
|
||||
@@ -3064,6 +3065,7 @@ bool CONNECTION_GRAPH::ercCheckBusToBusConflicts( const CONNECTION_SUBGRAPH* aSu
|
||||
if( !match )
|
||||
{
|
||||
std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( ERCE_BUS_TO_BUS_CONFLICT );
|
||||
ercItem->SetSheetSpecificPath( sheet );
|
||||
ercItem->SetItems( label, port );
|
||||
|
||||
SCH_MARKER* marker = new SCH_MARKER( ercItem, label->GetPosition() );
|
||||
@@ -3167,6 +3169,7 @@ bool CONNECTION_GRAPH::ercCheckBusToBusEntryConflicts( const CONNECTION_SUBGRAPH
|
||||
UnescapeString( netName ),
|
||||
UnescapeString( bus_name ) );
|
||||
std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( ERCE_BUS_ENTRY_CONFLICT );
|
||||
ercItem->SetSheetSpecificPath( sheet );
|
||||
ercItem->SetItems( bus_entry, bus_wire );
|
||||
ercItem->SetErrorMessage( msg );
|
||||
|
||||
@@ -3180,7 +3183,6 @@ bool CONNECTION_GRAPH::ercCheckBusToBusEntryConflicts( const CONNECTION_SUBGRAPH
|
||||
}
|
||||
|
||||
|
||||
// TODO(JE) Check sheet pins here too?
|
||||
bool CONNECTION_GRAPH::ercCheckNoConnects( const CONNECTION_SUBGRAPH* aSubgraph )
|
||||
{
|
||||
ERC_SETTINGS& settings = m_schematic->ErcSettings();
|
||||
@@ -3251,9 +3253,29 @@ bool CONNECTION_GRAPH::ercCheckNoConnects( const CONNECTION_SUBGRAPH* aSubgraph
|
||||
|
||||
if( aSubgraph->m_no_connect != nullptr )
|
||||
{
|
||||
// Special case: If the subgraph being checked consists of only a hier port/pin and
|
||||
// a no-connect, we don't issue a "no-connect connected" warning just because
|
||||
// connections exist on the sheet on the other side of the link.
|
||||
VECTOR2I noConnectPos = aSubgraph->m_no_connect->GetPosition();
|
||||
|
||||
for( SCH_SHEET_PIN* hierPin : aSubgraph->m_hier_pins )
|
||||
{
|
||||
if( hierPin->GetPosition() == noConnectPos )
|
||||
return true;
|
||||
}
|
||||
|
||||
for( SCH_HIERLABEL* hierLabel : aSubgraph->m_hier_ports )
|
||||
{
|
||||
if( hierLabel->GetPosition() == noConnectPos )
|
||||
return true;
|
||||
}
|
||||
|
||||
if( unique_pins.size() > 1 && settings.IsTestEnabled( ERCE_NOCONNECT_CONNECTED ) )
|
||||
{
|
||||
std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( ERCE_NOCONNECT_CONNECTED );
|
||||
ercItem->SetSheetSpecificPath( sheet );
|
||||
ercItem->SetItemsSheetPaths( sheet );
|
||||
|
||||
VECTOR2I pos;
|
||||
|
||||
if( pin )
|
||||
@@ -3277,6 +3299,8 @@ bool CONNECTION_GRAPH::ercCheckNoConnects( const CONNECTION_SUBGRAPH* aSubgraph
|
||||
{
|
||||
std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( ERCE_NOCONNECT_NOT_CONNECTED );
|
||||
ercItem->SetItems( aSubgraph->m_no_connect );
|
||||
ercItem->SetSheetSpecificPath( sheet );
|
||||
ercItem->SetItemsSheetPaths( sheet );
|
||||
|
||||
SCH_MARKER* marker = new SCH_MARKER( ercItem, aSubgraph->m_no_connect->GetPosition() );
|
||||
screen->Append( marker );
|
||||
@@ -3365,6 +3389,8 @@ bool CONNECTION_GRAPH::ercCheckNoConnects( const CONNECTION_SUBGRAPH* aSubgraph
|
||||
&& settings.IsTestEnabled( ERCE_PIN_NOT_CONNECTED ) )
|
||||
{
|
||||
std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( ERCE_PIN_NOT_CONNECTED );
|
||||
ercItem->SetSheetSpecificPath( sheet );
|
||||
ercItem->SetItemsSheetPaths( sheet );
|
||||
ercItem->SetItems( pin );
|
||||
|
||||
SCH_MARKER* marker = new SCH_MARKER( ercItem, pin->GetTransformedPosition() );
|
||||
@@ -3388,6 +3414,8 @@ bool CONNECTION_GRAPH::ercCheckNoConnects( const CONNECTION_SUBGRAPH* aSubgraph
|
||||
&& settings.IsTestEnabled( ERCE_PIN_NOT_CONNECTED ) )
|
||||
{
|
||||
std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( ERCE_PIN_NOT_CONNECTED );
|
||||
ercItem->SetSheetSpecificPath( sheet );
|
||||
ercItem->SetItemsSheetPaths( sheet );
|
||||
ercItem->SetItems( testPin );
|
||||
|
||||
SCH_MARKER* marker = new SCH_MARKER( ercItem,
|
||||
@@ -3409,6 +3437,7 @@ bool CONNECTION_GRAPH::ercCheckFloatingWires( const CONNECTION_SUBGRAPH* aSubgra
|
||||
if( aSubgraph->m_driver )
|
||||
return true;
|
||||
|
||||
const SCH_SHEET_PATH& sheet = aSubgraph->m_sheet;
|
||||
std::vector<SCH_ITEM*> wires;
|
||||
|
||||
// We've gotten this far, so we know we have no valid driver. All we need to do is check
|
||||
@@ -3427,6 +3456,7 @@ bool CONNECTION_GRAPH::ercCheckFloatingWires( const CONNECTION_SUBGRAPH* aSubgra
|
||||
SCH_SCREEN* screen = aSubgraph->m_sheet.LastScreen();
|
||||
|
||||
std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( ERCE_WIRE_DANGLING );
|
||||
ercItem->SetSheetSpecificPath( sheet );
|
||||
ercItem->SetItems( wires[0],
|
||||
wires.size() > 1 ? wires[1] : nullptr,
|
||||
wires.size() > 2 ? wires[2] : nullptr,
|
||||
@@ -3459,6 +3489,7 @@ bool CONNECTION_GRAPH::ercCheckLabels( const CONNECTION_SUBGRAPH* aSubgraph )
|
||||
if( aSubgraph->m_driver_connection->IsBus() )
|
||||
return true;
|
||||
|
||||
const SCH_SHEET_PATH& sheet = aSubgraph->m_sheet;
|
||||
ERC_SETTINGS& settings = m_schematic->ErcSettings();
|
||||
bool ok = true;
|
||||
int pinCount = 0;
|
||||
@@ -3480,6 +3511,7 @@ bool CONNECTION_GRAPH::ercCheckLabels( const CONNECTION_SUBGRAPH* aSubgraph )
|
||||
if( settings.IsTestEnabled( errCode ) )
|
||||
{
|
||||
std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( errCode );
|
||||
ercItem->SetSheetSpecificPath( sheet );
|
||||
ercItem->SetItems( aText );
|
||||
|
||||
SCH_MARKER* marker = new SCH_MARKER( ercItem, aText->GetPosition() );
|
||||
@@ -3614,6 +3646,8 @@ int CONNECTION_GRAPH::ercCheckHierSheets()
|
||||
{
|
||||
std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( ERCE_PIN_NOT_CONNECTED );
|
||||
ercItem->SetItems( pin );
|
||||
ercItem->SetSheetSpecificPath( sheet );
|
||||
ercItem->SetItemsSheetPaths( sheet );
|
||||
|
||||
SCH_MARKER* marker = new SCH_MARKER( ercItem, pin->GetPosition() );
|
||||
sheet.LastScreen()->Append( marker );
|
||||
|
||||
@@ -350,14 +350,35 @@ void DIALOG_CHANGE_SYMBOLS::updateFieldsList()
|
||||
}
|
||||
|
||||
// Update the listbox widget
|
||||
for( unsigned i = m_fieldsBox->GetCount() - 1; i >= MANDATORY_FIELDS; --i )
|
||||
m_fieldsBox->Delete( i );
|
||||
wxArrayInt checkedItems;
|
||||
wxArrayString checkedNames;
|
||||
|
||||
m_fieldsBox->GetCheckedItems( checkedItems );
|
||||
|
||||
for( int ii : checkedItems )
|
||||
checkedNames.push_back( m_fieldsBox->GetString( ii ) );
|
||||
|
||||
bool allChecked = true;
|
||||
|
||||
for( unsigned ii = 0; ii < m_fieldsBox->GetCount(); ++ii )
|
||||
{
|
||||
if( ii == REFERENCE_FIELD || ii == VALUE_FIELD )
|
||||
continue;
|
||||
|
||||
if( !m_fieldsBox->IsChecked( ii ) )
|
||||
allChecked = false;
|
||||
}
|
||||
|
||||
for( unsigned ii = m_fieldsBox->GetCount() - 1; ii >= MANDATORY_FIELDS; --ii )
|
||||
m_fieldsBox->Delete( ii );
|
||||
|
||||
for( const wxString& fieldName : fieldNames )
|
||||
{
|
||||
m_fieldsBox->Append( fieldName );
|
||||
|
||||
for( unsigned i = MANDATORY_FIELDS; i < m_fieldsBox->GetCount(); ++i )
|
||||
m_fieldsBox->Check( i, true );
|
||||
if( allChecked || alg::contains( checkedNames, fieldName ) )
|
||||
m_fieldsBox->Check( m_fieldsBox->GetCount() - 1, true );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2009 Wayne Stambaugh <stambaughw@gmail.com>
|
||||
* Copyright (C) 2014-2023 KiCad Developers, see CHANGELOG.txt for contributors.
|
||||
* Copyright (C) 2014-2024 KiCad Developers, see CHANGELOG.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
|
||||
@@ -667,6 +667,9 @@ bool DIALOG_SHEET_PROPERTIES::onSheetFilenameChanged( const wxString& aNewFilena
|
||||
if( m_clearAnnotationNewItems )
|
||||
*m_clearAnnotationNewItems = clearAnnotation;
|
||||
|
||||
// Rebuild the entire connection graph.
|
||||
m_frame->RecalculateConnections( GLOBAL_CLEANUP );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -334,7 +334,8 @@ bool IFACE::OnKifaceStart( PGM_BASE* aProgram, int aCtlBits )
|
||||
InitSettings( new EESCHEMA_SETTINGS );
|
||||
// Register the symbol editor settings as well because they share a KiFACE and need to be
|
||||
// loaded prior to use to avoid threading deadlocks
|
||||
aProgram->GetSettingsManager().RegisterSettings( new SYMBOL_EDITOR_SETTINGS );
|
||||
SYMBOL_EDITOR_SETTINGS* symSettings = new SYMBOL_EDITOR_SETTINGS();
|
||||
aProgram->GetSettingsManager().RegisterSettings( symSettings ); // manager takes ownership
|
||||
|
||||
// We intentionally register KifaceSettings after SYMBOL_EDITOR_SETTINGS
|
||||
// In legacy configs, many settings were in a single editor config nd the migration routine
|
||||
@@ -345,7 +346,12 @@ bool IFACE::OnKifaceStart( PGM_BASE* aProgram, int aCtlBits )
|
||||
start_common( aCtlBits );
|
||||
|
||||
if( !loadGlobalLibTable() )
|
||||
{
|
||||
// we didnt get anywhere deregister the settings
|
||||
aProgram->GetSettingsManager().FlushAndRelease( symSettings, false );
|
||||
aProgram->GetSettingsManager().FlushAndRelease( KifaceSettings(), false );
|
||||
return false;
|
||||
}
|
||||
|
||||
m_jobHandler = std::make_unique<EESCHEMA_JOBS_HANDLER>();
|
||||
|
||||
|
||||
@@ -91,7 +91,7 @@ void EESCHEMA_JOBS_HANDLER::InitRenderSettings( KIGFX::SCH_RENDER_SETTINGS* aRen
|
||||
aSch->Prj().GetProjectPath() );
|
||||
|
||||
if( !DS_DATA_MODEL::GetTheInstance().LoadDrawingSheet( filename ) )
|
||||
wxFprintf( stderr, _( "Error loading drawing sheet." ) );
|
||||
wxFprintf( stderr, _( "Error loading drawing sheet." ) + wxS( "\n" ) );
|
||||
}
|
||||
|
||||
|
||||
@@ -379,7 +379,7 @@ int EESCHEMA_JOBS_HANDLER::doSymExportSvg( JOB_SYM_EXPORT_SVG* aSvgJob,
|
||||
|
||||
if( !plotter->OpenFile( fn.GetFullPath() ) )
|
||||
{
|
||||
wxFprintf( stderr, _( "Unable to open destination '%s'" ), fn.GetFullPath() );
|
||||
wxFprintf( stderr, _( "Unable to open destination '%s'" ) + wxS( "\n" ), fn.GetFullPath() );
|
||||
|
||||
delete plotter;
|
||||
return CLI::EXIT_CODES::ERR_INVALID_INPUT_FILE;
|
||||
@@ -442,7 +442,7 @@ int EESCHEMA_JOBS_HANDLER::JobSymExportSvg( JOB* aJob )
|
||||
|
||||
if( !symbol )
|
||||
{
|
||||
wxFprintf( stderr, _( "There is no symbol selected to save." ) );
|
||||
wxFprintf( stderr, _( "There is no symbol selected to save." ) + wxS( "\n" ) );
|
||||
return CLI::EXIT_CODES::ERR_ARGS;
|
||||
}
|
||||
}
|
||||
|
||||
+8
-1
@@ -3,7 +3,7 @@
|
||||
*
|
||||
* Copyright (C) 2015 Jean-Pierre Charras, jp.charras at wanadoo.fr
|
||||
* Copyright (C) 2011 Wayne Stambaugh <stambaughw@gmail.com>
|
||||
* Copyright (C) 1992-2023 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
* Copyright (C) 1992-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
|
||||
@@ -215,6 +215,7 @@ void ERC_TESTER::TestTextVars( DS_PROXY_VIEW_ITEM* aDrawingSheet )
|
||||
std::shared_ptr<ERC_ITEM> ercItem =
|
||||
ERC_ITEM::Create( ERCE_UNRESOLVED_VARIABLE );
|
||||
ercItem->SetItems( &field );
|
||||
ercItem->SetSheetSpecificPath( sheet );
|
||||
|
||||
SCH_MARKER* marker = new SCH_MARKER( ercItem, pos );
|
||||
screen->Append( marker );
|
||||
@@ -232,6 +233,7 @@ void ERC_TESTER::TestTextVars( DS_PROXY_VIEW_ITEM* aDrawingSheet )
|
||||
std::shared_ptr<ERC_ITEM> ercItem =
|
||||
ERC_ITEM::Create( ERCE_UNRESOLVED_VARIABLE );
|
||||
ercItem->SetItems( &field );
|
||||
ercItem->SetSheetSpecificPath( sheet );
|
||||
|
||||
SCH_MARKER* marker = new SCH_MARKER( ercItem, field.GetPosition() );
|
||||
screen->Append( marker );
|
||||
@@ -245,6 +247,7 @@ void ERC_TESTER::TestTextVars( DS_PROXY_VIEW_ITEM* aDrawingSheet )
|
||||
std::shared_ptr<ERC_ITEM> ercItem =
|
||||
ERC_ITEM::Create( ERCE_UNRESOLVED_VARIABLE );
|
||||
ercItem->SetItems( pin );
|
||||
ercItem->SetSheetSpecificPath( sheet );
|
||||
|
||||
SCH_MARKER* marker = new SCH_MARKER( ercItem, pin->GetPosition() );
|
||||
screen->Append( marker );
|
||||
@@ -258,6 +261,7 @@ void ERC_TESTER::TestTextVars( DS_PROXY_VIEW_ITEM* aDrawingSheet )
|
||||
std::shared_ptr<ERC_ITEM> ercItem =
|
||||
ERC_ITEM::Create( ERCE_UNRESOLVED_VARIABLE );
|
||||
ercItem->SetItems( text );
|
||||
ercItem->SetSheetSpecificPath( sheet );
|
||||
|
||||
SCH_MARKER* marker = new SCH_MARKER( ercItem, text->GetPosition() );
|
||||
screen->Append( marker );
|
||||
@@ -270,6 +274,7 @@ void ERC_TESTER::TestTextVars( DS_PROXY_VIEW_ITEM* aDrawingSheet )
|
||||
std::shared_ptr<ERC_ITEM> ercItem =
|
||||
ERC_ITEM::Create( ERCE_UNRESOLVED_VARIABLE );
|
||||
ercItem->SetItems( textBox );
|
||||
ercItem->SetSheetSpecificPath( sheet );
|
||||
|
||||
SCH_MARKER* marker = new SCH_MARKER( ercItem, textBox->GetPosition() );
|
||||
screen->Append( marker );
|
||||
@@ -285,6 +290,7 @@ void ERC_TESTER::TestTextVars( DS_PROXY_VIEW_ITEM* aDrawingSheet )
|
||||
{
|
||||
std::shared_ptr<ERC_ITEM> erc = ERC_ITEM::Create( ERCE_UNRESOLVED_VARIABLE );
|
||||
erc->SetErrorMessage( _( "Unresolved text variable in drawing sheet" ) );
|
||||
erc->SetSheetSpecificPath( sheet );
|
||||
|
||||
SCH_MARKER* marker = new SCH_MARKER( erc, text->GetPosition() );
|
||||
screen->Append( marker );
|
||||
@@ -580,6 +586,7 @@ int ERC_TESTER::TestNoConnectPins()
|
||||
pair.second.size() > 2 ? pair.second[2] : nullptr,
|
||||
pair.second.size() > 3 ? pair.second[3] : nullptr );
|
||||
ercItem->SetErrorMessage( _( "Pins with 'no connection' type are connected" ) );
|
||||
ercItem->SetSheetSpecificPath( sheet );
|
||||
|
||||
SCH_MARKER* marker = new SCH_MARKER( ercItem, pair.first );
|
||||
sheet.LastScreen()->Append( marker );
|
||||
|
||||
@@ -466,6 +466,7 @@ bool SCH_EDIT_FRAME::OpenProjectFiles( const std::vector<wxString>& aFileSet, in
|
||||
}
|
||||
|
||||
schematic.PruneOrphanedSymbolInstances( Prj().GetProjectName(), Schematic().GetSheets() );
|
||||
schematic.PruneOrphanedSheetInstances( Prj().GetProjectName(), Schematic().GetSheets() );
|
||||
|
||||
Schematic().ConnectionGraph()->Reset();
|
||||
|
||||
|
||||
+29
-15
@@ -1369,49 +1369,63 @@ BITMAPS LIB_PIN::GetMenuImage() const
|
||||
}
|
||||
|
||||
|
||||
wxString LIB_PIN::GetItemDescription( UNITS_PROVIDER* aUnitsProvider, ALT* aAlt ) const
|
||||
{
|
||||
return getItemDescription( aAlt );
|
||||
}
|
||||
|
||||
|
||||
wxString LIB_PIN::GetItemDescription( UNITS_PROVIDER* aUnitsProvider ) const
|
||||
{
|
||||
// This code previously checked "m_name.IsEmpty()" to choose the correct
|
||||
return getItemDescription( nullptr );
|
||||
}
|
||||
|
||||
|
||||
wxString LIB_PIN::getItemDescription( ALT* aAlt ) const
|
||||
{
|
||||
// This code previously checked "m_name.IsEmpty()" to choose the correct
|
||||
// formatting path, but that check fails if the pin is called "~" which is
|
||||
// the default for an empty pin name. Instead we get the final display string
|
||||
// the default for an empty pin name. Instead we get the final display string
|
||||
// that will be shown and check if it's empty.
|
||||
|
||||
wxString shownName = UnescapeString( GetShownName() );
|
||||
wxString name = UnescapeString( aAlt ? aAlt->m_Name : GetShownName() );
|
||||
wxString electricalTypeName = ElectricalPinTypeGetText( aAlt ? aAlt->m_Type : m_type );
|
||||
wxString pinShapeName = PinShapeGetText( aAlt ? aAlt->m_Shape : m_shape );
|
||||
|
||||
if( IsVisible() )
|
||||
{
|
||||
if ( !shownName.IsEmpty() )
|
||||
if ( !name.IsEmpty() )
|
||||
{
|
||||
return wxString::Format( _( "Pin %s [%s, %s, %s]" ),
|
||||
GetShownNumber(),
|
||||
shownName,
|
||||
GetElectricalTypeName(),
|
||||
PinShapeGetText( m_shape ) );
|
||||
name,
|
||||
electricalTypeName,
|
||||
pinShapeName );
|
||||
}
|
||||
else
|
||||
{
|
||||
return wxString::Format( _( "Pin %s [%s, %s]" ),
|
||||
GetShownNumber(),
|
||||
GetElectricalTypeName(),
|
||||
PinShapeGetText( m_shape ) );
|
||||
electricalTypeName,
|
||||
pinShapeName );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if( !shownName.IsEmpty() )
|
||||
if( !name.IsEmpty() )
|
||||
{
|
||||
return wxString::Format( _( "Hidden pin %s [%s, %s, %s]" ),
|
||||
GetShownNumber(),
|
||||
shownName,
|
||||
GetElectricalTypeName(),
|
||||
PinShapeGetText( m_shape ) );
|
||||
name,
|
||||
electricalTypeName,
|
||||
pinShapeName );
|
||||
}
|
||||
else
|
||||
{
|
||||
return wxString::Format( _( "Hidden pin %s [%s, %s]" ),
|
||||
GetShownNumber(),
|
||||
GetElectricalTypeName(),
|
||||
PinShapeGetText( m_shape ) );
|
||||
electricalTypeName,
|
||||
pinShapeName );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -244,6 +244,7 @@ public:
|
||||
BITMAPS GetMenuImage() const override;
|
||||
|
||||
wxString GetItemDescription( UNITS_PROVIDER* aUnitsProvider ) const override;
|
||||
wxString GetItemDescription( UNITS_PROVIDER* aUnitsProvider, ALT* aAlt ) const;
|
||||
|
||||
EDA_ITEM* Clone() const override;
|
||||
|
||||
@@ -260,6 +261,8 @@ public:
|
||||
static const wxString GetCanonicalElectricalTypeName( ELECTRICAL_PINTYPE aType );
|
||||
|
||||
protected:
|
||||
wxString getItemDescription( ALT* aAlt ) const;
|
||||
|
||||
struct EXTENTS_CACHE
|
||||
{
|
||||
KIFONT::FONT* m_Font = nullptr;
|
||||
|
||||
@@ -414,7 +414,7 @@ void LIB_TEXTBOX::Plot( PLOTTER* aPlotter, bool aBackground, const VECTOR2I& aOf
|
||||
color = renderSettings->GetLayerColor( LAYER_DEVICE );
|
||||
|
||||
if( lineStyle == PLOT_DASH_TYPE::DEFAULT )
|
||||
lineStyle = PLOT_DASH_TYPE::DASH;
|
||||
lineStyle = PLOT_DASH_TYPE::SOLID;
|
||||
|
||||
if( aDimmed )
|
||||
{
|
||||
|
||||
+39
-19
@@ -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) 1992-2023 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
* Copyright (C) 1992-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
|
||||
@@ -51,6 +51,7 @@
|
||||
#include <sch_painter.h>
|
||||
#include <sch_sheet.h>
|
||||
#include <sch_marker.h>
|
||||
#include <sch_sheet_pin.h>
|
||||
#include <schematic.h>
|
||||
#include <settings/settings_manager.h>
|
||||
#include <advanced_config.h>
|
||||
@@ -133,7 +134,11 @@ SCH_EDIT_FRAME::SCH_EDIT_FRAME( KIWAY* aKiway, wxWindow* aParent ) :
|
||||
wxIcon icon;
|
||||
wxIconBundle icon_bundle;
|
||||
|
||||
icon.CopyFromBitmap( KiBitmap( BITMAPS::icon_eeschema ) );
|
||||
icon.CopyFromBitmap( KiBitmap( BITMAPS::icon_eeschema, 48 ) );
|
||||
icon_bundle.AddIcon( icon );
|
||||
icon.CopyFromBitmap( KiBitmap( BITMAPS::icon_eeschema, 128 ) );
|
||||
icon_bundle.AddIcon( icon );
|
||||
icon.CopyFromBitmap( KiBitmap( BITMAPS::icon_eeschema, 256 ) );
|
||||
icon_bundle.AddIcon( icon );
|
||||
icon.CopyFromBitmap( KiBitmap( BITMAPS::icon_eeschema_32 ) );
|
||||
icon_bundle.AddIcon( icon );
|
||||
@@ -950,7 +955,6 @@ void SCH_EDIT_FRAME::OnModify()
|
||||
RecalculateConnections( NO_CLEANUP );
|
||||
|
||||
GetCanvas()->Refresh();
|
||||
UpdateHierarchyNavigator();
|
||||
|
||||
if( !GetTitle().StartsWith( wxS( "*" ) ) )
|
||||
updateTitle();
|
||||
@@ -1113,6 +1117,10 @@ void SCH_EDIT_FRAME::OnClearFileHistory( wxCommandEvent& aEvent )
|
||||
|
||||
void SCH_EDIT_FRAME::NewProject()
|
||||
{
|
||||
// Only standalone mode can directly load a new document
|
||||
if( !Kiface().IsSingle() )
|
||||
return;
|
||||
|
||||
wxString pro_dir = m_mruPath;
|
||||
|
||||
wxFileDialog dlg( this, _( "New Schematic" ), pro_dir, wxEmptyString,
|
||||
@@ -1143,6 +1151,10 @@ void SCH_EDIT_FRAME::NewProject()
|
||||
|
||||
void SCH_EDIT_FRAME::LoadProject()
|
||||
{
|
||||
// Only standalone mode can directly load a new document
|
||||
if( !Kiface().IsSingle() )
|
||||
return;
|
||||
|
||||
wxString pro_dir = m_mruPath;
|
||||
wxString wildcards = AllSchematicFilesWildcard()
|
||||
+ wxS( "|" ) + KiCadSchematicFileWildcard()
|
||||
@@ -1503,37 +1515,46 @@ void SCH_EDIT_FRAME::RecalculateConnections( SCH_CLEANUP_FLAGS aCleanupFlags )
|
||||
|
||||
for( unsigned ii = 0; ii < changed_list->GetCount(); ++ii )
|
||||
{
|
||||
EDA_ITEM* item = changed_list->GetPickedItem( ii );
|
||||
SCH_ITEM* item = dynamic_cast<SCH_ITEM*>( changed_list->GetPickedItem( ii ) );
|
||||
|
||||
if( !item || !IsEeschemaType( item->Type() ) )
|
||||
// Ignore non SCH_ITEM objects and objects that are not connectable.
|
||||
if( !item || !item->IsConnectable() )
|
||||
continue;
|
||||
|
||||
SCH_SCREEN* screen = static_cast<SCH_SCREEN*>( changed_list->GetScreenForItem( ii ) );
|
||||
SCH_ITEM* sch_item = static_cast<SCH_ITEM*>( item );
|
||||
SCH_SHEET_PATHS& paths = screen->GetClientSheetPaths();
|
||||
|
||||
std::vector<VECTOR2I> tmp_pts = sch_item->GetConnectionPoints();
|
||||
std::vector<VECTOR2I> tmp_pts = item->GetConnectionPoints();
|
||||
pts.insert( pts.end(), tmp_pts.begin(), tmp_pts.end() );
|
||||
changed_items.insert( sch_item );
|
||||
changed_items.insert( item );
|
||||
|
||||
for( SCH_SHEET_PATH& path : paths )
|
||||
item_paths.insert( std::make_pair( path, sch_item ) );
|
||||
item_paths.insert( std::make_pair( path, item ) );
|
||||
}
|
||||
|
||||
for( VECTOR2I& pt: pts )
|
||||
{
|
||||
for( SCH_ITEM* item : GetScreen()->Items().Overlapping(pt ) )
|
||||
{
|
||||
if( !item->IsConnectable() )
|
||||
continue;
|
||||
|
||||
if( SCH_LINE* line = dyn_cast<SCH_LINE*>( item ) )
|
||||
if( item->Type() == SCH_LINE_T )
|
||||
{
|
||||
if( line->HitTest( pt ) )
|
||||
{
|
||||
if( item->HitTest( pt ) )
|
||||
changed_items.insert( item );
|
||||
}
|
||||
else if( item->Type() == SCH_SHEET_T )
|
||||
{
|
||||
SCH_SHEET* sheet = static_cast<SCH_SHEET*>( item );
|
||||
|
||||
wxCHECK2( sheet, continue );
|
||||
|
||||
std::vector<SCH_SHEET_PIN*> sheetPins = sheet->GetPins();
|
||||
changed_items.insert( sheetPins.begin(), sheetPins.end() );
|
||||
}
|
||||
else
|
||||
{
|
||||
// Non-connectable objects have already been pruned.
|
||||
if( item->IsConnected( pt ) )
|
||||
changed_items.insert( item );
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if( SCH_SYMBOL* sym = dyn_cast<SCH_SYMBOL*>( item ) )
|
||||
@@ -1549,8 +1570,7 @@ void SCH_EDIT_FRAME::RecalculateConnections( SCH_CLEANUP_FLAGS aCleanupFlags )
|
||||
}
|
||||
|
||||
std::set<std::pair<SCH_SHEET_PATH, SCH_ITEM*>> all_items =
|
||||
Schematic().ConnectionGraph()->ExtractAffectedItems(
|
||||
changed_items );
|
||||
Schematic().ConnectionGraph()->ExtractAffectedItems( changed_items );
|
||||
|
||||
all_items.insert( item_paths.begin(), item_paths.end() );
|
||||
|
||||
|
||||
@@ -843,12 +843,9 @@ void SCH_PAINTER::draw( const LIB_SHAPE *aShape, int aLayer, bool aDimmed )
|
||||
|
||||
case SHAPE_T::BEZIER:
|
||||
{
|
||||
std::deque<VECTOR2D> mappedPts;
|
||||
|
||||
for( const VECTOR2I& p : shape->GetBezierPoints() )
|
||||
mappedPts.push_back( mapCoords( p ) );
|
||||
|
||||
m_gal->DrawPolygon( mappedPts );
|
||||
m_gal->DrawCurve(
|
||||
mapCoords( shape->GetStart() ), mapCoords( shape->GetBezierC1() ),
|
||||
mapCoords( shape->GetBezierC2() ), mapCoords( shape->GetEnd() ) );
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -1851,12 +1848,8 @@ void SCH_PAINTER::draw( const SCH_SHAPE* aShape, int aLayer )
|
||||
|
||||
case SHAPE_T::BEZIER:
|
||||
{
|
||||
std::deque<VECTOR2D> pts;
|
||||
|
||||
for( const VECTOR2I &p : shape->GetPolyShape().Outline( 0 ).CPoints() )
|
||||
pts.push_back( p );
|
||||
|
||||
m_gal->DrawPolygon( pts );
|
||||
m_gal->DrawCurve( shape->GetStart(), shape->GetBezierC1(), shape->GetBezierC2(),
|
||||
shape->GetEnd() );
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
+10
-1
@@ -193,9 +193,18 @@ SCH_SYMBOL* SCH_PIN::GetParentSymbol() const
|
||||
|
||||
wxString SCH_PIN::GetItemDescription( UNITS_PROVIDER* aUnitsProvider ) const
|
||||
{
|
||||
LIB_PIN::ALT localStorage;
|
||||
LIB_PIN::ALT* alt = nullptr;
|
||||
|
||||
if( !m_alt.IsEmpty() )
|
||||
{
|
||||
localStorage = m_libPin->GetAlt( m_alt );
|
||||
alt = &localStorage;
|
||||
}
|
||||
|
||||
return wxString::Format( "Symbol %s %s",
|
||||
UnescapeString( GetParentSymbol()->GetField( REFERENCE_FIELD )->GetText() ),
|
||||
m_libPin->GetItemDescription( aUnitsProvider ) );
|
||||
m_libPin->GetItemDescription( aUnitsProvider, alt ) );
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -773,7 +773,6 @@ bool SCH_PLOTTER::plotOneSheetHpgl( const wxString& aFileName,
|
||||
plotter->SetPageSettings( aPageInfo );
|
||||
plotter->SetRenderSettings( aRenderSettings );
|
||||
plotter->RenderSettings()->LoadColors( m_colorSettings );
|
||||
plotter->SetColorMode( !aPlotSettings.m_blackAndWhite );
|
||||
plotter->SetViewport( aPlot0ffset, schIUScale.IU_PER_MILS/10, aScale, false );
|
||||
|
||||
// TODO this could be configurable
|
||||
|
||||
@@ -60,6 +60,7 @@
|
||||
#include <wx/log.h>
|
||||
#include <wx/zstream.h>
|
||||
#include <wx/wfstream.h>
|
||||
#include <wx/dir.h>
|
||||
#include <trigo.h>
|
||||
|
||||
// Harness port object itself does not contain color information about itself
|
||||
@@ -367,6 +368,24 @@ void SCH_ALTIUM_PLUGIN::ParseAltiumSch( const wxString& aFileName )
|
||||
// path as the parent sheet path.
|
||||
wxFileName loadAltiumFileName( parentFileName.GetPath(), sheet->GetFileName() );
|
||||
|
||||
if( !loadAltiumFileName.IsFileReadable() )
|
||||
{
|
||||
// Try case-insensitive search
|
||||
wxArrayString files;
|
||||
wxDir::GetAllFiles( parentFileName.GetPath(), &files, wxEmptyString, wxDIR_FILES | wxDIR_HIDDEN );
|
||||
|
||||
for( const wxString& candidate : files )
|
||||
{
|
||||
wxFileName candidateFname( candidate );
|
||||
|
||||
if( candidateFname.GetFullName().IsSameAs( sheet->GetFileName(), false ) )
|
||||
{
|
||||
loadAltiumFileName = candidateFname;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( loadAltiumFileName.GetFullName().IsEmpty() || !loadAltiumFileName.IsFileReadable() )
|
||||
{
|
||||
wxString msg;
|
||||
@@ -1411,21 +1430,28 @@ void SCH_ALTIUM_PLUGIN::ParsePolyline( const std::map<wxString, wxString>& aProp
|
||||
{
|
||||
ASCH_POLYLINE elem( aProperties );
|
||||
|
||||
if( elem.Points.size() < 2 )
|
||||
return;
|
||||
|
||||
SCH_SCREEN* screen = getCurrentScreen();
|
||||
wxCHECK( screen, /* void */ );
|
||||
|
||||
if( elem.OwnerPartID == ALTIUM_COMPONENT_NONE )
|
||||
{
|
||||
SCH_SHAPE* poly = new SCH_SHAPE( SHAPE_T::POLY );
|
||||
for( size_t i = 1; i < elem.Points.size(); i++ )
|
||||
{
|
||||
SCH_LINE* line = new SCH_LINE;
|
||||
|
||||
for( VECTOR2I& point : elem.Points )
|
||||
poly->AddPoint( point + m_sheetOffset );
|
||||
line->SetStartPoint( elem.Points[i - 1] + m_sheetOffset );
|
||||
line->SetEndPoint( elem.Points[i] + m_sheetOffset );
|
||||
|
||||
poly->SetStroke( STROKE_PARAMS( elem.LineWidth, GetPlotDashType( elem.LineStyle ),
|
||||
GetColorFromInt( elem.Color ) ) );
|
||||
poly->SetFlags( IS_NEW );
|
||||
line->SetStroke( STROKE_PARAMS( elem.LineWidth, GetPlotDashType( elem.LineStyle ),
|
||||
GetColorFromInt( elem.Color ) ) );
|
||||
|
||||
screen->Append( poly );
|
||||
line->SetFlags( IS_NEW );
|
||||
|
||||
screen->Append( line );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -2151,10 +2177,10 @@ VECTOR2I HelperGeneratePowerPortGraphics( LIB_SYMBOL* aKsymbol, ASCH_POWER_PORT_
|
||||
LIB_SHAPE* bezier = new LIB_SHAPE( aKsymbol, SHAPE_T::BEZIER );
|
||||
aKsymbol->AddDrawItem( bezier );
|
||||
bezier->SetStroke( STROKE_PARAMS( schIUScale.MilsToIU( 5 ), PLOT_DASH_TYPE::SOLID ) );
|
||||
bezier->AddPoint( { schIUScale.MilsToIU( 30 ), schIUScale.MilsToIU( -50 ) } );
|
||||
bezier->AddPoint( { schIUScale.MilsToIU( 30 ), schIUScale.MilsToIU( -87 ) } );
|
||||
bezier->AddPoint( { schIUScale.MilsToIU( -30 ), schIUScale.MilsToIU( -63 ) } );
|
||||
bezier->AddPoint( { schIUScale.MilsToIU( -30 ), schIUScale.MilsToIU( -100 ) } );
|
||||
bezier->SetStart( { schIUScale.MilsToIU( 30 ), schIUScale.MilsToIU( -50 ) } );
|
||||
bezier->SetBezierC1( { schIUScale.MilsToIU( 30 ), schIUScale.MilsToIU( -87 ) } );
|
||||
bezier->SetBezierC2( { schIUScale.MilsToIU( -30 ), schIUScale.MilsToIU( -63 ) } );
|
||||
bezier->SetEnd( { schIUScale.MilsToIU( -30 ), schIUScale.MilsToIU( -100 ) } );
|
||||
|
||||
return { 0, schIUScale.MilsToIU( 150 ) };
|
||||
}
|
||||
@@ -2317,10 +2343,17 @@ VECTOR2I HelperGeneratePowerPortGraphics( LIB_SYMBOL* aKsymbol, ASCH_POWER_PORT_
|
||||
void SCH_ALTIUM_PLUGIN::ParsePowerPort( const std::map<wxString, wxString>& aProperties )
|
||||
{
|
||||
ASCH_POWER_PORT elem( aProperties );
|
||||
LIB_ID libId = AltiumToKiCadLibID( getLibName(), elem.text );
|
||||
LIB_SYMBOL* libSymbol = nullptr;
|
||||
|
||||
const auto& powerSymbolIt = m_powerSymbols.find( elem.text );
|
||||
wxString symName( elem.text );
|
||||
wxString styleName = wxString( "Style" ) << static_cast<int>( elem.style );
|
||||
|
||||
if( !styleName.empty() )
|
||||
symName << '_' << styleName;
|
||||
|
||||
LIB_ID libId = AltiumToKiCadLibID( getLibName(), symName );
|
||||
LIB_SYMBOL* libSymbol = nullptr;
|
||||
|
||||
const auto& powerSymbolIt = m_powerSymbols.find( symName );
|
||||
|
||||
if( powerSymbolIt != m_powerSymbols.end() )
|
||||
{
|
||||
@@ -2358,7 +2391,7 @@ void SCH_ALTIUM_PLUGIN::ParsePowerPort( const std::map<wxString, wxString>& aPro
|
||||
|
||||
// this has to be done after parsing the LIB_SYMBOL!
|
||||
m_pi->SaveSymbol( getLibFileName().GetFullPath(), libSymbol, m_properties.get() );
|
||||
m_powerSymbols.insert( { elem.text, libSymbol } );
|
||||
m_powerSymbols.insert( { symName, libSymbol } );
|
||||
}
|
||||
|
||||
SCH_SCREEN* screen = getCurrentScreen();
|
||||
|
||||
@@ -790,6 +790,15 @@ LIB_FIELD* SCH_SEXPR_PARSER::parseProperty( std::unique_ptr<LIB_SYMBOL>& aSymbol
|
||||
CurOffset() );
|
||||
}
|
||||
|
||||
if( LIB_FIELD* existingName = aSymbol->FindField( name ) )
|
||||
{
|
||||
if( existingName->GetId() > MANDATORY_FIELDS )
|
||||
{
|
||||
THROW_PARSE_ERROR( wxString::Format( _( "Duplicate field '%s'" ), name ),
|
||||
CurSource(), CurLine(), CurLineNumber(), CurOffset() );
|
||||
}
|
||||
}
|
||||
|
||||
field->SetName( name );
|
||||
|
||||
// Correctly set the ID based on canonical (untranslated) field name
|
||||
@@ -3391,6 +3400,11 @@ SCH_SHAPE* SCH_SEXPR_PARSER::parseSchPolyLine()
|
||||
|
||||
case T_stroke:
|
||||
parseStroke( stroke );
|
||||
|
||||
// In 6.0, the default schematic line style was Dashed.
|
||||
if( m_requiredVersion <= 20211123 && stroke.GetPlotStyle() == PLOT_DASH_TYPE::DEFAULT )
|
||||
stroke.SetPlotStyle( PLOT_DASH_TYPE::DASH );
|
||||
|
||||
polyline->SetStroke( stroke );
|
||||
break;
|
||||
|
||||
|
||||
@@ -669,7 +669,19 @@ void SCH_LEGACY_PLUGIN_CACHE::loadField( std::unique_ptr<LIB_SYMBOL>& aSymbol,
|
||||
}
|
||||
else
|
||||
{
|
||||
parseQuotedString( field->m_name, aReader, line, &line, true ); // Optional.
|
||||
wxString fieldName = wxEmptyString;
|
||||
parseQuotedString( fieldName, aReader, line, &line, true ); // Optional.
|
||||
|
||||
if( fieldName.IsEmpty() )
|
||||
return;
|
||||
|
||||
if( aSymbol->FindField( fieldName ) != nullptr )
|
||||
{
|
||||
SCH_PARSE_ERROR( wxString::Format( _( "Duplicate field '%s'" ), fieldName ),
|
||||
aReader, line );
|
||||
}
|
||||
|
||||
field->m_name = fieldName;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -802,6 +802,10 @@ SCH_LINE* SCH_LEGACY_PLUGIN::loadWire( LINE_READER& aReader )
|
||||
if( !strCompare( "Line", line, &line ) )
|
||||
SCH_PARSE_ERROR( "invalid wire definition", aReader, line );
|
||||
|
||||
// The default graphical line style was Dashed.
|
||||
if( wire->GetLayer() == LAYER_NOTES )
|
||||
wire->SetLineStyle( PLOT_DASH_TYPE::DASH );
|
||||
|
||||
// Since Sept 15, 2017, a line style is alloved (width, style, color)
|
||||
// Only non default values are stored
|
||||
while( !is_eol( *line ) )
|
||||
|
||||
+66
-6
@@ -4,7 +4,7 @@
|
||||
* Copyright (C) 2013 Jean-Pierre Charras, jp.charras at wanadoo.fr
|
||||
* Copyright (C) 2012 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-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
|
||||
@@ -1634,8 +1634,10 @@ void SCH_SCREEN::PruneOrphanedSymbolInstances( const wxString& aProjectName,
|
||||
// The project name cannot be empty. Projects older than 7.0 did not save project names
|
||||
// when saving instance data. Running this algorithm with an empty project name would
|
||||
// clobber all instance data for projects other than the current one when a schematic
|
||||
// file is shared across multiple projects.
|
||||
wxCHECK( !aProjectName.IsEmpty(), /* void */ );
|
||||
// file is shared across multiple projects. Because running the schematic editor in
|
||||
// stand alone mode can result in an empty project name, do not assert here.
|
||||
if( aProjectName.IsEmpty() )
|
||||
return;
|
||||
|
||||
for( SCH_ITEM* item : Items().OfType( SCH_SYMBOL_T ) )
|
||||
{
|
||||
@@ -1655,7 +1657,7 @@ void SCH_SCREEN::PruneOrphanedSymbolInstances( const wxString& aProjectName,
|
||||
std::optional<SCH_SHEET_PATH> pathFound =
|
||||
aValidSheetPaths.GetSheetPathByKIIDPath( instance.m_Path );
|
||||
|
||||
// Check for paths that do not exist in the current project and paths that do
|
||||
// Check for paths that do not exist in the current project and paths that do
|
||||
// not contain the current symbol.
|
||||
if( !pathFound )
|
||||
pathsToPrune.emplace( instance.m_Path );
|
||||
@@ -1673,6 +1675,53 @@ void SCH_SCREEN::PruneOrphanedSymbolInstances( const wxString& aProjectName,
|
||||
}
|
||||
|
||||
|
||||
void SCH_SCREEN::PruneOrphanedSheetInstances( const wxString& aProjectName,
|
||||
const SCH_SHEET_LIST& aValidSheetPaths )
|
||||
{
|
||||
// The project name cannot be empty. Projects older than 7.0 did not save project names
|
||||
// when saving instance data. Running this algorithm with an empty project name would
|
||||
// clobber all instance data for projects other than the current one when a schematic
|
||||
// file is shared across multiple projects. Because running the schematic editor in
|
||||
// stand alone mode can result in an empty project name, do not assert here.
|
||||
if( aProjectName.IsEmpty() )
|
||||
return;
|
||||
|
||||
for( SCH_ITEM* item : Items().OfType( SCH_SHEET_T ) )
|
||||
{
|
||||
SCH_SHEET* sheet = static_cast<SCH_SHEET*>( item );
|
||||
|
||||
wxCHECK2( sheet, continue );
|
||||
|
||||
std::set<KIID_PATH> pathsToPrune;
|
||||
const std::vector<SCH_SHEET_INSTANCE> instances = sheet->GetInstances();
|
||||
|
||||
for( const SCH_SHEET_INSTANCE& instance : instances )
|
||||
{
|
||||
// Ignore instance paths from other projects.
|
||||
if( aProjectName != instance.m_ProjectName )
|
||||
continue;
|
||||
|
||||
std::optional<SCH_SHEET_PATH> pathFound =
|
||||
aValidSheetPaths.GetSheetPathByKIIDPath( instance.m_Path );
|
||||
|
||||
// Check for paths that do not exist in the current project and paths that do
|
||||
// not contain the current symbol.
|
||||
if( !pathFound )
|
||||
pathsToPrune.emplace( instance.m_Path );
|
||||
else if( pathFound.value().LastScreen() != this )
|
||||
pathsToPrune.emplace( pathFound.value().Path() );
|
||||
}
|
||||
|
||||
for( const KIID_PATH& sheetPath : pathsToPrune )
|
||||
{
|
||||
wxLogTrace( traceSchSheetPaths, wxS( "Pruning project '%s' sheet instance %s." ),
|
||||
aProjectName, sheetPath.AsString() );
|
||||
sheet->RemoveInstance( sheetPath );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#if defined(DEBUG)
|
||||
void SCH_SCREEN::Show( int nestLevel, std::ostream& os ) const
|
||||
{
|
||||
@@ -2092,11 +2141,22 @@ void SCH_SCREEN::MigrateSimModels()
|
||||
|
||||
|
||||
void SCH_SCREENS::PruneOrphanedSymbolInstances( const wxString& aProjectName,
|
||||
|
||||
const SCH_SHEET_LIST& aValidSheetPaths )
|
||||
{
|
||||
wxCHECK( !aProjectName.IsEmpty(), /* void */ );
|
||||
if( aProjectName.IsEmpty() )
|
||||
return;
|
||||
|
||||
for( SCH_SCREEN* screen = GetFirst(); screen; screen = GetNext() )
|
||||
screen->PruneOrphanedSymbolInstances( aProjectName, aValidSheetPaths );
|
||||
}
|
||||
|
||||
|
||||
void SCH_SCREENS::PruneOrphanedSheetInstances( const wxString& aProjectName,
|
||||
const SCH_SHEET_LIST& aValidSheetPaths )
|
||||
{
|
||||
if( aProjectName.IsEmpty() )
|
||||
return;
|
||||
|
||||
for( SCH_SCREEN* screen = GetFirst(); screen; screen = GetNext() )
|
||||
screen->PruneOrphanedSheetInstances( aProjectName, aValidSheetPaths );
|
||||
}
|
||||
|
||||
+23
-4
@@ -560,6 +560,21 @@ public:
|
||||
void PruneOrphanedSymbolInstances( const wxString& aProjectName,
|
||||
const SCH_SHEET_LIST& aValidSheetPaths );
|
||||
|
||||
/**
|
||||
* Remove all invalid sheet instance data in this screen object for the project defined
|
||||
* by \a aProjectName and the list of \a aValidSheetPaths.
|
||||
*
|
||||
* @warning This method will assert and exit on debug builds when \a aProjectName is empty.
|
||||
*
|
||||
* @note This method does not affect instance data for any other projects.
|
||||
*
|
||||
* @param aProjectName is the name of the current project.
|
||||
* @param aValidSheetPaths is the list of valid #SCH_SHEET_PATH objects for the current
|
||||
* project.
|
||||
*/
|
||||
void PruneOrphanedSheetInstances( const wxString& aProjectName,
|
||||
const SCH_SHEET_LIST& aValidSheetPaths );
|
||||
|
||||
private:
|
||||
friend SCH_EDIT_FRAME; // Only to populate m_symbolInstances.
|
||||
friend SCH_SEXPR_PARSER; // Only to load instance information from schematic file.
|
||||
@@ -587,12 +602,13 @@ private:
|
||||
size_t getLibSymbolNameMatches( const SCH_SYMBOL& aSymbol, std::vector<wxString>& aMatches );
|
||||
|
||||
|
||||
/**
|
||||
* Compare two #BUS_ALIAS objects by name. For sorting in the set.
|
||||
*/
|
||||
/**
|
||||
* Compare two #BUS_ALIAS objects by name. For sorting in the set.
|
||||
*/
|
||||
struct BusAliasCmp
|
||||
{
|
||||
bool operator()( const std::shared_ptr<BUS_ALIAS>& a, const std::shared_ptr<BUS_ALIAS>& b ) const
|
||||
bool operator()( const std::shared_ptr<BUS_ALIAS>& a,
|
||||
const std::shared_ptr<BUS_ALIAS>& b ) const
|
||||
{
|
||||
return a->GetName() < b->GetName();
|
||||
}
|
||||
@@ -811,6 +827,9 @@ public:
|
||||
void PruneOrphanedSymbolInstances( const wxString& aProjectName,
|
||||
const SCH_SHEET_LIST& aValidSheetPaths );
|
||||
|
||||
void PruneOrphanedSheetInstances( const wxString& aProjectName,
|
||||
const SCH_SHEET_LIST& aValidSheetPaths );
|
||||
|
||||
private:
|
||||
void addScreenToList( SCH_SCREEN* aScreen, SCH_SHEET* aSheet );
|
||||
void buildScreenList( SCH_SHEET* aSheet);
|
||||
|
||||
@@ -128,7 +128,7 @@ void SCH_SHAPE::Plot( PLOTTER* aPlotter, bool aBackground ) const
|
||||
if( !aPlotter->GetColorMode() )
|
||||
return;
|
||||
|
||||
if( m_fill == FILL_T::FILLED_WITH_COLOR && GetFillColor() != COLOR4D::UNSPECIFIED )
|
||||
if( IsFilled() )
|
||||
{
|
||||
if( GetFillColor() != COLOR4D::UNSPECIFIED )
|
||||
aPlotter->SetColor( GetFillColor() );
|
||||
|
||||
@@ -1318,3 +1318,18 @@ bool SCH_SHEET_LIST::HasPath( const KIID_PATH& aPath ) const
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool SCH_SHEET_LIST::ContainsSheet( const SCH_SHEET* aSheet ) const
|
||||
{
|
||||
for( const SCH_SHEET_PATH& path : *this )
|
||||
{
|
||||
for( size_t i = 0; i < path.size(); i++ )
|
||||
{
|
||||
if( path.at( i ) == aSheet )
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -674,6 +674,8 @@ public:
|
||||
|
||||
bool HasPath( const KIID_PATH& aPath ) const;
|
||||
|
||||
bool ContainsSheet( const SCH_SHEET* aSheet ) const;
|
||||
|
||||
private:
|
||||
SCH_SHEET_PATH m_currentSheetPath;
|
||||
};
|
||||
|
||||
+13
-10
@@ -1164,8 +1164,11 @@ std::vector<SCH_PIN*> SCH_SYMBOL::GetPins( const SCH_SHEET_PATH* aSheet ) const
|
||||
|
||||
for( const std::unique_ptr<SCH_PIN>& p : m_pins )
|
||||
{
|
||||
if( unit && p->GetLibPin()->GetUnit() && ( p->GetLibPin()->GetUnit() != unit ) )
|
||||
if( unit && p->GetLibPin() && p->GetLibPin()->GetUnit()
|
||||
&& ( p->GetLibPin()->GetUnit() != unit ) )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
pins.push_back( p.get() );
|
||||
}
|
||||
@@ -1942,7 +1945,7 @@ void SCH_SYMBOL::GetEndPoints( std::vector <DANGLING_END_ITEM>& aItemList )
|
||||
{
|
||||
LIB_PIN* lib_pin = pin->GetLibPin();
|
||||
|
||||
if( lib_pin->GetUnit() && m_unit && ( m_unit != lib_pin->GetUnit() ) )
|
||||
if( lib_pin && lib_pin->GetUnit() && m_unit && ( m_unit != lib_pin->GetUnit() ) )
|
||||
continue;
|
||||
|
||||
DANGLING_END_ITEM item( PIN_END, lib_pin, GetPinPhysicalPosition( lib_pin ), this );
|
||||
@@ -2018,8 +2021,8 @@ std::vector<VECTOR2I> SCH_SYMBOL::GetConnectionPoints() const
|
||||
{
|
||||
// Collect only pins attached to the current unit and convert.
|
||||
// others are not associated to this symbol instance
|
||||
int pin_unit = pin->GetLibPin()->GetUnit();
|
||||
int pin_convert = pin->GetLibPin()->GetConvert();
|
||||
int pin_unit = pin->GetLibPin() ? pin->GetLibPin()->GetUnit() : GetUnit();
|
||||
int pin_convert = pin->GetLibPin() ? pin->GetLibPin()->GetConvert() : GetConvert();
|
||||
|
||||
if( pin_unit > 0 && pin_unit != GetUnit() )
|
||||
continue;
|
||||
@@ -2109,8 +2112,8 @@ INSPECT_RESULT SCH_SYMBOL::Visit( INSPECTOR aInspector, void* aTestData,
|
||||
{
|
||||
// Collect only pins attached to the current unit and convert.
|
||||
// others are not associated to this symbol instance
|
||||
int pin_unit = pin->GetLibPin()->GetUnit();
|
||||
int pin_convert = pin->GetLibPin()->GetConvert();
|
||||
int pin_unit = pin->GetLibPin() ? pin->GetLibPin()->GetUnit() : GetUnit();
|
||||
int pin_convert = pin->GetLibPin() ? pin->GetLibPin()->GetConvert() : GetConvert();
|
||||
|
||||
if( pin_unit > 0 && pin_unit != GetUnit() )
|
||||
continue;
|
||||
@@ -2247,8 +2250,8 @@ bool SCH_SYMBOL::doIsConnected( const VECTOR2I& aPosition ) const
|
||||
|
||||
// Collect only pins attached to the current unit and convert.
|
||||
// others are not associated to this symbol instance
|
||||
int pin_unit = pin->GetLibPin()->GetUnit();
|
||||
int pin_convert = pin->GetLibPin()->GetConvert();
|
||||
int pin_unit = pin->GetLibPin() ? pin->GetLibPin()->GetUnit() : GetUnit();
|
||||
int pin_convert = pin->GetLibPin() ? pin->GetLibPin()->GetConvert() : GetConvert();
|
||||
|
||||
if( pin_unit > 0 && pin_unit != GetUnit() )
|
||||
continue;
|
||||
@@ -2430,8 +2433,8 @@ bool SCH_SYMBOL::IsPointClickableAnchor( const VECTOR2I& aPos ) const
|
||||
{
|
||||
for( const std::unique_ptr<SCH_PIN>& pin : m_pins )
|
||||
{
|
||||
int pin_unit = pin->GetLibPin()->GetUnit();
|
||||
int pin_convert = pin->GetLibPin()->GetConvert();
|
||||
int pin_unit = pin->GetLibPin() ? pin->GetLibPin()->GetUnit() : GetUnit();
|
||||
int pin_convert = pin->GetLibPin() ? pin->GetLibPin()->GetConvert() : GetConvert();
|
||||
|
||||
if( pin_unit > 0 && pin_unit != GetUnit() )
|
||||
continue;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2004 Jean-Pierre Charras, jaen-pierre.charras@gipsa-lab.inpg.com
|
||||
* Copyright (C) 2004-2022 KiCad Developers, see change_log.txt for contributors.
|
||||
* Copyright (C) 2004-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
|
||||
@@ -392,10 +392,17 @@ void SCH_EDIT_FRAME::RollbackSchematicFromUndo()
|
||||
{
|
||||
delete aItem;
|
||||
} );
|
||||
|
||||
// Only rebuild the hierarchy navigator if there are sheet changes.
|
||||
bool hasSheets = undo->ContainsItemType( SCH_SHEET_T );
|
||||
|
||||
delete undo;
|
||||
|
||||
SetSheetNumberAndCount();
|
||||
UpdateHierarchyNavigator();
|
||||
if( hasSheets )
|
||||
{
|
||||
SetSheetNumberAndCount();
|
||||
UpdateHierarchyNavigator();
|
||||
}
|
||||
|
||||
TestDanglingEnds();
|
||||
|
||||
|
||||
@@ -116,7 +116,11 @@ SYMBOL_EDIT_FRAME::SYMBOL_EDIT_FRAME( KIWAY* aKiway, wxWindow* aParent ) :
|
||||
wxIcon icon;
|
||||
wxIconBundle icon_bundle;
|
||||
|
||||
icon.CopyFromBitmap( KiBitmap( BITMAPS::icon_libedit ) );
|
||||
icon.CopyFromBitmap( KiBitmap( BITMAPS::icon_libedit, 48 ) );
|
||||
icon_bundle.AddIcon( icon );
|
||||
icon.CopyFromBitmap( KiBitmap( BITMAPS::icon_libedit, 256 ) );
|
||||
icon_bundle.AddIcon( icon );
|
||||
icon.CopyFromBitmap( KiBitmap( BITMAPS::icon_libedit, 128 ) );
|
||||
icon_bundle.AddIcon( icon );
|
||||
icon.CopyFromBitmap( KiBitmap( BITMAPS::icon_libedit_32 ) );
|
||||
icon_bundle.AddIcon( icon );
|
||||
|
||||
@@ -1252,7 +1252,7 @@ void SYMBOL_VIEWER_FRAME::onSelectNextSymbol( wxCommandEvent& aEvent )
|
||||
int ii = m_symbolList->GetSelection();
|
||||
|
||||
// Select the next symbol or stop at the end of the list.
|
||||
if( ii != wxNOT_FOUND || ii != (int) m_symbolList->GetCount() - 1 )
|
||||
if( ii != wxNOT_FOUND && ii < (int)(m_symbolList->GetCount() - 1) )
|
||||
ii += 1;
|
||||
|
||||
m_symbolList->SetSelection( ii );
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2019 CERN
|
||||
* Copyright (C) 2019-2023 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
* Copyright (C) 2019-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
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2019 CERN
|
||||
* Copyright (C) 2019-2023 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
* Copyright (C) 2019-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
|
||||
@@ -1218,9 +1218,10 @@ static std::vector<KICAD_T> deletableItems =
|
||||
|
||||
int SCH_EDIT_TOOL::DoDelete( const TOOL_EVENT& aEvent )
|
||||
{
|
||||
SCH_SCREEN* screen = m_frame->GetScreen();
|
||||
auto items = m_selectionTool->RequestSelection( deletableItems ).GetItems();
|
||||
bool appendToUndo = false;
|
||||
SCH_SCREEN* screen = m_frame->GetScreen();
|
||||
auto items = m_selectionTool->RequestSelection( deletableItems ).GetItems();
|
||||
bool appendToUndo = false;
|
||||
bool rebuildHierarchyNavigator = false;
|
||||
std::vector<VECTOR2I> pts;
|
||||
|
||||
if( items.empty() )
|
||||
@@ -1285,7 +1286,7 @@ int SCH_EDIT_TOOL::DoDelete( const TOOL_EVENT& aEvent )
|
||||
m_frame->RemoveFromScreen( sch_item, m_frame->GetScreen() );
|
||||
|
||||
if( sch_item->Type() == SCH_SHEET_T )
|
||||
m_frame->UpdateHierarchyNavigator();
|
||||
rebuildHierarchyNavigator = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1300,8 +1301,10 @@ int SCH_EDIT_TOOL::DoDelete( const TOOL_EVENT& aEvent )
|
||||
m_frame->DeleteJunction( junction, appendToUndo );
|
||||
}
|
||||
|
||||
m_frame->TestDanglingEnds();
|
||||
if( rebuildHierarchyNavigator )
|
||||
m_frame->UpdateHierarchyNavigator();
|
||||
|
||||
m_frame->TestDanglingEnds();
|
||||
m_frame->GetCanvas()->Refresh();
|
||||
m_frame->OnModify();
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2019 CERN
|
||||
* Copyright (C) 1992-2023 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
* Copyright (C) 1992-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
|
||||
@@ -1231,7 +1231,10 @@ int SCH_EDITOR_CONTROL::Undo( const TOOL_EVENT& aEvent )
|
||||
m_toolMgr->ProcessEvent( { TC_MESSAGE, TA_UNDO_REDO_PRE, AS_GLOBAL } );
|
||||
|
||||
// Get the old list
|
||||
PICKED_ITEMS_LIST* List = m_frame->PopCommandFromUndoList();
|
||||
PICKED_ITEMS_LIST* list = m_frame->PopCommandFromUndoList();
|
||||
|
||||
wxCHECK( m_frame && list, 0 );
|
||||
|
||||
size_t num_undos = m_frame->m_undoList.m_CommandsList.size();
|
||||
|
||||
// The cleanup routines normally run after an operation and so attempt to append their
|
||||
@@ -1240,9 +1243,15 @@ int SCH_EDITOR_CONTROL::Undo( const TOOL_EVENT& aEvent )
|
||||
PICKED_ITEMS_LIST* dummy = new PICKED_ITEMS_LIST();
|
||||
m_frame->PushCommandToUndoList( dummy );
|
||||
|
||||
m_frame->PutDataInPreviousState( List );
|
||||
m_frame->PutDataInPreviousState( list );
|
||||
|
||||
// Only rebuild the hierarchy navigator if there are sheet changes.
|
||||
if( list->ContainsItemType( SCH_SHEET_T ) )
|
||||
{
|
||||
m_frame->SetSheetNumberAndCount();
|
||||
m_frame->UpdateHierarchyNavigator();
|
||||
}
|
||||
|
||||
m_frame->SetSheetNumberAndCount();
|
||||
m_frame->TestDanglingEnds();
|
||||
m_frame->OnPageSettingsChange();
|
||||
|
||||
@@ -1252,8 +1261,8 @@ int SCH_EDITOR_CONTROL::Undo( const TOOL_EVENT& aEvent )
|
||||
delete m_frame->PopCommandFromUndoList();
|
||||
|
||||
// Now push the old command to the RedoList
|
||||
List->ReversePickersListOrder();
|
||||
m_frame->PushCommandToRedoList( List );
|
||||
list->ReversePickersListOrder();
|
||||
m_frame->PushCommandToRedoList( list );
|
||||
|
||||
m_toolMgr->GetTool<EE_SELECTION_TOOL>()->RebuildSelection();
|
||||
|
||||
@@ -1267,6 +1276,8 @@ int SCH_EDITOR_CONTROL::Undo( const TOOL_EVENT& aEvent )
|
||||
|
||||
int SCH_EDITOR_CONTROL::Redo( const TOOL_EVENT& aEvent )
|
||||
{
|
||||
wxCHECK( m_frame, 0 );
|
||||
|
||||
if( m_frame->GetRedoCommandCount() == 0 )
|
||||
return 0;
|
||||
|
||||
@@ -1276,6 +1287,8 @@ int SCH_EDITOR_CONTROL::Redo( const TOOL_EVENT& aEvent )
|
||||
/* Get the old list */
|
||||
PICKED_ITEMS_LIST* list = m_frame->PopCommandFromRedoList();
|
||||
|
||||
wxCHECK( list, 0 );
|
||||
|
||||
/* Redo the command: */
|
||||
m_frame->PutDataInPreviousState( list );
|
||||
|
||||
@@ -1283,7 +1296,13 @@ int SCH_EDITOR_CONTROL::Redo( const TOOL_EVENT& aEvent )
|
||||
list->ReversePickersListOrder();
|
||||
m_frame->PushCommandToUndoList( list );
|
||||
|
||||
m_frame->SetSheetNumberAndCount();
|
||||
// Only rebuild the hierarchy navigator if there are sheet changes.
|
||||
if( list->ContainsItemType( SCH_SHEET_T ) )
|
||||
{
|
||||
m_frame->SetSheetNumberAndCount();
|
||||
m_frame->UpdateHierarchyNavigator();
|
||||
}
|
||||
|
||||
m_frame->TestDanglingEnds();
|
||||
|
||||
m_toolMgr->GetTool<EE_SELECTION_TOOL>()->RebuildSelection();
|
||||
@@ -1401,27 +1420,41 @@ int SCH_EDITOR_CONTROL::Copy( const TOOL_EVENT& aEvent )
|
||||
}
|
||||
|
||||
|
||||
void SCH_EDITOR_CONTROL::updatePastedSymbol( SCH_SYMBOL* aSymbol, SCH_SCREEN* aPasteScreen,
|
||||
void SCH_EDITOR_CONTROL::updatePastedSymbol( SCH_SYMBOL* aSymbol,
|
||||
const SCH_SHEET_PATH& aPastePath,
|
||||
const KIID_PATH& aClipPath,
|
||||
bool aForceKeepAnnotations )
|
||||
{
|
||||
wxCHECK( m_frame && aSymbol && aPasteScreen, /* void */ );
|
||||
wxCHECK( m_frame && aSymbol, /* void */ );
|
||||
|
||||
SCH_SYMBOL_INSTANCE instance;
|
||||
SCH_SYMBOL_INSTANCE newInstance;
|
||||
bool instanceFound = false;
|
||||
KIID_PATH pasteLookupPath = aClipPath;
|
||||
|
||||
m_pastedSymbols.insert( aSymbol );
|
||||
|
||||
for( const SCH_SYMBOL_INSTANCE& tmp : aSymbol->GetInstanceReferences() )
|
||||
{
|
||||
if( tmp.m_Path.EndsWith( aClipPath ) )
|
||||
{
|
||||
newInstance = tmp;
|
||||
instanceFound = true;
|
||||
|
||||
wxLogDebug( wxS( "Pasting found symbol instance:\n\tpath: %s\n\tuuid: %s." ),
|
||||
aClipPath.AsString(), aSymbol->m_Uuid.AsString() );
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// The pasted symbol look up paths include the symbol UUID.
|
||||
pasteLookupPath.push_back( aSymbol->m_Uuid );
|
||||
|
||||
if( m_clipboardSymbolInstances.count( pasteLookupPath ) > 0 )
|
||||
{
|
||||
instance = m_clipboardSymbolInstances.at( pasteLookupPath );
|
||||
}
|
||||
else
|
||||
if( !instanceFound )
|
||||
{
|
||||
wxLogDebug( wxS( "Clipboard symbol instance **not** found:\n\tpath: %s\n\tuuid: %s." ),
|
||||
aClipPath.AsString(), aSymbol->m_Uuid.AsString() );
|
||||
|
||||
// Some legacy versions saved value fields escaped. While we still do in the symbol
|
||||
// editor, we don't anymore in the schematic, so be sure to unescape them.
|
||||
SCH_FIELD* valueField = aSymbol->GetField( VALUE_FIELD );
|
||||
@@ -1429,119 +1462,112 @@ void SCH_EDITOR_CONTROL::updatePastedSymbol( SCH_SYMBOL* aSymbol, SCH_SCREEN* aP
|
||||
|
||||
// Pasted from notepad or an older instance of eeschema. Use the values in the fields
|
||||
// instead.
|
||||
instance.m_Reference = aSymbol->GetField( REFERENCE_FIELD )->GetText();
|
||||
instance.m_Unit = aSymbol->GetUnit();
|
||||
newInstance.m_Reference = aSymbol->GetField( REFERENCE_FIELD )->GetText();
|
||||
newInstance.m_Unit = aSymbol->GetUnit();
|
||||
}
|
||||
|
||||
instance.m_Path = aPastePath.Path() + aClipPath;
|
||||
instance.m_ProjectName = m_frame->Prj().GetProjectName();
|
||||
newInstance.m_Path = aPastePath.Path();
|
||||
newInstance.m_ProjectName = m_frame->Prj().GetProjectName();
|
||||
|
||||
aSymbol->AddHierarchicalReference( instance );
|
||||
aSymbol->AddHierarchicalReference( newInstance );
|
||||
|
||||
if( !aForceKeepAnnotations )
|
||||
aSymbol->ClearAnnotation( &aPastePath, false );
|
||||
|
||||
// We might clear annotations but always leave the original unit number from the paste.
|
||||
aSymbol->SetUnit( instance.m_Unit );
|
||||
aSymbol->SetUnit( newInstance.m_Unit );
|
||||
}
|
||||
|
||||
|
||||
SCH_SHEET_PATH SCH_EDITOR_CONTROL::updatePastedSheet( const SCH_SHEET_PATH& aPastePath,
|
||||
const KIID_PATH& aClipPath, SCH_SHEET* aSheet,
|
||||
SCH_SHEET_PATH SCH_EDITOR_CONTROL::updatePastedSheet( SCH_SHEET* aSheet,
|
||||
const SCH_SHEET_PATH& aPastePath,
|
||||
const KIID_PATH& aClipPath,
|
||||
bool aForceKeepAnnotations,
|
||||
SCH_SHEET_LIST* aPastedSheetsSoFar,
|
||||
SCH_REFERENCE_LIST* aPastedSymbolsSoFar )
|
||||
SCH_SHEET_LIST* aPastedSheets,
|
||||
std::map<SCH_SHEET_PATH, SCH_REFERENCE_LIST>& aPastedSymbols )
|
||||
{
|
||||
wxCHECK( aSheet && aPastedSheetsSoFar && aPastedSymbolsSoFar, aPastePath );
|
||||
wxCHECK( aSheet && aPastedSheets, aPastePath );
|
||||
|
||||
SCH_SHEET_PATH sheetPath = aPastePath;
|
||||
sheetPath.push_back( aSheet );
|
||||
|
||||
aPastedSheetsSoFar->push_back( sheetPath );
|
||||
aPastedSheets->push_back( sheetPath );
|
||||
|
||||
if( aSheet->GetScreen() == nullptr )
|
||||
return sheetPath; // We can only really set the page number but not load any items
|
||||
|
||||
for( SCH_ITEM* item : aSheet->GetScreen()->Items() )
|
||||
{
|
||||
if( item->IsConnectable() )
|
||||
item->SetConnectivityDirty();
|
||||
|
||||
if( item->Type() == SCH_SYMBOL_T )
|
||||
{
|
||||
SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
|
||||
|
||||
updatePastedSymbol( symbol, aSheet->GetScreen(), sheetPath, aClipPath,
|
||||
aForceKeepAnnotations );
|
||||
wxCHECK2( symbol, continue );
|
||||
|
||||
// Only do this once if the symbol is shared across multiple sheets.
|
||||
if( !m_pastedSymbols.count( symbol ) )
|
||||
{
|
||||
for( SCH_PIN* pin : symbol->GetPins() )
|
||||
{
|
||||
const_cast<KIID&>( pin->m_Uuid ) = KIID();
|
||||
pin->SetConnectivityDirty();
|
||||
}
|
||||
}
|
||||
|
||||
updatePastedSymbol( symbol, sheetPath, aClipPath, aForceKeepAnnotations );
|
||||
}
|
||||
else if( item->Type() == SCH_SHEET_T )
|
||||
{
|
||||
SCH_SHEET* subsheet = static_cast<SCH_SHEET*>( item );
|
||||
|
||||
wxCHECK2( subsheet, continue );
|
||||
|
||||
// Make sure pins get a new UUID and set the dirty connectivity flag.
|
||||
if( !aPastedSheets->ContainsSheet( subsheet ) )
|
||||
{
|
||||
for( SCH_SHEET_PIN* pin : subsheet->GetPins() )
|
||||
{
|
||||
const_cast<KIID&>( pin->m_Uuid ) = KIID();
|
||||
pin->SetConnectivityDirty();
|
||||
}
|
||||
}
|
||||
|
||||
KIID_PATH newClipPath = aClipPath;
|
||||
newClipPath.push_back( subsheet->m_Uuid );
|
||||
|
||||
updatePastedSheet( sheetPath, newClipPath, subsheet, aForceKeepAnnotations,
|
||||
aPastedSheetsSoFar, aPastedSymbolsSoFar );
|
||||
|
||||
SCH_SHEET_PATH subSheetPath = sheetPath;
|
||||
|
||||
subSheetPath.push_back( subsheet );
|
||||
subSheetPath.GetSymbols( *aPastedSymbolsSoFar );
|
||||
updatePastedSheet( subsheet, sheetPath, newClipPath, aForceKeepAnnotations,
|
||||
aPastedSheets, aPastedSymbols );
|
||||
}
|
||||
}
|
||||
|
||||
sheetPath.GetSymbols( aPastedSymbols[aPastePath] );
|
||||
|
||||
return sheetPath;
|
||||
}
|
||||
|
||||
|
||||
void SCH_EDITOR_CONTROL::setPastedSheetInstances( const SCH_SHEET* aPastedSheet )
|
||||
void SCH_EDITOR_CONTROL::setPastedSymbolInstances( const SCH_SCREEN* aScreen )
|
||||
{
|
||||
wxCHECK( aPastedSheet, /* void */ );
|
||||
wxCHECK( aScreen, /* void */ );
|
||||
|
||||
for( const SCH_SHEET_INSTANCE& sheetInstance : aPastedSheet->GetInstances() )
|
||||
for( SCH_ITEM* item : aScreen->Items() )
|
||||
{
|
||||
KIID_PATH pathWithSheet = sheetInstance.m_Path;
|
||||
|
||||
pathWithSheet.push_back( aPastedSheet->m_Uuid );
|
||||
m_clipboardSheetInstances[pathWithSheet] = sheetInstance;
|
||||
}
|
||||
|
||||
const SCH_SCREEN* screen = aPastedSheet->GetScreen();
|
||||
|
||||
wxCHECK( screen, /* void */ );
|
||||
|
||||
for( SCH_ITEM* item : screen->Items() )
|
||||
{
|
||||
if( item->Type() == SCH_SHEET_T )
|
||||
if( item->Type() == SCH_SYMBOL_T )
|
||||
{
|
||||
const SCH_SHEET* sheet = static_cast<SCH_SHEET*>( item );
|
||||
SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
|
||||
|
||||
wxCHECK2( sheet, continue );
|
||||
wxCHECK2( symbol, continue );
|
||||
|
||||
setPastedSheetInstances( sheet );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void SCH_EDITOR_CONTROL::setPastedSymbolInstances( SCH_SCREENS& aScreenList )
|
||||
{
|
||||
for( SCH_SCREEN* screen = aScreenList.GetFirst(); screen; screen = aScreenList.GetNext() )
|
||||
{
|
||||
for( SCH_ITEM* item : screen->Items() )
|
||||
{
|
||||
if( item->Type() == SCH_SYMBOL_T )
|
||||
for( const SCH_SYMBOL_INSTANCE& symbolInstance : symbol->GetInstanceReferences() )
|
||||
{
|
||||
SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
|
||||
KIID_PATH pathWithSymbol = symbolInstance.m_Path;
|
||||
|
||||
wxCHECK2( symbol, continue );
|
||||
pathWithSymbol.push_back( symbol->m_Uuid );
|
||||
|
||||
for( const SCH_SYMBOL_INSTANCE& symbolInstance : symbol->GetInstanceReferences() )
|
||||
{
|
||||
KIID_PATH pathWithSymbol = symbolInstance.m_Path;
|
||||
|
||||
pathWithSymbol.push_back( symbol->m_Uuid );
|
||||
|
||||
m_clipboardSymbolInstances[pathWithSymbol] = symbolInstance;
|
||||
}
|
||||
m_clipboardSymbolInstances[pathWithSymbol] = symbolInstance;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1620,15 +1646,11 @@ int SCH_EDITOR_CONTROL::Paste( const TOOL_EVENT& aEvent )
|
||||
tempScreen->Append( text_item );
|
||||
}
|
||||
|
||||
SCH_SCREENS tempScreens( tempSheet );
|
||||
|
||||
m_pastedSymbols.clear();
|
||||
m_clipboardSheetInstances.clear();
|
||||
m_clipboardSymbolInstances.clear();
|
||||
|
||||
// Save pasted sheet and symbol instances.
|
||||
setPastedSheetInstances( &tempSheet );
|
||||
setPastedSymbolInstances( tempScreens );
|
||||
// Save pasted symbol instances.
|
||||
setPastedSymbolInstances( tempScreen );
|
||||
|
||||
tempScreen->MigrateSimModels();
|
||||
|
||||
@@ -1720,6 +1742,13 @@ int SCH_EDITOR_CONTROL::Paste( const TOOL_EVENT& aEvent )
|
||||
EDA_ITEM* item = loadedItems[i];
|
||||
KIID_PATH clipPath( wxT( "/" ) ); // clipboard is at root
|
||||
|
||||
SCH_ITEM* schItem = static_cast<SCH_ITEM*>( item );
|
||||
|
||||
wxCHECK2( schItem, continue );
|
||||
|
||||
if( schItem->IsConnectable() )
|
||||
schItem->SetConnectivityDirty();
|
||||
|
||||
if( item->Type() == SCH_SYMBOL_T )
|
||||
{
|
||||
SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
|
||||
@@ -1751,14 +1780,17 @@ int SCH_EDITOR_CONTROL::Paste( const TOOL_EVENT& aEvent )
|
||||
}
|
||||
|
||||
for( SCH_SHEET_PATH& instance : pasteInstances )
|
||||
updatePastedSymbol( symbol, tempScreen, instance, clipPath, forceKeepAnnotations );
|
||||
updatePastedSymbol( symbol, instance, clipPath, forceKeepAnnotations );
|
||||
|
||||
// Assign a new KIID
|
||||
const_cast<KIID&>( item->m_Uuid ) = KIID();
|
||||
|
||||
// Make sure pins get a new UUID
|
||||
for( SCH_PIN* pin : symbol->GetPins() )
|
||||
{
|
||||
const_cast<KIID&>( pin->m_Uuid ) = KIID();
|
||||
pin->SetConnectivityDirty();
|
||||
}
|
||||
|
||||
for( SCH_SHEET_PATH& instance : pasteInstances )
|
||||
{
|
||||
@@ -1831,6 +1863,9 @@ int SCH_EDITOR_CONTROL::Paste( const TOOL_EVENT& aEvent )
|
||||
m_frame->InitSheet( sheet, sheet->GetFileName() );
|
||||
}
|
||||
|
||||
// Save the symbol instances in case the user chooses to keep the existing
|
||||
// symbol annotation.
|
||||
setPastedSymbolInstances( sheet->GetScreen() );
|
||||
sheetsPasted = true;
|
||||
|
||||
// Push it to the clipboard path while it still has its old KIID
|
||||
@@ -1841,18 +1876,19 @@ int SCH_EDITOR_CONTROL::Paste( const TOOL_EVENT& aEvent )
|
||||
|
||||
// Make sure pins get a new UUID
|
||||
for( SCH_SHEET_PIN* pin : sheet->GetPins() )
|
||||
{
|
||||
const_cast<KIID&>( pin->m_Uuid ) = KIID();
|
||||
pin->SetConnectivityDirty();
|
||||
}
|
||||
|
||||
// Once we have our new KIID we can update all pasted instances. This will either
|
||||
// reset the annotations or copy "kept" annotations from the supplementary clipboard.
|
||||
for( SCH_SHEET_PATH& instance : pasteInstances )
|
||||
{
|
||||
SCH_SHEET_PATH sheetPath = updatePastedSheet( instance, clipPath, sheet,
|
||||
( forceKeepAnnotations && annotate.automatic ),
|
||||
&pastedSheets[instance],
|
||||
&pastedSymbols[instance] );
|
||||
|
||||
sheetPath.GetSymbols( pastedSymbols[instance] );
|
||||
SCH_SHEET_PATH subPath = updatePastedSheet( sheet, instance, clipPath,
|
||||
( forceKeepAnnotations && annotate.automatic ),
|
||||
&pastedSheets[instance],
|
||||
pastedSymbols );
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -1895,16 +1931,12 @@ int SCH_EDITOR_CONTROL::Paste( const TOOL_EVENT& aEvent )
|
||||
getView()->Hide( item, true );
|
||||
}
|
||||
|
||||
pasteInstances.SortByPageNumbers();
|
||||
|
||||
if( sheetsPasted )
|
||||
{
|
||||
// Update page numbers: Find next free numeric page number
|
||||
for( SCH_SHEET_PATH& instance : pasteInstances )
|
||||
for( SCH_SHEET_PATH& sheetPath : pasteInstances )
|
||||
{
|
||||
pastedSheets[instance].SortByPageNumbers();
|
||||
|
||||
for( SCH_SHEET_PATH& pastedSheet : pastedSheets[instance] )
|
||||
for( SCH_SHEET_PATH& pastedSheet : pastedSheets[sheetPath] )
|
||||
{
|
||||
int page = 1;
|
||||
wxString pageNum = wxString::Format( "%d", page );
|
||||
@@ -1912,8 +1944,33 @@ int SCH_EDITOR_CONTROL::Paste( const TOOL_EVENT& aEvent )
|
||||
while( hierarchy.PageNumberExists( pageNum ) )
|
||||
pageNum = wxString::Format( "%d", ++page );
|
||||
|
||||
pastedSheet.SetPageNumber( pageNum );
|
||||
SCH_SHEET_INSTANCE sheetInstance;
|
||||
|
||||
sheetInstance.m_Path = pastedSheet.Path();
|
||||
|
||||
// Don't include the actual sheet in the instance path.
|
||||
sheetInstance.m_Path.pop_back();
|
||||
sheetInstance.m_PageNumber = pageNum;
|
||||
sheetInstance.m_ProjectName = m_frame->Prj().GetProjectName();
|
||||
|
||||
SCH_SHEET* sheet = pastedSheet.Last();
|
||||
|
||||
wxCHECK2( sheet, continue );
|
||||
|
||||
sheet->AddInstance( sheetInstance );
|
||||
hierarchy.push_back( pastedSheet );
|
||||
|
||||
// Remove all pasted sheet instance data that is not part of the current project.
|
||||
std::vector<KIID_PATH> instancesToRemove;
|
||||
|
||||
for( const SCH_SHEET_INSTANCE& pastedInstance : sheet->GetInstances() )
|
||||
{
|
||||
if( !hierarchy.HasPath( pastedInstance.m_Path ) )
|
||||
instancesToRemove.push_back( pastedInstance.m_Path );
|
||||
}
|
||||
|
||||
for( const KIID_PATH& instancePath : instancesToRemove )
|
||||
sheet->RemoveInstance( instancePath );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1947,42 +2004,81 @@ int SCH_EDITOR_CONTROL::Paste( const TOOL_EVENT& aEvent )
|
||||
annotatedSymbols[sheetPath].AddItem( pastedSymbols[sheetPath][i] );
|
||||
}
|
||||
}
|
||||
|
||||
for( const SCH_SHEET_PATH& pastedSheetPath : pastedSheets[sheetPath] )
|
||||
{
|
||||
for( size_t i = 0; i < pastedSymbols[pastedSheetPath].GetCount(); i++ )
|
||||
{
|
||||
if( pasteMode == PASTE_MODE::UNIQUE_ANNOTATIONS
|
||||
|| pasteMode == PASTE_MODE::RESPECT_OPTIONS
|
||||
|| pastedSymbols[pastedSheetPath][i].AlwaysAnnotate() )
|
||||
{
|
||||
annotatedSymbols[pastedSheetPath].AddItem( pastedSymbols[pastedSheetPath][i] );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( !annotatedSymbols.empty() )
|
||||
{
|
||||
for( SCH_SHEET_PATH& instance : pasteInstances )
|
||||
for( const SCH_SHEET_PATH& path : pasteInstances )
|
||||
{
|
||||
annotatedSymbols[instance].SortByReferenceOnly();
|
||||
annotatedSymbols[path].SortByReferenceOnly();
|
||||
|
||||
if( pasteMode == PASTE_MODE::UNIQUE_ANNOTATIONS )
|
||||
annotatedSymbols[instance].ReannotateDuplicates( existingRefs );
|
||||
annotatedSymbols[path].ReannotateDuplicates( existingRefs );
|
||||
else
|
||||
annotatedSymbols[instance].ReannotateByOptions( (ANNOTATE_ORDER_T) annotate.sort_order,
|
||||
(ANNOTATE_ALGO_T) annotate.method,
|
||||
annotateStartNum, existingRefs,
|
||||
false,
|
||||
&hierarchy );
|
||||
annotatedSymbols[path].ReannotateByOptions( (ANNOTATE_ORDER_T) annotate.sort_order,
|
||||
(ANNOTATE_ALGO_T) annotate.method,
|
||||
annotateStartNum, existingRefs,
|
||||
false,
|
||||
&hierarchy );
|
||||
|
||||
annotatedSymbols[instance].UpdateAnnotation();
|
||||
annotatedSymbols[path].UpdateAnnotation();
|
||||
|
||||
// Update existing refs for next iteration
|
||||
for( size_t i = 0; i < annotatedSymbols[instance].GetCount(); i++ )
|
||||
existingRefs.AddItem( annotatedSymbols[instance][i] );
|
||||
for( size_t i = 0; i < annotatedSymbols[path].GetCount(); i++ )
|
||||
existingRefs.AddItem( annotatedSymbols[path][i] );
|
||||
|
||||
for( const SCH_SHEET_PATH& pastedSheetPath : pastedSheets[path] )
|
||||
{
|
||||
annotatedSymbols[pastedSheetPath].SortByReferenceOnly();
|
||||
|
||||
if( pasteMode == PASTE_MODE::UNIQUE_ANNOTATIONS )
|
||||
{
|
||||
annotatedSymbols[pastedSheetPath].ReannotateDuplicates( existingRefs );
|
||||
}
|
||||
else
|
||||
{
|
||||
annotatedSymbols[pastedSheetPath].ReannotateByOptions( (ANNOTATE_ORDER_T) annotate.sort_order,
|
||||
(ANNOTATE_ALGO_T) annotate.method,
|
||||
annotateStartNum, existingRefs,
|
||||
false,
|
||||
&hierarchy );
|
||||
}
|
||||
|
||||
annotatedSymbols[pastedSheetPath].UpdateAnnotation();
|
||||
|
||||
// Update existing refs for next iteration
|
||||
for( size_t i = 0; i < annotatedSymbols[pastedSheetPath].GetCount(); i++ )
|
||||
existingRefs.AddItem( annotatedSymbols[pastedSheetPath][i] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_frame->GetCurrentSheet().UpdateAllScreenReferences();
|
||||
|
||||
prunePastedSymbolInstances();
|
||||
|
||||
// The copy operation creates instance paths that are not valid for the current project or
|
||||
// saved as part of another project. Prune them now so they do not accumulate in the saved
|
||||
// schematic file.
|
||||
prunePastedSymbolInstances();
|
||||
|
||||
SCH_SCREENS allScreens( m_frame->Schematic().Root() );
|
||||
|
||||
allScreens.PruneOrphanedSymbolInstances( m_frame->Prj().GetProjectName(),
|
||||
m_frame->Schematic().GetSheets() );
|
||||
allScreens.PruneOrphanedSheetInstances( m_frame->Prj().GetProjectName(),
|
||||
m_frame->Schematic().GetSheets() );
|
||||
|
||||
// Now clear the previous selection, select the pasted items, and fire up the "move" tool.
|
||||
m_toolMgr->RunAction( EE_ACTIONS::clearSelection, true );
|
||||
|
||||
@@ -175,17 +175,15 @@ private:
|
||||
|
||||
void doCrossProbeSchToPcb( const TOOL_EVENT& aEvent, bool aForce );
|
||||
|
||||
void updatePastedSymbol( SCH_SYMBOL* aSymbol, SCH_SCREEN* aPasteScreen,
|
||||
const SCH_SHEET_PATH& aPastePath, const KIID_PATH& aClipPath,
|
||||
bool aForceKeepAnnotations );
|
||||
void updatePastedSymbol( SCH_SYMBOL* aSymbol, const SCH_SHEET_PATH& aPastePath,
|
||||
const KIID_PATH& aClipPath, bool aForceKeepAnnotations );
|
||||
|
||||
SCH_SHEET_PATH updatePastedSheet( const SCH_SHEET_PATH& aPastePath, const KIID_PATH& aClipPath,
|
||||
SCH_SHEET* aSheet, bool aForceKeepAnnotations,
|
||||
SCH_SHEET_LIST* aPastedSheetsSoFar,
|
||||
SCH_REFERENCE_LIST* aPastedSymbolsSoFar );
|
||||
SCH_SHEET_PATH updatePastedSheet( SCH_SHEET* aSheet, const SCH_SHEET_PATH& aPastePath,
|
||||
const KIID_PATH& aClipPath, bool aForceKeepAnnotations,
|
||||
SCH_SHEET_LIST* aPastedSheets,
|
||||
std::map<SCH_SHEET_PATH, SCH_REFERENCE_LIST>& aPastedSymbols );
|
||||
|
||||
void setPastedSheetInstances( const SCH_SHEET* aPastedSheet );
|
||||
void setPastedSymbolInstances( SCH_SCREENS& aScreenList );
|
||||
void setPastedSymbolInstances( const SCH_SCREEN* aScreen );
|
||||
|
||||
/**
|
||||
* Remove all pasted symbol instances that do not belong to the current project.
|
||||
@@ -239,9 +237,6 @@ private:
|
||||
// A map of KIID_PATH --> symbol instances for the clipboard contents.
|
||||
std::map<KIID_PATH, SCH_SYMBOL_INSTANCE> m_clipboardSymbolInstances;
|
||||
|
||||
// A map of KIID_PATH --> sheet instances for the clipboard contents.
|
||||
std::map<KIID_PATH, SCH_SHEET_INSTANCE> m_clipboardSheetInstances;
|
||||
|
||||
std::set<SCH_SYMBOL*> m_pastedSymbols;
|
||||
};
|
||||
|
||||
|
||||
@@ -603,12 +603,14 @@ int SCH_MOVE_TOOL::Main( const TOOL_EVENT& aEvent )
|
||||
}
|
||||
else
|
||||
{
|
||||
saveCopyInUndoList( (SCH_ITEM*) item, UNDO_REDO::CHANGED, appendUndo );
|
||||
saveCopyInUndoList( item, UNDO_REDO::CHANGED, appendUndo );
|
||||
appendUndo = true;
|
||||
}
|
||||
|
||||
SCH_ITEM* schItem = (SCH_ITEM*) item;
|
||||
schItem->SetStoredPos( schItem->GetPosition() );
|
||||
item->SetFlags( IS_MOVING );
|
||||
|
||||
if( SCH_ITEM* schItem = dynamic_cast<SCH_ITEM*>( item ) )
|
||||
schItem->SetStoredPos( schItem->GetPosition() );
|
||||
}
|
||||
|
||||
// Set up the starting position and move/drag offset
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
*
|
||||
* Copyright (C) 2004 Jean-Pierre Charras, jp.charras at wanadoo.fr
|
||||
* Copyright (C) 2008 Wayne Stambaugh <stambaughw@gmail.com>
|
||||
* Copyright (C) 2004-2022 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
* Copyright (C) 2004-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
|
||||
@@ -151,8 +151,6 @@ void HIERARCHY_PANE::UpdateHierarchySelection()
|
||||
m_events_bound = false;
|
||||
}
|
||||
|
||||
bool sheetSelected = false;
|
||||
|
||||
std::function<void( const wxTreeItemId& )> recursiveDescent =
|
||||
[&]( const wxTreeItemId& id )
|
||||
{
|
||||
@@ -162,21 +160,22 @@ void HIERARCHY_PANE::UpdateHierarchySelection()
|
||||
|
||||
if( itemData->m_SheetPath == m_frame->GetCurrentSheet() )
|
||||
{
|
||||
m_tree->EnsureVisible( id );
|
||||
wxTreeItemId parent = m_tree->GetItemParent( id );
|
||||
|
||||
if( parent.IsOk() && !m_tree->IsExpanded( parent ) )
|
||||
m_tree->Expand( parent );
|
||||
|
||||
if( !m_tree->IsVisible( id ) )
|
||||
m_tree->EnsureVisible( id );
|
||||
|
||||
m_tree->SetItemBold( id, true );
|
||||
m_tree->SetFocusedItem( id );
|
||||
}
|
||||
else
|
||||
{
|
||||
m_tree->SetItemBold( id, false );
|
||||
}
|
||||
|
||||
if( itemData->m_SheetPath.Last()->IsSelected() )
|
||||
{
|
||||
m_tree->EnsureVisible( id );
|
||||
m_tree->SelectItem( id );
|
||||
sheetSelected = true;
|
||||
}
|
||||
|
||||
wxTreeItemIdValue cookie;
|
||||
wxTreeItemId child = m_tree->GetFirstChild( id, cookie );
|
||||
|
||||
@@ -189,9 +188,6 @@ void HIERARCHY_PANE::UpdateHierarchySelection()
|
||||
|
||||
recursiveDescent( m_tree->GetRootItem() );
|
||||
|
||||
if( !sheetSelected && m_tree->GetSelection() )
|
||||
m_tree->SelectItem( m_tree->GetSelection(), false );
|
||||
|
||||
if( eventsWereBound )
|
||||
{
|
||||
// Enable selection events
|
||||
@@ -231,7 +227,8 @@ void HIERARCHY_PANE::UpdateHierarchyTree()
|
||||
buildHierarchyTree( &m_list, root );
|
||||
UpdateHierarchySelection();
|
||||
|
||||
m_tree->ExpandAll();
|
||||
if( m_tree->ItemHasChildren( root ) )
|
||||
m_tree->Expand( root );
|
||||
|
||||
if( eventsWereBound )
|
||||
{
|
||||
@@ -260,7 +257,7 @@ void HIERARCHY_PANE::onSelectSheetPath( wxTreeEvent& aEvent )
|
||||
|
||||
void HIERARCHY_PANE::onRightClick( wxTreeEvent& aEvent )
|
||||
{
|
||||
wxTreeItemId itemSel = m_tree->GetFocusedItem();
|
||||
wxTreeItemId itemSel = aEvent.GetItem();
|
||||
|
||||
if( !itemSel.IsOk() )
|
||||
return;
|
||||
|
||||
+1
-1
@@ -404,7 +404,7 @@ void D_CODE::ConvertShapeToPolygon( const GERBER_DRAW_ITEM* aParent )
|
||||
addHoleToPolygon( &m_Polygon, m_DrillShape, m_Drill, initialpos );
|
||||
|
||||
if( !m_Rotation.IsZero() ) // rotate polygonal shape:
|
||||
m_Polygon.Rotate( m_Rotation );
|
||||
m_Polygon.Rotate( -m_Rotation );
|
||||
|
||||
break;
|
||||
|
||||
|
||||
@@ -106,7 +106,11 @@ GERBVIEW_FRAME::GERBVIEW_FRAME( KIWAY* aKiway, wxWindow* aParent )
|
||||
wxIcon icon;
|
||||
wxIconBundle icon_bundle;
|
||||
|
||||
icon.CopyFromBitmap( KiBitmap( BITMAPS::icon_gerbview ) );
|
||||
icon.CopyFromBitmap( KiBitmap( BITMAPS::icon_gerbview, 48 ) );
|
||||
icon_bundle.AddIcon( icon );
|
||||
icon.CopyFromBitmap( KiBitmap( BITMAPS::icon_gerbview, 128 ) );
|
||||
icon_bundle.AddIcon( icon );
|
||||
icon.CopyFromBitmap( KiBitmap( BITMAPS::icon_gerbview, 256 ) );
|
||||
icon_bundle.AddIcon( icon );
|
||||
icon.CopyFromBitmap( KiBitmap( BITMAPS::icon_gerbview_32 ) );
|
||||
icon_bundle.AddIcon( icon );
|
||||
|
||||
@@ -175,6 +175,12 @@ public:
|
||||
* @return The macOS specific bundle data directory for KiCad
|
||||
*/
|
||||
static wxString GetWindowsFontConfigDir();
|
||||
|
||||
|
||||
/**
|
||||
* Gets the stock (install) data path, which is the base path for things like scripting, etc
|
||||
*/
|
||||
static wxString GetWindowsBaseSharePath();
|
||||
#endif
|
||||
|
||||
private:
|
||||
|
||||
@@ -68,6 +68,9 @@ public:
|
||||
*/
|
||||
virtual bool EndPlot() override;
|
||||
|
||||
/// HPGL doesn't handle color
|
||||
virtual void SetColorMode( bool aColorMode ) override {};
|
||||
|
||||
/// HPGL doesn't handle line thickness or color
|
||||
virtual void SetCurrentLineWidth( int width, void* aData = nullptr ) override
|
||||
{
|
||||
|
||||
@@ -522,12 +522,20 @@ public:
|
||||
return wxT( "EDIT_POINTS" );
|
||||
}
|
||||
|
||||
bool SwapX() const { return m_swapX; }
|
||||
void SetSwapX( bool aSwap ) { m_swapX = aSwap; }
|
||||
|
||||
bool SwapY() const { return m_swapY; }
|
||||
void SetSwapY( bool aSwap ) { m_swapY = aSwap; }
|
||||
|
||||
private:
|
||||
EDA_ITEM* m_parent; ///< Parent of the EDIT_POINTs.
|
||||
std::deque<EDIT_POINT> m_points; ///< EDIT_POINTs for modifying m_parent.
|
||||
std::deque<EDIT_LINE> m_lines; ///< EDIT_LINEs for modifying m_parent.
|
||||
std::list<int> m_contours; ///< Indices of end contour points.
|
||||
bool m_allowPoints; ///< If false, only allow editing of EDIT_LINES.
|
||||
EDA_ITEM* m_parent; ///< Parent of the EDIT_POINTs.
|
||||
bool m_swapX; ///< Parent's X coords are inverted.
|
||||
bool m_swapY; ///< Parent's Y coords are inverted.
|
||||
std::deque<EDIT_POINT> m_points; ///< EDIT_POINTs for modifying m_parent.
|
||||
std::deque<EDIT_LINE> m_lines; ///< EDIT_LINEs for modifying m_parent.
|
||||
std::list<int> m_contours; ///< Indices of end contour points.
|
||||
bool m_allowPoints; ///< If false, only allow editing of EDIT_LINES.
|
||||
};
|
||||
|
||||
#endif /* EDIT_POINTS_H_ */
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
*
|
||||
* Copyright (C) 2009 jean-pierre.charras@gipsa-lab.inpg.fr
|
||||
* Copyright (C) 2011 Wayne Stambaugh <stambaughw@gmail.com>
|
||||
* Copyright (C) 2009-2021 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
* Copyright (C) 2009-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
|
||||
@@ -156,6 +156,14 @@ public:
|
||||
*/
|
||||
bool ContainsItem( const EDA_ITEM* aItem ) const;
|
||||
|
||||
/**
|
||||
* Check the undo/redo list for any #EDA_ITEM of type \a aItemType.
|
||||
*
|
||||
* @param aItemType is an #EDA_ITEM type from the list of #KICAD_T types.
|
||||
* @return true if an item of \a aItemType is found in the pick list.
|
||||
*/
|
||||
bool ContainsItemType( KICAD_T aItemType ) const;
|
||||
|
||||
/**
|
||||
* @return Index of the searched item. If the item is not stored in the list, negative value
|
||||
* is returned.
|
||||
|
||||
@@ -89,7 +89,8 @@ CLI::EXPORT_PCB_DRILL_COMMAND::EXPORT_PCB_DRILL_COMMAND() : EXPORT_PCB_BASE_COMM
|
||||
|
||||
m_argParser.add_argument( ARG_GERBER_PRECISION )
|
||||
.help( UTF8STDSTR( _( "Precision of gerber coordinates (5 or 6)" ) ) )
|
||||
.default_value( 6 );
|
||||
.default_value( 6 )
|
||||
.scan<'i', int>();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -143,7 +143,11 @@ KICAD_MANAGER_FRAME::KICAD_MANAGER_FRAME( wxWindow* parent, const wxString& titl
|
||||
|
||||
if( IsNightlyVersion())
|
||||
{
|
||||
icon.CopyFromBitmap( KiBitmap( BITMAPS::icon_kicad_nightly ) );
|
||||
icon.CopyFromBitmap( KiBitmap( BITMAPS::icon_kicad_nightly, 48 ) );
|
||||
icon_bundle.AddIcon( icon );
|
||||
icon.CopyFromBitmap( KiBitmap( BITMAPS::icon_kicad_nightly, 128 ) );
|
||||
icon_bundle.AddIcon( icon );
|
||||
icon.CopyFromBitmap( KiBitmap( BITMAPS::icon_kicad_nightly, 256 ) );
|
||||
icon_bundle.AddIcon( icon );
|
||||
icon.CopyFromBitmap( KiBitmap( BITMAPS::icon_kicad_nightly_32 ) );
|
||||
icon_bundle.AddIcon( icon );
|
||||
@@ -152,7 +156,11 @@ KICAD_MANAGER_FRAME::KICAD_MANAGER_FRAME( wxWindow* parent, const wxString& titl
|
||||
}
|
||||
else
|
||||
{
|
||||
icon.CopyFromBitmap( KiBitmap( BITMAPS::icon_kicad ) );
|
||||
icon.CopyFromBitmap( KiBitmap( BITMAPS::icon_kicad, 48 ) );
|
||||
icon_bundle.AddIcon( icon );
|
||||
icon.CopyFromBitmap( KiBitmap( BITMAPS::icon_kicad, 128 ) );
|
||||
icon_bundle.AddIcon( icon );
|
||||
icon.CopyFromBitmap( KiBitmap( BITMAPS::icon_kicad, 256 ) );
|
||||
icon_bundle.AddIcon( icon );
|
||||
icon.CopyFromBitmap( KiBitmap( BITMAPS::icon_kicad_32 ) );
|
||||
icon_bundle.AddIcon( icon );
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Modifications Copyright (C) 2018-2021 KiCad Developers
|
||||
* Modifications Copyright (C) 2018-2023 KiCad Developers
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
@@ -56,10 +56,11 @@
|
||||
#include <math/box2.h>
|
||||
#include <math/vector2d.h>
|
||||
|
||||
class PolygonTriangulation
|
||||
#define TRIANGULATE_TRACE "triangulate"
|
||||
class POLYGON_TRIANGULATION
|
||||
{
|
||||
public:
|
||||
PolygonTriangulation( SHAPE_POLY_SET::TRIANGULATED_POLYGON& aResult ) :
|
||||
POLYGON_TRIANGULATION( SHAPE_POLY_SET::TRIANGULATED_POLYGON& aResult ) :
|
||||
m_result( aResult )
|
||||
{};
|
||||
|
||||
@@ -74,7 +75,8 @@ public:
|
||||
/// Place the polygon Vertices into a circular linked list
|
||||
/// and check for lists that have only 0, 1 or 2 elements and
|
||||
/// therefore cannot be polygons
|
||||
Vertex* firstVertex = createList( aPoly );
|
||||
VERTEX* firstVertex = createList( aPoly );
|
||||
|
||||
if( !firstVertex || firstVertex->prev == firstVertex->next )
|
||||
return false;
|
||||
|
||||
@@ -86,9 +88,9 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
struct Vertex
|
||||
struct VERTEX
|
||||
{
|
||||
Vertex( size_t aIndex, double aX, double aY, PolygonTriangulation* aParent ) :
|
||||
VERTEX( size_t aIndex, double aX, double aY, POLYGON_TRIANGULATION* aParent ) :
|
||||
i( aIndex ),
|
||||
x( aX ),
|
||||
y( aY ),
|
||||
@@ -96,14 +98,14 @@ private:
|
||||
{
|
||||
}
|
||||
|
||||
Vertex& operator=( const Vertex& ) = delete;
|
||||
Vertex& operator=( Vertex&& ) = delete;
|
||||
VERTEX& operator=( const VERTEX& ) = delete;
|
||||
VERTEX& operator=( VERTEX&& ) = delete;
|
||||
|
||||
bool operator==( const Vertex& rhs ) const
|
||||
bool operator==( const VERTEX& rhs ) const
|
||||
{
|
||||
return this->x == rhs.x && this->y == rhs.y;
|
||||
}
|
||||
bool operator!=( const Vertex& rhs ) const { return !( *this == rhs ); }
|
||||
bool operator!=( const VERTEX& rhs ) const { return !( *this == rhs ); }
|
||||
|
||||
|
||||
/**
|
||||
@@ -116,14 +118,14 @@ private:
|
||||
* @return the newly created vertex in the polygon that does not include the
|
||||
* reference vertex.
|
||||
*/
|
||||
Vertex* split( Vertex* b )
|
||||
VERTEX* split( VERTEX* b )
|
||||
{
|
||||
parent->m_vertices.emplace_back( i, x, y, parent );
|
||||
Vertex* a2 = &parent->m_vertices.back();
|
||||
VERTEX* a2 = &parent->m_vertices.back();
|
||||
parent->m_vertices.emplace_back( b->i, b->x, b->y, parent );
|
||||
Vertex* b2 = &parent->m_vertices.back();
|
||||
Vertex* an = next;
|
||||
Vertex* bp = b->prev;
|
||||
VERTEX* b2 = &parent->m_vertices.back();
|
||||
VERTEX* an = next;
|
||||
VERTEX* bp = b->prev;
|
||||
|
||||
next = b;
|
||||
b->prev = this;
|
||||
@@ -172,7 +174,7 @@ private:
|
||||
*/
|
||||
void updateList()
|
||||
{
|
||||
Vertex* p = next;
|
||||
VERTEX* p = next;
|
||||
|
||||
while( p != this )
|
||||
{
|
||||
@@ -201,14 +203,14 @@ private:
|
||||
*/
|
||||
void zSort()
|
||||
{
|
||||
std::deque<Vertex*> queue;
|
||||
std::deque<VERTEX*> queue;
|
||||
|
||||
queue.push_back( this );
|
||||
|
||||
for( auto p = next; p && p != this; p = p->next )
|
||||
queue.push_back( p );
|
||||
|
||||
std::sort( queue.begin(), queue.end(), []( const Vertex* a, const Vertex* b )
|
||||
std::sort( queue.begin(), queue.end(), []( const VERTEX* a, const VERTEX* b )
|
||||
{
|
||||
if( a->z != b->z )
|
||||
return a->z < b->z;
|
||||
@@ -222,7 +224,7 @@ private:
|
||||
return a->i < b->i;
|
||||
} );
|
||||
|
||||
Vertex* prev_elem = nullptr;
|
||||
VERTEX* prev_elem = nullptr;
|
||||
|
||||
for( auto elem : queue )
|
||||
{
|
||||
@@ -240,7 +242,7 @@ private:
|
||||
/**
|
||||
* Check to see if triangle surrounds our current vertex
|
||||
*/
|
||||
bool inTriangle( const Vertex& a, const Vertex& b, const Vertex& c )
|
||||
bool inTriangle( const VERTEX& a, const VERTEX& b, const VERTEX& c )
|
||||
{
|
||||
return ( c.x - x ) * ( a.y - y ) - ( a.x - x ) * ( c.y - y ) >= 0
|
||||
&& ( a.x - x ) * ( b.y - y ) - ( b.x - x ) * ( a.y - y ) >= 0
|
||||
@@ -250,18 +252,18 @@ private:
|
||||
const size_t i;
|
||||
const double x;
|
||||
const double y;
|
||||
PolygonTriangulation* parent;
|
||||
POLYGON_TRIANGULATION* parent;
|
||||
|
||||
// previous and next vertices nodes in a polygon ring
|
||||
Vertex* prev = nullptr;
|
||||
Vertex* next = nullptr;
|
||||
VERTEX* prev = nullptr;
|
||||
VERTEX* next = nullptr;
|
||||
|
||||
// z-order curve value
|
||||
int32_t z = 0;
|
||||
|
||||
// previous and next nodes in z-order
|
||||
Vertex* prevZ = nullptr;
|
||||
Vertex* nextZ = nullptr;
|
||||
VERTEX* prevZ = nullptr;
|
||||
VERTEX* nextZ = nullptr;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -294,14 +296,14 @@ private:
|
||||
* as the NULL triangles are inserted as Steiner points to improve the
|
||||
* triangulation regularity of polygons
|
||||
*/
|
||||
Vertex* removeNullTriangles( Vertex* aStart )
|
||||
VERTEX* removeNullTriangles( VERTEX* aStart )
|
||||
{
|
||||
Vertex* retval = nullptr;
|
||||
Vertex* p = aStart->next;
|
||||
VERTEX* retval = nullptr;
|
||||
VERTEX* p = aStart->next;
|
||||
|
||||
while( p != aStart )
|
||||
{
|
||||
if( area( p->prev, p, p->next ) == 0.0 )
|
||||
if( *p == *( p->next ) || area( p->prev, p, p->next ) == 0.0 )
|
||||
{
|
||||
p = p->prev;
|
||||
p->next->remove();
|
||||
@@ -310,6 +312,7 @@ private:
|
||||
if( p == p->next )
|
||||
break;
|
||||
}
|
||||
|
||||
p = p->next;
|
||||
};
|
||||
|
||||
@@ -327,9 +330,9 @@ private:
|
||||
/**
|
||||
* Take a Clipper path and converts it into a circular, doubly-linked list for triangulation.
|
||||
*/
|
||||
Vertex* createList( const ClipperLib::Path& aPath )
|
||||
VERTEX* createList( const ClipperLib::Path& aPath )
|
||||
{
|
||||
Vertex* tail = nullptr;
|
||||
VERTEX* tail = nullptr;
|
||||
double sum = 0.0;
|
||||
auto len = aPath.size();
|
||||
|
||||
@@ -368,9 +371,9 @@ private:
|
||||
/**
|
||||
* Take a #SHAPE_LINE_CHAIN and links each point into a circular, doubly-linked list.
|
||||
*/
|
||||
Vertex* createList( const SHAPE_LINE_CHAIN& points )
|
||||
VERTEX* createList( const SHAPE_LINE_CHAIN& points )
|
||||
{
|
||||
Vertex* tail = nullptr;
|
||||
VERTEX* tail = nullptr;
|
||||
double sum = 0.0;
|
||||
|
||||
// Check for winding order
|
||||
@@ -410,14 +413,14 @@ private:
|
||||
* an edited file), we create a single triangle and remove both vertices before attempting
|
||||
* to.
|
||||
*/
|
||||
bool earcutList( Vertex* aPoint, int pass = 0 )
|
||||
bool earcutList( VERTEX* aPoint, int pass = 0 )
|
||||
{
|
||||
if( !aPoint )
|
||||
return true;
|
||||
|
||||
Vertex* stop = aPoint;
|
||||
Vertex* prev;
|
||||
Vertex* next;
|
||||
VERTEX* stop = aPoint;
|
||||
VERTEX* prev;
|
||||
VERTEX* next;
|
||||
|
||||
while( aPoint->prev != aPoint->next )
|
||||
{
|
||||
@@ -436,7 +439,7 @@ private:
|
||||
continue;
|
||||
}
|
||||
|
||||
Vertex* nextNext = next->next;
|
||||
VERTEX* nextNext = next->next;
|
||||
|
||||
if( *prev != *nextNext && intersects( prev, aPoint, next, nextNext ) &&
|
||||
locallyInside( prev, nextNext ) &&
|
||||
@@ -472,7 +475,9 @@ private:
|
||||
}
|
||||
|
||||
// If we don't have any NULL triangles left, cut the polygon in two and try again
|
||||
splitPolygon( aPoint );
|
||||
if( !splitPolygon( aPoint ) )
|
||||
return false;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -501,11 +506,11 @@ private:
|
||||
*
|
||||
* @return true if aEar is the apex point of a ear in the polygon.
|
||||
*/
|
||||
bool isEar( Vertex* aEar ) const
|
||||
bool isEar( VERTEX* aEar ) const
|
||||
{
|
||||
const Vertex* a = aEar->prev;
|
||||
const Vertex* b = aEar;
|
||||
const Vertex* c = aEar->next;
|
||||
const VERTEX* a = aEar->prev;
|
||||
const VERTEX* b = aEar;
|
||||
const VERTEX* c = aEar->next;
|
||||
|
||||
// If the area >=0, then the three points for a concave sequence
|
||||
// with b as the reflex point
|
||||
@@ -523,7 +528,7 @@ private:
|
||||
const int32_t maxZ = zOrder( maxTX, maxTY );
|
||||
|
||||
// first look for points inside the triangle in increasing z-order
|
||||
Vertex* p = aEar->nextZ;
|
||||
VERTEX* p = aEar->nextZ;
|
||||
|
||||
while( p && p->z <= maxZ )
|
||||
{
|
||||
@@ -557,27 +562,65 @@ private:
|
||||
* independently. This is assured to generate at least one new ear if the
|
||||
* split is successful
|
||||
*/
|
||||
void splitPolygon( Vertex* start )
|
||||
bool splitPolygon( VERTEX* start )
|
||||
{
|
||||
Vertex* origPoly = start;
|
||||
VERTEX* origPoly = start;
|
||||
|
||||
// Our first attempts to split the polygon will be at overlapping points.
|
||||
// These are natural split points and we only need to switch the loop directions
|
||||
// to generate two new loops. Since they are overlapping, we are do not
|
||||
// need to create a new segment to disconnect the two loops.
|
||||
do
|
||||
{
|
||||
Vertex* marker = origPoly->next->next;
|
||||
VERTEX* nextZ = origPoly->nextZ;
|
||||
|
||||
if( nextZ && *nextZ == *origPoly )
|
||||
{
|
||||
std::swap( origPoly->next, nextZ->next );
|
||||
origPoly->next->prev = origPoly;
|
||||
nextZ->next->prev = nextZ;
|
||||
|
||||
origPoly->updateList();
|
||||
nextZ->updateList();
|
||||
return earcutList( origPoly ) && earcutList( nextZ );
|
||||
}
|
||||
|
||||
VERTEX* prevZ = origPoly->prevZ;
|
||||
|
||||
if( prevZ && *prevZ == *origPoly )
|
||||
{
|
||||
std::swap( origPoly->next, prevZ->next );
|
||||
origPoly->next->prev = origPoly;
|
||||
prevZ->next->prev = prevZ;
|
||||
|
||||
origPoly->updateList();
|
||||
prevZ->updateList();
|
||||
return earcutList( origPoly ) && earcutList( prevZ );
|
||||
}
|
||||
|
||||
origPoly = origPoly->next;
|
||||
|
||||
} while ( origPoly != start );
|
||||
|
||||
// If we've made it through the split algorithm and we still haven't found a
|
||||
// set of overlapping points, we need to create a new segment to split the polygon
|
||||
// into two separate polygons. We do this by finding the two vertices that form
|
||||
// a valid line (does not cross the existing polygon)
|
||||
do
|
||||
{
|
||||
VERTEX* marker = origPoly->next->next;
|
||||
|
||||
while( marker != origPoly->prev )
|
||||
{
|
||||
// Find a diagonal line that is wholly enclosed by the polygon interior
|
||||
if( origPoly->i != marker->i && goodSplit( origPoly, marker ) )
|
||||
{
|
||||
Vertex* newPoly = origPoly->split( marker );
|
||||
VERTEX* newPoly = origPoly->split( marker );
|
||||
|
||||
origPoly->updateList();
|
||||
newPoly->updateList();
|
||||
|
||||
earcutList( origPoly );
|
||||
earcutList( newPoly );
|
||||
return;
|
||||
return earcutList( origPoly ) && earcutList( newPoly );
|
||||
}
|
||||
|
||||
marker = marker->next;
|
||||
@@ -585,44 +628,87 @@ private:
|
||||
|
||||
origPoly = origPoly->next;
|
||||
} while( origPoly != start );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a segment joining two vertices lies fully inside the polygon.
|
||||
* To do this, we first ensure that the line isn't along the polygon edge.
|
||||
* Next, we know that if the line doesn't intersect the polygon, then it is
|
||||
* either fully inside or fully outside the polygon. Finally, by checking whether
|
||||
* the segment is enclosed by the local triangles, we distinguish between
|
||||
* these two cases and no further checks are needed.
|
||||
* either fully inside or fully outside the polygon. Next, we ensure that
|
||||
* the proposed split is inside the local area of the polygon at both ends
|
||||
* and the midpoint. Finally, we check to split creates two new polygons,
|
||||
* each with positive area.
|
||||
*/
|
||||
bool goodSplit( const Vertex* a, const Vertex* b ) const
|
||||
bool goodSplit( const VERTEX* a, const VERTEX* b ) const
|
||||
{
|
||||
return a->next->i != b->i &&
|
||||
a->prev->i != b->i &&
|
||||
!intersectsPolygon( a, b ) &&
|
||||
locallyInside( a, b );
|
||||
bool a_on_edge = ( a->nextZ && *a == *a->nextZ ) || ( a->prevZ && *a == *a->prevZ );
|
||||
bool b_on_edge = ( b->nextZ && *b == *b->nextZ ) || ( b->prevZ && *b == *b->prevZ );
|
||||
bool no_intersect = a->next->i != b->i && a->prev->i != b->i && !intersectsPolygon( a, b );
|
||||
bool local_split = locallyInside( a, b ) && locallyInside( b, a ) && middleInside( a, b );
|
||||
bool same_dir = area( a->prev, a, b->prev ) != 0.0 || area( a, b->prev, b ) != 0.0;
|
||||
bool has_len = ( *a == *b ) && area( a->prev, a, a->next ) > 0 && area( b->prev, b, b->next ) > 0;
|
||||
|
||||
|
||||
return no_intersect && local_split && ( same_dir || has_len ) && !a_on_edge && !b_on_edge;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the twice the signed area of the triangle formed by vertices p, q, and r.
|
||||
*/
|
||||
double area( const Vertex* p, const Vertex* q, const Vertex* r ) const
|
||||
double area( const VERTEX* p, const VERTEX* q, const VERTEX* r ) const
|
||||
{
|
||||
return ( q->y - p->y ) * ( r->x - q->x ) - ( q->x - p->x ) * ( r->y - q->y );
|
||||
}
|
||||
|
||||
|
||||
constexpr int sign( double aVal ) const
|
||||
{
|
||||
return ( aVal > 0 ) - ( aVal < 0 );
|
||||
}
|
||||
|
||||
/**
|
||||
* If p, q, and r are collinear and r lies between p and q, then return true.
|
||||
*/
|
||||
constexpr bool overlapping( const VERTEX* p, const VERTEX* q, const VERTEX* r ) const
|
||||
{
|
||||
return q->x <= std::max( p->x, r->x ) &&
|
||||
q->x >= std::min( p->x, r->x ) &&
|
||||
q->y <= std::max( p->y, r->y ) &&
|
||||
q->y >= std::min( p->y, r->y );
|
||||
}
|
||||
|
||||
/**
|
||||
* Check for intersection between two segments, end points included.
|
||||
*
|
||||
* @return true if p1-p2 intersects q1-q2.
|
||||
*/
|
||||
bool intersects( const Vertex* p1, const Vertex* q1, const Vertex* p2, const Vertex* q2 ) const
|
||||
bool intersects( const VERTEX* p1, const VERTEX* q1, const VERTEX* p2, const VERTEX* q2 ) const
|
||||
{
|
||||
if( ( *p1 == *q1 && *p2 == *q2 ) || ( *p1 == *q2 && *p2 == *q1 ) )
|
||||
int sign1 = sign( area( p1, q1, p2 ) );
|
||||
int sign2 = sign( area( p1, q1, q2 ) );
|
||||
int sign3 = sign( area( p2, q2, p1 ) );
|
||||
int sign4 = sign( area( p2, q2, q1 ) );
|
||||
|
||||
if( sign1 != sign2 && sign3 != sign4 )
|
||||
return true;
|
||||
|
||||
return ( area( p1, q1, p2 ) > 0 ) != ( area( p1, q1, q2 ) > 0 )
|
||||
&& ( area( p2, q2, p1 ) > 0 ) != ( area( p2, q2, q1 ) > 0 );
|
||||
if( sign1 == 0 && overlapping( p1, p2, q1 ) )
|
||||
return true;
|
||||
|
||||
if( sign2 == 0 && overlapping( p1, q2, q1 ) )
|
||||
return true;
|
||||
|
||||
if( sign3 == 0 && overlapping( p2, p1, q2 ) )
|
||||
return true;
|
||||
|
||||
if( sign4 == 0 && overlapping( p2, q1, q2 ) )
|
||||
return true;
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -631,9 +717,9 @@ private:
|
||||
*
|
||||
* @return true if the segment intersects the edge of the polygon.
|
||||
*/
|
||||
bool intersectsPolygon( const Vertex* a, const Vertex* b ) const
|
||||
bool intersectsPolygon( const VERTEX* a, const VERTEX* b ) const
|
||||
{
|
||||
const Vertex* p = a->next;
|
||||
const VERTEX* p = a->next;
|
||||
|
||||
do
|
||||
{
|
||||
@@ -658,7 +744,7 @@ private:
|
||||
*
|
||||
* @return true if the segment from a->b is inside a's polygon next to vertex a.
|
||||
*/
|
||||
bool locallyInside( const Vertex* a, const Vertex* b ) const
|
||||
bool locallyInside( const VERTEX* a, const VERTEX* b ) const
|
||||
{
|
||||
if( area( a->prev, a, a->next ) < 0 )
|
||||
return area( a, b, a->next ) >= 0 && area( a, a->prev, b ) >= 0;
|
||||
@@ -666,18 +752,40 @@ private:
|
||||
return area( a, b, a->prev ) < 0 || area( a, a->next, b ) < 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check to see if the segment halfway point between a and b is inside the polygon
|
||||
*/
|
||||
bool middleInside( const VERTEX* a, const VERTEX* b ) const
|
||||
{
|
||||
const VERTEX* p = a;
|
||||
bool inside = false;
|
||||
double px = ( a->x + b->x ) / 2;
|
||||
double py = ( a->y + b->y ) / 2;
|
||||
|
||||
do
|
||||
{
|
||||
if( ( ( p->y > py ) != ( p->next->y > py ) )
|
||||
&& ( px < ( p->next->x - p->x ) * ( py - p->y ) / ( p->next->y - p->y ) + p->x ) )
|
||||
inside = !inside;
|
||||
|
||||
p = p->next;
|
||||
} while( p != a );
|
||||
|
||||
return inside;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an entry in the vertices lookup and optionally inserts the newly created vertex
|
||||
* into an existing linked list.
|
||||
*
|
||||
* @return a pointer to the newly created vertex.
|
||||
*/
|
||||
Vertex* insertVertex( const VECTOR2I& pt, Vertex* last )
|
||||
VERTEX* insertVertex( const VECTOR2I& pt, VERTEX* last )
|
||||
{
|
||||
m_result.AddVertex( pt );
|
||||
m_vertices.emplace_back( m_result.GetVertexCount() - 1, pt.x, pt.y, this );
|
||||
|
||||
Vertex* p = &m_vertices.back();
|
||||
VERTEX* p = &m_vertices.back();
|
||||
|
||||
if( !last )
|
||||
{
|
||||
@@ -696,7 +804,7 @@ private:
|
||||
|
||||
private:
|
||||
BOX2I m_bbox;
|
||||
std::deque<Vertex> m_vertices;
|
||||
std::deque<VERTEX> m_vertices;
|
||||
SHAPE_POLY_SET::TRIANGULATED_POLYGON& m_result;
|
||||
};
|
||||
|
||||
|
||||
@@ -356,6 +356,9 @@ const BOX2I SHAPE_ARC::BBox( int aClearance ) const
|
||||
{
|
||||
BOX2I bbox( m_bbox );
|
||||
|
||||
if( m_width != 0 )
|
||||
bbox.Inflate( KiROUND( m_width / 2.0 ) + 1 );
|
||||
|
||||
if( aClearance != 0 )
|
||||
bbox.Inflate( aClearance );
|
||||
|
||||
|
||||
@@ -2764,7 +2764,7 @@ void SHAPE_POLY_SET::CacheTriangulation( bool aPartition, bool aSimplify )
|
||||
dest.erase( dest.end() - 1 );
|
||||
|
||||
dest.push_back( std::make_unique<TRIANGULATED_POLYGON>( forOutline ) );
|
||||
PolygonTriangulation tess( *dest.back() );
|
||||
POLYGON_TRIANGULATION tess( *dest.back() );
|
||||
|
||||
// If the tessellation fails, we re-fracture the polygon, which will
|
||||
// first simplify the system before fracturing and removing the holes
|
||||
@@ -2815,7 +2815,10 @@ void SHAPE_POLY_SET::CacheTriangulation( bool aPartition, bool aSimplify )
|
||||
|
||||
// This pushes the triangulation for all polys in partitions
|
||||
// to be referenced to the ii-th polygon
|
||||
m_triangulationValid &= triangulate( partitions, ii , m_triangulatedPolys );
|
||||
if( !triangulate( partitions, ii , m_triangulatedPolys ) )
|
||||
{
|
||||
wxLogTrace( TRIANGULATE_TRACE, "Failed to triangulate partitioned polygon %d", ii );
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -2826,7 +2829,10 @@ void SHAPE_POLY_SET::CacheTriangulation( bool aPartition, bool aSimplify )
|
||||
|
||||
tmpSet.Fracture( PM_FAST );
|
||||
|
||||
m_triangulationValid = triangulate( tmpSet, -1, m_triangulatedPolys );
|
||||
if( !triangulate( tmpSet, -1, m_triangulatedPolys ) )
|
||||
{
|
||||
wxLogTrace( TRIANGULATE_TRACE, "Failed to triangulate polygon" );
|
||||
}
|
||||
}
|
||||
|
||||
if( m_triangulationValid )
|
||||
|
||||
@@ -39,6 +39,54 @@
|
||||
// Returns true if the point P is on the segment S.
|
||||
// faster than TestSegmentHit() because P should be exactly on S
|
||||
// therefore works fine only for H, V and 45 deg segm (suitable for wires in eeschema)
|
||||
/*
|
||||
CircleCenterFrom3Points calculate the center of a circle defined by 3 points
|
||||
It is similar to CalcArcCenter( const VECTOR2D& aStart, const VECTOR2D& aMid, const VECTOR2D& aEnd )
|
||||
but it was needed to debug CalcArcCenter, so I keep it available for other issues in CalcArcCenter
|
||||
|
||||
The perpendicular bisector of the segment between two points is the
|
||||
set of all points equidistant from both. So if you take the
|
||||
perpendicular bisector of (x1,y1) and (x2,y2) and the perpendicular
|
||||
bisector of the segment from (x2,y2) to (x3,y3) and find the
|
||||
intersection of those lines, that point will be the center.
|
||||
|
||||
To find the equation of the perpendicular bisector of (x1,y1) to (x2,y2),
|
||||
you know that it passes through the midpoint of the segment:
|
||||
((x1+x2)/2,(y1+y2)/2), and if the slope of the line
|
||||
connecting (x1,y1) to (x2,y2) is m, the slope of the perpendicular
|
||||
bisector is -1/m. Work out the equations for the two lines, find
|
||||
their intersection, and bingo! You've got the coordinates of the center.
|
||||
|
||||
An error should occur if the three points lie on a line, and you'll
|
||||
need special code to check for the case where one of the slopes is zero.
|
||||
|
||||
see https://web.archive.org/web/20171223103555/http://mathforum.org/library/drmath/view/54323.html
|
||||
*/
|
||||
|
||||
//#define USE_ALTERNATE_CENTER_ALGO
|
||||
|
||||
#ifdef USE_ALTERNATE_CENTER_ALGO
|
||||
bool CircleCenterFrom3Points( const VECTOR2D& p1, const VECTOR2D& p2, const VECTOR2D& p3, VECTOR2D* aCenter )
|
||||
{
|
||||
// Move coordinate origin to p2, to simplify calculations
|
||||
VECTOR2D b = p1 - p2;
|
||||
VECTOR2D d = p3 - p2;
|
||||
double bc = ( b.x*b.x + b.y*b.y ) / 2.0;
|
||||
double cd = ( -d.x*d.x - d.y*d.y ) / 2.0;
|
||||
double det = -b.x*d.y + d.x*b.y;
|
||||
|
||||
if( fabs(det) < 1.0e-6 ) // arbitrary limit to avoid divide by 0
|
||||
return false;
|
||||
|
||||
det = 1/det;
|
||||
aCenter->x = ( -bc*d.y - cd*b.y ) * det;
|
||||
aCenter->y = ( b.x*cd + d.x*bc ) * det;
|
||||
*aCenter += p2;
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool IsPointOnSegment( const VECTOR2I& aSegStart, const VECTOR2I& aSegEnd,
|
||||
const VECTOR2I& aTestPoint )
|
||||
{
|
||||
@@ -302,8 +350,8 @@ const VECTOR2D CalcArcCenter( const VECTOR2D& aStart, const VECTOR2D& aEnd,
|
||||
const EDA_ANGLE& aAngle )
|
||||
{
|
||||
EDA_ANGLE angle( aAngle );
|
||||
VECTOR2I start = aStart;
|
||||
VECTOR2I end = aEnd;
|
||||
VECTOR2D start = aStart;
|
||||
VECTOR2D end = aEnd;
|
||||
|
||||
if( angle < ANGLE_0 )
|
||||
{
|
||||
@@ -337,6 +385,7 @@ const VECTOR2D CalcArcCenter( const VECTOR2D& aStart, const VECTOR2D& aEnd,
|
||||
const VECTOR2D CalcArcCenter( const VECTOR2D& aStart, const VECTOR2D& aMid, const VECTOR2D& aEnd )
|
||||
{
|
||||
VECTOR2D center;
|
||||
|
||||
double yDelta_21 = aMid.y - aStart.y;
|
||||
double xDelta_21 = aMid.x - aStart.x;
|
||||
double yDelta_32 = aEnd.y - aMid.y;
|
||||
@@ -385,10 +434,19 @@ const VECTOR2D CalcArcCenter( const VECTOR2D& aStart, const VECTOR2D& aMid, cons
|
||||
bSlope -= std::numeric_limits<double>::epsilon();
|
||||
}
|
||||
}
|
||||
#ifdef USE_ALTERNATE_CENTER_ALGO
|
||||
// We can call ArcCenterFrom3Points from here because special cases are filtered.
|
||||
CircleCenterFrom3Points( aStart, aMid, aEnd, ¢er );
|
||||
return center;
|
||||
#endif
|
||||
|
||||
// Prevent divide by zero error
|
||||
// a small value is used. std::numeric_limits<double>::epsilon() is too small and
|
||||
// generate false results
|
||||
if( aSlope == 0.0 )
|
||||
aSlope = std::numeric_limits<double>::epsilon();
|
||||
aSlope = 1e-10;
|
||||
if( bSlope == 0.0 )
|
||||
bSlope = 1e-10;
|
||||
|
||||
// What follows is the calculation of the center using the slope of the two lines as well as
|
||||
// the propagated error that occurs when rounding to the nearest nanometer. The error can be
|
||||
@@ -423,7 +481,6 @@ const VECTOR2D CalcArcCenter( const VECTOR2D& aStart, const VECTOR2D& aMid, cons
|
||||
+ daSlopeMidEndX * daSlopeMidEndX );
|
||||
|
||||
double centerX = ( abSlopeStartEndY + bSlopeStartMidX - aSlopeMidEndX ) / twiceBASlopeDiff;
|
||||
|
||||
double dCenterX = centerX * std::sqrt( ( dCenterNumeratorX / centerNumeratorX * dCenterNumeratorX / centerNumeratorX )
|
||||
+ ( dtwiceBASlopeDiff / twiceBASlopeDiff * dtwiceBASlopeDiff / twiceBASlopeDiff ) );
|
||||
|
||||
@@ -489,4 +546,3 @@ const VECTOR2I CalcArcCenter( const VECTOR2I& aStart, const VECTOR2I& aMid, cons
|
||||
return iCenter;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -103,7 +103,11 @@ PL_EDITOR_FRAME::PL_EDITOR_FRAME( KIWAY* aKiway, wxWindow* aParent ) :
|
||||
wxIcon icon;
|
||||
wxIconBundle icon_bundle;
|
||||
|
||||
icon.CopyFromBitmap( KiBitmap( BITMAPS::icon_pagelayout_editor ) );
|
||||
icon.CopyFromBitmap( KiBitmap( BITMAPS::icon_pagelayout_editor, 48 ) );
|
||||
icon_bundle.AddIcon( icon );
|
||||
icon.CopyFromBitmap( KiBitmap( BITMAPS::icon_pagelayout_editor, 128 ) );
|
||||
icon_bundle.AddIcon( icon );
|
||||
icon.CopyFromBitmap( KiBitmap( BITMAPS::icon_pagelayout_editor, 256 ) );
|
||||
icon_bundle.AddIcon( icon );
|
||||
icon.CopyFromBitmap( KiBitmap( BITMAPS::icon_pagelayout_editor_32 ) );
|
||||
icon_bundle.AddIcon( icon );
|
||||
|
||||
@@ -239,21 +239,22 @@ void PANEL_TRACK_WIDTH::OnTWResetButtonClick( wxCommandEvent& event )
|
||||
// Note: a wxString:Format( "%g", xx) is used to use local separator in floats
|
||||
|
||||
// Init main parameters:
|
||||
m_TrackCurrentValue->SetValue( wxString::Format( "%g", 1.0 ) );
|
||||
m_TrackDeltaTValue->SetValue( wxString::Format( "%g", 10.0 ) );
|
||||
m_TrackLengthValue->SetValue( wxString::Format( "%g", 20.0 ) );
|
||||
m_TrackDeltaTValue->ChangeValue( wxString::Format( "%g", 10.0 ) );
|
||||
m_TrackLengthValue->ChangeValue( wxString::Format( "%g", 20.0 ) );
|
||||
m_TW_CuLength_choiceUnit->SetSelection( 0 );
|
||||
m_TWResistivity->SetValue( wxString::Format( "%g", copper_resistivity ) );
|
||||
|
||||
// m_ExtTrackWidthValue is not reinitialized: it will be calculated from previous parameters
|
||||
m_ExtTrackWidthValue->ChangeValue( wxString::Format( "%g", 0.2 ) );
|
||||
m_TW_ExtTrackWidth_choiceUnit->SetSelection( 0 );
|
||||
m_ExtTrackThicknessValue->SetValue( wxString::Format( "%g", 0.035 ) );
|
||||
m_ExtTrackThicknessUnit->SetSelection( 0 );
|
||||
m_ExtTrackThicknessValue->ChangeValue( wxString::Format( "%g", 35.0 ) );
|
||||
m_ExtTrackThicknessUnit->SetSelection( 1 );
|
||||
|
||||
// m_IntTrackWidthValue is not reinitialized: it will be calculated from previous parameters
|
||||
m_IntTrackWidthValue->ChangeValue( wxString::Format( "%g", 0.2 ) );
|
||||
m_TW_IntTrackWidth_choiceUnit->SetSelection( 0 );
|
||||
m_IntTrackThicknessValue->SetValue( wxString::Format( "%g", 0.035 ) );
|
||||
m_IntTrackThicknessUnit->SetSelection( 0 );
|
||||
m_IntTrackThicknessValue->ChangeValue( wxString::Format( "%g", 35.0 ) );
|
||||
m_IntTrackThicknessUnit->SetSelection( 1 );
|
||||
|
||||
m_TrackCurrentValue->SetValue( wxString::Format( "%g", 1.0 ) );
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -102,7 +102,11 @@ PCB_CALCULATOR_FRAME::PCB_CALCULATOR_FRAME( KIWAY* aKiway, wxWindow* aParent ) :
|
||||
wxIcon icon;
|
||||
wxIconBundle icon_bundle;
|
||||
|
||||
icon.CopyFromBitmap( KiBitmap( BITMAPS::icon_pcbcalculator ) );
|
||||
icon.CopyFromBitmap( KiBitmap( BITMAPS::icon_pcbcalculator, 48 ) );
|
||||
icon_bundle.AddIcon( icon );
|
||||
icon.CopyFromBitmap( KiBitmap( BITMAPS::icon_pcbcalculator, 128 ) );
|
||||
icon_bundle.AddIcon( icon );
|
||||
icon.CopyFromBitmap( KiBitmap( BITMAPS::icon_pcbcalculator, 256 ) );
|
||||
icon_bundle.AddIcon( icon );
|
||||
icon.CopyFromBitmap( KiBitmap( BITMAPS::icon_pcbcalculator_32 ) );
|
||||
icon_bundle.AddIcon( icon );
|
||||
|
||||
@@ -151,10 +151,10 @@ PCB_CALCULATOR_SETTINGS::PCB_CALCULATOR_SETTINGS() :
|
||||
&m_TrackWidth.ext_track_width_units, 0 ) );
|
||||
|
||||
m_params.emplace_back( new PARAM<wxString>( "track_width.ext_track_thickness",
|
||||
&m_TrackWidth.ext_track_thickness, "0.035" ) );
|
||||
&m_TrackWidth.ext_track_thickness, "35" ) );
|
||||
|
||||
m_params.emplace_back( new PARAM<int>( "track_width.ext_track_thickness_units",
|
||||
&m_TrackWidth.ext_track_thickness_units, 0 ) );
|
||||
&m_TrackWidth.ext_track_thickness_units, 1 ) );
|
||||
|
||||
m_params.emplace_back( new PARAM<wxString>( "track_width.int_track_width",
|
||||
&m_TrackWidth.int_track_width, "0.2" ) );
|
||||
@@ -163,10 +163,10 @@ PCB_CALCULATOR_SETTINGS::PCB_CALCULATOR_SETTINGS() :
|
||||
&m_TrackWidth.int_track_width_units, 0 ) );
|
||||
|
||||
m_params.emplace_back( new PARAM<wxString>( "track_width.int_track_thickness",
|
||||
&m_TrackWidth.int_track_thickness, "0.035" ) );
|
||||
&m_TrackWidth.int_track_thickness, "35" ) );
|
||||
|
||||
m_params.emplace_back( new PARAM<int>( "track_width.int_track_thickness_units",
|
||||
&m_TrackWidth.int_track_thickness_units, 0 ) );
|
||||
&m_TrackWidth.int_track_thickness_units, 1 ) );
|
||||
|
||||
{
|
||||
const std::array<std::string, 8> transline_names = { "MicroStrip", "CoPlanar", "GrCoPlanar",
|
||||
|
||||
@@ -77,11 +77,12 @@ PANEL_SETUP_BOARD_STACKUP::PANEL_SETUP_BOARD_STACKUP( wxWindow* aParentWindow,
|
||||
PANEL_SETUP_BOARD_STACKUP_BASE( aParentWindow ),
|
||||
m_delectricMatList( DIELECTRIC_SUBSTRATE_LIST::DL_MATERIAL_DIELECTRIC ),
|
||||
m_solderMaskMatList( DIELECTRIC_SUBSTRATE_LIST::DL_MATERIAL_SOLDERMASK ),
|
||||
m_silkscreenMatList( DIELECTRIC_SUBSTRATE_LIST::DL_MATERIAL_SILKSCREEN )
|
||||
m_silkscreenMatList( DIELECTRIC_SUBSTRATE_LIST::DL_MATERIAL_SILKSCREEN ),
|
||||
m_board( aFrame->GetBoard() ),
|
||||
m_frame( aFrame ),
|
||||
m_lastUnits( aFrame->GetUserUnits() )
|
||||
{
|
||||
m_frame = aFrame;
|
||||
m_panelLayers = aPanelLayers;
|
||||
m_board = m_frame->GetBoard();
|
||||
m_brdSettings = &m_board->GetDesignSettings();
|
||||
|
||||
m_panel1->SetBorders( false, false, true, true );
|
||||
@@ -118,6 +119,8 @@ PANEL_SETUP_BOARD_STACKUP::PANEL_SETUP_BOARD_STACKUP( wxWindow* aParentWindow,
|
||||
buildLayerStackPanel( true );
|
||||
synchronizeWithBoard( true );
|
||||
computeBoardThickness();
|
||||
|
||||
m_frame->Bind( UNITS_CHANGED, &PANEL_SETUP_BOARD_STACKUP::onUnitsChanged, this );
|
||||
}
|
||||
|
||||
|
||||
@@ -127,6 +130,39 @@ PANEL_SETUP_BOARD_STACKUP::~PANEL_SETUP_BOARD_STACKUP()
|
||||
}
|
||||
|
||||
|
||||
void PANEL_SETUP_BOARD_STACKUP::onUnitsChanged( wxCommandEvent& event )
|
||||
{
|
||||
EDA_UNITS newUnits = m_frame->GetUserUnits();
|
||||
EDA_IU_SCALE scale = m_frame->GetIuScale();
|
||||
|
||||
auto convert =
|
||||
[&]( wxTextCtrl* aTextCtrl )
|
||||
{
|
||||
wxString str = aTextCtrl->GetValue();
|
||||
long long int temp = EDA_UNIT_UTILS::UI::ValueFromString( scale, m_lastUnits, str );
|
||||
str = EDA_UNIT_UTILS::UI::StringFromValue( scale, newUnits, temp, true );
|
||||
|
||||
// Don't use SetValue(); we don't want a bunch of event propagation as the actual
|
||||
// value hasn't changed, only its presentation.
|
||||
aTextCtrl->ChangeValue( str );
|
||||
};
|
||||
|
||||
for( BOARD_STACKUP_ROW_UI_ITEM& ui_item : m_rowUiItemsList )
|
||||
{
|
||||
BOARD_STACKUP_ITEM* item = ui_item.m_Item;
|
||||
|
||||
if( item->IsThicknessEditable() && item->IsEnabled() )
|
||||
convert( static_cast<wxTextCtrl*>( ui_item.m_ThicknessCtrl ) );
|
||||
}
|
||||
|
||||
convert( m_tcCTValue );
|
||||
|
||||
m_lastUnits = newUnits;
|
||||
|
||||
event.Skip();
|
||||
}
|
||||
|
||||
|
||||
void PANEL_SETUP_BOARD_STACKUP::onCopperLayersSelCount( wxCommandEvent& event )
|
||||
{
|
||||
int oldBoardWidth = static_cast<int>( m_frame->ValueFromString( m_tcCTValue->GetValue() ) );
|
||||
|
||||
@@ -228,6 +228,8 @@ private:
|
||||
*/
|
||||
wxBitmapComboBox* createColorBox( BOARD_STACKUP_ITEM* aStackupItem, int aRow );
|
||||
|
||||
void onUnitsChanged( wxCommandEvent& event );
|
||||
|
||||
/**
|
||||
* disconnect event handlers connected to wxControl items found in list m_controlItemsList
|
||||
*/
|
||||
@@ -253,6 +255,7 @@ private:
|
||||
BOARD* m_board;
|
||||
BOARD_DESIGN_SETTINGS* m_brdSettings;
|
||||
PCB_EDIT_FRAME* m_frame;
|
||||
EDA_UNITS m_lastUnits;
|
||||
wxSize m_numericTextCtrlSize; // Best size for wxTextCtrls with units
|
||||
wxSize m_numericFieldsSize; // Best size for wxTextCtrls without units
|
||||
wxArrayString m_core_prepreg_choice; // Used to display the option list in dialog
|
||||
|
||||
@@ -1139,17 +1139,17 @@ void DIALOG_DRC::OnDeleteAllClick( wxCommandEvent& aEvent )
|
||||
|
||||
if( numExcluded > 0 )
|
||||
{
|
||||
wxRichMessageDialog dlg( this, _( "Do you wish to delete excluded markers as well?" ),
|
||||
_( "Delete All Markers" ),
|
||||
wxOK | wxCANCEL | wxCENTER | wxICON_QUESTION );
|
||||
dlg.ShowCheckBox( _( "Delete exclusions" ), s_includeExclusions );
|
||||
wxMessageDialog dlg( this, _( "Delete exclusions too?" ), _( "Delete All Markers" ),
|
||||
wxYES_NO | wxCANCEL | wxCENTER | wxICON_QUESTION );
|
||||
dlg.SetYesNoLabels( _( "Errors and Warnings Only" ),
|
||||
_( "Errors, Warnings and Exclusions" ) );
|
||||
|
||||
int ret = dlg.ShowModal();
|
||||
|
||||
if( ret == wxID_CANCEL )
|
||||
return;
|
||||
else
|
||||
s_includeExclusions = dlg.IsCheckBoxChecked();
|
||||
else if( ret == wxID_NO )
|
||||
s_includeExclusions = true;
|
||||
}
|
||||
|
||||
deleteAllMarkers( s_includeExclusions );
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2020 Jon Evans <jon@craftyjon.com>
|
||||
* Copyright (C) 2020-2023 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
* Copyright (C) 2020-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
|
||||
@@ -403,9 +403,12 @@ PANEL_PCBNEW_COLOR_SETTINGS::PANEL_PCBNEW_COLOR_SETTINGS( wxWindow* aParent, BOA
|
||||
m_validLayers.push_back( id );
|
||||
}
|
||||
|
||||
// These layers are not in GAL_LAYER_ID_START ... GAL_LAYER_ID_BITMASK_END
|
||||
m_validLayers.push_back( LAYER_LOCKED_ITEM_SHADOW );
|
||||
m_validLayers.push_back( LAYER_CONFLICTS_SHADOW );
|
||||
m_validLayers.push_back( LAYER_PAGE_LIMITS );
|
||||
m_validLayers.push_back( LAYER_DRC_WARNING );
|
||||
m_validLayers.push_back( LAYER_DRC_EXCLUSION );
|
||||
|
||||
// NOTE: Main board layers are added by createSwatches()
|
||||
|
||||
|
||||
@@ -396,6 +396,7 @@ void PANEL_SETUP_RULES::onScintillaCharAdded( wxStyledTextEvent &aEvent )
|
||||
else if( sexprs.top() == wxT( "disallow" ) || isDisallowToken( sexprs.top() ) )
|
||||
{
|
||||
tokens = wxT( "buried_via|"
|
||||
"footprint|"
|
||||
"graphic|"
|
||||
"hole|"
|
||||
"micro_via|"
|
||||
|
||||
@@ -584,6 +584,9 @@ void DRC_TEST_PROVIDER_COPPER_CLEARANCE::testTrackClearances()
|
||||
// Visitor:
|
||||
[&]( BOARD_ITEM* other ) -> bool
|
||||
{
|
||||
if( m_drcEngine->IsCancelled() )
|
||||
return false;
|
||||
|
||||
if( other->Type() == PCB_PAD_T && static_cast<PAD*>( other )->IsFreePad() )
|
||||
{
|
||||
if( other->GetEffectiveShape( layer )->Collide( trackShape.get() ) )
|
||||
@@ -593,11 +596,11 @@ void DRC_TEST_PROVIDER_COPPER_CLEARANCE::testTrackClearances()
|
||||
if( it == freePadsUsageMap.end() )
|
||||
{
|
||||
freePadsUsageMap[ other ] = track->GetNetCode();
|
||||
return false;
|
||||
return true; // Continue colliding tests
|
||||
}
|
||||
else if( it->second == track->GetNetCode() )
|
||||
{
|
||||
return false;
|
||||
return true; // Continue colliding tests
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -619,7 +622,8 @@ void DRC_TEST_PROVIDER_COPPER_CLEARANCE::testTrackClearances()
|
||||
if( it != checkedPairs.end() )
|
||||
it->second.has_error = true;
|
||||
|
||||
return m_drcEngine->GetReportAllTrackErrors() && !m_drcEngine->IsCancelled();
|
||||
if( !m_drcEngine->GetReportAllTrackErrors() )
|
||||
return false; // We're done with this track
|
||||
}
|
||||
|
||||
return !m_drcEngine->IsCancelled();
|
||||
|
||||
@@ -109,18 +109,18 @@ void DRC_TEST_PROVIDER_SCHEMATIC_PARITY::testNetlist( NETLIST& aNetlist )
|
||||
|
||||
if( footprint == nullptr )
|
||||
{
|
||||
if( m_drcEngine->IsErrorLimitExceeded( DRCE_MISSING_FOOTPRINT ) )
|
||||
break;
|
||||
if( !m_drcEngine->IsErrorLimitExceeded( DRCE_MISSING_FOOTPRINT ) )
|
||||
{
|
||||
wxString msg;
|
||||
msg.Printf( _( "Missing footprint %s (%s)" ),
|
||||
component->GetReference(),
|
||||
component->GetValue() );
|
||||
|
||||
wxString msg;
|
||||
msg.Printf( _( "Missing footprint %s (%s)" ),
|
||||
component->GetReference(),
|
||||
component->GetValue() );
|
||||
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_MISSING_FOOTPRINT );
|
||||
|
||||
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_MISSING_FOOTPRINT );
|
||||
|
||||
drcItem->SetErrorMessage( msg );
|
||||
reportViolation( drcItem, wxPoint(), UNDEFINED_LAYER );
|
||||
drcItem->SetErrorMessage( msg );
|
||||
reportViolation( drcItem, wxPoint(), UNDEFINED_LAYER );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -149,7 +149,7 @@ void DRC_TEST_PROVIDER_SCHEMATIC_PARITY::testNetlist( NETLIST& aNetlist )
|
||||
{
|
||||
wxString msg;
|
||||
msg.Printf( _( "Pad missing net given by schematic (%s)." ),
|
||||
sch_net.GetNetName() );
|
||||
sch_net.GetNetName() );
|
||||
|
||||
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_NET_CONFLICT );
|
||||
drcItem->SetErrorMessage( msg );
|
||||
@@ -160,8 +160,8 @@ void DRC_TEST_PROVIDER_SCHEMATIC_PARITY::testNetlist( NETLIST& aNetlist )
|
||||
{
|
||||
wxString msg;
|
||||
msg.Printf( _( "Pad net (%s) doesn't match net given by schematic (%s)." ),
|
||||
pcb_netname,
|
||||
sch_net.GetNetName() );
|
||||
pcb_netname,
|
||||
sch_net.GetNetName() );
|
||||
|
||||
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_NET_CONFLICT );
|
||||
drcItem->SetErrorMessage( msg );
|
||||
@@ -180,8 +180,19 @@ void DRC_TEST_PROVIDER_SCHEMATIC_PARITY::testNetlist( NETLIST& aNetlist )
|
||||
if( !footprint->FindPadByNumber( sch_net.GetPinName() ) )
|
||||
{
|
||||
wxString msg;
|
||||
msg.Printf( _( "No pad found for pin %s in schematic." ),
|
||||
sch_net.GetPinName() );
|
||||
|
||||
if( sch_net.GetNetName().StartsWith( wxT( "unconnected-" ) ) )
|
||||
{
|
||||
msg = sch_net.GetPinName();
|
||||
}
|
||||
else
|
||||
{
|
||||
msg = wxString::Format( wxT( "%s (%s)" ),
|
||||
sch_net.GetPinName(),
|
||||
sch_net.GetNetName() );
|
||||
}
|
||||
|
||||
msg.Printf( _( "No pad found for pin %s in schematic." ), msg );
|
||||
|
||||
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_NET_CONFLICT );
|
||||
drcItem->SetErrorMessage( msg );
|
||||
|
||||
@@ -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) 1992-2021 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
* Copyright (C) 1992-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
|
||||
@@ -39,8 +39,11 @@
|
||||
#include <reporter.h>
|
||||
#include <gbr_metadata.h>
|
||||
|
||||
// set to 1 to use flashed oblong holes, 0 to draw them by a line.
|
||||
#define FLASH_OVAL_HOLE 1
|
||||
// set to 1 to use flashed oblong holes, 0 to draw them by a line (route holes).
|
||||
// WARNING: currently ( gerber-layer-format-specification-revision-2023-08 ),
|
||||
// oblong holes **must be routed* in a drill file and not flashed,
|
||||
// so set FLASH_OVAL_HOLE to 0
|
||||
#define FLASH_OVAL_HOLE 0
|
||||
|
||||
|
||||
GERBER_WRITER::GERBER_WRITER( BOARD* aPcb )
|
||||
@@ -131,7 +134,7 @@ bool GERBER_WRITER::CreateDrillandMapFilesSet( const wxString& aPlotDirectory, b
|
||||
|
||||
#if !FLASH_OVAL_HOLE
|
||||
// A helper class to transform an oblong hole to a segment
|
||||
static void convertOblong2Segment( wxSize aSize, double aOrient, VECTOR2I& aStart, VECTOR2I& aEnd );
|
||||
static void convertOblong2Segment( const VECTOR2I& aSize, const EDA_ANGLE& aOrient, VECTOR2I& aStart, VECTOR2I& aEnd );
|
||||
#endif
|
||||
|
||||
|
||||
@@ -233,7 +236,7 @@ int GERBER_WRITER::createDrillFile( wxString& aFullFilename, bool aIsNpth,
|
||||
if( hole_descr.m_Hole_Shape )
|
||||
{
|
||||
#if FLASH_OVAL_HOLE // set to 1 to use flashed oblong holes,
|
||||
// 0 to draw them as a line.
|
||||
// 0 to draw them as a line.
|
||||
plotter.FlashPadOval( hole_pos, hole_descr.m_Hole_Size, hole_descr.m_Hole_Orient,
|
||||
FILLED, &gbr_metadata );
|
||||
#else
|
||||
@@ -264,10 +267,10 @@ int GERBER_WRITER::createDrillFile( wxString& aFullFilename, bool aIsNpth,
|
||||
|
||||
|
||||
#if !FLASH_OVAL_HOLE
|
||||
void convertOblong2Segment( wxSize aSize, const EDA_ANGLE& aOrient, VECTOR2I& aStart,
|
||||
void convertOblong2Segment( const VECTOR2I& aSize, const EDA_ANGLE& aOrient, VECTOR2I& aStart,
|
||||
VECTOR2I& aEnd )
|
||||
{
|
||||
wxSize size( aSize );
|
||||
VECTOR2I size( aSize );
|
||||
EDA_ANGLE orient( aOrient );
|
||||
|
||||
/* The pad will be drawn as an oblong shape with size.y > size.x
|
||||
|
||||
@@ -315,6 +315,10 @@ bool PCB_EDIT_FRAME::Files_io_from_id( int id )
|
||||
{
|
||||
case ID_LOAD_FILE:
|
||||
{
|
||||
// Only standalone mode can directly load a new document
|
||||
if( !Kiface().IsSingle() )
|
||||
return false;
|
||||
|
||||
int open_ctl = 0;
|
||||
wxString fileName = Prj().AbsolutePath( GetBoard()->GetFileName() );
|
||||
|
||||
@@ -324,6 +328,7 @@ bool PCB_EDIT_FRAME::Files_io_from_id( int id )
|
||||
|
||||
case ID_IMPORT_NON_KICAD_BOARD:
|
||||
{
|
||||
// Note: we explicitly allow this even if not in standalone mode for now, even though it is dangerous.
|
||||
int open_ctl = 1;
|
||||
wxString fileName; // = Prj().AbsolutePath( GetBoard()->GetFileName() );
|
||||
|
||||
@@ -382,6 +387,10 @@ bool PCB_EDIT_FRAME::Files_io_from_id( int id )
|
||||
|
||||
case ID_NEW_BOARD:
|
||||
{
|
||||
// Only standalone mode can directly load a new document
|
||||
if( !Kiface().IsSingle() )
|
||||
return false;
|
||||
|
||||
if( IsContentModified() )
|
||||
{
|
||||
wxFileName fileName = GetBoard()->GetFileName();
|
||||
|
||||
@@ -119,7 +119,11 @@ FOOTPRINT_EDIT_FRAME::FOOTPRINT_EDIT_FRAME( KIWAY* aKiway, wxWindow* aParent ) :
|
||||
wxIcon icon;
|
||||
wxIconBundle icon_bundle;
|
||||
|
||||
icon.CopyFromBitmap( KiBitmap( BITMAPS::icon_modedit ) );
|
||||
icon.CopyFromBitmap( KiBitmap( BITMAPS::icon_modedit, 48 ) );
|
||||
icon_bundle.AddIcon( icon );
|
||||
icon.CopyFromBitmap( KiBitmap( BITMAPS::icon_modedit, 128 ) );
|
||||
icon_bundle.AddIcon( icon );
|
||||
icon.CopyFromBitmap( KiBitmap( BITMAPS::icon_modedit, 256 ) );
|
||||
icon_bundle.AddIcon( icon );
|
||||
icon.CopyFromBitmap( KiBitmap( BITMAPS::icon_modedit_32 ) );
|
||||
icon_bundle.AddIcon( icon );
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2019 Jean-Pierre Charras, jp.charras at wanadoo.fr
|
||||
* Copyright (C) 2019 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
* Copyright (C) 2019-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
|
||||
@@ -489,7 +489,7 @@ void DXF_IMPORT_PLUGIN::addInsert( const DL_InsertData& aData )
|
||||
MATRIX3x3D arbAxis = getArbitraryAxis( getExtrusion() );
|
||||
|
||||
MATRIX3x3D rot;
|
||||
rot.SetRotation( aData.angle );
|
||||
rot.SetRotation( DEG2RAD( -aData.angle ) ); // DL_InsertData angle is in degrees
|
||||
|
||||
MATRIX3x3D scale;
|
||||
scale.SetScale( VECTOR2D( aData.sx, aData.sy ) );
|
||||
|
||||
@@ -120,8 +120,8 @@ void GRAPHICS_IMPORTER_PCBNEW::AddArc( const VECTOR2D& aCenter, const VECTOR2D&
|
||||
// The criteria used here is radius < MAX_INT / 2.
|
||||
// this is not perfect, but we do not know the exact final position of the arc, so
|
||||
// we cannot test the coordinate values, because the arc can be moved before being placed.
|
||||
VECTOR2D center = CalcArcCenter( arc->GetStart(), arc->GetEnd(), aAngle );
|
||||
double radius = ( center - arc->GetStart() ).EuclideanNorm();
|
||||
VECTOR2D center = MapCoordinate( aCenter );
|
||||
double radius = ( center - MapCoordinate( aStart ) ).EuclideanNorm();
|
||||
double rd_max_value = std::numeric_limits<VECTOR2I::coord_type>::max() / 2.0;
|
||||
|
||||
if( radius >= rd_max_value )
|
||||
|
||||
@@ -374,7 +374,7 @@ void PCB_BASE_FRAME::FocusOnItems( std::vector<BOARD_ITEM*> aItems, PCB_LAYER_ID
|
||||
|
||||
focusPt = item->GetPosition();
|
||||
|
||||
if( aLayer == UNDEFINED_LAYER )
|
||||
if( aLayer == UNDEFINED_LAYER && item->GetLayerSet().any() )
|
||||
aLayer = item->GetLayerSet().Seq()[0];
|
||||
|
||||
switch( item->Type() )
|
||||
|
||||
@@ -220,7 +220,11 @@ PCB_EDIT_FRAME::PCB_EDIT_FRAME( KIWAY* aKiway, wxWindow* aParent ) :
|
||||
wxIcon icon;
|
||||
wxIconBundle icon_bundle;
|
||||
|
||||
icon.CopyFromBitmap( KiBitmap( BITMAPS::icon_pcbnew ) );
|
||||
icon.CopyFromBitmap( KiBitmap( BITMAPS::icon_pcbnew, 48 ) );
|
||||
icon_bundle.AddIcon( icon );
|
||||
icon.CopyFromBitmap( KiBitmap( BITMAPS::icon_pcbnew, 128 ) );
|
||||
icon_bundle.AddIcon( icon );
|
||||
icon.CopyFromBitmap( KiBitmap( BITMAPS::icon_pcbnew, 256 ) );
|
||||
icon_bundle.AddIcon( icon );
|
||||
icon.CopyFromBitmap( KiBitmap( BITMAPS::icon_pcbnew_32 ) );
|
||||
icon_bundle.AddIcon( icon );
|
||||
|
||||
@@ -844,7 +844,7 @@ void PCB_PAINTER::draw( const PCB_ARC* aArc, int aLayer )
|
||||
// Debug only: enable this code only to test the SHAPE_ARC::ConvertToPolyline function
|
||||
// and display the polyline created by it.
|
||||
#if 0
|
||||
SHAPE_ARC arc( aArc->GetCenter(), aArc->GetStart(), aArc->GetAngle() / 10.0, aArc->GetWidth() );
|
||||
SHAPE_ARC arc( aArc->GetCenter(), aArc->GetStart(), aArc->GetAngle(), aArc->GetWidth() );
|
||||
SHAPE_LINE_CHAIN arcSpine = arc.ConvertToPolyline( m_maxError );
|
||||
m_gal->SetLineWidth( m_pcbSettings.m_outlineWidth );
|
||||
m_gal->SetIsFill( false );
|
||||
|
||||
@@ -364,7 +364,21 @@ bool IFACE::OnKifaceStart( PGM_BASE* aProgram, int aCtlBits )
|
||||
start_common( aCtlBits );
|
||||
|
||||
if( !loadGlobalLibTable() )
|
||||
{
|
||||
// we didnt get anywhere deregister the
|
||||
aProgram->GetSettingsManager().FlushAndRelease(
|
||||
aProgram->GetSettingsManager().GetAppSettings<CVPCB_SETTINGS>(), false );
|
||||
|
||||
aProgram->GetSettingsManager().FlushAndRelease( KifaceSettings(), false );
|
||||
|
||||
aProgram->GetSettingsManager().FlushAndRelease(
|
||||
aProgram->GetSettingsManager().GetAppSettings<FOOTPRINT_EDITOR_SETTINGS>(), false );
|
||||
|
||||
aProgram->GetSettingsManager().FlushAndRelease(
|
||||
aProgram->GetSettingsManager().GetAppSettings<EDA_3D_VIEWER_SETTINGS>(), false );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
m_jobHandler = std::make_unique<PCBNEW_JOBS_HANDLER>();
|
||||
|
||||
|
||||
@@ -143,9 +143,9 @@ int PCBNEW_JOBS_HANDLER::JobExportSvg( JOB* aJob )
|
||||
if( aJob->IsCli() )
|
||||
{
|
||||
if( PCB_PLOT_SVG::Plot( brd, svgPlotOptions ) )
|
||||
wxPrintf( _( "Successfully created svg file" ) );
|
||||
wxPrintf( _( "Successfully created svg file" )+ wxS( "\n" ) );
|
||||
else
|
||||
wxPrintf( _( "Error creating svg file" ) );
|
||||
wxPrintf( _( "Error creating svg file" )+ wxS( "\n" ) );
|
||||
}
|
||||
|
||||
return CLI::EXIT_CODES::OK;
|
||||
@@ -775,7 +775,7 @@ int PCBNEW_JOBS_HANDLER::JobExportFpSvg( JOB* aJob )
|
||||
}
|
||||
|
||||
if( !svgJob->m_footprint.IsEmpty() && !singleFpPlotted )
|
||||
wxFprintf( stderr, _( "The given footprint could not be found to export." ) );
|
||||
wxFprintf( stderr, _( "The given footprint could not be found to export." ) + wxS( "\n" ) );
|
||||
|
||||
return CLI::EXIT_CODES::OK;
|
||||
}
|
||||
@@ -827,7 +827,7 @@ int PCBNEW_JOBS_HANDLER::doFpExportSvg( JOB_FP_EXPORT_SVG* aSvgJob, const FOOTPR
|
||||
svgPlotOptions.m_plotFrame = false;
|
||||
|
||||
if( !PCB_PLOT_SVG::Plot( brd.get(), svgPlotOptions ) )
|
||||
wxFprintf( stderr, _( "Error creating svg file" ) );
|
||||
wxFprintf( stderr, _( "Error creating svg file" ) + wxS( "\n" ) );
|
||||
|
||||
|
||||
return CLI::EXIT_CODES::OK;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2020 Thomas Pointhuber <thomas.pointhuber@gmx.at>
|
||||
* Copyright (C) 2021-2023 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
* Copyright (C) 2021-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
|
||||
@@ -42,6 +42,9 @@ const uint16_t ALTIUM_COMPONENT_NONE = std::numeric_limits<uint16_t>::max();
|
||||
// this constant specifies a item which does not define a polygon
|
||||
const uint16_t ALTIUM_POLYGON_NONE = std::numeric_limits<uint16_t>::max();
|
||||
|
||||
// 65534 seems to be belonging to board outline
|
||||
const uint16_t ALTIUM_POLYGON_BOARD = std::numeric_limits<uint16_t>::max() - 1;
|
||||
|
||||
|
||||
enum class ALTIUM_UNIT
|
||||
{
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2019-2020 Thomas Pointhuber <thomas.pointhuber@gmx.at>
|
||||
* Copyright (C) 2021-2023 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
* Copyright (C) 2021-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
|
||||
@@ -2457,8 +2457,12 @@ void ALTIUM_PCB::ConvertArcs6ToPcbShape( const AARC6& aElem, PCB_SHAPE* aShape )
|
||||
|
||||
void ALTIUM_PCB::ConvertArcs6ToBoardItem( const AARC6& aElem, const int aPrimitiveIndex )
|
||||
{
|
||||
if( aElem.is_polygonoutline || aElem.subpolyindex != ALTIUM_POLYGON_NONE )
|
||||
if( aElem.is_polygonoutline
|
||||
|| ( aElem.subpolyindex != ALTIUM_POLYGON_NONE
|
||||
&& aElem.subpolyindex != ALTIUM_POLYGON_BOARD ) )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if( aElem.is_keepout || aElem.layer == ALTIUM_LAYER::KEEP_OUT_LAYER
|
||||
|| IsAltiumLayerAPlane( aElem.layer ) )
|
||||
@@ -3156,8 +3160,12 @@ void ALTIUM_PCB::ParseTracks6Data( const ALTIUM_COMPOUND_FILE& aAltiumPcbFil
|
||||
|
||||
void ALTIUM_PCB::ConvertTracks6ToBoardItem( const ATRACK6& aElem, const int aPrimitiveIndex )
|
||||
{
|
||||
if( aElem.is_polygonoutline || aElem.subpolyindex != ALTIUM_POLYGON_NONE )
|
||||
if( aElem.is_polygonoutline
|
||||
|| ( aElem.subpolyindex != ALTIUM_POLYGON_NONE
|
||||
&& aElem.subpolyindex != ALTIUM_POLYGON_BOARD ) )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if( aElem.is_keepout || aElem.layer == ALTIUM_LAYER::KEEP_OUT_LAYER
|
||||
|| IsAltiumLayerAPlane( aElem.layer ) )
|
||||
|
||||
@@ -787,13 +787,17 @@ void CADSTAR_PCB_ARCHIVE_LOADER::loadLibraryFigures( const SYMDEF_PCB& aComponen
|
||||
{
|
||||
FIGURE& fig = figPair.second;
|
||||
|
||||
drawCadstarShape( fig.Shape, getKiCadLayer( fig.LayerID ),
|
||||
getLineThickness( fig.LineCodeID ),
|
||||
wxString::Format( wxT( "Component %s:%s -> Figure %s" ),
|
||||
aComponent.ReferenceName,
|
||||
aComponent.Alternate,
|
||||
fig.ID ),
|
||||
aFootprint );
|
||||
for( const PCB_LAYER_ID& layer : getKiCadLayerSet( fig.LayerID ).Seq() )
|
||||
{
|
||||
drawCadstarShape( fig.Shape,
|
||||
layer,
|
||||
getLineThickness( fig.LineCodeID ),
|
||||
wxString::Format( wxT( "Component %s:%s -> Figure %s" ),
|
||||
aComponent.ReferenceName,
|
||||
aComponent.Alternate,
|
||||
fig.ID ),
|
||||
aFootprint );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -801,14 +805,27 @@ void CADSTAR_PCB_ARCHIVE_LOADER::loadLibraryFigures( const SYMDEF_PCB& aComponen
|
||||
void CADSTAR_PCB_ARCHIVE_LOADER::loadLibraryCoppers( const SYMDEF_PCB& aComponent,
|
||||
FOOTPRINT* aFootprint )
|
||||
{
|
||||
int totalCopperPads = 0;
|
||||
bool compCopperError = false;
|
||||
|
||||
for( COMPONENT_COPPER compCopper : aComponent.ComponentCoppers )
|
||||
{
|
||||
int lineThickness = getKiCadLength( getCopperCode( compCopper.CopperCodeID ).CopperWidth );
|
||||
PCB_LAYER_ID copperLayer = getKiCadLayer( compCopper.LayerID );
|
||||
LSET layers = getKiCadLayerSet( compCopper.LayerID );
|
||||
LSET copperLayers = LSET::AllCuMask() & layers;
|
||||
LSET remainingLayers = layers;
|
||||
|
||||
if( compCopper.AssociatedPadIDs.size() > 0 && LSET::AllCuMask().Contains( copperLayer )
|
||||
if( !compCopperError && copperLayers.count() > 1 && compCopper.AssociatedPadIDs.size() > 0 )
|
||||
{
|
||||
// TODO: Fix when we have full padstacks
|
||||
wxLogError( _( "Footprint definition '%s' has component copper associated to a pad on "
|
||||
"multiple layers. Custom padstacks are not supported in KiCad. The "
|
||||
"copper items have been imported as graphical elements." ),
|
||||
aComponent.ReferenceName );
|
||||
|
||||
compCopperError = true;
|
||||
}
|
||||
|
||||
if( compCopper.AssociatedPadIDs.size() > 0 && copperLayers.count() == 1
|
||||
&& compCopper.Shape.Type == SHAPE_TYPE::SOLID )
|
||||
{
|
||||
// The copper is associated with pads and in an electrical layer which means it can
|
||||
@@ -836,7 +853,7 @@ void CADSTAR_PCB_ARCHIVE_LOADER::loadLibraryCoppers( const SYMDEF_PCB& aComponen
|
||||
|
||||
std::unique_ptr<PAD> pad = std::make_unique<PAD>( aFootprint );
|
||||
pad->SetAttribute( PAD_ATTRIB::SMD );
|
||||
pad->SetLayerSet( LSET( 1, copperLayer ) );
|
||||
pad->SetLayerSet( copperLayers );
|
||||
pad->SetNumber( anchorPad.Identifier.IsEmpty()
|
||||
? wxString::Format( wxT( "%ld" ), anchorPad.ID )
|
||||
: anchorPad.Identifier );
|
||||
@@ -876,14 +893,19 @@ void CADSTAR_PCB_ARCHIVE_LOADER::loadLibraryCoppers( const SYMDEF_PCB& aComponen
|
||||
// when finding pads by PAD_ID. See loadNets()
|
||||
|
||||
m_librarycopperpads[aComponent.ID][anchorPad.ID].push_back( aFootprint->Pads().size() );
|
||||
totalCopperPads++;
|
||||
|
||||
remainingLayers ^= copperLayers; // don't process copper layers again!
|
||||
}
|
||||
else
|
||||
|
||||
if( remainingLayers.any() )
|
||||
{
|
||||
drawCadstarShape( compCopper.Shape, copperLayer, lineThickness,
|
||||
wxString::Format( wxT( "Component %s:%s -> Copper element" ),
|
||||
aComponent.ReferenceName, aComponent.Alternate ),
|
||||
aFootprint );
|
||||
for( const PCB_LAYER_ID& layer : remainingLayers.Seq() )
|
||||
{
|
||||
drawCadstarShape( compCopper.Shape, layer, lineThickness,
|
||||
wxString::Format( wxT( "Component %s:%s -> Copper element" ),
|
||||
aComponent.ReferenceName, aComponent.Alternate ),
|
||||
aFootprint );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1362,10 +1384,15 @@ void CADSTAR_PCB_ARCHIVE_LOADER::loadFigures()
|
||||
for( std::pair<FIGURE_ID, FIGURE> figPair : Layout.Figures )
|
||||
{
|
||||
FIGURE& fig = figPair.second;
|
||||
drawCadstarShape( fig.Shape, getKiCadLayer( fig.LayerID ),
|
||||
getLineThickness( fig.LineCodeID ),
|
||||
wxString::Format( wxT( "FIGURE %s" ), fig.ID ),
|
||||
m_board, fig.GroupID );
|
||||
|
||||
for( const PCB_LAYER_ID& layer : getKiCadLayerSet( fig.LayerID ).Seq() )
|
||||
{
|
||||
drawCadstarShape( fig.Shape,
|
||||
layer,
|
||||
getLineThickness( fig.LineCodeID ),
|
||||
wxString::Format( wxT( "FIGURE %s" ), fig.ID ),
|
||||
m_board, fig.GroupID );
|
||||
}
|
||||
|
||||
//TODO process "swaprule" (doesn't seem to apply to Layout Figures?)
|
||||
//TODO process re-use block when KiCad Supports it
|
||||
@@ -4148,16 +4175,23 @@ LSET CADSTAR_PCB_ARCHIVE_LOADER::getKiCadLayerSet( const LAYER_ID& aCadstarLayer
|
||||
switch( layerType )
|
||||
{
|
||||
case LAYER_TYPE::ALLDOC:
|
||||
return LSET( 4, PCB_LAYER_ID::Dwgs_User, PCB_LAYER_ID::Cmts_User, PCB_LAYER_ID::Eco1_User,
|
||||
PCB_LAYER_ID::Eco2_User );
|
||||
return LSET( 4, PCB_LAYER_ID::Dwgs_User,
|
||||
PCB_LAYER_ID::Cmts_User,
|
||||
PCB_LAYER_ID::Eco1_User,
|
||||
PCB_LAYER_ID::Eco2_User )
|
||||
| LSET::UserDefinedLayers();
|
||||
|
||||
case LAYER_TYPE::ALLELEC:
|
||||
return LSET::AllCuMask( m_numCopperLayers );
|
||||
|
||||
case LAYER_TYPE::ALLLAYER:
|
||||
return LSET::AllLayersMask()
|
||||
^ ( LSET::AllCuMask( m_numCopperLayers ) ^ LSET::AllCuMask( MAX_CU_LAYERS ) )
|
||||
^ ( LSET( PCB_LAYER_ID::Rescue ) );
|
||||
return LSET::AllCuMask( m_numCopperLayers )
|
||||
| LSET( 4, PCB_LAYER_ID::Dwgs_User,
|
||||
PCB_LAYER_ID::Cmts_User,
|
||||
PCB_LAYER_ID::Eco1_User,
|
||||
PCB_LAYER_ID::Eco2_User )
|
||||
| LSET::UserDefinedLayers()
|
||||
| LSET::AllBoardTechMask();
|
||||
|
||||
default:
|
||||
return LSET( getKiCadLayer( aCadstarLayerID ) );
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2012 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
|
||||
* Copyright (C) 2012-2023 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
* Copyright (C) 2012-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
|
||||
@@ -2511,6 +2511,10 @@ void EAGLE_PLUGIN::deleteTemplates()
|
||||
|
||||
void EAGLE_PLUGIN::loadClasses( wxXmlNode* aClasses )
|
||||
{
|
||||
// Eagle board DTD defines the "classes" element as 0 or 1.
|
||||
if( !aClasses )
|
||||
return;
|
||||
|
||||
BOARD_DESIGN_SETTINGS& bds = m_board->GetDesignSettings();
|
||||
|
||||
m_xpath->push( "classes.class", "number" );
|
||||
@@ -2575,6 +2579,10 @@ void EAGLE_PLUGIN::loadClasses( wxXmlNode* aClasses )
|
||||
|
||||
void EAGLE_PLUGIN::loadSignals( wxXmlNode* aSignals )
|
||||
{
|
||||
// Eagle board DTD defines the "signals" element as 0 or 1.
|
||||
if( !aSignals )
|
||||
return;
|
||||
|
||||
ZONES zones; // per net
|
||||
int netCode = 1;
|
||||
|
||||
|
||||
@@ -1604,6 +1604,12 @@ int DRAWING_TOOL::PlaceImportedGraphics( const TOOL_EVENT& aEvent )
|
||||
|
||||
layer = newItems.front()->GetLayer();
|
||||
|
||||
if( !m_view->IsLayerVisible( layer ) )
|
||||
{
|
||||
m_frame->GetAppearancePanel()->SetLayerVisible( layer, true );
|
||||
m_frame->GetCanvas()->Refresh();
|
||||
}
|
||||
|
||||
m_view->Add( &preview );
|
||||
|
||||
// Clear the current selection then select the drawings so that edit tools work on them
|
||||
|
||||
@@ -644,10 +644,26 @@ int EDIT_TOOL::doMoveSelection( const TOOL_EVENT& aEvent, const wxString& aCommi
|
||||
}
|
||||
else
|
||||
{
|
||||
for( BOARD_ITEM* item : sel_items )
|
||||
if( showCourtyardConflicts )
|
||||
{
|
||||
if( showCourtyardConflicts && item->Type() == PCB_FOOTPRINT_T )
|
||||
drc_on_move->m_FpInMove.push_back( static_cast<FOOTPRINT*>( item ) );
|
||||
std::vector<FOOTPRINT*>& FPs = drc_on_move->m_FpInMove;
|
||||
|
||||
for( BOARD_ITEM* item : sel_items )
|
||||
{
|
||||
if( item->Type() == PCB_FOOTPRINT_T )
|
||||
FPs.push_back( static_cast<FOOTPRINT*>( item ) );
|
||||
|
||||
if( item->Type() == PCB_GROUP_T )
|
||||
{
|
||||
PCB_GROUP* group = static_cast<PCB_GROUP*>( item );
|
||||
group->RunOnDescendants(
|
||||
[&]( BOARD_ITEM* descendent )
|
||||
{
|
||||
if( descendent->Type() == PCB_FOOTPRINT_T )
|
||||
FPs.push_back( static_cast<FOOTPRINT*>( descendent ) );
|
||||
} );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_cursor = grid.BestDragOrigin( originalCursorPos, sel_items,
|
||||
|
||||
@@ -1546,26 +1546,29 @@ int PCB_CONTROL::UpdateMessagePanel( const TOOL_EVENT& aEvent )
|
||||
msgItems.emplace_back( _( "Selected Items" ),
|
||||
wxString::Format( wxT( "%d" ), selection.GetSize() ) );
|
||||
|
||||
std::set<wxString> netNames;
|
||||
std::set<wxString> netClasses;
|
||||
|
||||
for( EDA_ITEM* item : selection )
|
||||
if( m_isBoardEditor )
|
||||
{
|
||||
if( BOARD_CONNECTED_ITEM* bci = dynamic_cast<BOARD_CONNECTED_ITEM*>( item ) )
|
||||
std::set<wxString> netNames;
|
||||
std::set<wxString> netClasses;
|
||||
|
||||
for( EDA_ITEM* item : selection )
|
||||
{
|
||||
netNames.insert( UnescapeString( bci->GetNetname() ) );
|
||||
netClasses.insert( UnescapeString( bci->GetEffectiveNetClass()->GetName() ) );
|
||||
if( BOARD_CONNECTED_ITEM* bci = dynamic_cast<BOARD_CONNECTED_ITEM*>( item ) )
|
||||
{
|
||||
netNames.insert( UnescapeString( bci->GetNetname() ) );
|
||||
netClasses.insert( UnescapeString( bci->GetEffectiveNetClass()->GetName() ) );
|
||||
|
||||
if( netNames.size() > 1 && netClasses.size() > 1 )
|
||||
break;
|
||||
if( netNames.size() > 1 && netClasses.size() > 1 )
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if( netNames.size() == 1 )
|
||||
msgItems.emplace_back( _( "Net" ), *netNames.begin() );
|
||||
|
||||
if( netClasses.size() == 1 )
|
||||
msgItems.emplace_back( _( "Resolved Netclass" ), *netClasses.begin() );
|
||||
}
|
||||
|
||||
if( netNames.size() == 1 )
|
||||
msgItems.emplace_back( _( "Net" ), *netNames.begin() );
|
||||
|
||||
if( netClasses.size() == 1 )
|
||||
msgItems.emplace_back( _( "Resolved Netclass" ), *netClasses.begin() );
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -223,10 +223,23 @@ std::shared_ptr<EDIT_POINTS> PCB_POINT_EDITOR::makePoints( EDA_ITEM* aItem )
|
||||
break;
|
||||
|
||||
case SHAPE_T::RECT:
|
||||
points->AddPoint( shape->GetTopLeft() );
|
||||
points->AddPoint( VECTOR2I( shape->GetBotRight().x, shape->GetTopLeft().y ) );
|
||||
points->AddPoint( shape->GetBotRight() );
|
||||
points->AddPoint( VECTOR2I( shape->GetTopLeft().x, shape->GetBotRight().y ) );
|
||||
{
|
||||
VECTOR2I topLeft = shape->GetTopLeft();
|
||||
VECTOR2I botRight = shape->GetBotRight();
|
||||
|
||||
points->SetSwapX( topLeft.x > botRight.x );
|
||||
points->SetSwapY( topLeft.y > botRight.y );
|
||||
|
||||
if( points->SwapX() )
|
||||
std::swap( topLeft.x, botRight.x );
|
||||
|
||||
if( points->SwapY() )
|
||||
std::swap( topLeft.y, botRight.y );
|
||||
|
||||
points->AddPoint( topLeft );
|
||||
points->AddPoint( VECTOR2I( botRight.x, topLeft.y ) );
|
||||
points->AddPoint( botRight );
|
||||
points->AddPoint( VECTOR2I( topLeft.x, botRight.y ) );
|
||||
|
||||
points->AddLine( points->Point( RECT_TOP_LEFT ), points->Point( RECT_TOP_RIGHT ) );
|
||||
points->Line( RECT_TOP ).SetConstraint( new EC_PERPLINE( points->Line( RECT_TOP ) ) );
|
||||
@@ -238,6 +251,7 @@ std::shared_ptr<EDIT_POINTS> PCB_POINT_EDITOR::makePoints( EDA_ITEM* aItem )
|
||||
points->Line( RECT_LEFT ).SetConstraint( new EC_PERPLINE( points->Line( RECT_LEFT ) ) );
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case SHAPE_T::ARC:
|
||||
points->AddPoint( shape->GetCenter() );
|
||||
@@ -1135,6 +1149,27 @@ void PCB_POINT_EDITOR::updateItem() const
|
||||
|
||||
case SHAPE_T::RECT:
|
||||
{
|
||||
auto setLeft =
|
||||
[&]( int left )
|
||||
{
|
||||
m_editPoints->SwapX() ? shape->SetRight( left ) : shape->SetLeft( left );
|
||||
};
|
||||
auto setRight =
|
||||
[&]( int right )
|
||||
{
|
||||
m_editPoints->SwapX() ? shape->SetLeft( right ) : shape->SetRight( right );
|
||||
};
|
||||
auto setTop =
|
||||
[&]( int top )
|
||||
{
|
||||
m_editPoints->SwapY() ? shape->SetBottom( top ) : shape->SetTop( top );
|
||||
};
|
||||
auto setBottom =
|
||||
[&]( int bottom )
|
||||
{
|
||||
m_editPoints->SwapY() ? shape->SetTop( bottom ) : shape->SetBottom( bottom );
|
||||
};
|
||||
|
||||
VECTOR2I topLeft = m_editPoints->Point( RECT_TOP_LEFT ).GetPosition();
|
||||
VECTOR2I topRight = m_editPoints->Point( RECT_TOP_RIGHT ).GetPosition();
|
||||
VECTOR2I botLeft = m_editPoints->Point( RECT_BOT_LEFT ).GetPosition();
|
||||
@@ -1147,26 +1182,26 @@ void PCB_POINT_EDITOR::updateItem() const
|
||||
|| isModified( m_editPoints->Point( RECT_BOT_RIGHT ) )
|
||||
|| isModified( m_editPoints->Point( RECT_BOT_LEFT ) ) )
|
||||
{
|
||||
shape->SetLeft( topLeft.x );
|
||||
shape->SetTop( topLeft.y );
|
||||
shape->SetRight( botRight.x );
|
||||
shape->SetBottom( botRight.y );
|
||||
setLeft( topLeft.x );
|
||||
setTop( topLeft.y );
|
||||
setRight( botRight.x );
|
||||
setBottom( botRight.y );
|
||||
}
|
||||
else if( isModified( m_editPoints->Line( RECT_TOP ) ) )
|
||||
{
|
||||
shape->SetTop( topLeft.y );
|
||||
setTop( topLeft.y );
|
||||
}
|
||||
else if( isModified( m_editPoints->Line( RECT_LEFT ) ) )
|
||||
{
|
||||
shape->SetLeft( topLeft.x );
|
||||
setLeft( topLeft.x );
|
||||
}
|
||||
else if( isModified( m_editPoints->Line( RECT_BOT ) ) )
|
||||
{
|
||||
shape->SetBottom( botRight.y );
|
||||
setBottom( botRight.y );
|
||||
}
|
||||
else if( isModified( m_editPoints->Line( RECT_RIGHT ) ) )
|
||||
{
|
||||
shape->SetRight( botRight.x );
|
||||
setRight( botRight.x );
|
||||
}
|
||||
|
||||
for( unsigned i = 0; i < m_editPoints->LinesSize(); ++i )
|
||||
@@ -1748,13 +1783,25 @@ void PCB_POINT_EDITOR::updatePoints()
|
||||
break;
|
||||
|
||||
case SHAPE_T::RECT:
|
||||
m_editPoints->Point( RECT_TOP_LEFT ).SetPosition( shape->GetTopLeft() );
|
||||
m_editPoints->Point( RECT_TOP_RIGHT ).SetPosition( shape->GetBotRight().x,
|
||||
shape->GetTopLeft().y );
|
||||
m_editPoints->Point( RECT_BOT_RIGHT ).SetPosition( shape->GetBotRight() );
|
||||
m_editPoints->Point( RECT_BOT_LEFT ).SetPosition( shape->GetTopLeft().x,
|
||||
shape->GetBotRight().y );
|
||||
{
|
||||
VECTOR2I topLeft = shape->GetTopLeft();
|
||||
VECTOR2I botRight = shape->GetBotRight();
|
||||
|
||||
m_editPoints->SetSwapX( topLeft.x > botRight.x );
|
||||
m_editPoints->SetSwapY( topLeft.y > botRight.y );
|
||||
|
||||
if( m_editPoints->SwapX() )
|
||||
std::swap( topLeft.x, botRight.x );
|
||||
|
||||
if( m_editPoints->SwapY() )
|
||||
std::swap( topLeft.y, botRight.y );
|
||||
|
||||
m_editPoints->Point( RECT_TOP_LEFT ).SetPosition( topLeft );
|
||||
m_editPoints->Point( RECT_TOP_RIGHT ).SetPosition( botRight.x, topLeft.y );
|
||||
m_editPoints->Point( RECT_BOT_RIGHT ).SetPosition( botRight );
|
||||
m_editPoints->Point( RECT_BOT_LEFT ).SetPosition( topLeft.x, botRight.y );
|
||||
break;
|
||||
}
|
||||
|
||||
case SHAPE_T::ARC:
|
||||
m_editPoints->Point( ARC_CENTER ).SetPosition( shape->GetCenter() );
|
||||
|
||||
@@ -2578,9 +2578,27 @@ bool PCB_SELECTION_TOOL::Selectable( const BOARD_ITEM* aItem, bool checkVisibili
|
||||
|
||||
break;
|
||||
|
||||
case PCB_BITMAP_T:
|
||||
{
|
||||
if( !board()->IsElementVisible( LAYER_DRAW_BITMAPS ) )
|
||||
return false;
|
||||
|
||||
if( m_isFootprintEditor )
|
||||
{
|
||||
if( !view()->IsLayerVisible( aItem->GetLayer() ) )
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if( !board()->IsLayerVisible( aItem->GetLayer() ) )
|
||||
return false;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case PCB_FP_SHAPE_T:
|
||||
case PCB_FP_TEXTBOX_T:
|
||||
case PCB_BITMAP_T:
|
||||
if( m_isFootprintEditor )
|
||||
{
|
||||
if( !view()->IsLayerVisible( aItem->GetLayer() ) )
|
||||
@@ -2959,8 +2977,8 @@ void PCB_SELECTION_TOOL::GuessSelectionCandidates( GENERAL_COLLECTOR& aCollector
|
||||
{
|
||||
BOARD_ITEM* item = aCollector[i];
|
||||
|
||||
if( item->IsType( { PCB_TEXT_T, PCB_TEXTBOX_T, PCB_SHAPE_T, PCB_FOOTPRINT_T } )
|
||||
&& item->IsOnLayer( activeLayer ) )
|
||||
if( item->IsType( { PCB_TEXT_T, PCB_TEXTBOX_T, PCB_SHAPE_T } )
|
||||
&& silkLayers[ item->GetLayer() ] )
|
||||
{
|
||||
preferred.insert( item );
|
||||
}
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
#include <pcb_track.h>
|
||||
#include <pcb_text.h>
|
||||
#include <pcb_textbox.h>
|
||||
#include <pcb_dimension.h>
|
||||
#include <fp_text.h>
|
||||
#include <fp_textbox.h>
|
||||
#include <connectivity/connectivity_data.h>
|
||||
@@ -871,6 +872,19 @@ void ZONE_FILLER::addKnockout( BOARD_ITEM* aItem, PCB_LAYER_ID aLayer, int aGap,
|
||||
break;
|
||||
}
|
||||
|
||||
case PCB_DIM_ALIGNED_T:
|
||||
case PCB_DIM_LEADER_T:
|
||||
case PCB_DIM_CENTER_T:
|
||||
case PCB_DIM_RADIAL_T:
|
||||
case PCB_DIM_ORTHOGONAL_T:
|
||||
{
|
||||
PCB_DIMENSION_BASE* dim = static_cast<PCB_DIMENSION_BASE*>( aItem );
|
||||
|
||||
dim->TransformShapeToPolygon( aHoles, aLayer, aGap, m_maxError, ERROR_OUTSIDE, false );
|
||||
dim->PCB_TEXT::TransformShapeToPolygon( aHoles, aLayer, aGap, m_maxError, ERROR_OUTSIDE );
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
aItem->TransformShapeToPolygon( aHoles, aLayer, aGap, m_maxError, ERROR_OUTSIDE,
|
||||
aIgnoreLineWidth );
|
||||
|
||||
@@ -326,7 +326,9 @@
|
||||
"page_layout_descr_file": "",
|
||||
"plot_directory": "",
|
||||
"spice_adjust_passive_values": false,
|
||||
"spice_current_sheet_as_root": false,
|
||||
"spice_external_command": "C:\\Spice64\\bin\\ngspice \"%I\"",
|
||||
"spice_model_current_sheet_as_root": true,
|
||||
"spice_save_all_currents": false,
|
||||
"spice_save_all_voltages": false,
|
||||
"subpart_first_id": 65,
|
||||
|
||||
+168
-1915
File diff suppressed because it is too large
Load Diff
@@ -1,54 +1,9 @@
|
||||
KiCad schematic
|
||||
.include "/Users/jeff/kicad_arm/kicad/qa/data/eeschema/TL072-dual.lib"
|
||||
.include "/Users/jeff/kicad_arm/kicad/qa/data/eeschema/VDMOS_models.lib"
|
||||
.save all
|
||||
.probe alli
|
||||
.ic v(Tj1)={envtemp} v(Tj2)={envtemp}
|
||||
.temp {envtemp}
|
||||
.param envtemp=25
|
||||
.tran 200u 10
|
||||
.option RELTOL=.01 ABSTOL=1N VNTOL=10u
|
||||
.control
|
||||
set controlswait
|
||||
if $?sharedmode
|
||||
rusage
|
||||
else
|
||||
run
|
||||
rusage
|
||||
settype temperature tj1 tj2 tcase1 tcase2
|
||||
plot tj1 tj2 tcase1 tcase2
|
||||
plot in out xlimit 5.2 5.3
|
||||
end
|
||||
.endc
|
||||
.tran 100u 50m
|
||||
C2 out in 0.33u
|
||||
R1 in out 390k
|
||||
Rload1 out GND 8
|
||||
C7 Net-_C7-Pad1_ GND 300m
|
||||
Vamb1 Net-_R11-Pad1_ GND {envtemp}
|
||||
R14 Net-_R11-Pad1_ Net-_C7-Pad1_ 3
|
||||
C6 Net-_C6-Pad1_ GND 300m
|
||||
R13 Net-_C7-Pad1_ Tcase2 200m
|
||||
R12 GND Tj2 1G
|
||||
R9 GND Tj1 1G
|
||||
R10 Net-_C6-Pad1_ Tcase1 200m
|
||||
R11 Net-_R11-Pad1_ Net-_C6-Pad1_ 3
|
||||
R4 Net-_U1A--_ GND 1k
|
||||
C3 Net-_U1B-+_ GND 1u
|
||||
R2 Net-_U1B-+_ GND 10k
|
||||
XU1 Net-_R16-Pad2_ Net-_U1A--_ Net-_U1A-+_ GND Net-_U1B-+_ Net-_U1B--_ Net-_R17-Pad2_ VCC TL072c
|
||||
R5 Net-_M2-D_ Net-_U1A--_ 19.5k
|
||||
R17 Net-_M2-G_ Net-_R17-Pad2_ 100
|
||||
R6 Net-_M2-S_ Net-_U1B--_ 100k
|
||||
Vin1 in GND dc 0 ac 1 sin(0 0.5 100 20m)
|
||||
C1 VCC GND 1u
|
||||
R16 Net-_M1-G_ Net-_R16-Pad2_ 100
|
||||
C2 Net-_U1A-+_ in 330n
|
||||
R3 Net-_U1A-+_ Net-_U1B--_ 100k
|
||||
R1 VCC Net-_U1B-+_ 390k
|
||||
R7 Net-_M1-S_ Net-_M2-D_ 100m
|
||||
C4 Net-_M2-D_ out 10m
|
||||
R15 out GND 1k
|
||||
C5 out Net-_M2-D_ 1u
|
||||
M2 Net-_M2-D_ Net-_M2-G_ Net-_M2-S_ Tj2 Tcase2 IRFP240 thermal
|
||||
M1 VCC Net-_M1-G_ Net-_M1-S_ Tj1 Tcase1 IRFP240 thermal
|
||||
V1 VCC GND 36
|
||||
R8 Net-_M2-S_ GND 800m
|
||||
.end
|
||||
|
||||
@@ -109,6 +109,9 @@ BOOST_FIXTURE_TEST_CASE( ImmediateSBCKT, TEST_SIM_REGRESSIONS_FIXTURE )
|
||||
}
|
||||
|
||||
|
||||
// This test is flaky and fails on ngspice-42 / Linux.
|
||||
// Please replace it with something that is more stable
|
||||
#if 0
|
||||
BOOST_FIXTURE_TEST_CASE( LegacyFixups, TEST_SIM_REGRESSIONS_FIXTURE )
|
||||
{
|
||||
LOCALE_IO dummy;
|
||||
@@ -120,6 +123,7 @@ BOOST_FIXTURE_TEST_CASE( LegacyFixups, TEST_SIM_REGRESSIONS_FIXTURE )
|
||||
TestTranPoint( 0.01, { { "V(out)", -0.060 } } );
|
||||
TestTranPoint( 0.02, { { "V(out)", 0.856 } } );
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
BOOST_FIXTURE_TEST_CASE( DualNMOSAmp, TEST_SIM_REGRESSIONS_FIXTURE )
|
||||
@@ -130,8 +134,8 @@ BOOST_FIXTURE_TEST_CASE( DualNMOSAmp, TEST_SIM_REGRESSIONS_FIXTURE )
|
||||
MOCK_EXPECT( program.GetLocalEnvVariables ).returns( ENV_VAR_MAP() );
|
||||
|
||||
TestNetlist( "issue13162" );
|
||||
TestTranPoint( 0.030, { { "V(out)", 0.557 } } );
|
||||
TestTranPoint( 0.035, { { "V(out)", -1.437 } } );
|
||||
TestTranPoint( 0.030, { { "V(out)", 0.000829682 } } );
|
||||
TestTranPoint( 0.035, { { "V(out)", -0.000829692 } } );
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -197,6 +197,9 @@ BOOST_AUTO_TEST_CASE( Directives )
|
||||
#endif
|
||||
|
||||
|
||||
// This test is flaky and fails on ngspice-42 / Linux.
|
||||
// Please replace it with something that is more stable
|
||||
#if 0
|
||||
BOOST_AUTO_TEST_CASE( LegacyLaserDriver )
|
||||
{
|
||||
LOCALE_IO dummy;
|
||||
@@ -213,6 +216,7 @@ BOOST_AUTO_TEST_CASE( LegacyLaserDriver )
|
||||
// Test D1 current after the pulse
|
||||
TestTranPoint( 150e-9, { { "I(D1)", 0 } } );
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
BOOST_AUTO_TEST_CASE( LegacyPotentiometer )
|
||||
|
||||
@@ -613,6 +613,21 @@ set( BMAPS_128
|
||||
icon_pcbcalculator
|
||||
)
|
||||
|
||||
# 256 x 256 for icon sets (windows namely)
|
||||
set( BMAPS_256
|
||||
icon_cvpcb
|
||||
icon_eeschema
|
||||
icon_gerbview
|
||||
icon_kicad
|
||||
icon_kicad_nightly
|
||||
icon_libedit
|
||||
icon_modedit
|
||||
icon_pcbnew
|
||||
icon_pagelayout_editor
|
||||
icon_bitmap2component
|
||||
icon_pcbcalculator
|
||||
)
|
||||
|
||||
# Images in this section are generated at whatever resolution is set in the source SVG file
|
||||
# Use Inkscape Document Properties > Custom Size to set (make sure units are pixels)
|
||||
# These are used for images in the UI that are not-square or very large (infographics, etc)
|
||||
@@ -900,6 +915,8 @@ if( MAINTAIN_PNGS )
|
||||
|
||||
bitmap_dir( 128 128 "${BMAPS_128}" )
|
||||
|
||||
bitmap_dir( 256 256 "${BMAPS_256}" )
|
||||
|
||||
bitmap_dir( 48 48 "${BMAPS_BIG}" )
|
||||
|
||||
bitmap_dir( -1 -1 "${BMAPS_OTHER}" )
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 101 KiB After Width: | Height: | Size: 365 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 101 KiB After Width: | Height: | Size: 365 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 101 KiB After Width: | Height: | Size: 365 KiB |
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user