Compare commits
127 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| b29f91cc15 | |||
| f81313068e | |||
| 882756b676 | |||
| 8c3cd200d1 | |||
| a5fd03df88 | |||
| 2d2912c23d | |||
| 3106f6c9f4 | |||
| fde2b429b9 | |||
| 0593663462 | |||
| bce8c95647 | |||
| 4d729110d5 | |||
| 6c2b9eb433 | |||
| df223cced4 | |||
| 8e331628b6 | |||
| ceaf3fc72d | |||
| b004d7a1cb | |||
| f3ff9ddd31 | |||
| e5fa18c9b1 | |||
| d52f246b2a | |||
| 3dfbe582db | |||
| 431aa88612 | |||
| 03a1a8e6d3 | |||
| 5f6de83981 | |||
| 02d38db577 | |||
| bd1698f80e | |||
| 6de30b19a0 | |||
| 00ff5baf59 | |||
| 152252c685 | |||
| 3b0466f3e8 | |||
| 2ca7a76693 | |||
| af159c9841 | |||
| de9ae28bdb | |||
| 9f151025b3 | |||
| 549dca1a05 | |||
| da520f83ee | |||
| 47547713de | |||
| 705570923e | |||
| 2827835720 | |||
| bf95906f90 | |||
| e8d2c222b6 | |||
| f891c4641b | |||
| a65fc7f82a | |||
| 5bcd0a5828 | |||
| 74d8040e8c | |||
| c5514d43c7 | |||
| 0704e37eb5 | |||
| c94de31a8c | |||
| 2793e67bab | |||
| 3213ea582d | |||
| 6003097411 | |||
| 6390633a7b | |||
| dde5f2bed1 | |||
| 7c4b8d50dd | |||
| 56f58cf53f | |||
| 914e396e2e | |||
| f6bdd40c30 | |||
| 1bf1620157 | |||
| da85a5f6bf | |||
| e2219a0c4d | |||
| de46097ce0 | |||
| ae53986487 | |||
| 3cf3a3ebe0 | |||
| a62e6b1f7f | |||
| d99ce976b9 | |||
| 161d15dcea | |||
| 81319a5fcf | |||
| 628b4ca8b8 | |||
| d8ed1fea61 | |||
| 6f474a389f | |||
| 5a1a147585 | |||
| de9ef4ce70 | |||
| 835f358816 | |||
| 61cfe53be1 | |||
| 535982f245 | |||
| 8ee73903c6 | |||
| 292492bd01 | |||
| f1029b7280 | |||
| 578c0ef0f0 | |||
| 238c8df8b5 | |||
| 95acc1bf33 | |||
| 8dbfe79536 | |||
| 8f9830eb92 | |||
| bf0b80d676 | |||
| bc8e3c22d8 | |||
| 28ddfbadbf | |||
| e834374ad2 | |||
| 981aafd5d9 | |||
| 09960caa66 | |||
| cf6fd64758 | |||
| b08dccb7b3 | |||
| d6e5c74573 | |||
| ea93502ab3 | |||
| e1f402aa3d | |||
| 08f1b666d1 | |||
| 8d62725598 | |||
| cbd8b3c59e | |||
| e9cc66cc8d | |||
| 258b702dad | |||
| 6c3e891123 | |||
| 80937ae2c0 | |||
| 2d37b86530 | |||
| 8bdcd299d7 | |||
| 22e9985f5d | |||
| 594beef22e | |||
| 03ed7a4a27 | |||
| 8cbfd8af9f | |||
| c16e86be9a | |||
| b0e2aeb972 | |||
| fc06192643 | |||
| 2faaa0a042 | |||
| 2d4bcc6557 | |||
| ba72676edb | |||
| 1a2e2bd29a | |||
| 8b690c9a3c | |||
| 6d25e57cd7 | |||
| 7dfa715a45 | |||
| e8a10939b5 | |||
| 44ec38ad2d | |||
| 9cb6df9c38 | |||
| 4a5fdd4214 | |||
| fe7ed364b6 | |||
| 43f9863182 | |||
| 4987809fe3 | |||
| 894f424d14 | |||
| e21995c401 | |||
| bb7362ceba | |||
| 334268f5e7 |
+1
-1
@@ -40,6 +40,6 @@ include:
|
||||
- local: '/.gitlab/templates.yml'
|
||||
- local: '/.gitlab/Fedora-Linux-CI.yml'
|
||||
- local: '/.gitlab/Ubuntu-20.04-CI.yml'
|
||||
# - local: '/.gitlab/Windows-CI.yml'
|
||||
- local: '/.gitlab/Windows-CI.yml'
|
||||
- local: '/.gitlab/coverity.yml'
|
||||
- local: '/.gitlab/linux-metadata-validate.yml'
|
||||
|
||||
+13
-2
@@ -7,16 +7,27 @@ win64_build:
|
||||
- kicad-windows-1809
|
||||
extends: .only_code
|
||||
interruptible: false
|
||||
image: registry.gitlab.com/kicad/kicad-ci/source_containers/win64:msvc1809
|
||||
image: registry.gitlab.com/kicad/kicad-ci/windows-build-image/win1809-msvc:latest
|
||||
variables:
|
||||
VCPKG_BINARY_SOURCES: 'nuget,kicad,readwrite'
|
||||
cache:
|
||||
key: win64-vcpkg-"$CI_COMMIT_REF_SLUG"
|
||||
paths:
|
||||
- build\windows\vcpkg_installed
|
||||
- .vcpkgCache
|
||||
only:
|
||||
- branches@kicad/code/kicad
|
||||
- tags@kicad/code/kicad
|
||||
script:
|
||||
- C:\builder\build.ps1 -Env -Arch x64
|
||||
- $vcpkgCache=Join-Path -Path (Get-Location) -ChildPath ".vcpkgCache";$env:VCPKG_DEFAULT_BINARY_CACHE=$vcpkgCache;New-Item -ItemType Directory -Force -Path $vcpkgCache
|
||||
- nuget.exe sources add -Name kicad -Source "https://nuget.kicad.org:443/v3/index.json"
|
||||
- nuget.exe setapikey $env:KICAD_NUGET_KEY -Source "https://nuget.kicad.org:443/v3/index.json"
|
||||
- mkdir -p build/windows -Force
|
||||
- cd build/windows
|
||||
- cmake `
|
||||
-G "Ninja" `
|
||||
-DCMAKE_TOOLCHAIN_FILE=C:\build\vcpkg\scripts\buildsystems\vcpkg.cmake `
|
||||
-DCMAKE_TOOLCHAIN_FILE=C:\builder\vcpkg\scripts\buildsystems\vcpkg.cmake `
|
||||
-DCMAKE_BUILD_TYPE=Debug `
|
||||
-DKICAD_SCRIPTING_WXPYTHON=OFF `
|
||||
-DKICAD_USE_OCC=ON `
|
||||
|
||||
@@ -119,6 +119,7 @@ BOARD_ADAPTER::BOARD_ADAPTER() :
|
||||
SetFlag( FL_ZONE, true );
|
||||
SetFlag( FL_SILKSCREEN, true );
|
||||
SetFlag( FL_SOLDERMASK, true );
|
||||
SetFlag( FL_SOLDERPASTE, true );
|
||||
SetFlag( FL_SUBTRACT_MASK_FROM_SILK, false );
|
||||
|
||||
SetFlag( FL_RENDER_OPENGL_COPPER_THICKNESS, true );
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2015-2016 Mario Luzeiro <mrluzeiro@ua.pt>
|
||||
* Copyright (C) 1992-2021 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
* Copyright (C) 1992-2022 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
@@ -89,30 +89,32 @@ END_EVENT_TABLE()
|
||||
|
||||
EDA_3D_CANVAS::EDA_3D_CANVAS( wxWindow* aParent, const int* aAttribList,
|
||||
BOARD_ADAPTER& aBoardAdapter, CAMERA& aCamera,
|
||||
S3D_CACHE* a3DCachePointer )
|
||||
: HIDPI_GL_CANVAS( aParent, wxID_ANY, aAttribList, wxDefaultPosition, wxDefaultSize,
|
||||
S3D_CACHE* a3DCachePointer ) :
|
||||
HIDPI_GL_CANVAS( aParent, wxID_ANY, aAttribList, wxDefaultPosition, wxDefaultSize,
|
||||
wxFULL_REPAINT_ON_RESIZE ),
|
||||
m_eventDispatcher( nullptr ),
|
||||
m_parentStatusBar( nullptr ),
|
||||
m_parentInfoBar( nullptr ),
|
||||
m_glRC( nullptr ),
|
||||
m_is_opengl_initialized( false ),
|
||||
m_is_opengl_version_supported( true ),
|
||||
m_mouse_is_moving( false ),
|
||||
m_mouse_was_moved( false ),
|
||||
m_camera_is_moving( false ),
|
||||
m_render_pivot( false ),
|
||||
m_camera_moving_speed( 1.0f ),
|
||||
m_strtime_camera_movement( 0 ),
|
||||
m_animation_enabled( true ),
|
||||
m_moving_speed_multiplier( 3 ),
|
||||
m_boardAdapter( aBoardAdapter ),
|
||||
m_camera( aCamera ),
|
||||
m_3d_render( nullptr ),
|
||||
m_opengl_supports_raytracing( true ),
|
||||
m_render_raytracing_was_requested( false ),
|
||||
m_accelerator3DShapes( nullptr ),
|
||||
m_currentRollOverItem( nullptr )
|
||||
m_eventDispatcher( nullptr ),
|
||||
m_parentStatusBar( nullptr ),
|
||||
m_parentInfoBar( nullptr ),
|
||||
m_glRC( nullptr ),
|
||||
m_is_opengl_initialized( false ),
|
||||
m_is_opengl_version_supported( true ),
|
||||
m_editing_timeout_timer( this, wxID_HIGHEST + 1 ),
|
||||
m_redraw_trigger_timer( this, wxID_HIGHEST + 2 ),
|
||||
m_mouse_is_moving( false ),
|
||||
m_mouse_was_moved( false ),
|
||||
m_camera_is_moving( false ),
|
||||
m_render_pivot( false ),
|
||||
m_camera_moving_speed( 1.0f ),
|
||||
m_strtime_camera_movement( 0 ),
|
||||
m_animation_enabled( true ),
|
||||
m_moving_speed_multiplier( 3 ),
|
||||
m_boardAdapter( aBoardAdapter ),
|
||||
m_camera( aCamera ),
|
||||
m_3d_render( nullptr ),
|
||||
m_opengl_supports_raytracing( true ),
|
||||
m_render_raytracing_was_requested( false ),
|
||||
m_accelerator3DShapes( nullptr ),
|
||||
m_currentRollOverItem( nullptr )
|
||||
{
|
||||
wxLogTrace( m_logTrace, wxT( "EDA_3D_CANVAS::EDA_3D_CANVAS" ) );
|
||||
|
||||
@@ -845,8 +847,14 @@ void EDA_3D_CANVAS::OnMiddleUp( wxMouseEvent& event )
|
||||
}
|
||||
|
||||
|
||||
void EDA_3D_CANVAS::OnTimerTimeout_Editing( wxTimerEvent& /* event */ )
|
||||
void EDA_3D_CANVAS::OnTimerTimeout_Editing( wxTimerEvent& aEvent )
|
||||
{
|
||||
if( aEvent.GetId() != m_editing_timeout_timer.GetId() )
|
||||
{
|
||||
aEvent.Skip();
|
||||
return;
|
||||
}
|
||||
|
||||
m_mouse_is_moving = false;
|
||||
m_mouse_was_moved = false;
|
||||
|
||||
@@ -867,8 +875,14 @@ void EDA_3D_CANVAS::restart_editingTimeOut_Timer()
|
||||
}
|
||||
|
||||
|
||||
void EDA_3D_CANVAS::OnTimerTimeout_Redraw( wxTimerEvent& event )
|
||||
void EDA_3D_CANVAS::OnTimerTimeout_Redraw( wxTimerEvent& aEvent )
|
||||
{
|
||||
if( aEvent.GetId() != m_redraw_trigger_timer.GetId() )
|
||||
{
|
||||
aEvent.Skip();
|
||||
return;
|
||||
}
|
||||
|
||||
Request_refresh( true );
|
||||
}
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
# KiCad.
|
||||
#
|
||||
# Note: This version string should follow the semantic versioning system
|
||||
set( KICAD_SEMANTIC_VERSION "6.0.8" )
|
||||
set( KICAD_SEMANTIC_VERSION "6.0.9" )
|
||||
|
||||
# Default the version to the semantic version.
|
||||
# This is overridden by the git repository tag though (if using git)
|
||||
|
||||
@@ -40,10 +40,11 @@ static int DEFAULT_COL_WIDTHS[] = { 200, 600 };
|
||||
EDA_LIST_DIALOG::EDA_LIST_DIALOG( wxWindow* aParent, const wxString& aTitle,
|
||||
const wxArrayString& aItemHeaders,
|
||||
const std::vector<wxArrayString>& aItemList,
|
||||
const wxString& aPreselectText ) :
|
||||
const wxString& aPreselectText, bool aSortList ) :
|
||||
EDA_LIST_DIALOG_BASE( aParent, wxID_ANY, aTitle )
|
||||
{
|
||||
m_itemsList = &aItemList;
|
||||
m_sortList = aSortList;
|
||||
|
||||
m_filterBox->SetHint( _( "Filter" ) );
|
||||
|
||||
@@ -234,5 +235,6 @@ static int wxCALLBACK myCompareFunction( wxIntPtr aItem1, wxIntPtr aItem2,
|
||||
|
||||
void EDA_LIST_DIALOG::sortList()
|
||||
{
|
||||
m_listBox->SortItems( myCompareFunction, 0 );
|
||||
if( m_sortList )
|
||||
m_listBox->SortItems( myCompareFunction, 0 );
|
||||
}
|
||||
|
||||
@@ -250,7 +250,7 @@ static void netclassToGridRow( EDA_UNITS aUnits, wxGrid* aGrid, int aRow, const
|
||||
SET_MILS_CELL( GRID_WIREWIDTH, nc->GetWireWidth() );
|
||||
SET_MILS_CELL( GRID_BUSWIDTH, nc->GetBusWidth() );
|
||||
|
||||
wxString colorAsString = nc->GetSchematicColor().ToWxString( wxC2S_CSS_SYNTAX );
|
||||
wxString colorAsString = nc->GetSchematicColor().ToCSSString();
|
||||
aGrid->SetCellValue( aRow, GRID_SCHEMATIC_COLOR, colorAsString );
|
||||
|
||||
int lineStyleIdx = std::max( 0, nc->GetLineStyle() );
|
||||
|
||||
+17
-17
@@ -969,22 +969,27 @@ bool EDA_DRAW_FRAME::LibraryFileBrowser( bool doOpen, wxFileName& aFilename,
|
||||
wxString prompt = doOpen ? _( "Select Library" ) : _( "New Library" );
|
||||
aFilename.SetExt( ext );
|
||||
|
||||
wxString dir;
|
||||
wxString projectDir = Prj().IsNullProject() ? aFilename.GetPath() : Prj().GetProjectPath();
|
||||
wxString defaultDir;
|
||||
|
||||
if( GetMruPath().IsEmpty() )
|
||||
dir = aGlobalPath;
|
||||
if( aIsGlobal )
|
||||
{
|
||||
if( !GetMruPath().IsEmpty() && !GetMruPath().StartsWith( projectDir ) )
|
||||
defaultDir = GetMruPath();
|
||||
else
|
||||
defaultDir = aGlobalPath;
|
||||
}
|
||||
else
|
||||
dir = GetMruPath();
|
||||
|
||||
{
|
||||
if( !GetMruPath().IsEmpty() && GetMruPath().StartsWith( projectDir ) )
|
||||
defaultDir = GetMruPath();
|
||||
else
|
||||
defaultDir = projectDir;
|
||||
}
|
||||
|
||||
if( isDirectory && doOpen )
|
||||
{
|
||||
if( !aIsGlobal && GetMruPath().IsEmpty() )
|
||||
{
|
||||
dir = Prj().GetProjectPath();
|
||||
}
|
||||
|
||||
wxDirDialog dlg( this, prompt, dir, wxDD_DEFAULT_STYLE | wxDD_DIR_MUST_EXIST );
|
||||
wxDirDialog dlg( this, prompt, defaultDir, wxDD_DEFAULT_STYLE | wxDD_DIR_MUST_EXIST );
|
||||
|
||||
if( dlg.ShowModal() == wxID_CANCEL )
|
||||
return false;
|
||||
@@ -998,12 +1003,7 @@ bool EDA_DRAW_FRAME::LibraryFileBrowser( bool doOpen, wxFileName& aFilename,
|
||||
if( aFilename.GetName().empty() )
|
||||
aFilename.SetName( wxT( "Library" ) );
|
||||
|
||||
if( !aIsGlobal && GetMruPath().IsEmpty() )
|
||||
{
|
||||
dir = Prj().IsNullProject() ? aFilename.GetFullPath() : Prj().GetProjectPath();
|
||||
}
|
||||
|
||||
wxFileDialog dlg( this, prompt, dir, aFilename.GetFullName(),
|
||||
wxFileDialog dlg( this, prompt, defaultDir, aFilename.GetFullName(),
|
||||
wildcard, doOpen ? wxFD_OPEN | wxFD_FILE_MUST_EXIST
|
||||
: wxFD_SAVE | wxFD_CHANGE_DIR | wxFD_OVERWRITE_PROMPT );
|
||||
|
||||
|
||||
+27
-4
@@ -144,10 +144,33 @@ bool COLOR4D::SetFromWxString( const wxString& aColorString )
|
||||
}
|
||||
|
||||
|
||||
wxString COLOR4D::ToWxString( long flags ) const
|
||||
wxString COLOR4D::ToCSSString() const
|
||||
{
|
||||
wxColour c = ToColour();
|
||||
return c.GetAsString( flags );
|
||||
wxString str;
|
||||
|
||||
const int red = c.Red();
|
||||
const int green = c.Green();
|
||||
const int blue = c.Blue();
|
||||
const int alpha = c.Alpha();
|
||||
|
||||
if ( alpha == wxALPHA_OPAQUE )
|
||||
{
|
||||
str.Printf( wxT( "rgb(%d, %d, %d)" ), red, green, blue );
|
||||
}
|
||||
else // use rgba() form
|
||||
{
|
||||
wxString alpha_str = wxString::FromCDouble( alpha / 255.0, 3 );
|
||||
|
||||
// The wxC2S_CSS_SYNTAX is particularly sensitive to ','s (as it uses them for value
|
||||
// delimiters), and wxWidgets is known to be buggy in this respect when dealing with
|
||||
// Serbian and Russian locales (at least), so we enforce an extra level of safety.
|
||||
alpha_str.Replace( wxT( "," ), wxT( "." ) );
|
||||
|
||||
str.Printf( wxT( "rgba(%d, %d, %d, %s)" ), red, green, blue, alpha_str );
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
|
||||
@@ -271,13 +294,13 @@ const bool operator<( const COLOR4D& lhs, const COLOR4D& rhs )
|
||||
|
||||
std::ostream &operator<<( std::ostream &aStream, COLOR4D const &aColor )
|
||||
{
|
||||
return aStream << aColor.ToWxString( wxC2S_CSS_SYNTAX );
|
||||
return aStream << aColor.ToCSSString();
|
||||
}
|
||||
|
||||
|
||||
void to_json( nlohmann::json& aJson, const COLOR4D& aColor )
|
||||
{
|
||||
aJson = nlohmann::json( aColor.ToWxString( wxC2S_CSS_SYNTAX ).ToStdString() );
|
||||
aJson = nlohmann::json( aColor.ToCSSString().ToStdString() );
|
||||
}
|
||||
|
||||
|
||||
|
||||
+14
-1
@@ -31,6 +31,7 @@
|
||||
#include <typeinfo>
|
||||
#include <wx/utils.h>
|
||||
#include <wx/evtloop.h>
|
||||
#include <wx/socket.h>
|
||||
|
||||
|
||||
BEGIN_EVENT_TABLE( KIWAY_PLAYER, EDA_BASE_FRAME )
|
||||
@@ -65,7 +66,19 @@ KIWAY_PLAYER::KIWAY_PLAYER( wxWindow* aParent, wxWindowID aId, const wxString& a
|
||||
}
|
||||
|
||||
|
||||
KIWAY_PLAYER::~KIWAY_PLAYER() throw() {}
|
||||
KIWAY_PLAYER::~KIWAY_PLAYER() throw() {
|
||||
|
||||
// socket server must be destructed before we complete
|
||||
// destructing the frame or else we could crash
|
||||
// as the socket server holds a reference to this frame
|
||||
if( m_socketServer )
|
||||
{
|
||||
// ensure any event handling stops
|
||||
m_socketServer->Notify( false );
|
||||
|
||||
delete m_socketServer;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void KIWAY_PLAYER::KiwayMailIn( KIWAY_EXPRESS& aEvent )
|
||||
|
||||
@@ -77,7 +77,7 @@ NUMERIC_EVALUATOR::~NUMERIC_EVALUATOR()
|
||||
|
||||
void NUMERIC_EVALUATOR::Clear()
|
||||
{
|
||||
free( m_token.token );
|
||||
delete[] m_token.token;
|
||||
m_token.token = nullptr;
|
||||
m_token.input = nullptr;
|
||||
m_parseError = true;
|
||||
@@ -103,7 +103,7 @@ void NUMERIC_EVALUATOR::parseSetResult( double val )
|
||||
{
|
||||
// Naively printing this with %g produces "nan" on some platforms
|
||||
// and "-nan(ind)" on others (e.g. MSVC). So force a "standard" string.
|
||||
snprintf( m_token.token, m_token.OutLen, "%s", "NaN" );
|
||||
snprintf( m_token.token, m_token.outputLen, "%s", "NaN" );
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -111,7 +111,7 @@ void NUMERIC_EVALUATOR::parseSetResult( double val )
|
||||
// Warning: DO NOT use a format like %f or %g, because they can create issues.
|
||||
// especially %g can generate an exponent, incompatible with UNIT_BINDER
|
||||
// Use the optimized Double2Str
|
||||
snprintf( m_token.token, m_token.OutLen, "%s", Double2Str( val ).c_str() );
|
||||
snprintf( m_token.token, m_token.outputLen, "%s", Double2Str( val ).c_str() );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -159,12 +159,12 @@ void NUMERIC_EVALUATOR::newString( const wxString& aString )
|
||||
Clear();
|
||||
|
||||
m_originalText = aString;
|
||||
|
||||
m_token.token = reinterpret_cast<decltype( m_token.token )>( malloc( TokenStat::OutLen + 1 ) );
|
||||
strcpy( m_token.token, "0" );
|
||||
m_token.inputLen = aString.length();
|
||||
m_token.outputLen = std::max<std::size_t>( 64, m_token.inputLen + 1 );
|
||||
m_token.pos = 0;
|
||||
m_token.input = aString.mb_str();
|
||||
m_token.token = new char[m_token.outputLen]();
|
||||
m_token.token[0] = '0';
|
||||
|
||||
m_parseFinished = false;
|
||||
}
|
||||
|
||||
@@ -1038,7 +1038,7 @@ bool COMPILER::generateUCode( UCODE* aCode, CONTEXT* aPreflightContext )
|
||||
reportError( CST_CODEGEN, msg, node->srcPos - (int) node->value.str->length() );
|
||||
}
|
||||
|
||||
node->SetUop( TR_UOP_PUSH_VALUE, std::move( vref ) );
|
||||
node->SetUop( TR_UOP_PUSH_VAR, std::move( vref ) );
|
||||
node->isTerminal = true;
|
||||
break;
|
||||
}
|
||||
@@ -1090,10 +1090,12 @@ void UOP::Exec( CONTEXT* ctx )
|
||||
{
|
||||
case TR_UOP_PUSH_VAR:
|
||||
{
|
||||
VALUE* value = ctx->AllocValue();
|
||||
VALUE* value = nullptr;
|
||||
|
||||
if( m_ref )
|
||||
value->Set( m_ref->GetValue( ctx ) );
|
||||
value = ctx->StoreValue( m_ref->GetValue( ctx ) );
|
||||
else
|
||||
value = ctx->AllocValue();
|
||||
|
||||
ctx->Push( value );
|
||||
}
|
||||
@@ -1162,10 +1164,20 @@ void UOP::Exec( CONTEXT* ctx )
|
||||
result = arg1Value > arg2Value ? 1 : 0;
|
||||
break;
|
||||
case TR_OP_EQUAL:
|
||||
result = arg1 && arg2 && arg1->EqualTo( ctx, arg2 ) ? 1 : 0;
|
||||
if( !arg1 || !arg2 )
|
||||
result = arg1 == arg2 ? 1 : 0;
|
||||
else if( arg2->GetType() == VT_UNDEFINED )
|
||||
result = arg2->EqualTo( ctx, arg1 ) ? 1 : 0;
|
||||
else
|
||||
result = arg1->EqualTo( ctx, arg2 ) ? 1 : 0;
|
||||
break;
|
||||
case TR_OP_NOT_EQUAL:
|
||||
result = arg1 && arg2 && arg1->NotEqualTo( ctx, arg2 ) ? 1 : 0;
|
||||
if( !arg1 || !arg2 )
|
||||
result = arg1 != arg2 ? 1 : 0;
|
||||
else if( arg2->GetType() == VT_UNDEFINED )
|
||||
result = arg2->NotEqualTo( ctx, arg1 ) ? 1 : 0;
|
||||
else
|
||||
result = arg1->NotEqualTo( ctx, arg2 ) ? 1 : 0;
|
||||
break;
|
||||
case TR_OP_BOOL_AND:
|
||||
result = arg1Value != 0.0 && arg2Value != 0.0 ? 1 : 0;
|
||||
|
||||
@@ -8635,7 +8635,7 @@ const char* const newstroke_font[] =
|
||||
"F^K[KFYFY[K[",
|
||||
"F^K[KFYFY[K[",
|
||||
"F^K[KFYFY[K[",
|
||||
/* // Letterlike Symbols (2100-214F) */
|
||||
/* // Letterlike Symbols (2100-2125) */
|
||||
"F^K[KFYFY[K[", /* U+2100 */
|
||||
"F^K[KFYFY[K[",
|
||||
"F^K[KFYFY[K[",
|
||||
@@ -8674,7 +8674,8 @@ const char* const newstroke_font[] =
|
||||
"F^K[KFYFY[K[",
|
||||
"F^K[KFYFY[K[",
|
||||
"F^K[KFYFY[K[",
|
||||
"F^K[KFYFY[K[",
|
||||
"F^J[O[OWMVKTJQJLKIMGPFTFWGYIZLZQYTWVUWU[Z[",
|
||||
/* // Letterlike Symbols (2127-214F) */
|
||||
"F^K[KFYFY[K[",
|
||||
"F^K[KFYFY[K[",
|
||||
"F^K[KFYFY[K[",
|
||||
|
||||
+21
-15
@@ -79,18 +79,23 @@ void SCINTILLA_TRICKS::onThemeChanged( wxSysColourChangedEvent &aEvent )
|
||||
|
||||
void SCINTILLA_TRICKS::setupStyles()
|
||||
{
|
||||
wxTextCtrl dummy( m_te->GetParent(), wxID_ANY );
|
||||
wxColour foreground = dummy.GetForegroundColour();
|
||||
wxColour background = dummy.GetBackgroundColour();
|
||||
wxColour highlight = wxSystemSettings::GetColour( wxSYS_COLOUR_HIGHLIGHT );
|
||||
wxColour highlightText = wxSystemSettings::GetColour( wxSYS_COLOUR_HIGHLIGHTTEXT );
|
||||
wxTextCtrl dummy( m_te->GetParent(), wxID_ANY );
|
||||
wxColour foreground = dummy.GetForegroundColour();
|
||||
wxColour background = dummy.GetBackgroundColour();
|
||||
KIGFX::COLOR4D highlight = wxSystemSettings::GetColour( wxSYS_COLOUR_HIGHLIGHT );
|
||||
KIGFX::COLOR4D highlightText = wxSystemSettings::GetColour( wxSYS_COLOUR_HIGHLIGHTTEXT );
|
||||
|
||||
m_te->StyleSetForeground( wxSTC_STYLE_DEFAULT, foreground );
|
||||
m_te->StyleSetBackground( wxSTC_STYLE_DEFAULT, background );
|
||||
m_te->StyleClearAll();
|
||||
|
||||
m_te->SetSelForeground( true, highlightText );
|
||||
m_te->SetSelBackground( true, highlight );
|
||||
// Scintilla doesn't handle alpha channel, which at least OSX uses in some highlight colours,
|
||||
// such as "graphite".
|
||||
highlight = highlight.Mix( background, highlight.a ).WithAlpha( 1.0 );
|
||||
highlightText = highlightText.Mix( background, highlightText.a ).WithAlpha( 1.0 );
|
||||
|
||||
m_te->SetSelForeground( true, highlightText.ToColour() );
|
||||
m_te->SetSelBackground( true, highlight.ToColour() );
|
||||
m_te->SetCaretForeground( foreground );
|
||||
|
||||
if( !m_singleLine )
|
||||
@@ -105,14 +110,13 @@ void SCINTILLA_TRICKS::setupStyles()
|
||||
m_te->SetTabWidth( 4 );
|
||||
}
|
||||
|
||||
// Set up the brace highlighting
|
||||
unsigned char r = highlight.Red();
|
||||
unsigned char g = highlight.Green();
|
||||
unsigned char b = highlight.Blue();
|
||||
wxColour::MakeGrey( &r, &g, &b );
|
||||
highlight.Set( r, g, b );
|
||||
m_te->StyleSetForeground( wxSTC_STYLE_BRACELIGHT, highlightText );
|
||||
m_te->StyleSetBackground( wxSTC_STYLE_BRACELIGHT, highlight );
|
||||
// Set up the brace highlighting. Scintilla doesn't handle alpha, so we construct our own
|
||||
// 20% wash by blending with the background.
|
||||
KIGFX::COLOR4D braceText = foreground;
|
||||
KIGFX::COLOR4D braceHighlight = braceText.Mix( background, 0.2 );
|
||||
|
||||
m_te->StyleSetForeground( wxSTC_STYLE_BRACELIGHT, highlightText.ToColour() );
|
||||
m_te->StyleSetBackground( wxSTC_STYLE_BRACELIGHT, braceHighlight.ToColour() );
|
||||
m_te->StyleSetForeground( wxSTC_STYLE_BRACEBAD, *wxRED );
|
||||
}
|
||||
|
||||
@@ -228,7 +232,9 @@ void SCINTILLA_TRICKS::onCharHook( wxKeyEvent& aEvent )
|
||||
str = data.GetText();
|
||||
|
||||
ConvertSmartQuotesAndDashes( &str );
|
||||
m_te->BeginUndoAction();
|
||||
m_te->AddText( str );
|
||||
m_te->EndUndoAction();
|
||||
}
|
||||
|
||||
wxTheClipboard->Close();
|
||||
|
||||
@@ -230,7 +230,7 @@ COLOR_SETTINGS::COLOR_SETTINGS( const wxString& aFilename, bool aAbsolutePath )
|
||||
// Fix LAYER_VIA_HOLES color - before version 2, this setting had no effect
|
||||
nlohmann::json::json_pointer ptr( "/board/via_hole");
|
||||
|
||||
( *m_internals )[ptr] = COLOR4D( 0.5, 0.4, 0, 0.8 ).ToWxString( wxC2S_CSS_SYNTAX );
|
||||
( *m_internals )[ptr] = COLOR4D( 0.5, 0.4, 0, 0.8 ).ToCSSString();
|
||||
|
||||
return true;
|
||||
} );
|
||||
|
||||
@@ -146,7 +146,7 @@ void GRID_CELL_COLOR_SELECTOR::Create( wxWindow* aParent, wxWindowID aId,
|
||||
|
||||
wxString GRID_CELL_COLOR_SELECTOR::GetValue() const
|
||||
{
|
||||
return m_value.ToWxString( wxC2S_CSS_SYNTAX );
|
||||
return m_value.ToCSSString();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -210,12 +210,17 @@ CVPCB_MAINFRAME::CVPCB_MAINFRAME( KIWAY* aKiway, wxWindow* aParent ) :
|
||||
// Start the main processing loop
|
||||
m_toolManager->InvokeTool( "cvpcb.Control" );
|
||||
|
||||
m_filterTimer->StartOnce( 100 );
|
||||
|
||||
KIPLATFORM::APP::SetShutdownBlockReason( this, _( "Symbol to footprint changes are unsaved" ) );
|
||||
}
|
||||
|
||||
|
||||
CVPCB_MAINFRAME::~CVPCB_MAINFRAME()
|
||||
{
|
||||
// Stop the timer during destruction early to avoid potential race conditions (that do happen)
|
||||
m_filterTimer->Stop();
|
||||
|
||||
// Shutdown all running tools
|
||||
if( m_toolManager )
|
||||
m_toolManager->ShutdownAllTools();
|
||||
@@ -371,6 +376,9 @@ void CVPCB_MAINFRAME::setupEventHandlers()
|
||||
// Attach the events to the tool dispatcher
|
||||
Bind( wxEVT_CHAR, &TOOL_DISPATCHER::DispatchWxEvent, m_toolDispatcher );
|
||||
Bind( wxEVT_CHAR_HOOK, &TOOL_DISPATCHER::DispatchWxEvent, m_toolDispatcher );
|
||||
|
||||
m_filterTimer = new wxTimer( this );
|
||||
Bind( wxEVT_TIMER, &CVPCB_MAINFRAME::onTextFilterChangedTimer, this, m_filterTimer->GetId() );
|
||||
}
|
||||
|
||||
|
||||
@@ -421,6 +429,17 @@ void CVPCB_MAINFRAME::OnEnterFilteringText( wxCommandEvent& aEvent )
|
||||
// If the option FOOTPRINTS_LISTBOX::FILTERING_BY_TEXT_PATTERN is set, update the list
|
||||
// of available footprints which match the filter
|
||||
|
||||
m_filterTimer->StartOnce( 200 );
|
||||
}
|
||||
|
||||
|
||||
void CVPCB_MAINFRAME::onTextFilterChangedTimer( wxTimerEvent& aEvent )
|
||||
{
|
||||
// GTK loses the search-control's focus on a Refresh event, so we record the focus and
|
||||
// insertion point here and then restore them at the end.
|
||||
bool searchCtrlHasFocus = m_tcFilterString->HasFocus();
|
||||
long pos = m_tcFilterString->GetInsertionPoint();
|
||||
|
||||
COMPONENT* symbol = GetSelectedComponent();
|
||||
wxString libraryName = m_librariesListBox->GetSelectedLibrary();
|
||||
|
||||
@@ -435,6 +454,12 @@ void CVPCB_MAINFRAME::OnEnterFilteringText( wxCommandEvent& aEvent )
|
||||
RefreshFootprintViewer();
|
||||
|
||||
DisplayStatus();
|
||||
|
||||
if( searchCtrlHasFocus )
|
||||
{
|
||||
m_tcFilterString->SetFocus();
|
||||
m_tcFilterString->SetInsertionPoint( pos );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -357,6 +357,8 @@ private:
|
||||
|
||||
void updateFootprintViewerOnIdle( wxIdleEvent& aEvent );
|
||||
|
||||
void onTextFilterChangedTimer( wxTimerEvent& aEvent );
|
||||
|
||||
/**
|
||||
* Read the .equ files and populate the list of equivalents.
|
||||
*
|
||||
@@ -407,6 +409,7 @@ private:
|
||||
CVPCB_UNDO_REDO_LIST m_undoList;
|
||||
CVPCB_UNDO_REDO_LIST m_redoList;
|
||||
|
||||
wxTimer* m_filterTimer;
|
||||
bool m_viewerPendingUpdate;
|
||||
|
||||
};
|
||||
|
||||
+124
-75
@@ -2372,7 +2372,9 @@ bool CONNECTION_GRAPH::ercCheckMultipleDrivers( const CONNECTION_SUBGRAPH* aSubg
|
||||
|
||||
if( driver->Type() == SCH_GLOBAL_LABEL_T
|
||||
|| driver->Type() == SCH_HIER_LABEL_T
|
||||
|| driver->Type() == SCH_LABEL_T )
|
||||
|| driver->Type() == SCH_LABEL_T
|
||||
|| ( driver->Type() == SCH_PIN_T
|
||||
&& static_cast<SCH_PIN*>( driver )->IsPowerConnection() ) )
|
||||
{
|
||||
wxString primaryName = aSubgraph->GetNameForDriver( aSubgraph->m_driver );
|
||||
wxString secondaryName = aSubgraph->GetNameForDriver( driver );
|
||||
@@ -2852,13 +2854,11 @@ bool CONNECTION_GRAPH::ercCheckFloatingWires( const CONNECTION_SUBGRAPH* aSubgra
|
||||
bool CONNECTION_GRAPH::ercCheckLabels( const CONNECTION_SUBGRAPH* aSubgraph )
|
||||
{
|
||||
// Label connection rules:
|
||||
// Any label without a no-connect needs to have at least 2 pins, otherwise it is invalid
|
||||
// Local labels are flagged if they don't connect to any pins and don't have a no-connect
|
||||
// Global labels are flagged if they appear only once, don't connect to any local labels,
|
||||
// and don't have a no-connect marker
|
||||
|
||||
// So, if there is a no-connect, we will never generate a warning here
|
||||
if( aSubgraph->m_no_connect )
|
||||
return true;
|
||||
|
||||
if( !aSubgraph->m_driver_connection )
|
||||
return true;
|
||||
@@ -2870,28 +2870,46 @@ bool CONNECTION_GRAPH::ercCheckLabels( const CONNECTION_SUBGRAPH* aSubgraph )
|
||||
|
||||
ERC_SETTINGS& settings = m_schematic->ErcSettings();
|
||||
bool ok = true;
|
||||
SCH_TEXT* text = nullptr;
|
||||
bool hasOtherConnections = false;
|
||||
int pinCount = 0;
|
||||
|
||||
std::map<KICAD_T, std::vector<SCH_TEXT*>> label_map;
|
||||
|
||||
|
||||
auto hasPins =
|
||||
[]( const CONNECTION_SUBGRAPH* aLocSubgraph )
|
||||
[]( const CONNECTION_SUBGRAPH* aLocSubgraph ) -> int
|
||||
{
|
||||
int retval = 0;
|
||||
|
||||
for( const SCH_ITEM* item : aLocSubgraph->m_items )
|
||||
{
|
||||
switch( item->Type() )
|
||||
{
|
||||
case SCH_PIN_T:
|
||||
case SCH_SHEET_PIN_T:
|
||||
return true;
|
||||
++retval;
|
||||
break;
|
||||
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
return retval;
|
||||
};
|
||||
|
||||
auto reportError = [&]( SCH_TEXT* aText, int errCode )
|
||||
{
|
||||
if( settings.IsTestEnabled( errCode ) )
|
||||
{
|
||||
std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( errCode );
|
||||
ercItem->SetItems( aText );
|
||||
|
||||
SCH_MARKER* marker = new SCH_MARKER( ercItem, aText->GetPosition() );
|
||||
aSubgraph->m_sheet.LastScreen()->Append( marker );
|
||||
}
|
||||
};
|
||||
|
||||
pinCount = hasPins( aSubgraph );
|
||||
|
||||
for( SCH_ITEM* item : aSubgraph->m_items )
|
||||
{
|
||||
switch( item->Type() )
|
||||
@@ -2900,105 +2918,136 @@ bool CONNECTION_GRAPH::ercCheckLabels( const CONNECTION_SUBGRAPH* aSubgraph )
|
||||
case SCH_GLOBAL_LABEL_T:
|
||||
case SCH_HIER_LABEL_T:
|
||||
{
|
||||
text = static_cast<SCH_TEXT*>( item );
|
||||
SCH_TEXT* text = static_cast<SCH_TEXT*>( item );
|
||||
|
||||
label_map[item->Type()].push_back( text );
|
||||
|
||||
// Below, we'll create an ERC if the whole subgraph is unconnected. But, additionally,
|
||||
// we want to error if an individual label in the subgraph is floating, even if it's
|
||||
// connected to other valid things by way of another label on the same sheet.
|
||||
|
||||
if( text->IsDangling() && settings.IsTestEnabled( ERCE_LABEL_NOT_CONNECTED ) )
|
||||
if( text->IsDangling() )
|
||||
{
|
||||
std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( ERCE_LABEL_NOT_CONNECTED );
|
||||
ercItem->SetItems( text );
|
||||
|
||||
SCH_MARKER* marker = new SCH_MARKER( ercItem, text->GetPosition() );
|
||||
aSubgraph->m_sheet.LastScreen()->Append( marker );
|
||||
ok = false;
|
||||
reportError( text, ERCE_LABEL_NOT_CONNECTED );
|
||||
return false;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case SCH_PIN_T:
|
||||
case SCH_SHEET_PIN_T:
|
||||
hasOtherConnections = true;
|
||||
pinCount++;
|
||||
break;
|
||||
// If this subgraph has a no-connect, do not continue processing as we do not
|
||||
// submit no-connect errors for nets explicitly designated as no-connect
|
||||
case SCH_NO_CONNECT_T:
|
||||
return true;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if( !text )
|
||||
if( label_map.empty() )
|
||||
return true;
|
||||
|
||||
bool isGlobal = text->Type() == SCH_GLOBAL_LABEL_T;
|
||||
int errCode = isGlobal ? ERCE_GLOBLABEL : ERCE_LABEL_NOT_CONNECTED;
|
||||
|
||||
wxCHECK_MSG( m_schematic, true, wxT( "Null m_schematic in CONNECTION_GRAPH::ercCheckLabels" ) );
|
||||
|
||||
wxString name = EscapeString( text->GetShownText(), CTX_NETNAME );
|
||||
// Labels that have multiple pins connected are not dangling (may be used for naming segments)
|
||||
// so leave them without errors here
|
||||
if( pinCount > 1 )
|
||||
return true;
|
||||
|
||||
if( isGlobal )
|
||||
for( const auto& label_pair : label_map )
|
||||
{
|
||||
// This will be set to true if the global is connected to a pin above, but we want to
|
||||
// reset this to false so that globals get flagged if they only have a single instance
|
||||
// connected to a single pin
|
||||
hasOtherConnections = ( pinCount > 1 );
|
||||
|
||||
auto it = m_net_name_to_subgraphs_map.find( name );
|
||||
|
||||
if( it != m_net_name_to_subgraphs_map.end() )
|
||||
const KICAD_T type = label_pair.first;
|
||||
std::vector<SCH_TEXT*> label_vec = label_pair.second;
|
||||
switch( type )
|
||||
{
|
||||
if( it->second.size() > 1 || aSubgraph->m_multiple_drivers )
|
||||
hasOtherConnections = true;
|
||||
}
|
||||
}
|
||||
else if( text->Type() == SCH_HIER_LABEL_T )
|
||||
{
|
||||
// For a hier label, check if the parent pin is connected
|
||||
if( aSubgraph->m_hier_parent
|
||||
&& ( aSubgraph->m_hier_parent->m_strong_driver
|
||||
|| aSubgraph->m_hier_parent->m_drivers.size() > 1) )
|
||||
{
|
||||
// For now, a simple check: if there is more than one driver, the parent is probably
|
||||
// connected elsewhere (because at least one driver will be the hier pin itself)
|
||||
hasOtherConnections = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
auto pair = std::make_pair( aSubgraph->m_sheet, name );
|
||||
auto it = m_local_label_cache.find( pair );
|
||||
case SCH_GLOBAL_LABEL_T:
|
||||
if( !settings.IsTestEnabled( ERCE_GLOBLABEL ) )
|
||||
break;
|
||||
|
||||
if( it != m_local_label_cache.end() && it->second.size() > 1 )
|
||||
{
|
||||
for( const CONNECTION_SUBGRAPH* neighbor : it->second )
|
||||
for( SCH_TEXT* text : label_vec )
|
||||
{
|
||||
if( neighbor == aSubgraph )
|
||||
wxString name = EscapeString( text->GetShownText(), CTX_NETNAME );
|
||||
int allPins = pinCount;
|
||||
|
||||
// If the global label is connected to a subgraph but is not the driver
|
||||
// then there is a driver conflict somewhere that is handled by a different
|
||||
// ERC check. Here, we are just looking for unconnected elements
|
||||
if( name != aSubgraph->m_driver_connection->Name() )
|
||||
continue;
|
||||
|
||||
if( hasPins( neighbor ) )
|
||||
// Global labels are connected if there is another instance of
|
||||
// their name in the circuit
|
||||
auto it = m_net_name_to_subgraphs_map.find( name );
|
||||
|
||||
for( const CONNECTION_SUBGRAPH* neighbor : it->second )
|
||||
{
|
||||
hasOtherConnections = true;
|
||||
break;
|
||||
if( neighbor == aSubgraph )
|
||||
continue;
|
||||
|
||||
allPins += hasPins( neighbor );
|
||||
}
|
||||
|
||||
if( allPins < 2 )
|
||||
{
|
||||
reportError( text, ERCE_GLOBLABEL );
|
||||
ok = false;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
case SCH_HIER_LABEL_T:
|
||||
if( !settings.IsTestEnabled( ERCE_LABEL_NOT_CONNECTED ) )
|
||||
break;
|
||||
|
||||
for( SCH_TEXT* text : label_vec )
|
||||
{
|
||||
if( !aSubgraph->m_hier_parent
|
||||
|| ( !aSubgraph->m_hier_parent->m_strong_driver
|
||||
&& aSubgraph->m_hier_parent->m_drivers.size() <= 1 ) )
|
||||
{
|
||||
reportError( text, ERCE_LABEL_NOT_CONNECTED );
|
||||
ok = false;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
case SCH_LABEL_T:
|
||||
|
||||
if( !settings.IsTestEnabled( ERCE_LABEL_NOT_CONNECTED ) )
|
||||
break;
|
||||
|
||||
for( SCH_TEXT* text : label_vec )
|
||||
{
|
||||
int allPins = pinCount;
|
||||
wxString name = EscapeString( text->GetShownText(), CTX_NETNAME );
|
||||
|
||||
auto pair = std::make_pair( aSubgraph->m_sheet, name );
|
||||
auto it = m_local_label_cache.find( pair );
|
||||
|
||||
if( it == m_local_label_cache.end() )
|
||||
continue;
|
||||
|
||||
for( const CONNECTION_SUBGRAPH* neighbor : it->second )
|
||||
{
|
||||
if( neighbor == aSubgraph )
|
||||
continue;
|
||||
|
||||
allPins += hasPins( neighbor );
|
||||
}
|
||||
|
||||
if( allPins < 2 )
|
||||
{
|
||||
reportError( text, ERCE_LABEL_NOT_CONNECTED );
|
||||
ok = false;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if( !hasOtherConnections && settings.IsTestEnabled( errCode ) )
|
||||
{
|
||||
std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( errCode );
|
||||
ercItem->SetItems( text );
|
||||
|
||||
SCH_MARKER* marker = new SCH_MARKER( ercItem, text->GetPosition() );
|
||||
aSubgraph->m_sheet.LastScreen()->Append( marker );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
|
||||
@@ -83,8 +83,8 @@ public:
|
||||
* @param title is the title of the notebook page.
|
||||
* @param id_NetType is the netlist ID type.
|
||||
*/
|
||||
NETLIST_PAGE_DIALOG( wxNotebook* parent, const wxString& title,
|
||||
NETLIST_TYPE_ID id_NetType );
|
||||
NETLIST_PAGE_DIALOG( wxNotebook* aParent, const wxString& aTitle,
|
||||
NETLIST_TYPE_ID aIdNetType, bool aCustom );
|
||||
~NETLIST_PAGE_DIALOG() { };
|
||||
|
||||
/**
|
||||
@@ -102,8 +102,12 @@ public:
|
||||
wxBoxSizer* m_RightOptionsBoxSizer;
|
||||
wxBoxSizer* m_LowBoxSizer;
|
||||
|
||||
bool IsCustom() const { return m_custom; }
|
||||
|
||||
private:
|
||||
wxString m_pageNetFmtName;
|
||||
|
||||
bool m_custom;
|
||||
};
|
||||
|
||||
|
||||
@@ -125,6 +129,8 @@ private:
|
||||
bool TransferDataFromWindow() override;
|
||||
void NetlistUpdateOpt();
|
||||
|
||||
void updateGeneratorButtons();
|
||||
|
||||
// Called when changing the notebook page (and therefore the current netlist format)
|
||||
void OnNetlistTypeSelection( wxNotebookEvent& event ) override;
|
||||
|
||||
@@ -206,17 +212,18 @@ BEGIN_EVENT_TABLE( NETLIST_DIALOG, NETLIST_DIALOG_BASE )
|
||||
END_EVENT_TABLE()
|
||||
|
||||
|
||||
NETLIST_PAGE_DIALOG::NETLIST_PAGE_DIALOG( wxNotebook* parent, const wxString& title,
|
||||
NETLIST_TYPE_ID id_NetType ) :
|
||||
wxPanel( parent, -1, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL )
|
||||
NETLIST_PAGE_DIALOG::NETLIST_PAGE_DIALOG( wxNotebook* aParent, const wxString& aTitle,
|
||||
NETLIST_TYPE_ID aIdNetType, bool aCustom ) :
|
||||
wxPanel( aParent, -1, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL )
|
||||
{
|
||||
m_IdNetType = id_NetType;
|
||||
m_pageNetFmtName = title;
|
||||
m_IdNetType = aIdNetType;
|
||||
m_pageNetFmtName = aTitle;
|
||||
m_CommandStringCtrl = nullptr;
|
||||
m_TitleStringCtrl = nullptr;
|
||||
m_AdjustPassiveValues = nullptr;
|
||||
m_custom = aCustom;
|
||||
|
||||
parent->AddPage( this, title, false );
|
||||
aParent->AddPage( this, aTitle, false );
|
||||
|
||||
wxBoxSizer* MainBoxSizer = new wxBoxSizer( wxVERTICAL );
|
||||
SetSizer( MainBoxSizer );
|
||||
@@ -245,14 +252,14 @@ NETLIST_DIALOG::NETLIST_DIALOG( SCH_EDIT_FRAME* parent ) :
|
||||
page = nullptr;
|
||||
|
||||
// Add notebook pages:
|
||||
m_PanelNetType[PANELPCBNEW] = new NETLIST_PAGE_DIALOG( m_NoteBook, wxT( "KiCad" ),
|
||||
NET_TYPE_PCBNEW );
|
||||
m_PanelNetType[PANELPCBNEW] =
|
||||
new NETLIST_PAGE_DIALOG( m_NoteBook, wxT( "KiCad" ), NET_TYPE_PCBNEW, false );
|
||||
|
||||
m_PanelNetType[PANELORCADPCB2] = new NETLIST_PAGE_DIALOG( m_NoteBook, wxT( "OrcadPCB2" ),
|
||||
NET_TYPE_ORCADPCB2 );
|
||||
m_PanelNetType[PANELORCADPCB2] =
|
||||
new NETLIST_PAGE_DIALOG( m_NoteBook, wxT( "OrcadPCB2" ), NET_TYPE_ORCADPCB2, false );
|
||||
|
||||
m_PanelNetType[PANELCADSTAR] = new NETLIST_PAGE_DIALOG( m_NoteBook, wxT( "CadStar" ),
|
||||
NET_TYPE_CADSTAR );
|
||||
m_PanelNetType[PANELCADSTAR] =
|
||||
new NETLIST_PAGE_DIALOG( m_NoteBook, wxT( "CadStar" ), NET_TYPE_CADSTAR, false );
|
||||
|
||||
InstallPageSpice();
|
||||
InstallCustomPages();
|
||||
@@ -275,6 +282,8 @@ NETLIST_DIALOG::NETLIST_DIALOG( SCH_EDIT_FRAME* parent ) :
|
||||
|
||||
// Now all widgets have the size fixed, call FinishDialogSettings
|
||||
finishDialogSettings();
|
||||
|
||||
updateGeneratorButtons();
|
||||
}
|
||||
|
||||
|
||||
@@ -320,7 +329,7 @@ void NETLIST_DIALOG::OnRunSpiceButtUI( wxUpdateUIEvent& aEvent )
|
||||
void NETLIST_DIALOG::InstallPageSpice()
|
||||
{
|
||||
NETLIST_PAGE_DIALOG* page = m_PanelNetType[PANELSPICE] =
|
||||
new NETLIST_PAGE_DIALOG( m_NoteBook, wxT( "Spice" ), NET_TYPE_SPICE );
|
||||
new NETLIST_PAGE_DIALOG( m_NoteBook, wxT( "Spice" ), NET_TYPE_SPICE, false );
|
||||
|
||||
SCHEMATIC_SETTINGS& settings = m_Parent->Schematic().Settings();
|
||||
|
||||
@@ -385,7 +394,7 @@ NETLIST_PAGE_DIALOG* NETLIST_DIALOG::AddOneCustomPage( const wxString& aTitle,
|
||||
const wxString& aCommandString,
|
||||
NETLIST_TYPE_ID aNetTypeId )
|
||||
{
|
||||
NETLIST_PAGE_DIALOG* currPage = new NETLIST_PAGE_DIALOG( m_NoteBook, aTitle, aNetTypeId );
|
||||
NETLIST_PAGE_DIALOG* currPage = new NETLIST_PAGE_DIALOG( m_NoteBook, aTitle, aNetTypeId, true );
|
||||
|
||||
currPage->m_LowBoxSizer->Add( new wxStaticText( currPage, -1, _( "Title:" ) ), 0,
|
||||
wxGROW | wxLEFT | wxRIGHT | wxTOP, 5 );
|
||||
@@ -413,12 +422,7 @@ NETLIST_PAGE_DIALOG* NETLIST_DIALOG::AddOneCustomPage( const wxString& aTitle,
|
||||
|
||||
void NETLIST_DIALOG::OnNetlistTypeSelection( wxNotebookEvent& event )
|
||||
{
|
||||
NETLIST_PAGE_DIALOG* currPage = (NETLIST_PAGE_DIALOG*) m_NoteBook->GetCurrentPage();
|
||||
|
||||
if( currPage == nullptr )
|
||||
return;
|
||||
|
||||
m_buttonDelGenerator->Enable( currPage->m_IdNetType >= NET_TYPE_CUSTOM1 );
|
||||
updateGeneratorButtons();
|
||||
}
|
||||
|
||||
|
||||
@@ -588,6 +592,9 @@ void NETLIST_DIALOG::OnDelGenerator( wxCommandEvent& event )
|
||||
{
|
||||
NETLIST_PAGE_DIALOG* currPage = (NETLIST_PAGE_DIALOG*) m_NoteBook->GetCurrentPage();
|
||||
|
||||
if( !currPage->IsCustom() )
|
||||
return;
|
||||
|
||||
currPage->m_CommandStringCtrl->SetValue( wxEmptyString );
|
||||
currPage->m_TitleStringCtrl->SetValue( wxEmptyString );
|
||||
|
||||
@@ -712,6 +719,17 @@ void NETLIST_DIALOG_ADD_GENERATOR::OnBrowseGenerators( wxCommandEvent& event )
|
||||
}
|
||||
|
||||
|
||||
void NETLIST_DIALOG::updateGeneratorButtons()
|
||||
{
|
||||
NETLIST_PAGE_DIALOG* currPage = (NETLIST_PAGE_DIALOG*) m_NoteBook->GetCurrentPage();
|
||||
|
||||
if( currPage == nullptr )
|
||||
return;
|
||||
|
||||
m_buttonDelGenerator->Enable( currPage->IsCustom() );
|
||||
}
|
||||
|
||||
|
||||
int InvokeDialogNetList( SCH_EDIT_FRAME* aCaller )
|
||||
{
|
||||
NETLIST_DIALOG dlg( aCaller );
|
||||
|
||||
@@ -409,6 +409,11 @@ bool SCH_PRINTOUT::OnBeginDocument( int startPage, int endPage )
|
||||
*/
|
||||
void SCH_PRINTOUT::PrintPage( SCH_SCREEN* aScreen )
|
||||
{
|
||||
// Warning:
|
||||
// When printing many pages, changes in the current wxDC will affect all next printings
|
||||
// because all prints are using the same wxPrinterDC after creation
|
||||
// So be careful and reinit parameters, especially when using offsets.
|
||||
|
||||
wxPoint tmp_startvisu;
|
||||
wxSize pageSizeIU; // Page size in internal units
|
||||
wxPoint old_org;
|
||||
@@ -439,16 +444,31 @@ void SCH_PRINTOUT::PrintPage( SCH_SCREEN* aScreen )
|
||||
int xoffset = ( fitRect.width - pageSizeIU.x ) / 2;
|
||||
int yoffset = ( fitRect.height - pageSizeIU.y ) / 2;
|
||||
|
||||
// Using a wxAffineMatrix2D has a big advantage: it handles different pages orientations
|
||||
//(PORTRAIT/LANDSCAPE), but the affine matrix is not always supported
|
||||
if( dc->CanUseTransformMatrix() )
|
||||
{
|
||||
wxAffineMatrix2D matrix = dc->GetTransformMatrix();
|
||||
wxAffineMatrix2D matrix; // starts from a unity matrix (the current wxDC default)
|
||||
|
||||
// Check for portrait/landscape mismatch:
|
||||
if( ( fitRect.width > fitRect.height ) != ( pageSizeIU.x > pageSizeIU.y ) )
|
||||
{
|
||||
// Rotate the coordinates, and keep the draw coordinates inside the page
|
||||
matrix.Rotate( M_PI_2 );
|
||||
xoffset = ( fitRect.height - pageSizeIU.x ) / 2;
|
||||
yoffset = ( fitRect.width - pageSizeIU.y ) / 2;
|
||||
matrix.Translate( 0, -pageSizeIU.y );
|
||||
|
||||
// Recalculate the offsets and page sizes according to the page rotation
|
||||
std::swap( pageSizeIU.x, pageSizeIU.y );
|
||||
FitThisSizeToPaper( pageSizeIU );
|
||||
fitRect = GetLogicalPaperRect();
|
||||
|
||||
xoffset = ( fitRect.width - pageSizeIU.x ) / 2;
|
||||
yoffset = ( fitRect.height - pageSizeIU.y ) / 2;
|
||||
|
||||
// All the coordinates will be rotated 90 deg when printing,
|
||||
// so the X,Y offset vector must be rotated -90 deg before printing
|
||||
std::swap( xoffset, yoffset );
|
||||
yoffset = -yoffset;
|
||||
}
|
||||
|
||||
matrix.Translate( xoffset, yoffset );
|
||||
@@ -456,12 +476,8 @@ void SCH_PRINTOUT::PrintPage( SCH_SCREEN* aScreen )
|
||||
}
|
||||
else
|
||||
{
|
||||
// wxWidgets appears to have a bug when OffsetLogicalOrigin()'s yoffset changes from
|
||||
// page to page.
|
||||
// NB: this is a workaround, not a fix. The Y centering will be off, but this is less
|
||||
// annoying than a blank page. See https://bugs.launchpad.net/kicad/+bug/1464773.
|
||||
yoffset = 0;
|
||||
|
||||
SetLogicalOrigin( 0, 0 ); // Reset all offset settings made previously.
|
||||
// When printing previous pages (all prints are using the same wxDC)
|
||||
OffsetLogicalOrigin( xoffset, yoffset );
|
||||
}
|
||||
|
||||
|
||||
@@ -758,8 +758,14 @@ bool DIALOG_SYMBOL_PROPERTIES::TransferDataFromWindow()
|
||||
}
|
||||
else
|
||||
{
|
||||
SCH_FIELD* newField = otherUnit->AddField( m_fields->at( ii ) );
|
||||
const_cast<KIID&>( newField->m_Uuid ) = KIID();
|
||||
SCH_FIELD newField( m_fields->at( ii ) );
|
||||
const_cast<KIID&>( newField.m_Uuid ) = KIID();
|
||||
|
||||
newField.Offset( -m_symbol->GetPosition() );
|
||||
newField.Offset( otherUnit->GetPosition() );
|
||||
|
||||
newField.SetParent( otherUnit );
|
||||
otherUnit->AddField( newField );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -321,7 +321,20 @@ void IFACE::SaveFileAs( const wxString& aProjectBasePath, const wxString& aProje
|
||||
ext == KiCadSchematicFileExtension + BackupFileSuffix )
|
||||
{
|
||||
if( destFile.GetName() == aProjectName )
|
||||
{
|
||||
destFile.SetName( aNewProjectName );
|
||||
}
|
||||
else if( destFile.GetName() == aNewProjectName )
|
||||
{
|
||||
wxString msg;
|
||||
|
||||
if( !aErrors.empty() )
|
||||
aErrors += "\n";
|
||||
|
||||
msg.Printf( _( "Cannot copy file '%s'." ), destFile.GetFullPath() );
|
||||
aErrors += msg;
|
||||
return;
|
||||
}
|
||||
|
||||
// Sheet paths when auto-generated are relative to the root, so those will stay
|
||||
// pointing to whatever they were pointing at.
|
||||
|
||||
@@ -526,7 +526,7 @@ wxString LIB_SYMBOL::SubReference( int aUnit, bool aAddSeparator )
|
||||
}
|
||||
|
||||
|
||||
void LIB_SYMBOL::Print( const RENDER_SETTINGS* aSettings, const wxPoint& aOffset,
|
||||
void LIB_SYMBOL::PrintBackground( const RENDER_SETTINGS* aSettings, const wxPoint& aOffset,
|
||||
int aUnit, int aConvert, const LIB_SYMBOL_OPTIONS& aOpts )
|
||||
{
|
||||
/* draw background for filled items using background option
|
||||
@@ -553,6 +553,12 @@ void LIB_SYMBOL::Print( const RENDER_SETTINGS* aSettings, const wxPoint& aOffset
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void LIB_SYMBOL::Print( const RENDER_SETTINGS* aSettings, const wxPoint& aOffset, int aUnit,
|
||||
int aConvert, const LIB_SYMBOL_OPTIONS& aOpts )
|
||||
{
|
||||
|
||||
for( LIB_ITEM& item : m_drawings )
|
||||
{
|
||||
|
||||
@@ -314,6 +314,17 @@ public:
|
||||
void Print( const RENDER_SETTINGS* aSettings, const wxPoint& aOffset,
|
||||
int aMulti, int aConvert, const LIB_SYMBOL_OPTIONS& aOpts );
|
||||
|
||||
/**
|
||||
* Print just the background fills of a symbol
|
||||
*
|
||||
* @param aOffset - Position of symbol.
|
||||
* @param aMulti - unit if multiple units per symbol.
|
||||
* @param aConvert - Symbol conversion (DeMorgan) if available.
|
||||
* @param aOpts - Drawing options
|
||||
*/
|
||||
void PrintBackground( const RENDER_SETTINGS *aSettings, const wxPoint &aOffset, int aMulti,
|
||||
int aConvert, const LIB_SYMBOL_OPTIONS &aOpts );
|
||||
|
||||
/**
|
||||
* Plot lib symbol to plotter.
|
||||
* Lib Fields not are plotted here, because this plot function
|
||||
|
||||
@@ -332,7 +332,9 @@ XNODE* NETLIST_EXPORTER_XML::makeSymbols( unsigned aCtl )
|
||||
xproperty->AddAttribute( wxT( "name" ), sheetField.GetCanonicalName() );
|
||||
|
||||
if( m_resolveTextVars )
|
||||
xproperty->AddAttribute( wxT( "value" ), sheetField.GetShownText() );
|
||||
// do not allow GetShownText() to add any prefix useful only when displaying
|
||||
// the field on screen
|
||||
xproperty->AddAttribute( wxT( "value" ), sheetField.GetShownText( 0, false ) );
|
||||
else
|
||||
xproperty->AddAttribute( wxT( "value" ), sheetField.GetText() );
|
||||
}
|
||||
|
||||
@@ -40,7 +40,7 @@ except IOError:
|
||||
f = sys.stdout
|
||||
|
||||
# Create a new csv writer object to use as the output formatter
|
||||
out = csv.writer(f, delimiter=',', quotechar='\"', quoting=csv.QUOTE_ALL)
|
||||
out = csv.writer(f, lineterminator='\n', delimiter=',', quotechar='\"', quoting=csv.QUOTE_ALL)
|
||||
|
||||
# Output a set of rows for a header providing general information
|
||||
out.writerow(['Source:', net.getSource()])
|
||||
|
||||
@@ -102,7 +102,7 @@ void SCH_FIELD::SetId( int aId )
|
||||
}
|
||||
|
||||
|
||||
wxString SCH_FIELD::GetShownText( int aDepth ) const
|
||||
wxString SCH_FIELD::GetShownText( int aDepth, bool aAllowExtraText ) const
|
||||
{
|
||||
std::function<bool( wxString* )> symbolResolver =
|
||||
[&]( wxString* token ) -> bool
|
||||
@@ -185,7 +185,7 @@ wxString SCH_FIELD::GetShownText( int aDepth ) const
|
||||
}
|
||||
else if( m_parent && m_parent->Type() == SCH_SHEET_T )
|
||||
{
|
||||
if( m_id == SHEETFILENAME )
|
||||
if( m_id == SHEETFILENAME && aAllowExtraText )
|
||||
text = _( "File:" ) + wxS( " " )+ text;
|
||||
}
|
||||
|
||||
|
||||
@@ -114,7 +114,7 @@ public:
|
||||
|
||||
void SetId( int aId );
|
||||
|
||||
wxString GetShownText( int aDepth = 0 ) const override;
|
||||
wxString GetShownText( int aDepth = 0, bool aAllowExtraText = true ) const override;
|
||||
|
||||
/**
|
||||
* Adjusters to allow EDA_TEXT to draw/print/etc. text in absolute coords.
|
||||
|
||||
@@ -285,6 +285,15 @@ public:
|
||||
*/
|
||||
virtual void Print( const RENDER_SETTINGS* aSettings, const wxPoint& aOffset ) = 0;
|
||||
|
||||
/**
|
||||
* Print the (optional) backaground elements if they exist
|
||||
* @param aSettings Print settings
|
||||
* @param aOffset is the drawing offset (usually {0,0} but can be different when moving an
|
||||
* object).
|
||||
*/
|
||||
|
||||
virtual void PrintBackground( const RENDER_SETTINGS* aSettings, const wxPoint& aOffset ) {};
|
||||
|
||||
/**
|
||||
* Move the item by \a aMoveVector to a new position.
|
||||
*/
|
||||
|
||||
@@ -572,7 +572,7 @@ SCH_SHEET* SCH_SEXPR_PLUGIN::Load( const wxString& aFileName, SCHEMATIC* aSchema
|
||||
|
||||
newSheet->SetFileName( relPath.GetFullPath() );
|
||||
m_rootSheet = newSheet.get();
|
||||
loadHierarchy( newSheet.get() );
|
||||
loadHierarchy( SCH_SHEET_PATH(), newSheet.get() );
|
||||
|
||||
// If we got here, the schematic loaded successfully.
|
||||
sheet = newSheet.release();
|
||||
@@ -583,7 +583,7 @@ SCH_SHEET* SCH_SEXPR_PLUGIN::Load( const wxString& aFileName, SCHEMATIC* aSchema
|
||||
wxCHECK_MSG( aSchematic->IsValid(), nullptr, "Can't append to a schematic with no root!" );
|
||||
m_rootSheet = &aSchematic->Root();
|
||||
sheet = aAppendToMe;
|
||||
loadHierarchy( sheet );
|
||||
loadHierarchy( SCH_SHEET_PATH(), sheet );
|
||||
}
|
||||
|
||||
wxASSERT( m_currentPath.size() == 1 ); // only the project path should remain
|
||||
@@ -596,7 +596,7 @@ SCH_SHEET* SCH_SEXPR_PLUGIN::Load( const wxString& aFileName, SCHEMATIC* aSchema
|
||||
|
||||
// Everything below this comment is recursive. Modify with care.
|
||||
|
||||
void SCH_SEXPR_PLUGIN::loadHierarchy( SCH_SHEET* aSheet )
|
||||
void SCH_SEXPR_PLUGIN::loadHierarchy( const SCH_SHEET_PATH& aParentSheetPath, SCH_SHEET* aSheet )
|
||||
{
|
||||
SCH_SCREEN* screen = nullptr;
|
||||
|
||||
@@ -618,7 +618,34 @@ void SCH_SEXPR_PLUGIN::loadHierarchy( SCH_SHEET* aSheet )
|
||||
wxLogTrace( traceSchLegacyPlugin, "Current path '%s'", m_currentPath.top() );
|
||||
wxLogTrace( traceSchLegacyPlugin, "Loading '%s'", fileName.GetFullPath() );
|
||||
|
||||
m_rootSheet->SearchHierarchy( fileName.GetFullPath(), &screen );
|
||||
SCH_SHEET_PATH ancestorSheetPath = aParentSheetPath;
|
||||
|
||||
while( !ancestorSheetPath.empty() )
|
||||
{
|
||||
if( ancestorSheetPath.LastScreen()->GetFileName() == fileName.GetFullPath() )
|
||||
{
|
||||
if( m_error.IsEmpty() )
|
||||
{
|
||||
m_error = _( "The entire schematic could not be loaded. Errors occurred "
|
||||
"attempting to load hierarchical sheets." );
|
||||
}
|
||||
|
||||
if( !m_error.IsEmpty() )
|
||||
m_error += "\n";
|
||||
|
||||
m_error += wxString::Format( _( "Error loading schematic '%s'." ),
|
||||
fileName.GetFullPath() );
|
||||
|
||||
fileName = wxEmptyString;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
ancestorSheetPath.pop_back();
|
||||
}
|
||||
|
||||
if( ancestorSheetPath.empty() )
|
||||
m_rootSheet->SearchHierarchy( fileName.GetFullPath(), &screen );
|
||||
|
||||
if( screen )
|
||||
{
|
||||
@@ -659,7 +686,10 @@ void SCH_SEXPR_PLUGIN::loadHierarchy( SCH_SHEET* aSheet )
|
||||
aSheet->GetScreen()->SetFileExists( false );
|
||||
}
|
||||
|
||||
// This was moved out of the try{} block so that any sheets definitionsthat
|
||||
SCH_SHEET_PATH currentSheetPath = aParentSheetPath;
|
||||
currentSheetPath.push_back( aSheet );
|
||||
|
||||
// This was moved out of the try{} block so that any sheet definitions that
|
||||
// the plugin fully parsed before the exception was raised will be loaded.
|
||||
for( SCH_ITEM* aItem : aSheet->GetScreen()->Items().OfType( SCH_SHEET_T ) )
|
||||
{
|
||||
@@ -667,7 +697,7 @@ void SCH_SEXPR_PLUGIN::loadHierarchy( SCH_SHEET* aSheet )
|
||||
SCH_SHEET* sheet = static_cast<SCH_SHEET*>( aItem );
|
||||
|
||||
// Recursion starts here.
|
||||
loadHierarchy( sheet );
|
||||
loadHierarchy( currentSheetPath, sheet );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -137,7 +137,7 @@ public:
|
||||
static void FormatLibSymbol( LIB_SYMBOL* aPart, OUTPUTFORMATTER& aFormatter );
|
||||
|
||||
private:
|
||||
void loadHierarchy( SCH_SHEET* aSheet );
|
||||
void loadHierarchy( const SCH_SHEET_PATH& aParentSheetPath, SCH_SHEET* aSheet );
|
||||
void loadFile( const wxString& aFileName, SCH_SHEET* aSheet );
|
||||
|
||||
void saveSymbol( SCH_SYMBOL* aSymbol, SCH_SHEET_PATH* aSheetPath, int aNestLevel );
|
||||
|
||||
@@ -2352,7 +2352,7 @@ void SCH_LEGACY_PLUGIN::saveLine( SCH_LINE* aLine )
|
||||
|
||||
if( aLine->GetLineColor() != COLOR4D::UNSPECIFIED )
|
||||
m_out->Print( 0, " %s",
|
||||
TO_UTF8( aLine->GetLineColor().ToColour().GetAsString( wxC2S_CSS_SYNTAX ) ) );
|
||||
TO_UTF8( aLine->GetLineColor().ToCSSString() ) );
|
||||
}
|
||||
|
||||
m_out->Print( 0, "\n" );
|
||||
|
||||
@@ -45,7 +45,9 @@
|
||||
|
||||
#include <symbol_library.h>
|
||||
#include <connection_graph.h>
|
||||
#include <lib_item.h>
|
||||
#include <lib_pin.h>
|
||||
#include <lib_shape.h>
|
||||
#include <sch_symbol.h>
|
||||
#include <sch_junction.h>
|
||||
#include <sch_line.h>
|
||||
@@ -815,18 +817,21 @@ void SCH_SCREEN::Print( const RENDER_SETTINGS* aSettings )
|
||||
}
|
||||
|
||||
/// Sort to ensure plot-order consistency with screen drawing
|
||||
std::sort( other.begin(), other.end(),
|
||||
std::stable_sort( other.begin(), other.end(),
|
||||
[]( const SCH_ITEM* a, const SCH_ITEM* b )
|
||||
{
|
||||
if( a->Type() == b->Type() )
|
||||
return a->GetLayer() > b->GetLayer();
|
||||
|
||||
return a->Type() > b->Type();
|
||||
return a->Type() < b->Type();
|
||||
} );
|
||||
|
||||
for( SCH_ITEM* item : bitmaps )
|
||||
item->Print( aSettings, wxPoint( 0, 0 ) );
|
||||
|
||||
for( SCH_ITEM* item : other )
|
||||
item->PrintBackground( aSettings, wxPoint( 0, 0 ) );
|
||||
|
||||
for( SCH_ITEM* item : other )
|
||||
item->Print( aSettings, wxPoint( 0, 0 ) );
|
||||
|
||||
|
||||
@@ -409,6 +409,19 @@ int SCH_SYMBOL::GetUnitCount() const
|
||||
}
|
||||
|
||||
|
||||
|
||||
void SCH_SYMBOL::PrintBackground( const RENDER_SETTINGS* aSettings, const wxPoint& aOffset )
|
||||
{
|
||||
LIB_SYMBOL_OPTIONS opts;
|
||||
opts.transform = m_transform;
|
||||
opts.draw_visible_fields = false;
|
||||
opts.draw_hidden_fields = false;
|
||||
|
||||
if( m_part )
|
||||
m_part->PrintBackground( aSettings, m_pos + aOffset, m_unit, m_convert, opts );
|
||||
}
|
||||
|
||||
|
||||
void SCH_SYMBOL::Print( const RENDER_SETTINGS* aSettings, const wxPoint& aOffset )
|
||||
{
|
||||
LIB_SYMBOL_OPTIONS opts;
|
||||
|
||||
+11
-2
@@ -488,12 +488,21 @@ public:
|
||||
/**
|
||||
* Print a symbol.
|
||||
*
|
||||
* @param aDC is the device context (can be null).
|
||||
* @param aOffset is the drawing offset (usually wxPoint(0,0), but can be different when
|
||||
* @param aSettings Render settings controlling output
|
||||
* @param aOffset is the drawing offset (usually VECTOR2I(0,0), but can be different when
|
||||
* moving an object)
|
||||
*/
|
||||
void Print( const RENDER_SETTINGS* aSettings, const wxPoint& aOffset ) override;
|
||||
|
||||
/**
|
||||
* Print only the background parts of a symbol (if any)
|
||||
*
|
||||
* @param aSettings Render settings controlling output
|
||||
* @param aOffset is the drawing offset (usually VECTOR2I(0,0), but can be different when
|
||||
* moving an object)
|
||||
*/
|
||||
void PrintBackground( const RENDER_SETTINGS* aSettings, const wxPoint& aOffset ) override;
|
||||
|
||||
void SwapData( SCH_ITEM* aItem ) override;
|
||||
|
||||
/**
|
||||
|
||||
@@ -597,7 +597,7 @@ void SCH_TEXT::GetContextualTextVars( wxArrayString* aVars ) const
|
||||
}
|
||||
|
||||
|
||||
wxString SCH_TEXT::GetShownText( int aDepth ) const
|
||||
wxString SCH_TEXT::GetShownText( int aDepth, bool aAllowExtraText ) const
|
||||
{
|
||||
std::function<bool( wxString* )> textResolver =
|
||||
[&]( wxString* token ) -> bool
|
||||
|
||||
+1
-1
@@ -139,7 +139,7 @@ public:
|
||||
*/
|
||||
void GetContextualTextVars( wxArrayString* aVars ) const;
|
||||
|
||||
wxString GetShownText( int aDepth = 0 ) const override;
|
||||
wxString GetShownText( int aDepth = 0, bool aAllowExtraText = true ) const override;
|
||||
|
||||
/**
|
||||
* Increment the label text, if it ends with a number.
|
||||
|
||||
@@ -559,6 +559,19 @@ void NGSPICE::init_dll()
|
||||
Command( "set noaskquit" );
|
||||
Command( "set nomoremode" );
|
||||
|
||||
// reset and remcirc give an error if no circuit is loaded, so load an empty circuit at the
|
||||
// start.
|
||||
|
||||
vector<char*> lines;
|
||||
lines.push_back( strdup( "*" ) );
|
||||
lines.push_back( strdup( ".end" ) );
|
||||
lines.push_back( nullptr ); // Sentinel.
|
||||
|
||||
m_ngSpice_Circ( lines.data() );
|
||||
|
||||
for( auto line : lines )
|
||||
free( line );
|
||||
|
||||
m_initialized = true;
|
||||
}
|
||||
|
||||
|
||||
@@ -93,5 +93,7 @@ void SYMBOL_EDIT_FRAME::PrintPage( const RENDER_SETTINGS* aSettings )
|
||||
plot_offset.x = pagesize.x / 2;
|
||||
plot_offset.y = pagesize.y / 2;
|
||||
|
||||
m_symbol->PrintBackground( aSettings, plot_offset, m_unit, m_convert, LIB_SYMBOL_OPTIONS() );
|
||||
|
||||
m_symbol->Print( aSettings, plot_offset, m_unit, m_convert, LIB_SYMBOL_OPTIONS() );
|
||||
}
|
||||
|
||||
@@ -531,7 +531,8 @@ LIB_ID SYMBOL_LIBRARY_MANAGER::RevertSymbol( const wxString& aAlias, const wxStr
|
||||
}
|
||||
else
|
||||
{
|
||||
symbolBuf->SetSymbol( new LIB_SYMBOL( original ) );
|
||||
// copy the initial data to the current symbol to restore
|
||||
*symbolBuf->GetSymbol() = original;
|
||||
m_frame.SyncLibraries( false );
|
||||
}
|
||||
|
||||
|
||||
@@ -750,6 +750,7 @@ int SCH_DRAWING_TOOLS::SingleClickPlace( const TOOL_EVENT& aEvent )
|
||||
}
|
||||
|
||||
SCH_ITEM* newItem = static_cast<SCH_ITEM*>( previewItem->Clone() );
|
||||
const_cast<KIID&>( newItem->m_Uuid ) = KIID();
|
||||
newItem->SetPosition( cursorPos );
|
||||
newItem->SetFlags( IS_NEW );
|
||||
|
||||
|
||||
@@ -244,7 +244,7 @@ bool SYMBOL_EDITOR_PIN_TOOL::PlacePin( LIB_PIN* aPin )
|
||||
|
||||
if( !status )
|
||||
{
|
||||
if( aPin->IsNew() )
|
||||
if( aPin->IsNew() && !aPin->HasFlag( IS_PASTED ) )
|
||||
delete aPin;
|
||||
|
||||
return false;
|
||||
|
||||
@@ -442,7 +442,6 @@ EDA_ITEM* GERBVIEW_SELECTION_TOOL::disambiguationMenu( GERBER_COLLECTOR* aCollec
|
||||
if( current )
|
||||
{
|
||||
current->ClearBrightened();
|
||||
getView()->Hide( current, false );
|
||||
highlightGroup.Remove( current );
|
||||
getView()->MarkTargetDirty( KIGFX::TARGET_OVERLAY );
|
||||
}
|
||||
@@ -454,7 +453,6 @@ EDA_ITEM* GERBVIEW_SELECTION_TOOL::disambiguationMenu( GERBER_COLLECTOR* aCollec
|
||||
{
|
||||
current = ( *aCollector )[id - 1];
|
||||
current->SetBrightened();
|
||||
getView()->Hide( current, true );
|
||||
highlightGroup.Add( current );
|
||||
getView()->MarkTargetDirty( KIGFX::TARGET_OVERLAY );
|
||||
}
|
||||
@@ -477,10 +475,9 @@ EDA_ITEM* GERBVIEW_SELECTION_TOOL::disambiguationMenu( GERBER_COLLECTOR* aCollec
|
||||
}
|
||||
}
|
||||
|
||||
if( current && current->IsBrightened() )
|
||||
if( current )
|
||||
{
|
||||
current->ClearBrightened();
|
||||
getView()->Hide( current, false );
|
||||
getView()->MarkTargetDirty( KIGFX::TARGET_OVERLAY );
|
||||
}
|
||||
|
||||
|
||||
@@ -2128,8 +2128,13 @@ skipcodes 26 0
|
||||
// Combining Diacritical Marks For Symbols (20D0-20FF)
|
||||
skipcodes 48 0
|
||||
|
||||
// Letterlike Symbols (2100-214F)
|
||||
skipcodes 80 0
|
||||
// Letterlike Symbols (2100-2125)
|
||||
skipcodes 38 0
|
||||
|
||||
+ OMEGA_CAP
|
||||
|
||||
// Letterlike Symbols (2127-214F)
|
||||
skipcodes 41 0
|
||||
|
||||
// Number Forms (2150-218F)
|
||||
skipcodes 64 0
|
||||
|
||||
@@ -148,6 +148,12 @@ public:
|
||||
virtual LSET GetLayerSet() const { return LSET( m_layer ); }
|
||||
virtual void SetLayerSet( LSET aLayers )
|
||||
{
|
||||
if( aLayers.count() == 1 )
|
||||
{
|
||||
SetLayer( aLayers.Seq()[0] );
|
||||
return;
|
||||
}
|
||||
|
||||
wxFAIL_MSG( wxT( "Attempted to SetLayerSet() on a single-layer object." ) );
|
||||
|
||||
// Derived classes which support multiple layers must implement this
|
||||
|
||||
@@ -52,7 +52,8 @@ public:
|
||||
*/
|
||||
EDA_LIST_DIALOG( wxWindow* aParent, const wxString& aTitle, const wxArrayString& aItemHeaders,
|
||||
const std::vector<wxArrayString>& aItemList,
|
||||
const wxString& aPreselectText = wxEmptyString );
|
||||
const wxString& aPreselectText = wxEmptyString,
|
||||
bool aSortList = true );
|
||||
|
||||
void SetListLabel( const wxString& aLabel );
|
||||
void SetOKLabel( const wxString& aLabel );
|
||||
@@ -80,6 +81,7 @@ private:
|
||||
|
||||
private:
|
||||
const std::vector<wxArrayString>* m_itemsList;
|
||||
bool m_sortList;
|
||||
};
|
||||
|
||||
|
||||
|
||||
+4
-1
@@ -158,8 +158,11 @@ public:
|
||||
*
|
||||
* @param aDepth is used to prevent infinite recursions and loops when expanding
|
||||
* text variables.
|
||||
* @param aAllowExtraText true to allow adding more text than the initial expanded text,
|
||||
* for intance a title, a prefix for texts in display functions.
|
||||
* False to disable any added text (for instance when writing the shown text in netlists).
|
||||
*/
|
||||
virtual wxString GetShownText( int aDepth = 0 ) const { return m_shown_text; }
|
||||
virtual wxString GetShownText( int aDepth = 0, bool aAllowExtraText = true ) const { return m_shown_text; }
|
||||
|
||||
/**
|
||||
* Returns a shortened version (max 15 characters) of the shown text
|
||||
|
||||
@@ -166,7 +166,7 @@ public:
|
||||
*/
|
||||
bool SetFromWxString( const wxString& aColorString );
|
||||
|
||||
wxString ToWxString( long flags ) const;
|
||||
wxString ToCSSString() const;
|
||||
|
||||
bool SetFromHexString( const wxString& aColorString );
|
||||
wxString ToHexString() const;
|
||||
|
||||
@@ -1275,7 +1275,7 @@ public:
|
||||
m_gal->BeginDrawing();
|
||||
}
|
||||
|
||||
~GAL_DRAWING_CONTEXT()
|
||||
~GAL_DRAWING_CONTEXT() noexcept( false )
|
||||
{
|
||||
m_gal->EndDrawing();
|
||||
}
|
||||
|
||||
@@ -159,11 +159,14 @@ private:
|
||||
/* Token state for input string. */
|
||||
struct TokenStat
|
||||
{
|
||||
enum { OutLen = 32 };
|
||||
TokenStat() : input( nullptr ), token( nullptr ), inputLen( 0 ), pos( 0 ) { /* empty */ }
|
||||
TokenStat() :
|
||||
input( nullptr ), token( nullptr ), inputLen( 0 ), outputLen( 0 ), pos( 0 )
|
||||
{ /* empty */ }
|
||||
|
||||
const char* input; // current input string ("var=4")
|
||||
char* token; // output token ("var", type:VAR; "4", type:VALUE)
|
||||
size_t inputLen; // strlen(input)
|
||||
size_t outputLen; // At least 64, up to input length
|
||||
size_t pos; // current index
|
||||
}
|
||||
m_token;
|
||||
|
||||
@@ -277,7 +277,7 @@ public:
|
||||
virtual ~VAR_REF() {};
|
||||
|
||||
virtual VAR_TYPE_T GetType() const = 0;
|
||||
virtual VALUE GetValue( CONTEXT* aCtx ) = 0;
|
||||
virtual VALUE* GetValue( CONTEXT* aCtx ) = 0;
|
||||
};
|
||||
|
||||
|
||||
@@ -293,7 +293,7 @@ public:
|
||||
|
||||
virtual ~CONTEXT()
|
||||
{
|
||||
for( auto &v : m_ownedValues )
|
||||
for( VALUE* v : m_ownedValues )
|
||||
{
|
||||
delete v;
|
||||
}
|
||||
@@ -305,6 +305,12 @@ public:
|
||||
return m_ownedValues.back();
|
||||
}
|
||||
|
||||
VALUE* StoreValue( VALUE* aValue )
|
||||
{
|
||||
m_ownedValues.emplace_back( aValue );
|
||||
return m_ownedValues.back();
|
||||
}
|
||||
|
||||
void Push( VALUE* v )
|
||||
{
|
||||
m_stack[ m_stackPtr++ ] = v;
|
||||
|
||||
+2
-2
@@ -92,11 +92,11 @@ public:
|
||||
void RemoveAll();
|
||||
|
||||
/*
|
||||
* Search for highest level group containing item.
|
||||
* Search for highest level group inside of aScope, containing item.
|
||||
*
|
||||
* @param aScope restricts the search to groups within the group scope.
|
||||
* @param isFootprintEditor true if we should stop promoting at the footprint level
|
||||
* @return group containing item, if it exists, otherwise, NULL
|
||||
* @return group inside of aScope, containing item, if exists, otherwise, nullptr
|
||||
*/
|
||||
static PCB_GROUP* TopLevelGroup( BOARD_ITEM* aItem, PCB_GROUP* aScope, bool isFootprintEditor );
|
||||
|
||||
|
||||
@@ -276,34 +276,9 @@ public:
|
||||
return ( d1 <= 1 && d2 <= 1 );
|
||||
}
|
||||
|
||||
bool ApproxCollinear( const SEG& aSeg ) const
|
||||
{
|
||||
ecoord p, q, r;
|
||||
CanonicalCoefs( p, q, r );
|
||||
|
||||
ecoord dist1 = ( p * aSeg.A.x + q * aSeg.A.y + r ) / sqrt( p * p + q * q );
|
||||
ecoord dist2 = ( p * aSeg.B.x + q * aSeg.B.y + r ) / sqrt( p * p + q * q );
|
||||
|
||||
return std::abs( dist1 ) <= 1 && std::abs( dist2 ) <= 1;
|
||||
}
|
||||
|
||||
bool ApproxParallel( const SEG& aSeg, int aDistanceThreshold = 1 ) const
|
||||
{
|
||||
ecoord p, q, r;
|
||||
CanonicalCoefs( p, q, r );
|
||||
|
||||
ecoord dist1 = ( p * aSeg.A.x + q * aSeg.A.y + r ) / sqrt( p * p + q * q );
|
||||
ecoord dist2 = ( p * aSeg.B.x + q * aSeg.B.y + r ) / sqrt( p * p + q * q );
|
||||
|
||||
return std::abs( dist1 - dist2 ) <= aDistanceThreshold;
|
||||
}
|
||||
|
||||
bool ApproxPerpendicular( const SEG& aSeg ) const
|
||||
{
|
||||
SEG perp = PerpendicularSeg( A );
|
||||
|
||||
return aSeg.ApproxParallel( perp );
|
||||
}
|
||||
bool ApproxCollinear( const SEG& aSeg, int aDistanceThreshold = 1 ) const;
|
||||
bool ApproxParallel( const SEG& aSeg, int aDistanceThreshold = 1 ) const;
|
||||
bool ApproxPerpendicular( const SEG& aSeg ) const;
|
||||
|
||||
bool Overlaps( const SEG& aSeg ) const
|
||||
{
|
||||
@@ -394,6 +369,8 @@ private:
|
||||
bool intersects( const SEG& aSeg, bool aIgnoreEndpoints = false, bool aLines = false,
|
||||
VECTOR2I* aPt = nullptr ) const;
|
||||
|
||||
bool mutualDistance( const SEG& aSeg, ecoord& aD1, ecoord& aD2 ) const;
|
||||
|
||||
private:
|
||||
///< index within the parent shape (used when m_is_local == false)
|
||||
int m_index;
|
||||
|
||||
@@ -229,7 +229,7 @@ public:
|
||||
// calculate the right common area coordinate:
|
||||
int right = std::min( me.m_Pos.x + me.m_Size.x, rect.m_Pos.x + rect.m_Size.x );
|
||||
// calculate the upper common area coordinate:
|
||||
int top = std::max( me.m_Pos.y, aRect.m_Pos.y );
|
||||
int top = std::max( me.m_Pos.y, rect.m_Pos.y );
|
||||
// calculate the lower common area coordinate:
|
||||
int bottom = std::min( me.m_Pos.y + me.m_Size.y, rect.m_Pos.y + rect.m_Size.y );
|
||||
|
||||
|
||||
@@ -273,7 +273,7 @@ void CornerListToPolygon( SHAPE_POLY_SET& outline, std::vector<ROUNDED_CORNER>&
|
||||
endAngle = RAD2DECIDEG( angle );
|
||||
}
|
||||
|
||||
if( aInflate )
|
||||
if( aInflate && tanAngle2 )
|
||||
{
|
||||
radius += aInflate;
|
||||
cornerPosition += incoming.Resize( aInflate / tanAngle2 )
|
||||
|
||||
@@ -349,3 +349,63 @@ int SEG::LineDistance( const VECTOR2I& aP, bool aDetermineSide ) const
|
||||
return aDetermineSide ? dist : std::abs( dist );
|
||||
}
|
||||
|
||||
|
||||
bool SEG::mutualDistance( const SEG& aSeg, ecoord& aD1, ecoord& aD2 ) const
|
||||
{
|
||||
SEG a( *this );
|
||||
SEG b( aSeg );
|
||||
|
||||
if( a.SquaredLength() < b.SquaredLength() )
|
||||
{
|
||||
std::swap(a, b);
|
||||
}
|
||||
|
||||
ecoord p = ecoord{ a.A.y } - a.B.y;
|
||||
ecoord q = ecoord{ a.B.x } - a.A.x;
|
||||
ecoord r = -p * a.A.x - q * a.A.y;
|
||||
|
||||
ecoord l = p * p + q * q;
|
||||
|
||||
if( l == 0 )
|
||||
return false;
|
||||
|
||||
ecoord det1 = p * b.A.x + q * b.A.y + r;
|
||||
ecoord det2 = p * b.B.x + q * b.B.y + r;
|
||||
|
||||
ecoord dsq1 = rescale( det1, det1, l );
|
||||
ecoord dsq2 = rescale( det2, det2, l );
|
||||
|
||||
aD1 = sgn( det1 ) * isqrt( dsq1 );
|
||||
aD2 = sgn( det2 ) * isqrt( dsq2 );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SEG::ApproxCollinear( const SEG& aSeg, int aDistanceThreshold ) const
|
||||
{
|
||||
ecoord d1, d2;
|
||||
|
||||
if( ! mutualDistance( aSeg, d1, d2 ) )
|
||||
return false;
|
||||
|
||||
return std::abs( d1 ) <= aDistanceThreshold && std::abs( d2 ) <= aDistanceThreshold;
|
||||
}
|
||||
|
||||
|
||||
bool SEG::ApproxParallel( const SEG& aSeg, int aDistanceThreshold ) const
|
||||
{
|
||||
ecoord d1, d2;
|
||||
|
||||
if( ! mutualDistance( aSeg, d1, d2 ) )
|
||||
return false;
|
||||
|
||||
return std::abs( d1 - d2 ) <= (ecoord) aDistanceThreshold;
|
||||
}
|
||||
|
||||
|
||||
bool SEG::ApproxPerpendicular( const SEG& aSeg ) const
|
||||
{
|
||||
SEG perp = PerpendicularSeg( A );
|
||||
|
||||
return aSeg.ApproxParallel( perp );
|
||||
}
|
||||
|
||||
@@ -1791,6 +1791,12 @@ SHAPE_LINE_CHAIN& SHAPE_LINE_CHAIN::Simplify( bool aRemoveColinear )
|
||||
const VECTOR2I SHAPE_LINE_CHAIN::NearestPoint( const VECTOR2I& aP,
|
||||
bool aAllowInternalShapePoints ) const
|
||||
{
|
||||
if( PointCount() == 0 )
|
||||
{
|
||||
// The only right answer here is "don't crash".
|
||||
return { 0, 0 };
|
||||
}
|
||||
|
||||
int min_d = INT_MAX;
|
||||
int nearest = 0;
|
||||
|
||||
@@ -1842,6 +1848,12 @@ const VECTOR2I SHAPE_LINE_CHAIN::NearestPoint( const VECTOR2I& aP,
|
||||
|
||||
const VECTOR2I SHAPE_LINE_CHAIN::NearestPoint( const SEG& aSeg, int& dist ) const
|
||||
{
|
||||
if( PointCount() == 0 )
|
||||
{
|
||||
// The only right answer here is "don't crash".
|
||||
return { 0, 0 };
|
||||
}
|
||||
|
||||
int nearest = 0;
|
||||
|
||||
dist = INT_MAX;
|
||||
|
||||
@@ -83,15 +83,18 @@ bool KIPLATFORM::APP::IsOperatingSystemUnsupported()
|
||||
|
||||
bool KIPLATFORM::APP::RegisterApplicationRestart( const wxString& aCommandLine )
|
||||
{
|
||||
// Command line arguments with spaces require quotes.
|
||||
wxString restartCmd = wxS( "\"" ) + aCommandLine + wxS( "\"" );
|
||||
|
||||
// Ensure we don't exceed the maximum allowable size
|
||||
if( aCommandLine.length() > RESTART_MAX_CMD_LINE - 1 )
|
||||
if( restartCmd.length() > RESTART_MAX_CMD_LINE - 1 )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
HRESULT hr = S_OK;
|
||||
|
||||
hr = ::RegisterApplicationRestart( aCommandLine.wc_str(), RESTART_NO_PATCH );
|
||||
hr = ::RegisterApplicationRestart( restartCmd.wc_str(), RESTART_NO_PATCH );
|
||||
|
||||
return SUCCEEDED( hr );
|
||||
}
|
||||
|
||||
@@ -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-2021 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
* Copyright (C) 2019-2022 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
@@ -357,6 +357,14 @@ int PL_EDIT_TOOL::DoDelete( const TOOL_EVENT& aEvent )
|
||||
if( selection.Size() == 0 )
|
||||
return 0;
|
||||
|
||||
|
||||
// Do not delete an item if it is currently a new item being created to avoid a crash
|
||||
// In this case the selection contains only one item.
|
||||
DS_DRAW_ITEM_BASE* currItem = static_cast<DS_DRAW_ITEM_BASE*>( selection.Front() );
|
||||
|
||||
if( currItem->GetFlags() & ( IS_NEW ) )
|
||||
return 0;
|
||||
|
||||
m_frame->SaveCopyInUndoList();
|
||||
|
||||
while( selection.Front() )
|
||||
|
||||
@@ -437,6 +437,13 @@ if( EXISTS ${CMAKE_CURRENT_BINARY_DIR}/doxygen-xml )
|
||||
set( SWIG_OPTS ${SWIG_OPTS} -I${CMAKE_CURRENT_BINARY_DIR}/docstrings )
|
||||
endif()
|
||||
|
||||
# This command is needed only with SWIG version < 4 to disable a python section "def swig_import_helper()"
|
||||
# found at the beginning of pcbnew.py, but not longer existing in SWIG version >= 4
|
||||
if( ${SWIG_VERSION} VERSION_LESS 4.0.0 )
|
||||
set( OPT_CMD COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_SOURCE_DIR}/scripting/build_tools/fix_swig_imports.py ${CMAKE_CURRENT_BINARY_DIR}/pcbnew.py )
|
||||
endif()
|
||||
|
||||
|
||||
add_custom_command( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/pcbnew_wrap.cxx
|
||||
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/pcbnew.py
|
||||
|
||||
@@ -487,9 +494,8 @@ add_custom_command( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/pcbnew_wrap.cxx
|
||||
COMMAND ${SWIG_EXECUTABLE}
|
||||
${SWIG_OPTS} -o ${CMAKE_CURRENT_BINARY_DIR}/pcbnew_wrap.cxx ${CMAKE_SOURCE_DIR}/pcbnew/python/swig/pcbnew.i
|
||||
|
||||
COMMAND ${PYTHON_EXECUTABLE}
|
||||
${CMAKE_SOURCE_DIR}/scripting/build_tools/fix_swig_imports.py
|
||||
${CMAKE_CURRENT_BINARY_DIR}/pcbnew.py
|
||||
# Optional command for SWIG version < 4 to disable a python section "def swig_import_helper()"
|
||||
${OPT_CMD}
|
||||
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
)
|
||||
|
||||
@@ -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-2021 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
* Copyright (C) 2019-2022 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
@@ -307,7 +307,8 @@ void PANEL_SETUP_BOARD_STACKUP::onAddDielectricLayer( wxCommandEvent& event )
|
||||
}
|
||||
}
|
||||
|
||||
EDA_LIST_DIALOG dlg( m_parentDialog, _( "Add Dielectric Layer" ), headers, d_list );
|
||||
EDA_LIST_DIALOG dlg( m_parentDialog, _( "Add Dielectric Layer" ), headers, d_list,
|
||||
wxEmptyString, false /* do not sort the list: it is **expected** in stack order */);
|
||||
dlg.SetListLabel( _( "Select layer to add:" ) );
|
||||
dlg.HideFilter();
|
||||
|
||||
@@ -363,7 +364,8 @@ void PANEL_SETUP_BOARD_STACKUP::onRemoveDielectricLayer( wxCommandEvent& event )
|
||||
}
|
||||
}
|
||||
|
||||
EDA_LIST_DIALOG dlg( m_parentDialog, _( "Remove Dielectric Layer" ), headers, d_list );
|
||||
EDA_LIST_DIALOG dlg( m_parentDialog, _( "Remove Dielectric Layer" ), headers, d_list,
|
||||
wxEmptyString, false /* do not sort the list: it is **expected** in stack order */);
|
||||
dlg.SetListLabel( _( "Select layer to remove:" ) );
|
||||
dlg.HideFilter();
|
||||
|
||||
@@ -606,7 +608,6 @@ void PANEL_SETUP_BOARD_STACKUP::synchronizeWithBoard( bool aFullSync )
|
||||
|
||||
void PANEL_SETUP_BOARD_STACKUP::showOnlyActiveLayers()
|
||||
{
|
||||
|
||||
// Now enable/disable stackup items, according to the m_enabledLayers config
|
||||
// Calculate copper layer count from m_enabledLayers, and *do not use* brd_stackup
|
||||
// for that, because it is not necessary up to date
|
||||
@@ -1214,13 +1215,15 @@ bool PANEL_SETUP_BOARD_STACKUP::TransferDataFromWindow()
|
||||
void PANEL_SETUP_BOARD_STACKUP::ImportSettingsFrom( BOARD* aBoard )
|
||||
{
|
||||
BOARD* savedBrd = m_board;
|
||||
m_board = aBoard;
|
||||
|
||||
BOARD_DESIGN_SETTINGS* savedSettings = m_brdSettings;
|
||||
m_brdSettings = &aBoard->GetDesignSettings();
|
||||
|
||||
m_enabledLayers = m_panelLayers->GetUILayerMask() & BOARD_STACKUP::StackupAllowedBrdLayers();
|
||||
synchronizeWithBoard( true );
|
||||
m_enabledLayers = m_board->GetEnabledLayers() & BOARD_STACKUP::StackupAllowedBrdLayers();
|
||||
|
||||
rebuildLayerStackPanel();
|
||||
synchronizeWithBoard( true );
|
||||
computeBoardThickness();
|
||||
|
||||
m_brdSettings = savedSettings;
|
||||
|
||||
@@ -669,10 +669,9 @@ void CN_CONNECTIVITY_ALGO::MarkNetAsDirty( int aNet )
|
||||
|
||||
void CN_VISITOR::checkZoneItemConnection( CN_ZONE_LAYER* aZoneLayer, CN_ITEM* aItem )
|
||||
{
|
||||
if( aZoneLayer->Net() != aItem->Net() && !aItem->CanChangeNet() )
|
||||
return;
|
||||
PCB_LAYER_ID layer = aZoneLayer->GetLayer();
|
||||
|
||||
if( !aZoneLayer->BBox().Intersects( aItem->BBox() ) )
|
||||
if( !aItem->Parent()->IsOnLayer( layer ) )
|
||||
return;
|
||||
|
||||
int accuracy = 0;
|
||||
@@ -703,9 +702,6 @@ void CN_VISITOR::checkZoneZoneConnection( CN_ZONE_LAYER* aZoneLayerA, CN_ZONE_LA
|
||||
if( aZoneLayerA->Layer() != aZoneLayerB->Layer() )
|
||||
return;
|
||||
|
||||
if( aZoneLayerB->Net() != aZoneLayerA->Net() )
|
||||
return; // we only test zones belonging to the same net
|
||||
|
||||
const BOX2I& boxA = aZoneLayerA->BBox();
|
||||
const BOX2I& boxB = aZoneLayerB->BBox();
|
||||
|
||||
@@ -765,6 +761,10 @@ bool CN_VISITOR::operator()( CN_ITEM* aCandidate )
|
||||
if( parentA == parentB )
|
||||
return true;
|
||||
|
||||
// Don't connect items in different nets that can't be changed
|
||||
if( !aCandidate->CanChangeNet() && !m_item->CanChangeNet() && aCandidate->Net() != m_item->Net() )
|
||||
return true;
|
||||
|
||||
LSET commonLayers = parentA->GetLayerSet() & parentB->GetLayerSet();
|
||||
|
||||
if( !commonLayers.any() )
|
||||
|
||||
@@ -249,8 +249,8 @@ void DIALOG_BOARD_SETUP::OnAuxiliaryAction( wxCommandEvent& event )
|
||||
// separately, and stackup can be imported only after layers options
|
||||
if( importDlg.m_LayersOpt->GetValue() )
|
||||
{
|
||||
m_layers->ImportSettingsFrom( otherBoard );
|
||||
m_physicalStackup->ImportSettingsFrom( otherBoard );
|
||||
m_layers->ImportSettingsFrom( otherBoard );
|
||||
}
|
||||
|
||||
if( importDlg.m_TextAndGraphicsOpt->GetValue() )
|
||||
|
||||
@@ -58,9 +58,6 @@ private:
|
||||
|
||||
bool m_flipStartEnd;
|
||||
|
||||
wxFloatingPointValidator<double> m_AngleValidator;
|
||||
double m_AngleValue;
|
||||
|
||||
public:
|
||||
DIALOG_GRAPHIC_ITEM_PROPERTIES( PCB_BASE_EDIT_FRAME* aParent, BOARD_ITEM* aItem );
|
||||
~DIALOG_GRAPHIC_ITEM_PROPERTIES() {};
|
||||
@@ -94,9 +91,7 @@ DIALOG_GRAPHIC_ITEM_PROPERTIES::DIALOG_GRAPHIC_ITEM_PROPERTIES( PCB_BASE_EDIT_FR
|
||||
m_bezierCtrl1Y( aParent, m_BezierPointC1YLabel, m_BezierC1Y_Ctrl, m_BezierPointC1YUnit ),
|
||||
m_bezierCtrl2X( aParent, m_BezierPointC2XLabel, m_BezierC2X_Ctrl, m_BezierPointC2XUnit ),
|
||||
m_bezierCtrl2Y( aParent, m_BezierPointC2YLabel, m_BezierC2Y_Ctrl, m_BezierPointC2YUnit ),
|
||||
m_flipStartEnd( false ),
|
||||
m_AngleValidator( 1, &m_AngleValue ),
|
||||
m_AngleValue( 0.0 )
|
||||
m_flipStartEnd( false )
|
||||
{
|
||||
m_parent = aParent;
|
||||
m_item = dynamic_cast<PCB_SHAPE*>( aItem );
|
||||
@@ -113,9 +108,6 @@ DIALOG_GRAPHIC_ITEM_PROPERTIES::DIALOG_GRAPHIC_ITEM_PROPERTIES( PCB_BASE_EDIT_FR
|
||||
m_bezierCtrl2Y.SetCoordType( ORIGIN_TRANSFORMS::ABS_Y_COORD );
|
||||
|
||||
m_angle.SetUnits( EDA_UNITS::DEGREES );
|
||||
m_AngleValidator.SetRange( -359.9, 359.9 );
|
||||
m_angleCtrl->SetValidator( m_AngleValidator );
|
||||
m_AngleValidator.SetWindow( m_angleCtrl );
|
||||
|
||||
// Do not allow locking items in the footprint editor
|
||||
m_locked->Show( dynamic_cast<PCB_EDIT_FRAME*>( aParent ) != nullptr );
|
||||
@@ -189,7 +181,7 @@ bool DIALOG_GRAPHIC_ITEM_PROPERTIES::TransferDataToWindow()
|
||||
|
||||
case SHAPE_T::ARC:
|
||||
SetTitle( _( "Arc Properties" ) );
|
||||
m_AngleValue = m_item->GetArcAngle() / 10.0;
|
||||
m_angle.SetDoubleValue( m_item->GetArcAngle() );
|
||||
m_filledCtrl->Show( false );
|
||||
break;
|
||||
|
||||
@@ -310,7 +302,8 @@ bool DIALOG_GRAPHIC_ITEM_PROPERTIES::TransferDataFromWindow()
|
||||
|
||||
if( m_item->GetShape() == SHAPE_T::ARC )
|
||||
{
|
||||
VECTOR2D center = CalcArcCenter( m_item->GetStart(), m_item->GetEnd(), m_AngleValue );
|
||||
VECTOR2D center = CalcArcCenter( m_item->GetStart(), m_item->GetEnd(),
|
||||
m_angle.GetDoubleValue() / 10.0 );
|
||||
|
||||
m_item->SetCenter( wxPoint( KiROUND( center.x ), KiROUND( center.y ) ) );
|
||||
}
|
||||
|
||||
@@ -1242,13 +1242,11 @@ bool DIALOG_PAD_PROPERTIES::padValuesOK()
|
||||
// Test hole size against pad size
|
||||
if( m_dummyPad->IsOnCopperLayer() )
|
||||
{
|
||||
LSET lset = m_dummyPad->GetLayerSet() & LSET::AllCuMask();
|
||||
PCB_LAYER_ID layer = lset.Seq().at( 0 );
|
||||
int maxError = m_board->GetDesignSettings().m_MaxError;
|
||||
SHAPE_POLY_SET padOutline;
|
||||
|
||||
m_dummyPad->TransformShapeWithClearanceToPolygon( padOutline, layer, 0, maxError,
|
||||
ERROR_LOC::ERROR_INSIDE );
|
||||
m_dummyPad->TransformShapeWithClearanceToPolygon( padOutline, UNDEFINED_LAYER, 0,
|
||||
maxError, ERROR_INSIDE );
|
||||
|
||||
const SHAPE_SEGMENT* drillShape = m_dummyPad->GetEffectiveHoleShape();
|
||||
const SEG drillSeg = drillShape->GetSeg();
|
||||
|
||||
@@ -1345,12 +1345,7 @@ std::shared_ptr<SHAPE> DRC_ENGINE::GetShape( BOARD_ITEM* aItem, PCB_LAYER_ID aLa
|
||||
|
||||
if( aPad->GetAttribute() == PAD_ATTRIB::PTH )
|
||||
{
|
||||
BOARD_DESIGN_SETTINGS& bds = aPad->GetBoard()->GetDesignSettings();
|
||||
|
||||
// Note: drill size represents finish size, which means the actual holes size is the
|
||||
// plating thickness larger.
|
||||
auto hole = static_cast<SHAPE_SEGMENT*>( aPad->GetEffectiveHoleShape()->Clone() );
|
||||
hole->SetWidth( hole->GetWidth() + bds.GetHolePlatingThickness() );
|
||||
return std::make_shared<SHAPE_SEGMENT>( *hole );
|
||||
}
|
||||
|
||||
|
||||
@@ -23,10 +23,15 @@
|
||||
|
||||
#include <common.h>
|
||||
#include <pcb_track.h>
|
||||
#include <pad.h>
|
||||
#include <footprint.h>
|
||||
#include <drc/drc_engine.h>
|
||||
#include <drc/drc_item.h>
|
||||
#include <drc/drc_rule.h>
|
||||
#include <drc/drc_test_provider.h>
|
||||
#include <macros.h>
|
||||
#include <convert_basic_shapes_to_polygon.h>
|
||||
#include <board_design_settings.h>
|
||||
|
||||
/*
|
||||
Via/pad annular ring width test. Checks if there's sufficient copper ring around
|
||||
@@ -87,24 +92,138 @@ bool DRC_TEST_PROVIDER_ANNULAR_WIDTH::Run()
|
||||
if( !reportPhase( _( "Checking via annular rings..." ) ) )
|
||||
return false; // DRC cancelled
|
||||
|
||||
int maxError = m_drcEngine->GetBoard()->GetDesignSettings().m_MaxError;
|
||||
|
||||
auto calcEffort =
|
||||
[]( BOARD_ITEM* item )
|
||||
{
|
||||
switch( item->Type() )
|
||||
{
|
||||
case PCB_VIA_T:
|
||||
return 1;
|
||||
|
||||
case PCB_PAD_T:
|
||||
{
|
||||
PAD* pad = static_cast<PAD*>( item );
|
||||
|
||||
if( !pad->HasHole() || pad->GetAttribute() != PAD_ATTRIB::PTH )
|
||||
return 0;
|
||||
|
||||
if( pad->GetOffset() == wxPoint( 0, 0 ) )
|
||||
{
|
||||
switch( pad->GetShape() )
|
||||
{
|
||||
case PAD_SHAPE::CHAMFERED_RECT:
|
||||
if( pad->GetChamferRectRatio() > 0.30 )
|
||||
break;
|
||||
|
||||
KI_FALLTHROUGH;
|
||||
|
||||
case PAD_SHAPE::CIRCLE:
|
||||
case PAD_SHAPE::OVAL:
|
||||
case PAD_SHAPE::RECT:
|
||||
case PAD_SHAPE::ROUNDRECT:
|
||||
return 1;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 100;
|
||||
}
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
auto checkAnnularWidth =
|
||||
[&]( BOARD_ITEM* item ) -> bool
|
||||
{
|
||||
if( m_drcEngine->IsErrorLimitExceeded( DRCE_ANNULAR_WIDTH ) )
|
||||
return false;
|
||||
|
||||
int v_min = 0;
|
||||
int v_max = 0;
|
||||
PCB_VIA* via = dyn_cast<PCB_VIA*>( item );
|
||||
int annularWidth = 0;
|
||||
|
||||
// fixme: check minimum IAR/OAR ring for THT pads too
|
||||
if( !via )
|
||||
switch( item->Type() )
|
||||
{
|
||||
case PCB_VIA_T:
|
||||
{
|
||||
PCB_VIA* via = static_cast<PCB_VIA*>( item );
|
||||
annularWidth = ( via->GetWidth() - via->GetDrillValue() ) / 2;
|
||||
break;
|
||||
}
|
||||
|
||||
case PCB_PAD_T:
|
||||
{
|
||||
PAD* pad = static_cast<PAD*>( item );
|
||||
bool handled = false;
|
||||
|
||||
if( !pad->HasHole() || pad->GetAttribute() != PAD_ATTRIB::PTH )
|
||||
return true;
|
||||
|
||||
if( pad->GetOffset() == wxPoint( 0, 0 ) )
|
||||
{
|
||||
switch( pad->GetShape() )
|
||||
{
|
||||
case PAD_SHAPE::CHAMFERED_RECT:
|
||||
if( pad->GetChamferRectRatio() > 0.30 )
|
||||
break;
|
||||
|
||||
KI_FALLTHROUGH;
|
||||
|
||||
case PAD_SHAPE::CIRCLE:
|
||||
case PAD_SHAPE::OVAL:
|
||||
case PAD_SHAPE::RECT:
|
||||
case PAD_SHAPE::ROUNDRECT:
|
||||
annularWidth = std::min( pad->GetSizeX() - pad->GetDrillSizeX(),
|
||||
pad->GetSizeY() - pad->GetDrillSizeY() ) / 2;
|
||||
handled = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if( !handled )
|
||||
{
|
||||
// Slow (but general purpose) method.
|
||||
SHAPE_POLY_SET padOutline;
|
||||
|
||||
pad->TransformShapeWithClearanceToPolygon( padOutline, UNDEFINED_LAYER, 0,
|
||||
maxError, ERROR_INSIDE );
|
||||
|
||||
if( !padOutline.Collide( pad->GetPosition() ) )
|
||||
{
|
||||
// Hole outside pad
|
||||
annularWidth = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
const SHAPE_SEGMENT* slot = pad->GetEffectiveHoleShape();
|
||||
|
||||
// Disable is-inside test in SquaredDistance
|
||||
padOutline.Outline( 0 ).SetClosed( false );
|
||||
|
||||
SEG::ecoord dist_sq = padOutline.SquaredDistance( slot->GetSeg() );
|
||||
annularWidth = sqrt( dist_sq ) - slot->GetWidth() / 2;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
|
||||
// PADSTACKS TODO: once we have padstacks we'll need to run this per-layer....
|
||||
auto constraint = m_drcEngine->EvalRules( ANNULAR_WIDTH_CONSTRAINT, via, nullptr,
|
||||
auto constraint = m_drcEngine->EvalRules( ANNULAR_WIDTH_CONSTRAINT, item, nullptr,
|
||||
UNDEFINED_LAYER );
|
||||
int annularWidth = ( via->GetWidth() - via->GetDrillValue() ) / 2;
|
||||
int v_min = 0;
|
||||
int v_max = 0;
|
||||
bool fail_min = false;
|
||||
bool fail_max = false;
|
||||
|
||||
@@ -126,39 +245,69 @@ bool DRC_TEST_PROVIDER_ANNULAR_WIDTH::Run()
|
||||
wxString msg;
|
||||
|
||||
if( fail_min )
|
||||
{
|
||||
msg.Printf( _( "(%s min annular width %s; actual %s)" ),
|
||||
constraint.GetName(),
|
||||
MessageTextFromValue( userUnits(), v_min ),
|
||||
MessageTextFromValue( userUnits(), annularWidth ) );
|
||||
}
|
||||
|
||||
if( fail_max )
|
||||
{
|
||||
msg.Printf( _( "(%s max annular width %s; actual %s)" ),
|
||||
constraint.GetName(),
|
||||
MessageTextFromValue( userUnits(), v_max ),
|
||||
MessageTextFromValue( userUnits(), annularWidth ) );
|
||||
}
|
||||
|
||||
drcItem->SetErrorMessage( drcItem->GetErrorText() + wxS( " " ) + msg );
|
||||
drcItem->SetItems( item );
|
||||
drcItem->SetViolatingRule( constraint.GetParentRule() );
|
||||
|
||||
reportViolation( drcItem, via->GetPosition() );
|
||||
reportViolation( drcItem, item->GetPosition() );
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
BOARD* board = m_drcEngine->GetBoard();
|
||||
int ii = 0;
|
||||
size_t ii = 0;
|
||||
size_t total = 0;
|
||||
|
||||
for( PCB_TRACK* item : board->Tracks() )
|
||||
total += calcEffort( item );
|
||||
|
||||
for( FOOTPRINT* footprint : board->Footprints() )
|
||||
{
|
||||
for( PAD* pad : footprint->Pads() )
|
||||
total += calcEffort( pad );
|
||||
}
|
||||
|
||||
for( PCB_TRACK* item : board->Tracks() )
|
||||
{
|
||||
if( !reportProgress( ii++, board->Tracks().size(), delta ) )
|
||||
ii += calcEffort( item );
|
||||
|
||||
if( !reportProgress( ii, total, delta ) )
|
||||
return false; // DRC cancelled
|
||||
|
||||
if( !checkAnnularWidth( item ) )
|
||||
break;
|
||||
}
|
||||
|
||||
for( FOOTPRINT* footprint : board->Footprints() )
|
||||
{
|
||||
for( PAD* pad : footprint->Pads() )
|
||||
{
|
||||
ii += calcEffort( pad );
|
||||
|
||||
if( !reportProgress( ii, total, delta ) )
|
||||
return false; // DRC cancelled
|
||||
|
||||
if( !checkAnnularWidth( pad ) )
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
reportRuleStatistics();
|
||||
|
||||
return true;
|
||||
|
||||
@@ -449,11 +449,6 @@ void DRC_TEST_PROVIDER_COPPER_CLEARANCE::testItemAgainstZones( BOARD_ITEM* aItem
|
||||
const SHAPE_SEGMENT* hole = pad->GetEffectiveHoleShape();
|
||||
int size = hole->GetWidth();
|
||||
|
||||
// Note: drill size represents finish size, which means the actual hole
|
||||
// size is 2x the plating thickness larger.
|
||||
if( pad->GetAttribute() == PAD_ATTRIB::PTH )
|
||||
size += 2 * m_board->GetDesignSettings().GetHolePlatingThickness();
|
||||
|
||||
itemShape = std::make_shared<SHAPE_SEGMENT>( hole->GetSeg(), size );
|
||||
}
|
||||
}
|
||||
@@ -537,7 +532,7 @@ void DRC_TEST_PROVIDER_COPPER_CLEARANCE::testTrackClearances()
|
||||
|
||||
reportAux( wxT( "Testing %d tracks & vias..." ), m_board->Tracks().size() );
|
||||
|
||||
std::map< std::pair<BOARD_ITEM*, BOARD_ITEM*>, int> checkedPairs;
|
||||
std::map< std::pair<BOARD_ITEM*, BOARD_ITEM*>, LSET> checkedPairs;
|
||||
|
||||
for( PCB_TRACK* track : m_board->Tracks() )
|
||||
{
|
||||
@@ -570,13 +565,15 @@ void DRC_TEST_PROVIDER_COPPER_CLEARANCE::testTrackClearances()
|
||||
if( static_cast<void*>( a ) > static_cast<void*>( b ) )
|
||||
std::swap( a, b );
|
||||
|
||||
if( checkedPairs.count( { a, b } ) )
|
||||
auto it = checkedPairs.find( { a, b } );
|
||||
|
||||
if( it != checkedPairs.end() && it->second.test( layer ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
checkedPairs[ { a, b } ] = 1;
|
||||
checkedPairs[ { a, b } ].set( layer );
|
||||
return true;
|
||||
}
|
||||
},
|
||||
|
||||
@@ -18,15 +18,14 @@
|
||||
*/
|
||||
|
||||
|
||||
#include <common.h>
|
||||
#include <board.h>
|
||||
#include <board_design_settings.h>
|
||||
#include <pcb_track.h>
|
||||
|
||||
#include <drc/drc_engine.h>
|
||||
#include <drc/drc_item.h>
|
||||
#include <drc/drc_rule.h>
|
||||
#include <drc/drc_test_provider.h>
|
||||
#include <drc/drc_length_report.h>
|
||||
#include <drc/drc_rtree.h>
|
||||
|
||||
#include <geometry/shape_segment.h>
|
||||
@@ -277,7 +276,7 @@ bool test::DRC_TEST_PROVIDER_DIFF_PAIR_COUPLING::Run()
|
||||
{
|
||||
m_board = m_drcEngine->GetBoard();
|
||||
|
||||
|
||||
int epsilon = m_board->GetDesignSettings().GetDRCEpsilon();
|
||||
|
||||
std::map<DIFF_PAIR_KEY, DIFF_PAIR_ITEMS> dpRuleMatches;
|
||||
|
||||
@@ -423,10 +422,10 @@ bool test::DRC_TEST_PROVIDER_DIFF_PAIR_COUPLING::Run()
|
||||
auto val = gapConstraint->GetValue();
|
||||
bool insideRange = true;
|
||||
|
||||
if( val.HasMin() && gap < val.Min() )
|
||||
if( val.HasMin() && gap < val.Min() - epsilon )
|
||||
insideRange = false;
|
||||
|
||||
if( val.HasMax() && gap > val.Max() )
|
||||
if( val.HasMax() && gap > val.Max() + epsilon )
|
||||
insideRange = false;
|
||||
|
||||
// if(val.HasMin() && val.HasMax() )
|
||||
|
||||
+1
-1
@@ -408,7 +408,7 @@ double FP_TEXT::ViewGetLOD( int aLayer, KIGFX::VIEW* aView ) const
|
||||
}
|
||||
|
||||
|
||||
wxString FP_TEXT::GetShownText( int aDepth ) const
|
||||
wxString FP_TEXT::GetShownText( int aDepth, bool aAllowExtraText ) const
|
||||
{
|
||||
const FOOTPRINT* parentFootprint = static_cast<FOOTPRINT*>( GetParent() );
|
||||
wxASSERT( parentFootprint );
|
||||
|
||||
+1
-1
@@ -221,7 +221,7 @@ public:
|
||||
|
||||
EDA_ITEM* Clone() const override;
|
||||
|
||||
virtual wxString GetShownText( int aDepth = 0 ) const override;
|
||||
virtual wxString GetShownText( int aDepth = 0, bool aAllowExtraText = true ) const override;
|
||||
|
||||
virtual const BOX2I ViewBBox() const override;
|
||||
|
||||
|
||||
@@ -156,6 +156,20 @@ bool PAD::IsLocked() const
|
||||
};
|
||||
|
||||
|
||||
bool PAD::IsNoConnectPad() const
|
||||
{
|
||||
return GetShortNetname().StartsWith( wxT( "unconnected-(" ) )
|
||||
&& ( m_pinType == wxT( "no_connect" ) || m_pinType.EndsWith( wxT( "+no_connect" ) ) );
|
||||
}
|
||||
|
||||
|
||||
bool PAD::IsFreePad() const
|
||||
{
|
||||
return GetShortNetname().StartsWith( wxT( "unconnected-(" ) )
|
||||
&& m_pinType == wxT( "free" );
|
||||
}
|
||||
|
||||
|
||||
LSET PAD::PTHMask()
|
||||
{
|
||||
static LSET saved = LSET::AllCuMask() | LSET( 2, F_Mask, B_Mask );
|
||||
@@ -1506,6 +1520,9 @@ void PAD::ImportSettingsFrom( const PAD& aMasterPad )
|
||||
|
||||
SetOrientation( pad_rot );
|
||||
|
||||
SetRemoveUnconnected( aMasterPad.GetRemoveUnconnected() );
|
||||
SetKeepTopBottom( aMasterPad.GetKeepTopBottom() );
|
||||
|
||||
SetSize( aMasterPad.GetSize() );
|
||||
SetDelta( wxSize( 0, 0 ) );
|
||||
SetOffset( aMasterPad.GetOffset() );
|
||||
|
||||
@@ -102,6 +102,11 @@ public:
|
||||
return false;
|
||||
}
|
||||
|
||||
bool HasHole() const
|
||||
{
|
||||
return GetDrillSizeX() > 0 && GetDrillSizeY() > 0;
|
||||
}
|
||||
|
||||
FOOTPRINT* GetParent() const;
|
||||
|
||||
wxString GetParentAsString() const { return m_parent->m_Uuid.AsString(); }
|
||||
@@ -155,6 +160,18 @@ public:
|
||||
return GetParent() == other->GetParent() && m_number == other->m_number;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if the pad is associated with an "unconnected" pin (or a no-connect symbol)
|
||||
* and has no net.
|
||||
*/
|
||||
bool IsNoConnectPad() const;
|
||||
|
||||
/**
|
||||
* @return true if the pad is associated with a "free" pin (not-internally-connected) and has
|
||||
* not yet been assigned another net (ie: by being routed to).
|
||||
*/
|
||||
bool IsFreePad() const;
|
||||
|
||||
/**
|
||||
* Set the new shape of this pad.
|
||||
*/
|
||||
|
||||
@@ -576,6 +576,9 @@ bool isInsideArea( BOARD_ITEM* aItem, const EDA_RECT& aItemBBox, PCB_EXPR_CONTEX
|
||||
if( !aArea || aArea == aItem || aArea->GetParent() == aItem )
|
||||
return false;
|
||||
|
||||
if( !( aArea->GetLayerSet() & aItem->GetLayerSet() ).any() )
|
||||
return false;
|
||||
|
||||
BOARD* board = aArea->GetBoard();
|
||||
std::unique_lock<std::mutex> cacheLock( board->m_CachesMutex );
|
||||
PCB_LAYER_ID layer = aCtx->GetLayer();
|
||||
@@ -897,7 +900,8 @@ class PCB_LAYER_VALUE : public LIBEVAL::VALUE
|
||||
{
|
||||
public:
|
||||
PCB_LAYER_VALUE( PCB_LAYER_ID aLayer ) :
|
||||
LIBEVAL::VALUE( double( aLayer ) )
|
||||
LIBEVAL::VALUE( LayerName( aLayer ) ),
|
||||
m_layer( aLayer )
|
||||
{};
|
||||
|
||||
virtual bool EqualTo( LIBEVAL::CONTEXT* aCtx, const VALUE* b ) const override
|
||||
@@ -930,25 +934,25 @@ public:
|
||||
mask = i->second;
|
||||
}
|
||||
|
||||
PCB_LAYER_ID layerId = ToLAYER_ID( (int) AsDouble() );
|
||||
|
||||
return mask.Contains( layerId );
|
||||
return mask.Contains( m_layer );
|
||||
}
|
||||
|
||||
protected:
|
||||
PCB_LAYER_ID m_layer;
|
||||
};
|
||||
|
||||
|
||||
LIBEVAL::VALUE PCB_EXPR_VAR_REF::GetValue( LIBEVAL::CONTEXT* aCtx )
|
||||
LIBEVAL::VALUE* PCB_EXPR_VAR_REF::GetValue( LIBEVAL::CONTEXT* aCtx )
|
||||
{
|
||||
PCB_EXPR_CONTEXT* context = static_cast<PCB_EXPR_CONTEXT*>( aCtx );
|
||||
|
||||
if( m_itemIndex == 2 )
|
||||
{
|
||||
PCB_EXPR_CONTEXT* context = static_cast<PCB_EXPR_CONTEXT*>( aCtx );
|
||||
return PCB_LAYER_VALUE( context->GetLayer() );
|
||||
}
|
||||
return new PCB_LAYER_VALUE( context->GetLayer() );
|
||||
|
||||
BOARD_ITEM* item = GetObject( aCtx );
|
||||
|
||||
if( !item )
|
||||
return LIBEVAL::VALUE();
|
||||
return new LIBEVAL::VALUE();
|
||||
|
||||
auto it = m_matchingTypes.find( TYPE_HASH( *item ) );
|
||||
|
||||
@@ -958,12 +962,12 @@ LIBEVAL::VALUE PCB_EXPR_VAR_REF::GetValue( LIBEVAL::CONTEXT* aCtx )
|
||||
// simpler "A.Via_Type == 'buried'" is perfectly clear. Instead, return an undefined
|
||||
// value when the property doesn't appear on a particular object.
|
||||
|
||||
return LIBEVAL::VALUE();
|
||||
return new LIBEVAL::VALUE();
|
||||
}
|
||||
else
|
||||
{
|
||||
if( m_type == LIBEVAL::VT_NUMERIC )
|
||||
return LIBEVAL::VALUE( (double) item->Get<int>( it->second ) );
|
||||
return new LIBEVAL::VALUE( (double) item->Get<int>( it->second ) );
|
||||
else
|
||||
{
|
||||
wxString str;
|
||||
@@ -971,7 +975,7 @@ LIBEVAL::VALUE PCB_EXPR_VAR_REF::GetValue( LIBEVAL::CONTEXT* aCtx )
|
||||
if( !m_isEnum )
|
||||
{
|
||||
str = item->Get<wxString>( it->second );
|
||||
return LIBEVAL::VALUE( str );
|
||||
return new LIBEVAL::VALUE( str );
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -979,51 +983,56 @@ LIBEVAL::VALUE PCB_EXPR_VAR_REF::GetValue( LIBEVAL::CONTEXT* aCtx )
|
||||
bool valid = any.GetAs<wxString>( &str );
|
||||
|
||||
if( valid )
|
||||
return LIBEVAL::VALUE( str );
|
||||
{
|
||||
if( it->second->Name() == wxT( "Layer" ) )
|
||||
return new PCB_LAYER_VALUE( context->GetBoard()->GetLayerID( str ) );
|
||||
else
|
||||
return new LIBEVAL::VALUE( str );
|
||||
}
|
||||
}
|
||||
|
||||
return LIBEVAL::VALUE();
|
||||
return new LIBEVAL::VALUE();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
LIBEVAL::VALUE PCB_EXPR_NETCLASS_REF::GetValue( LIBEVAL::CONTEXT* aCtx )
|
||||
LIBEVAL::VALUE* PCB_EXPR_NETCLASS_REF::GetValue( LIBEVAL::CONTEXT* aCtx )
|
||||
{
|
||||
BOARD_ITEM* item = GetObject( aCtx );
|
||||
|
||||
if( !item )
|
||||
return LIBEVAL::VALUE();
|
||||
return new LIBEVAL::VALUE();
|
||||
|
||||
if( item->IsConnected() )
|
||||
return LIBEVAL::VALUE( static_cast<BOARD_CONNECTED_ITEM*>( item )->GetNetClassName() );
|
||||
return new LIBEVAL::VALUE( static_cast<BOARD_CONNECTED_ITEM*>( item )->GetNetClassName() );
|
||||
else
|
||||
return LIBEVAL::VALUE();
|
||||
return new LIBEVAL::VALUE();
|
||||
}
|
||||
|
||||
|
||||
LIBEVAL::VALUE PCB_EXPR_NETNAME_REF::GetValue( LIBEVAL::CONTEXT* aCtx )
|
||||
LIBEVAL::VALUE* PCB_EXPR_NETNAME_REF::GetValue( LIBEVAL::CONTEXT* aCtx )
|
||||
{
|
||||
BOARD_ITEM* item = GetObject( aCtx );
|
||||
|
||||
if( !item )
|
||||
return LIBEVAL::VALUE();
|
||||
return new LIBEVAL::VALUE();
|
||||
|
||||
if( item->IsConnected() )
|
||||
return LIBEVAL::VALUE( static_cast<BOARD_CONNECTED_ITEM*>( item )->GetNetname() );
|
||||
return new LIBEVAL::VALUE( static_cast<BOARD_CONNECTED_ITEM*>( item )->GetNetname() );
|
||||
else
|
||||
return LIBEVAL::VALUE();
|
||||
return new LIBEVAL::VALUE();
|
||||
}
|
||||
|
||||
|
||||
LIBEVAL::VALUE PCB_EXPR_TYPE_REF::GetValue( LIBEVAL::CONTEXT* aCtx )
|
||||
LIBEVAL::VALUE* PCB_EXPR_TYPE_REF::GetValue( LIBEVAL::CONTEXT* aCtx )
|
||||
{
|
||||
BOARD_ITEM* item = GetObject( aCtx );
|
||||
|
||||
if( !item )
|
||||
return LIBEVAL::VALUE();
|
||||
return new LIBEVAL::VALUE();
|
||||
|
||||
return LIBEVAL::VALUE( ENUM_MAP<KICAD_T>::Instance().ToString( item->Type() ) );
|
||||
return new LIBEVAL::VALUE( ENUM_MAP<KICAD_T>::Instance().ToString( item->Type() ) );
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -103,7 +103,7 @@ public:
|
||||
m_matchingTypes[type_hash] = prop;
|
||||
}
|
||||
|
||||
virtual LIBEVAL::VALUE GetValue( LIBEVAL::CONTEXT* aCtx ) override;
|
||||
LIBEVAL::VALUE* GetValue( LIBEVAL::CONTEXT* aCtx ) override;
|
||||
|
||||
BOARD_ITEM* GetObject( const LIBEVAL::CONTEXT* aCtx ) const;
|
||||
|
||||
@@ -126,7 +126,7 @@ public:
|
||||
//printf("*** CreateVarRef %p %d\n", this, aItemIndex );
|
||||
}
|
||||
|
||||
LIBEVAL::VALUE GetValue( LIBEVAL::CONTEXT* aCtx ) override;
|
||||
LIBEVAL::VALUE* GetValue( LIBEVAL::CONTEXT* aCtx ) override;
|
||||
};
|
||||
|
||||
|
||||
@@ -141,7 +141,7 @@ public:
|
||||
//printf("*** CreateVarRef %p %d\n", this, aItemIndex );
|
||||
}
|
||||
|
||||
LIBEVAL::VALUE GetValue( LIBEVAL::CONTEXT* aCtx ) override;
|
||||
LIBEVAL::VALUE* GetValue( LIBEVAL::CONTEXT* aCtx ) override;
|
||||
};
|
||||
|
||||
|
||||
@@ -155,7 +155,7 @@ public:
|
||||
//printf("*** CreateVarRef %p %d\n", this, aItemIndex );
|
||||
}
|
||||
|
||||
LIBEVAL::VALUE GetValue( LIBEVAL::CONTEXT* aCtx ) override;
|
||||
LIBEVAL::VALUE* GetValue( LIBEVAL::CONTEXT* aCtx ) override;
|
||||
};
|
||||
|
||||
|
||||
|
||||
+27
-18
@@ -70,21 +70,26 @@ void PCB_GROUP::RemoveAll()
|
||||
}
|
||||
|
||||
|
||||
PCB_GROUP* getTopLevelGroup( BOARD_ITEM* aItem, PCB_GROUP* aScope, bool isFootprintEditor )
|
||||
/*
|
||||
* @return if not in the footprint editor and aItem is in a footprint, returns the
|
||||
* footprint's parent group. Otherwise, returns the aItem's parent group.
|
||||
*/
|
||||
PCB_GROUP* getClosestGroup( BOARD_ITEM* aItem, bool isFootprintEditor )
|
||||
{
|
||||
PCB_GROUP* group = nullptr;
|
||||
|
||||
if( isFootprintEditor )
|
||||
{
|
||||
group = aItem->GetParentGroup();
|
||||
}
|
||||
if( !isFootprintEditor && aItem->GetParent() && aItem->GetParent()->Type() == PCB_FOOTPRINT_T )
|
||||
return aItem->GetParent()->GetParentGroup();
|
||||
else
|
||||
{
|
||||
if( aItem->GetParent() && aItem->GetParent()->Type() == PCB_FOOTPRINT_T )
|
||||
group = aItem->GetParent()->GetParentGroup();
|
||||
else
|
||||
group = aItem->GetParentGroup();
|
||||
}
|
||||
return aItem->GetParentGroup();
|
||||
}
|
||||
|
||||
|
||||
/// Returns the top level group inside the aScope group, or nullptr
|
||||
PCB_GROUP* getNestedGroup( BOARD_ITEM* aItem, PCB_GROUP* aScope, bool isFootprintEditor )
|
||||
{
|
||||
PCB_GROUP* group = getClosestGroup( aItem, isFootprintEditor );
|
||||
|
||||
if( group == aScope )
|
||||
return nullptr;
|
||||
|
||||
while( group && group->GetParentGroup() && group->GetParentGroup() != aScope )
|
||||
{
|
||||
@@ -97,19 +102,23 @@ PCB_GROUP* getTopLevelGroup( BOARD_ITEM* aItem, PCB_GROUP* aScope, bool isFootpr
|
||||
return group;
|
||||
}
|
||||
|
||||
|
||||
PCB_GROUP* PCB_GROUP::TopLevelGroup( BOARD_ITEM* aItem, PCB_GROUP* aScope, bool isFootprintEditor )
|
||||
{
|
||||
PCB_GROUP* candidate = getTopLevelGroup( aItem, aScope, isFootprintEditor );
|
||||
|
||||
return candidate == aScope ? nullptr : candidate;
|
||||
return getNestedGroup( aItem, aScope, isFootprintEditor );
|
||||
}
|
||||
|
||||
|
||||
bool PCB_GROUP::WithinScope( BOARD_ITEM* aItem, PCB_GROUP* aScope, bool isFootprintEditor )
|
||||
{
|
||||
PCB_GROUP* candidate = getTopLevelGroup( aItem, aScope, isFootprintEditor );
|
||||
PCB_GROUP* group = getClosestGroup( aItem, isFootprintEditor );
|
||||
|
||||
return candidate == aScope;
|
||||
if( group && group == aScope )
|
||||
return true;
|
||||
|
||||
PCB_GROUP* nested = getNestedGroup( aItem, aScope, isFootprintEditor );
|
||||
|
||||
return nested && nested->GetParentGroup() && nested->GetParentGroup() == aScope;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1247,6 +1247,9 @@ void PCB_PAINTER::draw( const PAD* aPad, int aLayer )
|
||||
{
|
||||
const SHAPE_SIMPLE* poly = static_cast<const SHAPE_SIMPLE*>( shape );
|
||||
|
||||
if( poly->PointCount() < 2 ) // Careful of empty pads
|
||||
break;
|
||||
|
||||
if( margin.x < 0 ) // The poly shape must be deflated
|
||||
{
|
||||
int numSegs = GetArcToSegmentCount( -margin.x, m_maxError, 360.0 );
|
||||
@@ -1347,7 +1350,9 @@ void PCB_PAINTER::draw( const PAD* aPad, int aLayer )
|
||||
// Use ERROR_INSIDE because it avoids Clipper and is therefore much faster.
|
||||
aPad->TransformShapeWithClearanceToPolygon( polySet, ToLAYER_ID( aLayer ),
|
||||
clearance, m_maxError, ERROR_INSIDE );
|
||||
m_gal->DrawPolygon( polySet );
|
||||
|
||||
if( polySet.Outline( 0 ).PointCount() > 2 ) // Careful of empty pads
|
||||
m_gal->DrawPolygon( polySet );
|
||||
}
|
||||
}
|
||||
else if( aPad->GetEffectiveHoleShape() && clearance > 0 )
|
||||
|
||||
+1
-1
@@ -53,7 +53,7 @@ PCB_TEXT::~PCB_TEXT()
|
||||
}
|
||||
|
||||
|
||||
wxString PCB_TEXT::GetShownText( int aDepth ) const
|
||||
wxString PCB_TEXT::GetShownText( int aDepth, bool aAllowExtraText ) const
|
||||
{
|
||||
BOARD* board = dynamic_cast<BOARD*>( GetParent() );
|
||||
|
||||
|
||||
+1
-1
@@ -62,7 +62,7 @@ public:
|
||||
return false;
|
||||
}
|
||||
|
||||
wxString GetShownText( int aDepth = 0 ) const override;
|
||||
wxString GetShownText( int aDepth = 0, bool aAllowExtraText = true ) const override;
|
||||
|
||||
/// PCB_TEXTs are always visible:
|
||||
void SetVisible( bool aVisible ) override { /* do nothing */}
|
||||
|
||||
@@ -1013,12 +1013,7 @@ std::shared_ptr<SHAPE> PCB_VIA::GetEffectiveShape( PCB_LAYER_ID aLayer, FLASHING
|
||||
}
|
||||
else
|
||||
{
|
||||
int radius = GetDrillValue() / 2;
|
||||
|
||||
if( GetBoard() )
|
||||
radius += GetBoard()->GetDesignSettings().GetHolePlatingThickness();
|
||||
|
||||
return std::make_shared<SHAPE_CIRCLE>( m_Start, radius );
|
||||
return std::make_shared<SHAPE_CIRCLE>( m_Start, GetDrillValue() / 2 );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4500,10 +4500,14 @@ PAD* PCB_PARSER::parsePAD( FOOTPRINT* aParent )
|
||||
if( !pad->GetRemoveUnconnected() )
|
||||
pad->SetKeepTopBottom( true );
|
||||
|
||||
// Zero-sized pads are not really selectable and likely cause crashes.
|
||||
// They are not supported by KiCad and are removed on loading
|
||||
// Zero-sized pads are likely algorithmically unsafe.
|
||||
if( pad->GetSizeX() <= 0 || pad->GetSizeY() <= 0 )
|
||||
return nullptr;
|
||||
{
|
||||
pad->SetSize( wxSize( IU_PER_MM * 0.001, IU_PER_MM * 0.001 ) );
|
||||
|
||||
wxLogWarning( wxT( "Invalid zero-sized pad pinned to 1µm in\nfile: %s\nline: %d\noffset: %d" ),
|
||||
CurSource(), CurLineNumber(), CurOffset() );
|
||||
}
|
||||
|
||||
return pad.release();
|
||||
}
|
||||
|
||||
@@ -266,6 +266,15 @@ void DRAGGER::SetMode( int aMode )
|
||||
}
|
||||
|
||||
|
||||
const std::vector<int> DRAGGER::CurrentNets() const
|
||||
{
|
||||
if( m_mode == PNS::DM_VIA )
|
||||
return std::vector<int>( 1, m_draggedVia.net );
|
||||
else
|
||||
return std::vector<int>( 1, m_draggedLine.Net() );
|
||||
}
|
||||
|
||||
|
||||
bool DRAGGER::dragMarkObstacles( const VECTOR2I& aP )
|
||||
{
|
||||
// fixme: rewrite using shared_ptr...
|
||||
|
||||
@@ -88,10 +88,7 @@ public:
|
||||
*
|
||||
* Returns the net code(s) of currently routed track(s).
|
||||
*/
|
||||
const std::vector<int> CurrentNets() const override
|
||||
{
|
||||
return std::vector<int>( 1, m_draggedLine.Net() );
|
||||
}
|
||||
const std::vector<int> CurrentNets() const override;
|
||||
|
||||
/**
|
||||
* Function CurrentLayer()
|
||||
|
||||
@@ -51,6 +51,10 @@ bool ITEM::collideSimple( const ITEM* aOther, const NODE* aNode, bool aDifferent
|
||||
if( aDifferentNetsOnly && m_net == aOther->m_net && m_net >= 0 && aOther->m_net >= 0 )
|
||||
return false;
|
||||
|
||||
// a pad associated with a "free" pin (NIC) doesn't have a net until it has been used
|
||||
if( aDifferentNetsOnly && ( IsFreePad() || aOther->IsFreePad() ) )
|
||||
return false;
|
||||
|
||||
// check if we are not on completely different layers first
|
||||
if( !m_layers.Overlaps( aOther->m_layers ) )
|
||||
return false;
|
||||
|
||||
@@ -81,6 +81,7 @@ public:
|
||||
m_rank = -1;
|
||||
m_routable = true;
|
||||
m_isVirtual = false;
|
||||
m_isFreePad = false;
|
||||
m_isCompoundShapePrimitive = false;
|
||||
}
|
||||
|
||||
@@ -96,6 +97,7 @@ public:
|
||||
m_rank = aOther.m_rank;
|
||||
m_routable = aOther.m_routable;
|
||||
m_isVirtual = aOther.m_isVirtual;
|
||||
m_isFreePad = aOther.m_isFreePad;
|
||||
m_isCompoundShapePrimitive = aOther.m_isCompoundShapePrimitive;
|
||||
}
|
||||
|
||||
@@ -232,6 +234,9 @@ public:
|
||||
void SetRoutable( bool aRoutable ) { m_routable = aRoutable; }
|
||||
bool IsRoutable() const { return m_routable; }
|
||||
|
||||
void SetIsFreePad( bool aIsFreePad = true ) { m_isFreePad = aIsFreePad; }
|
||||
bool IsFreePad() const { return m_isFreePad; }
|
||||
|
||||
bool IsVirtual() const
|
||||
{
|
||||
return m_isVirtual;
|
||||
@@ -256,6 +261,7 @@ protected:
|
||||
int m_rank;
|
||||
bool m_routable;
|
||||
bool m_isVirtual;
|
||||
bool m_isFreePad;
|
||||
bool m_isCompoundShapePrimitive;
|
||||
};
|
||||
|
||||
|
||||
@@ -251,7 +251,7 @@ bool PNS_PCBNEW_RULE_RESOLVER::QueryConstraint( PNS::CONSTRAINT_TYPE aType,
|
||||
|
||||
if( parentA )
|
||||
{
|
||||
parentA->SetLayer( (PCB_LAYER_ID) aLayer );
|
||||
parentA->SetLayer( ToLAYER_ID( aLayer ) );
|
||||
static_cast<BOARD_CONNECTED_ITEM*>( parentA )->SetNetCode( aItemA->Net(), true );
|
||||
}
|
||||
}
|
||||
@@ -269,13 +269,13 @@ bool PNS_PCBNEW_RULE_RESOLVER::QueryConstraint( PNS::CONSTRAINT_TYPE aType,
|
||||
|
||||
if( parentB )
|
||||
{
|
||||
parentB->SetLayer( (PCB_LAYER_ID) aLayer );
|
||||
parentB->SetLayer( ToLAYER_ID( aLayer ) );
|
||||
static_cast<BOARD_CONNECTED_ITEM*>( parentB )->SetNetCode( aItemB->Net(), true );
|
||||
}
|
||||
}
|
||||
|
||||
if( parentA )
|
||||
hostConstraint = drcEngine->EvalRules( hostType, parentA, parentB, (PCB_LAYER_ID) aLayer );
|
||||
hostConstraint = drcEngine->EvalRules( hostType, parentA, parentB, ToLAYER_ID( aLayer ) );
|
||||
|
||||
if( hostConstraint.IsNull() )
|
||||
return false;
|
||||
@@ -318,26 +318,39 @@ int PNS_PCBNEW_RULE_RESOLVER::Clearance( const PNS::ITEM* aA, const PNS::ITEM* a
|
||||
return it->second;
|
||||
|
||||
PNS::CONSTRAINT constraint;
|
||||
int rv = 0;
|
||||
int layer;
|
||||
int rv = 0;
|
||||
LAYER_RANGE layers;
|
||||
|
||||
if( !aA->Layers().IsMultilayer() || !aB || aB->Layers().IsMultilayer() )
|
||||
layer = aA->Layer();
|
||||
if( !aB )
|
||||
layers = aA->Layers();
|
||||
else if( isEdge( aA ) )
|
||||
layers = aB->Layers();
|
||||
else if( isEdge( aB ) )
|
||||
layers = aA->Layers();
|
||||
else
|
||||
layer = aB->Layer();
|
||||
layers = aA->Layers().Intersection( aB->Layers() );
|
||||
|
||||
if( isCopper( aA ) && ( !aB || isCopper( aB ) ) )
|
||||
{
|
||||
if( QueryConstraint( PNS::CONSTRAINT_TYPE::CT_CLEARANCE, aA, aB, layer, &constraint ) )
|
||||
rv = constraint.m_Value.Min();
|
||||
}
|
||||
// Normalize layer range (no -1 magic numbers)
|
||||
layers = layers.Intersection( LAYER_RANGE( PCBNEW_LAYER_ID_START, PCB_LAYER_ID_COUNT - 1 ) );
|
||||
|
||||
if( isEdge( aA ) || ( aB && isEdge( aB ) ) )
|
||||
for( int layer = layers.Start(); layer <= layers.End(); ++layer )
|
||||
{
|
||||
if( QueryConstraint( PNS::CONSTRAINT_TYPE::CT_EDGE_CLEARANCE, aA, aB, layer, &constraint ) )
|
||||
if( isCopper( aA ) && ( !aB || isCopper( aB ) ) )
|
||||
{
|
||||
if( constraint.m_Value.Min() > rv )
|
||||
rv = constraint.m_Value.Min();
|
||||
if( QueryConstraint( PNS::CONSTRAINT_TYPE::CT_CLEARANCE, aA, aB, layer, &constraint ) )
|
||||
{
|
||||
if( constraint.m_Value.Min() > rv )
|
||||
rv = constraint.m_Value.Min();
|
||||
}
|
||||
}
|
||||
|
||||
if( isEdge( aA ) || ( aB && isEdge( aB ) ) )
|
||||
{
|
||||
if( QueryConstraint( PNS::CONSTRAINT_TYPE::CT_EDGE_CLEARANCE, aA, aB, layer, &constraint ) )
|
||||
{
|
||||
if( constraint.m_Value.Min() > rv )
|
||||
rv = constraint.m_Value.Min();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -533,8 +546,8 @@ bool PNS_KICAD_IFACE_BASE::ImportSizes( PNS::SIZES_SETTINGS& aSizes, PNS::ITEM*
|
||||
viaDiameter = std::max( viaDiameter, constraint.m_Value.Opt() );
|
||||
}
|
||||
|
||||
if( m_ruleResolver->QueryConstraint( PNS::CONSTRAINT_TYPE::CT_VIA_HOLE, aStartItem, nullptr,
|
||||
m_startLayer, &constraint ) )
|
||||
if( m_ruleResolver->QueryConstraint( PNS::CONSTRAINT_TYPE::CT_VIA_HOLE, aStartItem,
|
||||
nullptr, m_startLayer, &constraint ) )
|
||||
{
|
||||
viaDrill = std::max( viaDrill, constraint.m_Value.Opt() );
|
||||
}
|
||||
@@ -947,6 +960,9 @@ std::unique_ptr<PNS::SOLID> PNS_KICAD_IFACE_BASE::syncPad( PAD* aPad )
|
||||
solid->SetPadToDie( aPad->GetPadToDieLength() );
|
||||
solid->SetOrientation( aPad->GetOrientation() );
|
||||
|
||||
if( aPad->IsFreePad() )
|
||||
solid->SetIsFreePad();
|
||||
|
||||
wxPoint wx_c = aPad->ShapePos();
|
||||
wxPoint offset = aPad->GetOffset();
|
||||
|
||||
@@ -964,13 +980,16 @@ std::unique_ptr<PNS::SOLID> PNS_KICAD_IFACE_BASE::syncPad( PAD* aPad )
|
||||
if( aPad->GetAttribute() != PAD_ATTRIB::NPTH )
|
||||
{
|
||||
BOARD_DESIGN_SETTINGS& bds = m_board->GetDesignSettings();
|
||||
slot->SetWidth( slot->GetWidth() + bds.GetHolePlatingThickness() * 2 );
|
||||
slot->SetWidth( slot->GetWidth() );
|
||||
}
|
||||
|
||||
solid->SetHole( slot );
|
||||
}
|
||||
|
||||
std::shared_ptr<SHAPE> shape = aPad->GetEffectiveShape();
|
||||
// We generate a single SOLID for a pad, so we have to treat it as ALWAYS_FLASHED and then
|
||||
// perform layer-specific flashing tests internally.
|
||||
std::shared_ptr<SHAPE> shape = aPad->GetEffectiveShape( UNDEFINED_LAYER,
|
||||
FLASHING::ALWAYS_FLASHED );
|
||||
|
||||
if( shape->HasIndexableSubshapes() && shape->GetIndexableSubshapeCount() == 1 )
|
||||
{
|
||||
@@ -1041,7 +1060,7 @@ std::unique_ptr<PNS::VIA> PNS_KICAD_IFACE_BASE::syncVia( PCB_VIA* aVia )
|
||||
|
||||
BOARD_DESIGN_SETTINGS& bds = m_board->GetDesignSettings();
|
||||
via->SetHole( SHAPE_CIRCLE( aVia->GetPosition(),
|
||||
aVia->GetDrillValue() / 2 + bds.GetHolePlatingThickness() ) );
|
||||
aVia->GetDrillValue() / 2 ) );
|
||||
|
||||
return via;
|
||||
}
|
||||
@@ -1254,14 +1273,14 @@ bool PNS_KICAD_IFACE::IsFlashedOnLayer( const PNS::ITEM* aItem, int aLayer ) con
|
||||
{
|
||||
const PCB_VIA* via = static_cast<const PCB_VIA*>( aItem->Parent() );
|
||||
|
||||
return via->FlashLayer( static_cast<PCB_LAYER_ID>( aLayer ) );
|
||||
return via->FlashLayer( ToLAYER_ID( aLayer ) );
|
||||
}
|
||||
|
||||
case PCB_PAD_T:
|
||||
{
|
||||
const PAD* pad = static_cast<const PAD*>( aItem->Parent() );
|
||||
|
||||
return pad->FlashLayer( static_cast<PCB_LAYER_ID>( aLayer ) );
|
||||
return pad->FlashLayer( ToLAYER_ID( aLayer ) );
|
||||
}
|
||||
|
||||
default:
|
||||
|
||||
@@ -105,6 +105,22 @@ public:
|
||||
m_end = aOther.m_end;
|
||||
}
|
||||
|
||||
LAYER_RANGE Intersection( const LAYER_RANGE& aOther ) const
|
||||
{
|
||||
LAYER_RANGE overlap;
|
||||
|
||||
overlap.m_start = std::max( m_start, aOther.m_start );
|
||||
|
||||
if( m_end < 0 )
|
||||
overlap.m_end = aOther.m_end;
|
||||
else if( aOther.m_end < 0 )
|
||||
overlap.m_end = m_end;
|
||||
else
|
||||
overlap.m_end = std::min( m_end, aOther.m_end );
|
||||
|
||||
return overlap;
|
||||
}
|
||||
|
||||
///< Shortcut for comparisons/overlap tests
|
||||
static LAYER_RANGE All()
|
||||
{
|
||||
|
||||
@@ -134,13 +134,14 @@ ITEM* TOOL_BASE::pickSingleItem( const VECTOR2I& aWhere, int aNet, int aLayer, b
|
||||
//if( item->Parent() && !item->Parent()->ViewIsVisible() )
|
||||
// continue;
|
||||
|
||||
if( aNet <= 0 || item->Net() == aNet )
|
||||
if( item->OfKind( ITEM::SOLID_T ) && aIgnorePads )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
else if( aNet <= 0 || item->Net() == aNet )
|
||||
{
|
||||
if( item->OfKind( ITEM::VIA_T | ITEM::SOLID_T ) )
|
||||
{
|
||||
if( item->OfKind( ITEM::SOLID_T ) && aIgnorePads )
|
||||
continue;
|
||||
|
||||
SEG::ecoord d = ( item->Shape()->Centre() - aWhere ).SquaredEuclideanNorm();
|
||||
|
||||
if( d < dist[2] )
|
||||
@@ -174,12 +175,18 @@ ITEM* TOOL_BASE::pickSingleItem( const VECTOR2I& aWhere, int aNet, int aLayer, b
|
||||
}
|
||||
}
|
||||
}
|
||||
else if( item->OfKind( ITEM::SOLID_T ) && item->IsFreePad() )
|
||||
{
|
||||
// Allow free pads only when already inside pad
|
||||
if( item->Shape()->Collide( aWhere ) )
|
||||
{
|
||||
prioritized[0] = item;
|
||||
dist[0] = 0;
|
||||
}
|
||||
}
|
||||
else if ( item->Net() == 0 && m_router->Settings().Mode() == RM_MarkObstacles )
|
||||
{
|
||||
// Allow unconnected items as last resort in RM_MarkObstacles mode
|
||||
if( item->OfKind( ITEM::SOLID_T ) && aIgnorePads )
|
||||
continue;
|
||||
|
||||
if( item->Layers().Overlaps( tl ) )
|
||||
prioritized[4] = item;
|
||||
}
|
||||
|
||||
+100
-12
@@ -49,6 +49,7 @@ using namespace std::placeholders;
|
||||
#include <tools/pcb_actions.h>
|
||||
#include <tools/pcb_selection_tool.h>
|
||||
#include <tools/pcb_grid_helper.h>
|
||||
#include <string_utils.h>
|
||||
|
||||
#include "router_tool.h"
|
||||
#include "pns_segment.h"
|
||||
@@ -170,7 +171,8 @@ static const TOOL_ACTION ACT_SwitchCornerMode( "pcbnew.InteractiveRouter.SwitchR
|
||||
|
||||
ROUTER_TOOL::ROUTER_TOOL() :
|
||||
TOOL_BASE( "pcbnew.InteractiveRouter" ),
|
||||
m_lastTargetLayer( UNDEFINED_LAYER )
|
||||
m_lastTargetLayer( UNDEFINED_LAYER ),
|
||||
m_inRouterTool( false )
|
||||
{
|
||||
}
|
||||
|
||||
@@ -615,6 +617,54 @@ void ROUTER_TOOL::switchLayerOnViaPlacement()
|
||||
|
||||
m_router->SwitchLayer( *newLayer );
|
||||
m_lastTargetLayer = *newLayer;
|
||||
|
||||
updateSizesAfterLayerSwitch( ToLAYER_ID( *newLayer ) );
|
||||
}
|
||||
|
||||
|
||||
void ROUTER_TOOL::updateSizesAfterLayerSwitch( PCB_LAYER_ID targetLayer )
|
||||
{
|
||||
std::vector<int> nets = m_router->GetCurrentNets();
|
||||
|
||||
PNS::SIZES_SETTINGS sizes = m_router->Sizes();
|
||||
BOARD_DESIGN_SETTINGS& bds = board()->GetDesignSettings();
|
||||
std::shared_ptr<DRC_ENGINE>& drcEngine = bds.m_DRCEngine;
|
||||
DRC_CONSTRAINT constraint;
|
||||
|
||||
PCB_TRACK dummyTrack( board() );
|
||||
dummyTrack.SetLayer( targetLayer );
|
||||
dummyTrack.SetNetCode( nets.empty() ? 0 : nets[0] );
|
||||
|
||||
if( bds.UseNetClassTrack() || !sizes.TrackWidthIsExplicit() )
|
||||
{
|
||||
constraint = drcEngine->EvalRules( TRACK_WIDTH_CONSTRAINT, &dummyTrack, nullptr,
|
||||
targetLayer );
|
||||
|
||||
if( !constraint.IsNull() )
|
||||
sizes.SetTrackWidth( std::max( bds.m_TrackMinWidth, constraint.m_Value.Opt() ) );
|
||||
}
|
||||
|
||||
if( nets.size() >= 2 && ( bds.UseNetClassDiffPair() || !sizes.TrackWidthIsExplicit() ) )
|
||||
{
|
||||
PCB_TRACK dummyTrackB( board() );
|
||||
dummyTrackB.SetLayer( targetLayer );
|
||||
dummyTrackB.SetNetCode( nets[1] );
|
||||
|
||||
constraint = drcEngine->EvalRules( TRACK_WIDTH_CONSTRAINT, &dummyTrack, &dummyTrackB,
|
||||
targetLayer );
|
||||
|
||||
if( !constraint.IsNull() )
|
||||
sizes.SetDiffPairWidth( std::max( bds.m_TrackMinWidth, constraint.m_Value.Opt() ) );
|
||||
|
||||
constraint = drcEngine->EvalRules( DIFF_PAIR_GAP_CONSTRAINT, &dummyTrack, &dummyTrackB,
|
||||
targetLayer );
|
||||
|
||||
if( !constraint.IsNull() )
|
||||
sizes.SetDiffPairGap( std::max( bds.m_MinClearance, constraint.m_Value.Opt() ) );
|
||||
}
|
||||
|
||||
m_router->UpdateSizes( sizes );
|
||||
frame()->UpdateMsgPanel();
|
||||
}
|
||||
|
||||
|
||||
@@ -782,6 +832,7 @@ int ROUTER_TOOL::handleLayerSwitch( const TOOL_EVENT& aEvent, bool aForceVia )
|
||||
|
||||
if( !aForceVia && m_router && m_router->SwitchLayer( targetLayer ) )
|
||||
{
|
||||
updateSizesAfterLayerSwitch( targetLayer );
|
||||
updateEndItem( aEvent );
|
||||
m_router->Move( m_endSnapPoint, m_endItem ); // refresh
|
||||
return 0;
|
||||
@@ -1348,6 +1399,11 @@ void ROUTER_TOOL::breakTrack()
|
||||
|
||||
int ROUTER_TOOL::MainLoop( const TOOL_EVENT& aEvent )
|
||||
{
|
||||
if( m_inRouterTool )
|
||||
return 0;
|
||||
|
||||
REENTRANCY_GUARD guard( &m_inRouterTool );
|
||||
|
||||
PNS::ROUTER_MODE mode = aEvent.Parameter<PNS::ROUTER_MODE>();
|
||||
PCB_EDIT_FRAME* frame = getEditFrame<PCB_EDIT_FRAME>();
|
||||
VIEW_CONTROLS* controls = getViewControls();
|
||||
@@ -1459,6 +1515,7 @@ int ROUTER_TOOL::MainLoop( const TOOL_EVENT& aEvent )
|
||||
else if( evt->IsAction( &PCB_ACTIONS::layerChanged ) )
|
||||
{
|
||||
m_router->SwitchLayer( frame->GetActiveLayer() );
|
||||
updateSizesAfterLayerSwitch( frame->GetActiveLayer() );
|
||||
updateStartItem( *evt );
|
||||
}
|
||||
else if( evt->IsKeyPressed() )
|
||||
@@ -1705,10 +1762,10 @@ int ROUTER_TOOL::InlineDrag( const TOOL_EVENT& aEvent )
|
||||
item->SetLocked( false );
|
||||
}
|
||||
|
||||
m_toolMgr->RunAction( PCB_ACTIONS::selectionClear, true );
|
||||
|
||||
Activate();
|
||||
|
||||
m_toolMgr->RunAction( PCB_ACTIONS::selectionClear, true );
|
||||
m_router->SyncWorld();
|
||||
m_startItem = nullptr;
|
||||
|
||||
PNS::ITEM* startItem = nullptr;
|
||||
@@ -1985,10 +2042,10 @@ int ROUTER_TOOL::InlineBreakTrack( const TOOL_EVENT& aEvent )
|
||||
if( item->Type() != PCB_TRACE_T )
|
||||
return 0;
|
||||
|
||||
m_toolMgr->RunAction( PCB_ACTIONS::selectionClear, true );
|
||||
|
||||
Activate();
|
||||
|
||||
m_toolMgr->RunAction( PCB_ACTIONS::selectionClear, true );
|
||||
m_router->SyncWorld();
|
||||
m_startItem = m_router->GetWorld()->FindItemByParent( item );
|
||||
|
||||
TOOL_MANAGER* toolManager = frame()->GetToolManager();
|
||||
@@ -2085,22 +2142,53 @@ void ROUTER_TOOL::UpdateMessagePanel()
|
||||
PNS::SIZES_SETTINGS sizes( m_router->Sizes() );
|
||||
PNS::RULE_RESOLVER* resolver = m_iface->GetRuleResolver();
|
||||
bool isDiffPair = m_router->Mode() == PNS::ROUTER_MODE::PNS_MODE_ROUTE_DIFF_PAIR;
|
||||
std::vector<int> nets = m_router->GetCurrentNets();
|
||||
wxString description;
|
||||
wxString secondary;
|
||||
|
||||
if( m_startItem && m_startItem->Net() > 0 )
|
||||
if( isDiffPair )
|
||||
{
|
||||
wxString description = isDiffPair ? _( "Routing Diff Pair: %s" ) : _( "Routing Track: %s" );
|
||||
wxASSERT( nets.size() >= 2 );
|
||||
|
||||
NETINFO_ITEM* netInfo = board()->FindNet( m_startItem->Net() );
|
||||
wxASSERT( netInfo );
|
||||
NETINFO_ITEM* netA = board()->FindNet( nets[0] );
|
||||
NETINFO_ITEM* netB = board()->FindNet( nets[1] );
|
||||
wxASSERT( netA );
|
||||
wxASSERT( netB );
|
||||
|
||||
items.emplace_back( wxString::Format( description, netInfo->GetNetname() ),
|
||||
wxString::Format( _( "Net Class: %s" ), netInfo->GetNetClassName() ) );
|
||||
description = wxString::Format( _( "Routing Diff Pair: %s" ),
|
||||
netA->GetNetname() + wxT( ", " ) + netB->GetNetname() );
|
||||
|
||||
wxString netclass;
|
||||
NETCLASS* netclassA = netA->GetNetClass();
|
||||
NETCLASS* netclassB = netB->GetNetClass();
|
||||
|
||||
if( netclassA == netclassB )
|
||||
netclass = netclassA->GetName();
|
||||
else
|
||||
netclass = netclassA->GetName() + wxT( ", " ) + netclassB->GetName();
|
||||
|
||||
secondary = wxString::Format( _( "Net Class: %s" ),
|
||||
UnescapeString( netclass ) );
|
||||
}
|
||||
else if( !nets.empty() )
|
||||
{
|
||||
NETINFO_ITEM* net = board()->FindNet( nets[0] );
|
||||
wxASSERT( net );
|
||||
|
||||
description = wxString::Format( _( "Routing Track: %s" ),
|
||||
net->GetNetname() );
|
||||
|
||||
secondary = wxString::Format( _( "Net Class: %s" ),
|
||||
UnescapeString( net->GetNetClass()->GetName() ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
items.emplace_back( _( "Routing Track" ), _( "(no net)" ) );
|
||||
description = _( "Routing Track" );
|
||||
secondary = _( "(no net)" );
|
||||
}
|
||||
|
||||
items.emplace_back( description, secondary );
|
||||
|
||||
wxString cornerMode;
|
||||
|
||||
if( m_router->Settings().GetFreeAngleMode() )
|
||||
|
||||
@@ -75,6 +75,7 @@ private:
|
||||
|
||||
int getStartLayer( const PNS::ITEM* aItem );
|
||||
void switchLayerOnViaPlacement();
|
||||
void updateSizesAfterLayerSwitch( PCB_LAYER_ID targetLayer );
|
||||
|
||||
int onLayerCommand( const TOOL_EVENT& aEvent );
|
||||
int onViaCommand( const TOOL_EVENT& aEvent );
|
||||
@@ -89,6 +90,8 @@ private:
|
||||
std::shared_ptr<ACTION_MENU> m_trackViaMenu;
|
||||
|
||||
int m_lastTargetLayer;
|
||||
|
||||
bool m_inRouterTool; // Re-entrancy guard
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -83,11 +83,11 @@ bool PCB_EDIT_FRAME::ImportSpecctraSession( const wxString& fullFileName )
|
||||
return false;
|
||||
}
|
||||
|
||||
OnModify();
|
||||
|
||||
GetBoard()->GetConnectivity()->Clear();
|
||||
GetBoard()->GetConnectivity()->Build( GetBoard() );
|
||||
|
||||
OnModify();
|
||||
|
||||
if( GetCanvas() ) // Update view:
|
||||
{
|
||||
// Update footprint positions
|
||||
|
||||
@@ -2376,7 +2376,7 @@ int DRAWING_TOOL::DrawVia( const TOOL_EVENT& aEvent )
|
||||
{
|
||||
BOARD_ITEM* item = static_cast<BOARD_ITEM*>( it.first );
|
||||
|
||||
if( !(item->GetLayerSet() & lset ).any() )
|
||||
if( !( item->GetLayerSet() & lset ).any() )
|
||||
continue;
|
||||
|
||||
if( PCB_TRACK* track = dyn_cast<PCB_TRACK*>( item ) )
|
||||
@@ -2412,25 +2412,26 @@ int DRAWING_TOOL::DrawVia( const TOOL_EVENT& aEvent )
|
||||
if( DRC_ENGINE::IsNetTie( aOther ) )
|
||||
return false;
|
||||
|
||||
DRC_CONSTRAINT constraint;
|
||||
DRC_CONSTRAINT constraint;
|
||||
int clearance;
|
||||
BOARD_CONNECTED_ITEM* connectedItem = dynamic_cast<BOARD_CONNECTED_ITEM*>( aOther );
|
||||
ZONE* zone = dynamic_cast<ZONE*>( aOther );
|
||||
|
||||
if( ( aOther->Type() == PCB_ZONE_T || aOther->Type() == PCB_FP_ZONE_T )
|
||||
&& static_cast<ZONE*>( aOther )->GetIsRuleArea() )
|
||||
if( zone && zone->GetIsRuleArea() )
|
||||
{
|
||||
ZONE* ruleArea = static_cast<ZONE*>( aOther );
|
||||
|
||||
if( ruleArea->GetDoNotAllowVias() )
|
||||
return ruleArea->Outline()->Collide( aVia->GetPosition(), aVia->GetWidth() / 2 );
|
||||
if( zone->GetDoNotAllowVias() )
|
||||
return zone->Outline()->Collide( aVia->GetPosition(), aVia->GetWidth() / 2 );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
BOARD_CONNECTED_ITEM* cItem = dynamic_cast<BOARD_CONNECTED_ITEM*>( aOther );
|
||||
if( connectedItem )
|
||||
{
|
||||
int connectedItemNet = connectedItem->GetNetCode();
|
||||
|
||||
if( cItem && cItem->GetNetCode() == aVia->GetNetCode() )
|
||||
return false;
|
||||
|
||||
int clearance;
|
||||
if( connectedItemNet == 0 || connectedItemNet == aVia->GetNetCode() )
|
||||
return false;
|
||||
}
|
||||
|
||||
for( PCB_LAYER_ID layer : aOther->GetLayerSet().Seq() )
|
||||
{
|
||||
@@ -2576,7 +2577,7 @@ int DRAWING_TOOL::DrawVia( const TOOL_EVENT& aEvent )
|
||||
{
|
||||
for( ZONE* z : m_board->Zones() )
|
||||
{
|
||||
if( z->IsOnLayer( m_frame->GetActiveLayer() ) )
|
||||
if( z->IsOnLayer( layer ) )
|
||||
{
|
||||
if( z->HitTestFilledArea( layer, position ) )
|
||||
return z->GetNetCode();
|
||||
|
||||
+137
-93
@@ -290,20 +290,49 @@ int EDIT_TOOL::Drag( const TOOL_EVENT& aEvent )
|
||||
sTool->FilterCollectorForFreePads( aCollector );
|
||||
sTool->FilterCollectorForHierarchy( aCollector, true );
|
||||
|
||||
// drop a knee between two segments to a single segment
|
||||
if( aCollector.GetCount() == 2 && dynamic_cast<PCB_TRACK*>( aCollector[0] ) )
|
||||
if( aCollector.GetCount() > 1 )
|
||||
sTool->GuessSelectionCandidates( aCollector, aPt );
|
||||
|
||||
/*
|
||||
* If we have a knee between two segments, or a via attached to two segments,
|
||||
* then drop the selection to a single item.
|
||||
*/
|
||||
|
||||
std::vector<PCB_TRACK*> tracks;
|
||||
std::vector<PCB_TRACK*> vias;
|
||||
|
||||
for( EDA_ITEM* item : aCollector )
|
||||
{
|
||||
static KICAD_T types[] = { PCB_VIA_T, PCB_TRACE_T, PCB_ARC_T, EOT };
|
||||
if( PCB_TRACK* track = dynamic_cast<PCB_TRACK*>( item ) )
|
||||
{
|
||||
if( track->Type() == PCB_VIA_T )
|
||||
vias.push_back( track );
|
||||
else
|
||||
tracks.push_back( track );
|
||||
}
|
||||
}
|
||||
|
||||
PCB_TRACK* a = static_cast<PCB_TRACK*>( aCollector[0] );
|
||||
PCB_TRACK* b = static_cast<PCB_TRACK*>( aCollector[1] );
|
||||
const auto& c = aCollector[0]->GetBoard()->GetConnectivity();
|
||||
auto connected = []( PCB_TRACK* track, const wxPoint& pt )
|
||||
{
|
||||
return track->GetStart() == pt || track->GetEnd() == pt;
|
||||
};
|
||||
|
||||
int dist = a->GetWidth() / 2;
|
||||
auto connectedItems = c->GetConnectedItemsAtAnchor( a, aPt, types, dist );
|
||||
|
||||
if( alg::contains( connectedItems, b ) )
|
||||
aCollector.Remove( b );
|
||||
if( tracks.size() == 2 && vias.size() == 0 )
|
||||
{
|
||||
if( connected( tracks[0], tracks[1]->GetStart() )
|
||||
|| connected( tracks[0], tracks[1]->GetEnd() ) )
|
||||
{
|
||||
aCollector.Remove( tracks[1] );
|
||||
}
|
||||
}
|
||||
else if( tracks.size() == 2 && vias.size() == 1 )
|
||||
{
|
||||
if( connected( tracks[0], vias[0]->GetPosition() )
|
||||
&& connected( tracks[1], vias[0]->GetPosition() ) )
|
||||
{
|
||||
aCollector.Remove( tracks[0] );
|
||||
aCollector.Remove( tracks[1] );
|
||||
}
|
||||
}
|
||||
},
|
||||
true /* prompt user regarding locked items */ );
|
||||
@@ -703,7 +732,7 @@ int EDIT_TOOL::MoveWithReference( const TOOL_EVENT& aEvent )
|
||||
|
||||
// Note: aEvent MUST NOT be const&; the source will get de-allocated if we go into the picker's
|
||||
// event loop.
|
||||
int EDIT_TOOL::doMoveSelection( TOOL_EVENT aEvent, bool aPickReference )
|
||||
int EDIT_TOOL::doMoveSelection( TOOL_EVENT aEvent, bool aPickReference, bool aReselect )
|
||||
{
|
||||
PCB_BASE_EDIT_FRAME* editFrame = getEditFrame<PCB_BASE_EDIT_FRAME>();
|
||||
KIGFX::VIEW_CONTROLS* controls = getViewControls();
|
||||
@@ -1082,6 +1111,15 @@ int EDIT_TOOL::doMoveSelection( TOOL_EVENT aEvent, bool aPickReference )
|
||||
// Discard reference point when selection is "dropped" onto the board
|
||||
selection.ClearReferencePoint();
|
||||
|
||||
// Unselect all items to clear selection flags and then re-select the originally selected
|
||||
// items.
|
||||
m_toolMgr->RunAction( PCB_ACTIONS::selectionClear, true );
|
||||
|
||||
// In the case where the original items are temporary, we don't want to reselect
|
||||
// as the items may be invalidated by the Revert above
|
||||
if( !restore_state || aReselect )
|
||||
m_toolMgr->RunAction( PCB_ACTIONS::selectItems, true, &orig_items );
|
||||
|
||||
// TODO: there's an encapsulation leak here: this commit often has more than just the move
|
||||
// in it; for instance it might have a paste, append board, etc. as well.
|
||||
if( restore_state )
|
||||
@@ -1092,11 +1130,6 @@ int EDIT_TOOL::doMoveSelection( TOOL_EVENT aEvent, bool aPickReference )
|
||||
// Remove the dynamic ratsnest from the screen
|
||||
m_toolMgr->RunAction( PCB_ACTIONS::hideDynamicRatsnest, true );
|
||||
|
||||
// Unselect all items to clear selection flags and then re-select the originally selected
|
||||
// items.
|
||||
m_toolMgr->RunAction( PCB_ACTIONS::selectionClear, true );
|
||||
m_toolMgr->RunAction( PCB_ACTIONS::selectItems, true, &orig_items );
|
||||
|
||||
editFrame->PopTool( tool );
|
||||
editFrame->GetCanvas()->SetCurrentCursor( KICURSOR::ARROW );
|
||||
|
||||
@@ -1760,82 +1793,12 @@ int EDIT_TOOL::Flip( const TOOL_EVENT& aEvent )
|
||||
}
|
||||
|
||||
|
||||
int EDIT_TOOL::Remove( const TOOL_EVENT& aEvent )
|
||||
void EDIT_TOOL::DeleteItems( const PCB_SELECTION& aItems, bool aIsCut )
|
||||
{
|
||||
PCB_BASE_EDIT_FRAME* editFrame = getEditFrame<PCB_BASE_EDIT_FRAME>();
|
||||
|
||||
if( isRouterActive() )
|
||||
{
|
||||
m_toolMgr->RunAction( PCB_ACTIONS::routerUndoLastSegment, true );
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::string tool = aEvent.GetCommandStr().value();
|
||||
editFrame->PushTool( tool );
|
||||
|
||||
std::vector<BOARD_ITEM*> lockedItems;
|
||||
Activate();
|
||||
|
||||
// get a copy instead of reference (as we're going to clear the selection before removing items)
|
||||
PCB_SELECTION selectionCopy;
|
||||
bool isCut = aEvent.Parameter<PCB_ACTIONS::REMOVE_FLAGS>() == PCB_ACTIONS::REMOVE_FLAGS::CUT;
|
||||
bool isAlt = aEvent.Parameter<PCB_ACTIONS::REMOVE_FLAGS>() == PCB_ACTIONS::REMOVE_FLAGS::ALT;
|
||||
|
||||
// If we are in a "Cut" operation, then the copied selection exists already and we want to
|
||||
// delete exactly that; no more, no fewer. Any filtering for locked items must be done in
|
||||
// the copyToClipboard() routine.
|
||||
if( isCut )
|
||||
{
|
||||
selectionCopy = m_selectionTool->GetSelection();
|
||||
}
|
||||
else
|
||||
{
|
||||
// When not in free-pad mode we normally auto-promote selected pads to their parent
|
||||
// footprints. But this is probably a little too dangerous for a destructive operation,
|
||||
// so we just do the promotion but not the deletion (allowing for a second delete to do
|
||||
// it if that's what the user wanted).
|
||||
selectionCopy = m_selectionTool->RequestSelection(
|
||||
[]( const VECTOR2I& aPt, GENERAL_COLLECTOR& aCollector, PCB_SELECTION_TOOL* sTool )
|
||||
{
|
||||
} );
|
||||
|
||||
size_t beforeFPCount = selectionCopy.CountType( PCB_FOOTPRINT_T );
|
||||
|
||||
m_selectionTool->RequestSelection(
|
||||
[]( const VECTOR2I& aPt, GENERAL_COLLECTOR& aCollector, PCB_SELECTION_TOOL* sTool )
|
||||
{
|
||||
sTool->FilterCollectorForFreePads( aCollector );
|
||||
} );
|
||||
|
||||
if( !selectionCopy.IsHover()
|
||||
&& m_selectionTool->GetSelection().CountType( PCB_FOOTPRINT_T ) > beforeFPCount )
|
||||
{
|
||||
wxBell();
|
||||
canvas()->Refresh();
|
||||
editFrame->PopTool( tool );
|
||||
return 0;
|
||||
}
|
||||
|
||||
// In "alternative" mode, we expand selected track items to their full connection.
|
||||
if( isAlt && ( selectionCopy.HasType( PCB_TRACE_T ) || selectionCopy.HasType( PCB_VIA_T ) ) )
|
||||
{
|
||||
m_toolMgr->RunAction( PCB_ACTIONS::selectConnection, true );
|
||||
}
|
||||
|
||||
// Finally run RequestSelection() one more time to find out what user wants to do about
|
||||
// locked objects.
|
||||
selectionCopy = m_selectionTool->RequestSelection(
|
||||
[]( const VECTOR2I& aPt, GENERAL_COLLECTOR& aCollector, PCB_SELECTION_TOOL* sTool )
|
||||
{
|
||||
sTool->FilterCollectorForFreePads( aCollector );
|
||||
},
|
||||
true /* prompt user regarding locked items */ );
|
||||
}
|
||||
|
||||
// As we are about to remove items, they have to be removed from the selection first
|
||||
m_toolMgr->RunAction( PCB_ACTIONS::selectionClear, true );
|
||||
|
||||
for( EDA_ITEM* item : selectionCopy )
|
||||
for( EDA_ITEM* item : aItems )
|
||||
{
|
||||
PCB_GROUP* parentGroup = static_cast<BOARD_ITEM*>( item )->GetParentGroup();
|
||||
|
||||
@@ -1891,7 +1854,7 @@ int EDIT_TOOL::Remove( const TOOL_EVENT& aEvent )
|
||||
// is called from inside a cutout when the zone is selected.
|
||||
{
|
||||
// Only interact with cutouts when deleting and a single item is selected
|
||||
if( !isCut && selectionCopy.GetSize() == 1 )
|
||||
if( !aIsCut && aItems.GetSize() == 1 )
|
||||
{
|
||||
VECTOR2I curPos = getViewControls()->GetCursorPosition();
|
||||
ZONE* zone = static_cast<ZONE*>( item );
|
||||
@@ -1978,10 +1941,91 @@ int EDIT_TOOL::Remove( const TOOL_EVENT& aEvent )
|
||||
if( enteredGroup && enteredGroup->GetItems().empty() )
|
||||
m_selectionTool->ExitGroup();
|
||||
|
||||
if( isCut )
|
||||
if( aIsCut )
|
||||
m_commit->Push( _( "Cut" ) );
|
||||
else
|
||||
m_commit->Push( _( "Delete" ) );
|
||||
}
|
||||
|
||||
|
||||
int EDIT_TOOL::Remove( const TOOL_EVENT& aEvent )
|
||||
{
|
||||
PCB_BASE_EDIT_FRAME* editFrame = getEditFrame<PCB_BASE_EDIT_FRAME>();
|
||||
|
||||
if( isRouterActive() )
|
||||
{
|
||||
m_toolMgr->RunAction( PCB_ACTIONS::routerUndoLastSegment, true );
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::string tool{};
|
||||
|
||||
if( aEvent.GetCommandStr() )
|
||||
{
|
||||
tool = aEvent.GetCommandStr().value();
|
||||
editFrame->PushTool( tool );
|
||||
}
|
||||
|
||||
std::vector<BOARD_ITEM*> lockedItems;
|
||||
Activate();
|
||||
|
||||
// get a copy instead of reference (as we're going to clear the selection before removing items)
|
||||
PCB_SELECTION selectionCopy;
|
||||
bool isCut = aEvent.Parameter<PCB_ACTIONS::REMOVE_FLAGS>() == PCB_ACTIONS::REMOVE_FLAGS::CUT;
|
||||
bool isAlt = aEvent.Parameter<PCB_ACTIONS::REMOVE_FLAGS>() == PCB_ACTIONS::REMOVE_FLAGS::ALT;
|
||||
|
||||
// If we are in a "Cut" operation, then the copied selection exists already and we want to
|
||||
// delete exactly that; no more, no fewer. Any filtering for locked items must be done in
|
||||
// the copyToClipboard() routine.
|
||||
if( isCut )
|
||||
{
|
||||
selectionCopy = m_selectionTool->GetSelection();
|
||||
}
|
||||
else
|
||||
{
|
||||
// When not in free-pad mode we normally auto-promote selected pads to their parent
|
||||
// footprints. But this is probably a little too dangerous for a destructive operation,
|
||||
// so we just do the promotion but not the deletion (allowing for a second delete to do
|
||||
// it if that's what the user wanted).
|
||||
selectionCopy = m_selectionTool->RequestSelection(
|
||||
[]( const VECTOR2I& aPt, GENERAL_COLLECTOR& aCollector, PCB_SELECTION_TOOL* sTool )
|
||||
{
|
||||
} );
|
||||
|
||||
size_t beforeFPCount = selectionCopy.CountType( PCB_FOOTPRINT_T );
|
||||
|
||||
m_selectionTool->RequestSelection(
|
||||
[]( const VECTOR2I& aPt, GENERAL_COLLECTOR& aCollector, PCB_SELECTION_TOOL* sTool )
|
||||
{
|
||||
sTool->FilterCollectorForFreePads( aCollector );
|
||||
} );
|
||||
|
||||
if( !selectionCopy.IsHover()
|
||||
&& m_selectionTool->GetSelection().CountType( PCB_FOOTPRINT_T ) > beforeFPCount )
|
||||
{
|
||||
wxBell();
|
||||
canvas()->Refresh();
|
||||
editFrame->PopTool( tool );
|
||||
return 0;
|
||||
}
|
||||
|
||||
// In "alternative" mode, we expand selected track items to their full connection.
|
||||
if( isAlt && ( selectionCopy.HasType( PCB_TRACE_T ) || selectionCopy.HasType( PCB_VIA_T ) ) )
|
||||
{
|
||||
m_toolMgr->RunAction( PCB_ACTIONS::selectConnection, true );
|
||||
}
|
||||
|
||||
// Finally run RequestSelection() one more time to find out what user wants to do about
|
||||
// locked objects.
|
||||
selectionCopy = m_selectionTool->RequestSelection(
|
||||
[]( const VECTOR2I& aPt, GENERAL_COLLECTOR& aCollector, PCB_SELECTION_TOOL* sTool )
|
||||
{
|
||||
sTool->FilterCollectorForFreePads( aCollector );
|
||||
},
|
||||
true /* prompt user regarding locked items */ );
|
||||
}
|
||||
|
||||
DeleteItems( selectionCopy, isCut );
|
||||
|
||||
editFrame->PopTool( tool );
|
||||
return 0;
|
||||
@@ -2220,7 +2264,7 @@ int EDIT_TOOL::Duplicate( const TOOL_EVENT& aEvent )
|
||||
// If items were duplicated, pick them up
|
||||
// this works well for "dropping" copies around and pushes the commit
|
||||
TOOL_EVENT evt = PCB_ACTIONS::move.MakeEvent();
|
||||
Move( evt );
|
||||
doMoveSelection( evt, false, false );
|
||||
|
||||
// Deslect the duplicated item if we originally started as a hover selection
|
||||
if( is_hover )
|
||||
@@ -2465,7 +2509,7 @@ int EDIT_TOOL::cutToClipboard( const TOOL_EVENT& aEvent )
|
||||
// N.B. Setting the CUT flag prevents lock filtering as we only want to delete the items
|
||||
// that were copied to the clipboard, no more, no fewer. Filtering for locked item, if
|
||||
// any will be done in the copyToClipboard() routine
|
||||
TOOL_EVENT evt( aEvent.Category(), aEvent.Action(), TOOL_ACTION_SCOPE::AS_GLOBAL );
|
||||
TOOL_EVENT evt( aEvent.Category(), aEvent.Action(), "Cut", TOOL_ACTION_SCOPE::AS_GLOBAL );
|
||||
evt.SetParameter( PCB_ACTIONS::REMOVE_FLAGS::CUT );
|
||||
Remove( evt );
|
||||
}
|
||||
|
||||
@@ -123,6 +123,8 @@ public:
|
||||
*/
|
||||
int Remove( const TOOL_EVENT& aEvent );
|
||||
|
||||
void DeleteItems( const PCB_SELECTION& aItems, bool aIsCut );
|
||||
|
||||
/**
|
||||
* Duplicate the current selection and starts a move action.
|
||||
*/
|
||||
@@ -180,7 +182,7 @@ private:
|
||||
bool invokeInlineRouter( int aDragMode );
|
||||
bool isRouterActive() const;
|
||||
|
||||
int doMoveSelection( TOOL_EVENT aEvent, bool aPickReference = false );
|
||||
int doMoveSelection( TOOL_EVENT aEvent, bool aPickReference = false, bool aReselect = true );
|
||||
|
||||
bool pickReferencePoint( const wxString& aTooltip, const wxString& aSuccessMessage,
|
||||
const wxString& aCanceledMessage, VECTOR2I& aReferencePoint );
|
||||
|
||||
@@ -59,7 +59,7 @@ void PAD_TOOL::Reset( RESET_REASON aReason )
|
||||
if( aReason == MODEL_RELOAD )
|
||||
m_lastPadNumber = wxT( "1" );
|
||||
|
||||
if( m_editPad != niluuid )
|
||||
if( board() && board()->GetItem( m_editPad ) == DELETED_BOARD_ITEM::GetInstance() )
|
||||
{
|
||||
PCB_DISPLAY_OPTIONS opts = frame()->GetDisplayOptions();
|
||||
bool highContrast = ( opts.m_ContrastModeDisplay != HIGH_CONTRAST_MODE::NORMAL );
|
||||
@@ -68,9 +68,9 @@ void PAD_TOOL::Reset( RESET_REASON aReason )
|
||||
m_toolMgr->RunAction( ACTIONS::highContrastMode, true );
|
||||
|
||||
frame()->GetInfoBar()->Dismiss();
|
||||
}
|
||||
|
||||
m_editPad = niluuid;
|
||||
m_editPad = niluuid;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -591,8 +591,13 @@ int PCB_CONTROL::DeleteItemCursor( const TOOL_EVENT& aEvent )
|
||||
|
||||
PCB_SELECTION_TOOL* selectionTool = m_toolMgr->GetTool<PCB_SELECTION_TOOL>();
|
||||
selectionTool->UnbrightenItem( m_pickerItem );
|
||||
selectionTool->AddItemToSel( m_pickerItem, true /*quiet mode*/ );
|
||||
m_toolMgr->RunAction( ACTIONS::doDelete, true );
|
||||
|
||||
PCB_SELECTION items;
|
||||
items.Add( m_pickerItem );
|
||||
|
||||
EDIT_TOOL* editTool = m_toolMgr->GetTool<EDIT_TOOL>();
|
||||
editTool->DeleteItems( items, false );
|
||||
|
||||
m_pickerItem = nullptr;
|
||||
}
|
||||
|
||||
@@ -724,6 +729,79 @@ static void pasteFootprintItemsToFootprintEditor( FOOTPRINT* aClipFootprint, BOA
|
||||
}
|
||||
|
||||
|
||||
void PCB_CONTROL::pruneItemLayers( std::vector<BOARD_ITEM*>& aItems )
|
||||
{
|
||||
LSET enabledLayers = board()->GetEnabledLayers();
|
||||
std::vector<BOARD_ITEM*> returnItems;
|
||||
bool fpItemDeleted = false;
|
||||
|
||||
auto processFPItem =
|
||||
[&]( FOOTPRINT* aFootprint, BOARD_ITEM* aItem )
|
||||
{
|
||||
LSET allowed = aItem->GetLayerSet() & enabledLayers;
|
||||
|
||||
if( allowed.any() )
|
||||
{
|
||||
aItem->SetLayerSet( allowed );
|
||||
}
|
||||
else
|
||||
{
|
||||
aFootprint->Remove( aItem );
|
||||
fpItemDeleted = true;
|
||||
}
|
||||
};
|
||||
|
||||
for( BOARD_ITEM* item : aItems )
|
||||
{
|
||||
if( item->Type() == PCB_FOOTPRINT_T )
|
||||
{
|
||||
FOOTPRINT* fp = static_cast<FOOTPRINT*>( item );
|
||||
|
||||
if( !enabledLayers.test( fp->Reference().GetLayer() ) )
|
||||
fp->Reference().SetLayer( fp->IsFlipped() ? B_SilkS : F_SilkS );
|
||||
|
||||
if( !enabledLayers.test( fp->Value().GetLayer() ) )
|
||||
fp->Value().SetLayer( fp->IsFlipped() ? B_Fab : F_Fab );
|
||||
|
||||
// NOTE: all traversals from the back as processFPItem() might delete the item
|
||||
|
||||
for( int ii = static_cast<int>( fp->Pads().size() ) - 1; ii >= 0; ii-- )
|
||||
processFPItem( fp, fp->Pads()[ii] );
|
||||
|
||||
for( int ii = static_cast<int>( fp->Zones().size() ) - 1; ii >= 0; ii-- )
|
||||
processFPItem( fp, fp->Zones()[ii] );
|
||||
|
||||
for( int ii = static_cast<int>( fp->GraphicalItems().size() ) - 1; ii >= 0; ii-- )
|
||||
processFPItem( fp, fp->GraphicalItems()[ii] );
|
||||
|
||||
if( fp->GraphicalItems().size() || fp->Pads().size() || fp->Zones().size() )
|
||||
returnItems.push_back( fp );
|
||||
}
|
||||
else
|
||||
{
|
||||
LSET allowed = item->GetLayerSet() & enabledLayers;
|
||||
|
||||
if( allowed.any() )
|
||||
{
|
||||
item->SetLayerSet( allowed );
|
||||
returnItems.push_back( item );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( ( returnItems.size() < aItems.size() ) || fpItemDeleted )
|
||||
{
|
||||
// We have no existing strings in 6.0 that are even remotely appropriate here, so the
|
||||
// best we can do is show the user English and let them use Google Translate.
|
||||
DisplayError( m_frame, wxT( "Warning: some pasted items were on layers which are not "
|
||||
"present in the current board.\n"
|
||||
"These items could not be pasted.\n" ) );
|
||||
}
|
||||
|
||||
aItems = returnItems;
|
||||
}
|
||||
|
||||
|
||||
int PCB_CONTROL::Paste( const TOOL_EVENT& aEvent )
|
||||
{
|
||||
CLIPBOARD_IO pi;
|
||||
@@ -813,6 +891,8 @@ int PCB_CONTROL::Paste( const TOOL_EVENT& aEvent )
|
||||
|
||||
delete clipBoard;
|
||||
|
||||
pruneItemLayers( pastedItems );
|
||||
|
||||
placeBoardItems( pastedItems, true, true,
|
||||
pasteMode == PASTE_MODE::UNIQUE_ANNOTATIONS );
|
||||
}
|
||||
@@ -859,6 +939,8 @@ int PCB_CONTROL::Paste( const TOOL_EVENT& aEvent )
|
||||
pastedItems.push_back( clipFootprint );
|
||||
}
|
||||
|
||||
pruneItemLayers( pastedItems );
|
||||
|
||||
placeBoardItems( pastedItems, true, true, pasteMode == PASTE_MODE::UNIQUE_ANNOTATIONS );
|
||||
break;
|
||||
}
|
||||
@@ -974,6 +1056,8 @@ int PCB_CONTROL::placeBoardItems( BOARD* aBoard, bool aAnchorAtOrigin, bool aRea
|
||||
// selection created aBoard that has the group and all descendants in it.
|
||||
moveUnflaggedItems( aBoard->Groups(), items, isNew );
|
||||
|
||||
pruneItemLayers( items );
|
||||
|
||||
return placeBoardItems( items, isNew, aAnchorAtOrigin, aReannotateDuplicates );
|
||||
}
|
||||
|
||||
|
||||
@@ -109,6 +109,12 @@ private:
|
||||
*/
|
||||
void unfilledZoneCheck();
|
||||
|
||||
/**
|
||||
* Helper for pasting. Remove non-enabled layers from the items in \a aItems. If an item
|
||||
* exists only on non-enabled layers, it will be removed entirely.
|
||||
*/
|
||||
void pruneItemLayers( std::vector<BOARD_ITEM*>& aItems );
|
||||
|
||||
/**
|
||||
* Add and select or just select for move/place command a list of board items.
|
||||
*
|
||||
|
||||
@@ -27,8 +27,6 @@
|
||||
#include "pcb_actions.h"
|
||||
#include "pcb_grid_helper.h"
|
||||
#include <view/view_controls.h>
|
||||
#include <tool/tool_manager.h>
|
||||
#include "pcb_selection_tool.h"
|
||||
|
||||
|
||||
PCB_PICKER_TOOL::PCB_PICKER_TOOL() :
|
||||
@@ -57,6 +55,7 @@ int PCB_PICKER_TOOL::Main( const TOOL_EVENT& aEvent )
|
||||
[&]()
|
||||
{
|
||||
frame->GetCanvas()->SetCurrentCursor( m_cursor );
|
||||
controls->ShowCursor( true );
|
||||
};
|
||||
|
||||
// Set initial cursor
|
||||
@@ -168,6 +167,7 @@ int PCB_PICKER_TOOL::Main( const TOOL_EVENT& aEvent )
|
||||
|
||||
reset();
|
||||
controls->ForceCursorPosition( false );
|
||||
controls->ShowCursor( false );
|
||||
|
||||
if( !tool.empty() )
|
||||
frame->PopTool( tool );
|
||||
|
||||
@@ -522,8 +522,11 @@ PCB_SELECTION& PCB_SELECTION_TOOL::RequestSelection( CLIENT_SELECTION_FILTER aCl
|
||||
enum DISPOSITION { BEFORE = 1, AFTER, BOTH };
|
||||
|
||||
std::map<EDA_ITEM*, DISPOSITION> itemDispositions;
|
||||
GENERAL_COLLECTORS_GUIDE guide = getCollectorsGuide();
|
||||
GENERAL_COLLECTOR collector;
|
||||
|
||||
collector.SetGuide( &guide );
|
||||
|
||||
for( EDA_ITEM* item : m_selection )
|
||||
{
|
||||
collector.Append( item );
|
||||
@@ -2312,7 +2315,7 @@ void PCB_SELECTION_TOOL::highlightInternal( BOARD_ITEM* aItem, int aMode, bool a
|
||||
else if( aMode == BRIGHTENED )
|
||||
aItem->SetBrightened();
|
||||
|
||||
if( aUsingOverlay )
|
||||
if( aUsingOverlay && aMode != BRIGHTENED )
|
||||
view()->Hide( aItem, true ); // Hide the original item, so it is shown only on overlay
|
||||
|
||||
if( aItem->Type() == PCB_FOOTPRINT_T )
|
||||
@@ -2355,7 +2358,7 @@ void PCB_SELECTION_TOOL::unhighlightInternal( BOARD_ITEM* aItem, int aMode, bool
|
||||
else if( aMode == BRIGHTENED )
|
||||
aItem->ClearBrightened();
|
||||
|
||||
if( aUsingOverlay )
|
||||
if( aUsingOverlay && aMode != BRIGHTENED )
|
||||
view()->Hide( aItem, false ); // // Restore original item visibility
|
||||
|
||||
if( aItem->Type() == PCB_FOOTPRINT_T )
|
||||
@@ -2700,28 +2703,26 @@ void PCB_SELECTION_TOOL::FilterCollectorForHierarchy( GENERAL_COLLECTOR& aCollec
|
||||
if( !m_isFootprintEditor && parent && parent->Type() == PCB_FOOTPRINT_T )
|
||||
start = parent;
|
||||
|
||||
// If a group is entered, disallow selections of objects outside the group.
|
||||
if( m_enteredGroup && !PCB_GROUP::WithinScope( item, m_enteredGroup, m_isFootprintEditor ) )
|
||||
{
|
||||
aCollector.Remove( item );
|
||||
continue;
|
||||
}
|
||||
|
||||
// If any element is a member of a group, replace those elements with the top containing
|
||||
// group.
|
||||
PCB_GROUP* aTop = PCB_GROUP::TopLevelGroup( start, m_enteredGroup, m_isFootprintEditor );
|
||||
|
||||
if( aTop )
|
||||
if( PCB_GROUP* top = PCB_GROUP::TopLevelGroup( start, m_enteredGroup, m_isFootprintEditor ) )
|
||||
{
|
||||
if( aTop != item )
|
||||
if( top != item )
|
||||
{
|
||||
toAdd.insert( aTop );
|
||||
aTop->SetFlags( TEMP_SELECTED );
|
||||
toAdd.insert( top );
|
||||
top->SetFlags(CANDIDATE );
|
||||
|
||||
aCollector.Remove( item );
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else if( m_enteredGroup
|
||||
&& !PCB_GROUP::WithinScope( item, m_enteredGroup, m_isFootprintEditor ) )
|
||||
{
|
||||
// If a group is entered, disallow selections of objects outside the group.
|
||||
aCollector.Remove( item );
|
||||
continue;
|
||||
}
|
||||
|
||||
// Footprints are a bit easier as they can't be nested.
|
||||
if( parent && ( parent->GetFlags() & TEMP_SELECTED ) )
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user