Compare commits

...

21 Commits

Author SHA1 Message Date
Dhineshkumar S
2f06ffa279 Merge branch 'feature-revert-all-settings-defaults-7273' into 'master'
Add option to restore the default settings on startup.

Closes #7273

See merge request kicad/code/kicad!2079
2025-09-11 19:19:34 +00:00
Jeff Young
18b56539a6 Keep Board Setup in front when called from DRC dialog. 2025-09-11 15:47:13 +01:00
Jeff Young
9b006c4f3b Formatting. 2025-09-11 15:47:13 +01:00
Jeff Young
8035a66152 Flag non-compiling rule conditions when running DRC.
Also, clear custom rules after an error before
trying to reload just implicit rules.
2025-09-11 15:47:13 +01:00
jean-pierre charras
45166bf5c3 Gerbview: fix broken behavior for deprecated command IPPOS and IPNEG
Fixes https://gitlab.com/kicad/code/kicad/-/issues/21715
2025-09-11 14:30:50 +02:00
Jeff Young
6ab6283e2e LIBEVAL::CONTEXT manages its own local VALUEs.
Don't use std::unique_ptr as we'll just free the
value right after storing it.

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

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

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

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

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

Fixes https://gitlab.com/kicad/code/kicad/-/issues/21696
2025-09-10 18:10:43 +02:00
Dhinesh
13cd170f5a Add options for startup key handling
Implements resetting default settings on startup.

Fixes https://gitlab.com/kicad/code/kicad/-/issues/7273
2025-01-07 12:27:21 -08:00
396 changed files with 36083 additions and 10128 deletions

View File

@ -277,7 +277,7 @@ void RENDER_3D_RAYTRACE_BASE::renderTracing( uint8_t* ptrPBO, REPORTER* aStatusR
BS::multi_future<void> futures; BS::multi_future<void> futures;
for( size_t i = 0; i < tp.get_thread_count(); ++i ) for( size_t i = 0; i < tp.get_thread_count(); ++i )
futures.push_back( tp.submit( processBlocks ) ); futures.push_back( tp.submit_task( processBlocks ) );
futures.wait(); futures.wait();

View File

@ -214,6 +214,7 @@ set( KICOMMON_SRCS
trace_helpers.cpp trace_helpers.cpp
wildcards_and_files_ext.cpp wildcards_and_files_ext.cpp
wx_filename.cpp wx_filename.cpp
startup_key_handler.cpp
singleton.cpp singleton.cpp
pgm_base.cpp pgm_base.cpp

View File

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

View File

@ -1059,9 +1059,13 @@ std::vector<wxWindow*> EDA_DRAW_FRAME::findDialogs()
} }
void EDA_DRAW_FRAME::FocusOnLocation( const VECTOR2I& aPos ) void EDA_DRAW_FRAME::FocusOnLocation( const VECTOR2I& aPos, bool aAllowScroll )
{ {
bool centerView = false; bool centerView = false;
std::vector<BOX2D> dialogScreenRects;
if( aAllowScroll )
{
BOX2D r = GetCanvas()->GetView()->GetViewport(); BOX2D r = GetCanvas()->GetView()->GetViewport();
// Center if we're off the current view, or within 10% of its edge // Center if we're off the current view, or within 10% of its edge
@ -1070,8 +1074,6 @@ void EDA_DRAW_FRAME::FocusOnLocation( const VECTOR2I& aPos )
if( !r.Contains( aPos ) ) if( !r.Contains( aPos ) )
centerView = true; centerView = true;
std::vector<BOX2D> dialogScreenRects;
for( wxWindow* dialog : findDialogs() ) for( wxWindow* dialog : findDialogs() )
{ {
dialogScreenRects.emplace_back( ToVECTOR2D( GetCanvas()->ScreenToClient( dialog->GetScreenPosition() ) ), dialogScreenRects.emplace_back( ToVECTOR2D( GetCanvas()->ScreenToClient( dialog->GetScreenPosition() ) ),
@ -1086,6 +1088,7 @@ void EDA_DRAW_FRAME::FocusOnLocation( const VECTOR2I& aPos )
if( rect.Contains( GetCanvas()->GetView()->ToScreen( aPos ) ) ) if( rect.Contains( GetCanvas()->GetView()->ToScreen( aPos ) ) )
centerView = true; centerView = true;
} }
}
if( centerView ) if( centerView )
{ {

View File

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

View File

@ -1160,7 +1160,9 @@ void UOP::Exec( CONTEXT* ctx )
return; return;
case TR_OP_METHOD_CALL: case TR_OP_METHOD_CALL:
if( m_func )
m_func( ctx, m_ref.get() ); m_func( ctx, m_ref.get() );
return; return;
default: default:
@ -1321,9 +1323,8 @@ VALUE* UCODE::Run( CONTEXT* ctx )
} }
catch(...) catch(...)
{ {
// rules which fail outright should not be fired // rules which fail outright should not be fired; return 0/false
std::unique_ptr<VALUE> temp_false = std::make_unique<VALUE>( 0 ); return ctx->StoreValue( new VALUE( 0 ) );
return ctx->StoreValue( temp_false.get() );
} }
if( ctx->SP() == 1 ) if( ctx->SP() == 1 )
@ -1339,8 +1340,7 @@ VALUE* UCODE::Run( CONTEXT* ctx )
wxASSERT( ctx->SP() == 1 ); wxASSERT( ctx->SP() == 1 );
// non-well-formed rules should not be fired on a release build // non-well-formed rules should not be fired on a release build
std::unique_ptr<VALUE> temp_false = std::make_unique<VALUE>( 0 ); return ctx->StoreValue( new VALUE( 0 ) );
return ctx->StoreValue( temp_false.get() );
} }
} }

View File

@ -0,0 +1,120 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright The KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <functional>
#include <startup_key_handler.h>
#include <wx/msgdlg.h>
#include <gestfich.h>
#include <paths.h>
#include <confirm.h>
StartupKeyHandler::StartupKeyHandler()
{
//Setup Keys and required actions to perform
m_keyActions[{ WXK_CONTROL }] = { KEY_ACTION::RESET_TO_FACTORY_DEFAULTS };
}
StartupKeyHandler::~StartupKeyHandler()
{
m_keyActions.clear();
}
void StartupKeyHandler::CheckStartupKeys()
{
for( const auto& [keySequence, actions] : m_keyActions )
{
// We can request multiple combinations of modifying keys
if( std::all_of( keySequence.begin(), keySequence.end(),
[]( wxKeyCode keyCode )
{
return isKeyActionRequested( keyCode );
} ) )
{
performKeyActions( actions );
}
}
}
bool StartupKeyHandler::isKeyActionRequested( wxKeyCode aKeyCode )
{
return wxGetKeyState( aKeyCode );
}
void StartupKeyHandler::performKeyActions( const std::vector<KEY_ACTION>& aActions )
{
for( const KEY_ACTION& action : aActions )
{
switch( action )
{
case KEY_ACTION::RESET_TO_FACTORY_DEFAULTS:
resetToFactoryDefaults();
break;
default: break;
}
}
}
void StartupKeyHandler::resetToFactoryDefaults()
{
wxString errors;
if( IsOK( nullptr, _( "Reset settings to default?" ) ) )
{
wxString sourcePath = PATHS::GetUserSettingsPath();
wxString destPath = sourcePath + ".backup";
// Remove existing backup if exists
if( !RmDirRecursive( destPath, &errors ) )
{
if( !errors.empty() )
{
DisplayErrorMessage( nullptr, errors );
return;
}
}
// Create backup before deleting
if( !CopyDirectory( sourcePath, destPath, errors ) )
{
if( !errors.empty() )
{
DisplayErrorMessage( nullptr, errors );
return;
}
}
//delete
if( !RmDirRecursive( sourcePath, &errors ) )
{
if( !errors.empty() )
{
DisplayErrorMessage( nullptr, errors );
return;
}
}
}
}

View File

@ -158,6 +158,43 @@ TOOL_DISPATCHER::~TOOL_DISPATCHER()
delete st; delete st;
} }
int TOOL_DISPATCHER::decodeModifiers( const wxKeyboardState* aState )
{
int mods = 0;
int wxmods = aState->GetModifiers();
// Returns the state of key modifiers (Alt, Ctrl and so on). Be carefull:
// the flag wxMOD_ALTGR is defined in wxWidgets as wxMOD_CONTROL|wxMOD_ALT
// So AltGr key cannot used as modifier key because it is the same as Alt key + Ctrl key.
#if CAN_USE_ALTGR_KEY
if( wxmods & wxMOD_ALTGR )
mods |= MD_ALTGR;
else
#endif
{
if( wxmods & wxMOD_CONTROL )
mods |= MD_CTRL;
if( wxmods & wxMOD_ALT )
mods |= MD_ALT;
}
if( wxmods & wxMOD_SHIFT )
mods |= MD_SHIFT;
#ifdef wxMOD_META
if( wxmods & wxMOD_META )
mods |= MD_META;
#endif
#ifdef wxMOD_WIN
if( wxmods & wxMOD_WIN )
mods |= MD_SUPER;
#endif
return mods;
}
void TOOL_DISPATCHER::ResetState() void TOOL_DISPATCHER::ResetState()
{ {

View File

@ -642,9 +642,13 @@ void LIB_TREE::onQueryCharHook( wxKeyEvent& aKeyStroke )
int mods = aKeyStroke.GetModifiers(); int mods = aKeyStroke.GetModifiers();
if( mods & wxMOD_ALTGR ) // the flag wxMOD_ALTGR is defined in wxWidgets as wxMOD_CONTROL|wxMOD_ALT
hotkey += MD_ALTGR; // So AltGr key cannot used as modifier key because it is the same as Alt key + Ctrl key.
#if CAN_USE_ALTGR_KEY
if( wxmods & wxMOD_ALTGR )
mods |= MD_ALTGR;
else else
#endif
{ {
if( mods & wxMOD_CONTROL ) if( mods & wxMOD_CONTROL )
hotkey += MD_CTRL; hotkey += MD_CTRL;

View File

@ -670,7 +670,7 @@ long WIDGET_HOTKEY_LIST::MapKeypressToKeycode( const wxKeyEvent& aEvent )
{ {
long key = aEvent.GetKeyCode(); long key = aEvent.GetKeyCode();
bool is_tab = aEvent.IsKeyInCategory( WXK_CATEGORY_TAB ); bool is_tab = aEvent.IsKeyInCategory( WXK_CATEGORY_TAB );
printf("key %lX mod %X\n", key, aEvent.GetModifiers());
if( key == WXK_ESCAPE ) if( key == WXK_ESCAPE )
{ {
return 0; return 0;
@ -698,9 +698,13 @@ long WIDGET_HOTKEY_LIST::MapKeypressToKeycode( const wxKeyEvent& aEvent )
if( ( mods & wxMOD_SHIFT ) && ( keyIsLetter || key > 256 || key == 9 || key == 32 ) ) if( ( mods & wxMOD_SHIFT ) && ( keyIsLetter || key > 256 || key == 9 || key == 32 ) )
key |= MD_SHIFT; key |= MD_SHIFT;
if( mods & wxMOD_ALTGR ) // the flag wxMOD_ALTGR is defined in wxWidgets as wxMOD_CONTROL|wxMOD_ALT
key |= MD_ALTGR; // So AltGr key cannot used as modifier key because it is the same as Alt key + Ctrl key.
#if CAN_USE_ALTGR_KEY
if( wxmods & wxMOD_ALTGR )
mods |= MD_ALTGR;
else else
#endif
{ {
if( mods & wxMOD_CONTROL ) if( mods & wxMOD_CONTROL )
key |= MD_CTRL; key |= MD_CTRL;

View File

@ -1614,10 +1614,9 @@ void CONNECTION_GRAPH::resolveAllDrivers()
thread_pool& tp = GetKiCadThreadPool(); thread_pool& tp = GetKiCadThreadPool();
auto results = tp.parallelize_loop( dirty_graphs.size(), auto results = tp.submit_loop( 0, dirty_graphs.size(),
[&]( const int a, const int b) [&]( const int ii )
{ {
for( int ii = a; ii < b; ++ii )
update_lambda( dirty_graphs[ii] ); update_lambda( dirty_graphs[ii] );
}); });
results.wait(); results.wait();
@ -2257,10 +2256,9 @@ void CONNECTION_GRAPH::buildConnectionGraph( std::function<void( SCH_ITEM* )>* a
thread_pool& tp = GetKiCadThreadPool(); thread_pool& tp = GetKiCadThreadPool();
auto results = tp.parallelize_loop( m_driver_subgraphs.size(), auto results = tp.submit_loop( 0, m_driver_subgraphs.size(),
[&]( const int a, const int b) [&]( const int ii )
{ {
for( int ii = a; ii < b; ++ii )
m_driver_subgraphs[ii]->UpdateItemConnections(); m_driver_subgraphs[ii]->UpdateItemConnections();
}); });
@ -2464,12 +2462,11 @@ void CONNECTION_GRAPH::buildConnectionGraph( std::function<void( SCH_ITEM* )>* a
return 1; return 1;
}; };
auto results2 = tp.parallelize_loop( m_driver_subgraphs.size(), auto results2 = tp.submit_loop( 0, m_driver_subgraphs.size(),
[&]( const int a, const int b) [&]( const int ii )
{ {
for( int ii = a; ii < b; ++ii )
updateItemConnectionsTask( m_driver_subgraphs[ii] ); updateItemConnectionsTask( m_driver_subgraphs[ii] );
}); } );
results2.wait(); results2.wait();
m_net_code_to_subgraphs_map.clear(); m_net_code_to_subgraphs_map.clear();

View File

@ -42,6 +42,7 @@
#include <id.h> #include <id.h>
#include <confirm.h> #include <confirm.h>
#include <widgets/wx_html_report_box.h> #include <widgets/wx_html_report_box.h>
#include <widgets/std_bitmap_button.h>
#include <dialogs/dialog_text_entry.h> #include <dialogs/dialog_text_entry.h>
#include <string_utils.h> #include <string_utils.h>
#include <kiplatform/ui.h> #include <kiplatform/ui.h>
@ -76,15 +77,15 @@ DIALOG_ERC::DIALOG_ERC( SCH_EDIT_FRAME* parent ) :
m_running( false ), m_running( false ),
m_ercRun( false ), m_ercRun( false ),
m_centerMarkerOnIdle( nullptr ), m_centerMarkerOnIdle( nullptr ),
m_severities( 0 ) m_crossprobe( true ),
m_scroll_on_crossprobe( true )
{ {
m_currentSchematic = &parent->Schematic(); m_currentSchematic = &parent->Schematic();
SetName( DIALOG_ERC_WINDOW_NAME ); // Set a window name to be able to find it SetName( DIALOG_ERC_WINDOW_NAME ); // Set a window name to be able to find it
KIPLATFORM::UI::SetFloatLevel( this ); KIPLATFORM::UI::SetFloatLevel( this );
if( EESCHEMA_SETTINGS* cfg = GetAppSettings<EESCHEMA_SETTINGS>( "eeschema" ) ) m_bMenu->SetBitmap( KiBitmapBundle( BITMAPS::config ) );
m_severities = cfg->m_Appearance.erc_severities;
m_messages->SetImmediateMode(); m_messages->SetImmediateMode();
@ -92,7 +93,7 @@ DIALOG_ERC::DIALOG_ERC( SCH_EDIT_FRAME* parent ) :
m_markerTreeModel = new ERC_TREE_MODEL( parent, m_markerDataView ); m_markerTreeModel = new ERC_TREE_MODEL( parent, m_markerDataView );
m_markerDataView->AssociateModel( m_markerTreeModel ); m_markerDataView->AssociateModel( m_markerTreeModel );
m_markerTreeModel->Update( m_markerProvider, m_severities ); m_markerTreeModel->Update( m_markerProvider, getSeverities() );
m_ignoredList->InsertColumn( 0, wxEmptyString, wxLIST_FORMAT_LEFT, DEFAULT_SINGLE_COL_WIDTH ); m_ignoredList->InsertColumn( 0, wxEmptyString, wxLIST_FORMAT_LEFT, DEFAULT_SINGLE_COL_WIDTH );
@ -129,8 +130,11 @@ DIALOG_ERC::DIALOG_ERC( SCH_EDIT_FRAME* parent ) :
SetFocus(); SetFocus();
syncCheckboxes(); if( EESCHEMA_SETTINGS* cfg = GetAppSettings<EESCHEMA_SETTINGS>( "eeschema" ) )
updateDisplayedCounts(); {
m_crossprobe = cfg->m_ERCDialog.crossprobe;
m_scroll_on_crossprobe = cfg->m_ERCDialog.scroll_on_crossprobe;
}
// Now all widgets have the size fixed, call FinishDialogSettings // Now all widgets have the size fixed, call FinishDialogSettings
finishDialogSettings(); finishDialogSettings();
@ -148,7 +152,10 @@ DIALOG_ERC::~DIALOG_ERC()
g_lastERCIgnored.push_back( { m_ignoredList->GetItemText( ii ), m_ignoredList->GetItemData( ii ) } ); g_lastERCIgnored.push_back( { m_ignoredList->GetItemText( ii ), m_ignoredList->GetItemData( ii ) } );
if( EESCHEMA_SETTINGS* cfg = GetAppSettings<EESCHEMA_SETTINGS>( "eeschema" ) ) if( EESCHEMA_SETTINGS* cfg = GetAppSettings<EESCHEMA_SETTINGS>( "eeschema" ) )
cfg->m_Appearance.erc_severities = m_severities; {
cfg->m_ERCDialog.crossprobe = m_crossprobe;
cfg->m_ERCDialog.scroll_on_crossprobe = m_scroll_on_crossprobe;
}
m_markerTreeModel->DecRef(); m_markerTreeModel->DecRef();
} }
@ -189,6 +196,59 @@ void DIALOG_ERC::UpdateAnnotationWarning()
} }
int DIALOG_ERC::getSeverities()
{
int severities = 0;
if( m_showErrors->GetValue() )
severities |= RPT_SEVERITY_ERROR;
if( m_showWarnings->GetValue() )
severities |= RPT_SEVERITY_WARNING;
if( m_showExclusions->GetValue() )
severities |= RPT_SEVERITY_EXCLUSION;
return severities;
}
void DIALOG_ERC::OnMenu( wxCommandEvent& event )
{
// Build a pop menu:
wxMenu menu;
menu.Append( 4206, _( "Cross-probe Selected Items" ),
_( "Highlight corresponding items on canvas when selected in the ERC list" ),
wxITEM_CHECK );
menu.Check( 4206, m_crossprobe );
menu.Append( 4207, _( "Center on Cross-probe" ),
_( "When cross-probing, scroll the canvas so that the item is visible" ),
wxITEM_CHECK );
menu.Check( 4207, m_scroll_on_crossprobe );
// menu_id is the selected submenu id from the popup menu or wxID_NONE
int menu_id = m_bMenu->GetPopupMenuSelectionFromUser( menu );
if( menu_id == 0 || menu_id == 4206 )
{
m_crossprobe = !m_crossprobe;
}
else if( menu_id == 1 || menu_id == 4207 )
{
m_scroll_on_crossprobe = !m_scroll_on_crossprobe;
}
}
bool DIALOG_ERC::TransferDataToWindow()
{
UpdateData();
return true;
}
bool DIALOG_ERC::updateUI() bool DIALOG_ERC::updateUI()
{ {
// If ERC checks ever get slow enough we'll want a progress indicator... // If ERC checks ever get slow enough we'll want a progress indicator...
@ -217,6 +277,13 @@ void DIALOG_ERC::Report( const wxString& aMessage )
} }
void DIALOG_ERC::UpdateData()
{
m_markerTreeModel->Update( m_markerProvider, getSeverities() );
updateDisplayedCounts();
}
void DIALOG_ERC::updateDisplayedCounts() void DIALOG_ERC::updateDisplayedCounts()
{ {
int numErrors = 0; int numErrors = 0;
@ -348,30 +415,14 @@ void DIALOG_ERC::OnCloseErcDialog( wxCloseEvent& aEvent )
// Dialog is mode-less so let the parent know that it needs to be destroyed. // Dialog is mode-less so let the parent know that it needs to be destroyed.
if( !IsModal() && !IsQuasiModal() ) if( !IsModal() && !IsQuasiModal() )
{ {
wxCommandEvent* evt = new wxCommandEvent( EDA_EVT_CLOSE_ERC_DIALOG, wxID_ANY ); if( wxWindow* parent = GetParent() )
wxQueueEvent( parent, new wxCommandEvent( EDA_EVT_CLOSE_ERC_DIALOG, wxID_ANY ) );
wxWindow* parent = GetParent();
if( parent )
wxQueueEvent( parent, evt );
} }
aEvent.Skip(); aEvent.Skip();
} }
static int RPT_SEVERITY_ALL = RPT_SEVERITY_WARNING | RPT_SEVERITY_ERROR | RPT_SEVERITY_EXCLUSION;
void DIALOG_ERC::syncCheckboxes()
{
m_showAll->SetValue( m_severities == RPT_SEVERITY_ALL );
m_showErrors->SetValue( m_severities & RPT_SEVERITY_ERROR );
m_showWarnings->SetValue( m_severities & RPT_SEVERITY_WARNING );
m_showExclusions->SetValue( m_severities & RPT_SEVERITY_EXCLUSION );
}
void DIALOG_ERC::OnLinkClicked( wxHtmlLinkEvent& event ) void DIALOG_ERC::OnLinkClicked( wxHtmlLinkEvent& event )
{ {
m_parent->OnAnnotate(); m_parent->OnAnnotate();
@ -446,8 +497,7 @@ void DIALOG_ERC::OnRunERCClick( wxCommandEvent& event )
} }
if( m_cancelled ) if( m_cancelled )
// @spellingerror m_messages->Report( _( "-------- ERC cancelled by user.<br><br>" ), RPT_SEVERITY_INFO );
m_messages->Report( _( "-------- ERC canceled by user.<br><br>" ), RPT_SEVERITY_INFO );
else else
m_messages->Report( _( "Done.<br><br>" ), RPT_SEVERITY_INFO ); m_messages->Report( _( "Done.<br><br>" ), RPT_SEVERITY_INFO );
@ -508,7 +558,7 @@ void DIALOG_ERC::testErc()
} }
// Update marker list: // Update marker list:
m_markerTreeModel->Update( m_markerProvider, m_severities ); m_markerTreeModel->Update( m_markerProvider, getSeverities() );
// Display new markers from the current screen: // Display new markers from the current screen:
for( SCH_ITEM* marker : m_parent->GetScreen()->Items().OfType( SCH_MARKER_T ) ) for( SCH_ITEM* marker : m_parent->GetScreen()->Items().OfType( SCH_MARKER_T ) )
@ -523,6 +573,12 @@ void DIALOG_ERC::testErc()
void DIALOG_ERC::OnERCItemSelected( wxDataViewEvent& aEvent ) void DIALOG_ERC::OnERCItemSelected( wxDataViewEvent& aEvent )
{ {
if( !m_crossprobe )
{
aEvent.Skip();
return;
}
const KIID& itemID = RC_TREE_MODEL::ToUUID( aEvent.GetItem() ); const KIID& itemID = RC_TREE_MODEL::ToUUID( aEvent.GetItem() );
SCH_SHEET_PATH sheet; SCH_SHEET_PATH sheet;
SCH_ITEM* item = m_parent->Schematic().ResolveItem( itemID, &sheet, true ); SCH_ITEM* item = m_parent->Schematic().ResolveItem( itemID, &sheet, true );
@ -568,7 +624,7 @@ void DIALOG_ERC::OnERCItemSelected( wxDataViewEvent& aEvent )
m_parent->RedrawScreen( m_parent->GetScreen()->m_ScrollCenter, false ); m_parent->RedrawScreen( m_parent->GetScreen()->m_ScrollCenter, false );
} }
m_parent->FocusOnItem( item ); m_parent->FocusOnItem( item, m_scroll_on_crossprobe );
redrawDrawPanel(); redrawDrawPanel();
} }
@ -762,7 +818,7 @@ void DIALOG_ERC::OnERCItemRClick( wxDataViewEvent& aEvent )
m_parent->GetCanvas()->GetView()->Update( marker ); m_parent->GetCanvas()->GetView()->Update( marker );
// Update view // Update view
if( m_severities & RPT_SEVERITY_EXCLUSION ) if( getSeverities() & RPT_SEVERITY_EXCLUSION )
static_cast<RC_TREE_MODEL*>( aEvent.GetModel() )->ValueChanged( node ); static_cast<RC_TREE_MODEL*>( aEvent.GetModel() )->ValueChanged( node );
else else
static_cast<RC_TREE_MODEL*>( aEvent.GetModel() )->DeleteCurrentItem( false ); static_cast<RC_TREE_MODEL*>( aEvent.GetModel() )->DeleteCurrentItem( false );
@ -788,7 +844,7 @@ void DIALOG_ERC::OnERCItemRClick( wxDataViewEvent& aEvent )
} }
// Rebuild model and view // Rebuild model and view
static_cast<RC_TREE_MODEL*>( aEvent.GetModel() )->Update( m_markerProvider, m_severities ); static_cast<RC_TREE_MODEL*>( aEvent.GetModel() )->Update( m_markerProvider, getSeverities() );
modified = true; modified = true;
break; break;
@ -804,7 +860,7 @@ void DIALOG_ERC::OnERCItemRClick( wxDataViewEvent& aEvent )
} }
// Rebuild model and view // Rebuild model and view
static_cast<RC_TREE_MODEL*>( aEvent.GetModel() )->Update( m_markerProvider, m_severities ); static_cast<RC_TREE_MODEL*>( aEvent.GetModel() )->Update( m_markerProvider, getSeverities() );
modified = true; modified = true;
break; break;
@ -830,7 +886,7 @@ void DIALOG_ERC::OnERCItemRClick( wxDataViewEvent& aEvent )
ScreenList.DeleteMarkers( MARKER_BASE::MARKER_ERC, rcItem->GetErrorCode() ); ScreenList.DeleteMarkers( MARKER_BASE::MARKER_ERC, rcItem->GetErrorCode() );
// Rebuild model and view // Rebuild model and view
static_cast<RC_TREE_MODEL*>( aEvent.GetModel() )->Update( m_markerProvider, m_severities ); static_cast<RC_TREE_MODEL*>( aEvent.GetModel() )->Update( m_markerProvider, getSeverities() );
modified = true; modified = true;
} }
break; break;
@ -956,7 +1012,7 @@ void DIALOG_ERC::ExcludeMarker( SCH_MARKER* aMarker )
m_parent->GetCanvas()->GetView()->Update( marker ); m_parent->GetCanvas()->GetView()->Update( marker );
// Update view // Update view
if( m_severities & RPT_SEVERITY_EXCLUSION ) if( getSeverities() & RPT_SEVERITY_EXCLUSION )
m_markerTreeModel->ValueChanged( node ); m_markerTreeModel->ValueChanged( node );
else else
m_markerTreeModel->DeleteCurrentItem( false ); m_markerTreeModel->DeleteCurrentItem( false );
@ -976,28 +1032,14 @@ void DIALOG_ERC::OnEditViolationSeverities( wxHyperlinkEvent& aEvent )
void DIALOG_ERC::OnSeverity( wxCommandEvent& aEvent ) void DIALOG_ERC::OnSeverity( wxCommandEvent& aEvent )
{ {
int flag = 0;
if( aEvent.GetEventObject() == m_showAll ) if( aEvent.GetEventObject() == m_showAll )
flag = RPT_SEVERITY_ALL; {
else if( aEvent.GetEventObject() == m_showErrors ) m_showErrors->SetValue( true );
flag = RPT_SEVERITY_ERROR; m_showWarnings->SetValue( aEvent.IsChecked() );
else if( aEvent.GetEventObject() == m_showWarnings ) m_showExclusions->SetValue( aEvent.IsChecked() );
flag = RPT_SEVERITY_WARNING; }
else if( aEvent.GetEventObject() == m_showExclusions )
flag = RPT_SEVERITY_EXCLUSION;
if( aEvent.IsChecked() ) UpdateData();
m_severities |= flag;
else if( aEvent.GetEventObject() == m_showAll )
m_severities = RPT_SEVERITY_ERROR;
else
m_severities &= ~flag;
syncCheckboxes();
m_markerTreeModel->Update( m_markerProvider, m_severities );
updateDisplayedCounts();
} }

View File

@ -49,6 +49,8 @@ public:
DIALOG_ERC( SCH_EDIT_FRAME* parent ); DIALOG_ERC( SCH_EDIT_FRAME* parent );
~DIALOG_ERC(); ~DIALOG_ERC();
bool TransferDataToWindow() override;
// PROGRESS_REPORTER_BASE calls // PROGRESS_REPORTER_BASE calls
bool updateUI() override; bool updateUI() override;
void AdvancePhase( const wxString& aMessage ) override; void AdvancePhase( const wxString& aMessage ) override;
@ -66,10 +68,14 @@ public:
*/ */
void ExcludeMarker( SCH_MARKER* aMarker = nullptr ); void ExcludeMarker( SCH_MARKER* aMarker = nullptr );
void UpdateData();
void UpdateAnnotationWarning(); void UpdateAnnotationWarning();
private: private:
int getSeverities();
// from DIALOG_ERC_BASE: // from DIALOG_ERC_BASE:
void OnMenu( wxCommandEvent& aEvent ) override;
void OnCloseErcDialog( wxCloseEvent& event ) override; void OnCloseErcDialog( wxCloseEvent& event ) override;
void OnRunERCClick( wxCommandEvent& event ) override; void OnRunERCClick( wxCommandEvent& event ) override;
void OnDeleteOneClick( wxCommandEvent& event ) override; void OnDeleteOneClick( wxCommandEvent& event ) override;
@ -92,8 +98,6 @@ private:
void testErc(); void testErc();
bool writeReport( const wxString& aFullFileName );
void deleteAllMarkers( bool aIncludeExclusions ); void deleteAllMarkers( bool aIncludeExclusions );
void syncCheckboxes(); void syncCheckboxes();
@ -114,7 +118,8 @@ private:
const SCH_MARKER* m_centerMarkerOnIdle; const SCH_MARKER* m_centerMarkerOnIdle;
int m_severities; bool m_crossprobe;
bool m_scroll_on_crossprobe;
}; };

View File

@ -5,6 +5,7 @@
// PLEASE DO *NOT* EDIT THIS FILE! // PLEASE DO *NOT* EDIT THIS FILE!
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
#include "widgets/std_bitmap_button.h"
#include "widgets/wx_html_report_box.h" #include "widgets/wx_html_report_box.h"
#include "widgets/wx_infobar.h" #include "widgets/wx_infobar.h"
@ -29,6 +30,24 @@ DIALOG_ERC_BASE::DIALOG_ERC_BASE( wxWindow* parent, wxWindowID id, const wxStrin
wxBoxSizer* bMainSizer; wxBoxSizer* bMainSizer;
bMainSizer = new wxBoxSizer( wxVERTICAL ); bMainSizer = new wxBoxSizer( wxVERTICAL );
wxGridBagSizer* gbSizerOptions;
gbSizerOptions = new wxGridBagSizer( 0, 0 );
gbSizerOptions->SetFlexibleDirection( wxBOTH );
gbSizerOptions->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED );
m_bMenu = new STD_BITMAP_BUTTON( this, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxDefaultSize, wxBU_AUTODRAW|0 );
m_bMenu->SetMinSize( wxSize( 30,30 ) );
gbSizerOptions->Add( m_bMenu, wxGBPosition( 0, 2 ), wxGBSpan( 2, 1 ), wxALIGN_CENTER_VERTICAL, 5 );
gbSizerOptions->AddGrowableCol( 0 );
gbSizerOptions->AddGrowableCol( 1 );
gbSizerOptions->AddGrowableRow( 0 );
gbSizerOptions->AddGrowableRow( 1 );
bMainSizer->Add( gbSizerOptions, 0, wxEXPAND|wxLEFT, 5 );
m_runningResultsBook = new wxSimplebook( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0 ); m_runningResultsBook = new wxSimplebook( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0 );
running = new wxPanel( m_runningResultsBook, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL ); running = new wxPanel( m_runningResultsBook, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL );
wxBoxSizer* bSizer14; wxBoxSizer* bSizer14;
@ -195,6 +214,7 @@ DIALOG_ERC_BASE::DIALOG_ERC_BASE( wxWindow* parent, wxWindowID id, const wxStrin
// Connect Events // Connect Events
this->Connect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( DIALOG_ERC_BASE::OnCloseErcDialog ) ); this->Connect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( DIALOG_ERC_BASE::OnCloseErcDialog ) );
m_bMenu->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_ERC_BASE::OnMenu ), NULL, this );
m_messages->Connect( wxEVT_COMMAND_HTML_LINK_CLICKED, wxHtmlLinkEventHandler( DIALOG_ERC_BASE::OnLinkClicked ), NULL, this ); m_messages->Connect( wxEVT_COMMAND_HTML_LINK_CLICKED, wxHtmlLinkEventHandler( DIALOG_ERC_BASE::OnLinkClicked ), NULL, this );
m_markerDataView->Connect( wxEVT_COMMAND_DATAVIEW_ITEM_ACTIVATED, wxDataViewEventHandler( DIALOG_ERC_BASE::OnERCItemDClick ), NULL, this ); m_markerDataView->Connect( wxEVT_COMMAND_DATAVIEW_ITEM_ACTIVATED, wxDataViewEventHandler( DIALOG_ERC_BASE::OnERCItemDClick ), NULL, this );
m_markerDataView->Connect( wxEVT_COMMAND_DATAVIEW_ITEM_CONTEXT_MENU, wxDataViewEventHandler( DIALOG_ERC_BASE::OnERCItemRClick ), NULL, this ); m_markerDataView->Connect( wxEVT_COMMAND_DATAVIEW_ITEM_CONTEXT_MENU, wxDataViewEventHandler( DIALOG_ERC_BASE::OnERCItemRClick ), NULL, this );
@ -216,6 +236,7 @@ DIALOG_ERC_BASE::~DIALOG_ERC_BASE()
{ {
// Disconnect Events // Disconnect Events
this->Disconnect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( DIALOG_ERC_BASE::OnCloseErcDialog ) ); this->Disconnect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( DIALOG_ERC_BASE::OnCloseErcDialog ) );
m_bMenu->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_ERC_BASE::OnMenu ), NULL, this );
m_messages->Disconnect( wxEVT_COMMAND_HTML_LINK_CLICKED, wxHtmlLinkEventHandler( DIALOG_ERC_BASE::OnLinkClicked ), NULL, this ); m_messages->Disconnect( wxEVT_COMMAND_HTML_LINK_CLICKED, wxHtmlLinkEventHandler( DIALOG_ERC_BASE::OnLinkClicked ), NULL, this );
m_markerDataView->Disconnect( wxEVT_COMMAND_DATAVIEW_ITEM_ACTIVATED, wxDataViewEventHandler( DIALOG_ERC_BASE::OnERCItemDClick ), NULL, this ); m_markerDataView->Disconnect( wxEVT_COMMAND_DATAVIEW_ITEM_ACTIVATED, wxDataViewEventHandler( DIALOG_ERC_BASE::OnERCItemDClick ), NULL, this );
m_markerDataView->Disconnect( wxEVT_COMMAND_DATAVIEW_ITEM_CONTEXT_MENU, wxDataViewEventHandler( DIALOG_ERC_BASE::OnERCItemRClick ), NULL, this ); m_markerDataView->Disconnect( wxEVT_COMMAND_DATAVIEW_ITEM_CONTEXT_MENU, wxDataViewEventHandler( DIALOG_ERC_BASE::OnERCItemRClick ), NULL, this );

View File

@ -14,7 +14,7 @@
<property name="embedded_files_path">res</property> <property name="embedded_files_path">res</property>
<property name="encoding">UTF-8</property> <property name="encoding">UTF-8</property>
<property name="file">dialog_erc_base</property> <property name="file">dialog_erc_base</property>
<property name="first_id">1000</property> <property name="first_id">7100</property>
<property name="internationalize">1</property> <property name="internationalize">1</property>
<property name="lua_skip_events">1</property> <property name="lua_skip_events">1</property>
<property name="lua_ui_table">UI</property> <property name="lua_ui_table">UI</property>
@ -135,6 +135,101 @@
<property name="name">bMainSizer</property> <property name="name">bMainSizer</property>
<property name="orient">wxVERTICAL</property> <property name="orient">wxVERTICAL</property>
<property name="permission">none</property> <property name="permission">none</property>
<object class="sizeritem" expanded="true">
<property name="border">5</property>
<property name="flag">wxEXPAND|wxLEFT</property>
<property name="proportion">0</property>
<object class="wxGridBagSizer" expanded="true">
<property name="empty_cell_size"></property>
<property name="flexible_direction">wxBOTH</property>
<property name="growablecols">0,1</property>
<property name="growablerows">0,1</property>
<property name="hgap">0</property>
<property name="minimum_size"></property>
<property name="name">gbSizerOptions</property>
<property name="non_flexible_grow_mode">wxFLEX_GROWMODE_SPECIFIED</property>
<property name="permission">none</property>
<property name="vgap">0</property>
<object class="gbsizeritem" expanded="true">
<property name="border">5</property>
<property name="colspan">1</property>
<property name="column">2</property>
<property name="flag">wxALIGN_CENTER_VERTICAL</property>
<property name="row">0</property>
<property name="rowspan">2</property>
<object class="wxBitmapButton" expanded="true">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
<property name="TopDockable">1</property>
<property name="aui_layer">0</property>
<property name="aui_name"></property>
<property name="aui_position">0</property>
<property name="aui_row">0</property>
<property name="auth_needed">0</property>
<property name="best_size"></property>
<property name="bg"></property>
<property name="bitmap"></property>
<property name="caption"></property>
<property name="caption_visible">1</property>
<property name="center_pane">0</property>
<property name="close_button">1</property>
<property name="context_help"></property>
<property name="context_menu">1</property>
<property name="current"></property>
<property name="default">0</property>
<property name="default_pane">0</property>
<property name="disabled"></property>
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="drag_accept_files">0</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
<property name="focus"></property>
<property name="font"></property>
<property name="gripper">0</property>
<property name="hidden">0</property>
<property name="id">wxID_ANY</property>
<property name="label">Refresh Grouping</property>
<property name="margins"></property>
<property name="markup">0</property>
<property name="max_size"></property>
<property name="maximize_button">0</property>
<property name="maximum_size"></property>
<property name="min_size"></property>
<property name="minimize_button">0</property>
<property name="minimum_size">30,30</property>
<property name="moveable">1</property>
<property name="name">m_bMenu</property>
<property name="pane_border">1</property>
<property name="pane_position"></property>
<property name="pane_size"></property>
<property name="permission">protected</property>
<property name="pin_button">1</property>
<property name="pos"></property>
<property name="position"></property>
<property name="pressed"></property>
<property name="resize">Resizable</property>
<property name="show">1</property>
<property name="size"></property>
<property name="style"></property>
<property name="subclass">STD_BITMAP_BUTTON; widgets/std_bitmap_button.h; forward_declare</property>
<property name="toolbar_pane">0</property>
<property name="tooltip"></property>
<property name="validator_data_type"></property>
<property name="validator_style">wxFILTER_NONE</property>
<property name="validator_type">wxDefaultValidator</property>
<property name="validator_variable"></property>
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style"></property>
<event name="OnButtonClick">OnMenu</event>
</object>
</object>
</object>
</object>
<object class="sizeritem" expanded="true"> <object class="sizeritem" expanded="true">
<property name="border">5</property> <property name="border">5</property>
<property name="flag">wxEXPAND|wxTOP|wxRIGHT</property> <property name="flag">wxEXPAND|wxTOP|wxRIGHT</property>

View File

@ -10,6 +10,7 @@
#include <wx/artprov.h> #include <wx/artprov.h>
#include <wx/xrc/xmlres.h> #include <wx/xrc/xmlres.h>
#include <wx/intl.h> #include <wx/intl.h>
class STD_BITMAP_BUTTON;
class WX_HTML_REPORT_BOX; class WX_HTML_REPORT_BOX;
class WX_INFOBAR; class WX_INFOBAR;
@ -20,13 +21,16 @@ class WX_INFOBAR;
#include <wx/colour.h> #include <wx/colour.h>
#include <wx/settings.h> #include <wx/settings.h>
#include <wx/string.h> #include <wx/string.h>
#include <wx/bmpbuttn.h>
#include <wx/bitmap.h>
#include <wx/image.h>
#include <wx/icon.h>
#include <wx/button.h>
#include <wx/gbsizer.h>
#include <wx/html/htmlwin.h> #include <wx/html/htmlwin.h>
#include <wx/gauge.h> #include <wx/gauge.h>
#include <wx/sizer.h> #include <wx/sizer.h>
#include <wx/panel.h> #include <wx/panel.h>
#include <wx/bitmap.h>
#include <wx/image.h>
#include <wx/icon.h>
#include <wx/notebook.h> #include <wx/notebook.h>
#include <wx/dataview.h> #include <wx/dataview.h>
#include <wx/listctrl.h> #include <wx/listctrl.h>
@ -35,12 +39,11 @@ class WX_INFOBAR;
#include <wx/stattext.h> #include <wx/stattext.h>
#include <wx/checkbox.h> #include <wx/checkbox.h>
#include <widgets/number_badge.h> #include <widgets/number_badge.h>
#include <wx/button.h>
#include <wx/dialog.h> #include <wx/dialog.h>
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
#define ID_ERASE_DRC_MARKERS 1000 #define ID_ERASE_DRC_MARKERS 7100
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
/// Class DIALOG_ERC_BASE /// Class DIALOG_ERC_BASE
@ -51,6 +54,7 @@ class DIALOG_ERC_BASE : public DIALOG_SHIM
protected: protected:
WX_INFOBAR* m_infoBar; WX_INFOBAR* m_infoBar;
STD_BITMAP_BUTTON* m_bMenu;
wxSimplebook* m_runningResultsBook; wxSimplebook* m_runningResultsBook;
wxPanel* running; wxPanel* running;
wxNotebook* m_runningNotebook; wxNotebook* m_runningNotebook;
@ -82,6 +86,7 @@ class DIALOG_ERC_BASE : public DIALOG_SHIM
// Virtual event handlers, override them in your derived class // Virtual event handlers, override them in your derived class
virtual void OnCloseErcDialog( wxCloseEvent& event ) { event.Skip(); } virtual void OnCloseErcDialog( wxCloseEvent& event ) { event.Skip(); }
virtual void OnMenu( wxCommandEvent& event ) { event.Skip(); }
virtual void OnLinkClicked( wxHtmlLinkEvent& event ) { event.Skip(); } virtual void OnLinkClicked( wxHtmlLinkEvent& event ) { event.Skip(); }
virtual void OnERCItemDClick( wxDataViewEvent& event ) { event.Skip(); } virtual void OnERCItemDClick( wxDataViewEvent& event ) { event.Skip(); }
virtual void OnERCItemRClick( wxDataViewEvent& event ) { event.Skip(); } virtual void OnERCItemRClick( wxDataViewEvent& event ) { event.Skip(); }

View File

@ -921,16 +921,28 @@ void DIALOG_SYMBOL_FIELDS_TABLE::OnMenu( wxCommandEvent& event )
// Build a pop menu: // Build a pop menu:
wxMenu menu; wxMenu menu;
menu.Append( 4204, _( "Include 'DNP' Symbols" ), wxEmptyString, wxITEM_CHECK ); menu.Append( 4204, _( "Include 'DNP' Symbols" ),
menu.Append( 4205, _( "Include 'Exclude from BOM' Symbols" ), wxEmptyString, wxITEM_CHECK ); _( "Show symbols marked 'DNP' in the table. This setting also controls whether or not 'DNP' "
menu.AppendSeparator(); "symbols are included on export." ),
menu.Append( 4206, _( "Highlight on Cross Probe" ), wxEmptyString, wxITEM_CHECK ); wxITEM_CHECK );
menu.Append( 4207, _( "Select on Cross Probe" ), wxEmptyString, wxITEM_CHECK );
menu.Check( 4204, !m_dataModel->GetExcludeDNP() ); menu.Check( 4204, !m_dataModel->GetExcludeDNP() );
menu.Append( 4205, _( "Include 'Exclude from BOM' Symbols" ),
_( "Show symbols marked 'Exclude from BOM' in the table. Symbols marked 'Exclude from BOM' "
"are never included on export." ),
wxITEM_CHECK );
menu.Check( 4205, m_dataModel->GetIncludeExcludedFromBOM() ); menu.Check( 4205, m_dataModel->GetIncludeExcludedFromBOM() );
menu.AppendSeparator();
menu.Append( 4206, _( "Highlight on Cross-probe" ),
_( "Highlight corresponding item on canvas when it is selected in the table" ),
wxITEM_CHECK );
menu.Check( 4206, cfg.selection_mode == 0 ); menu.Check( 4206, cfg.selection_mode == 0 );
menu.Append( 4207, _( "Select on Cross-probe" ),
_( "Select corresponding item on canvas when it is selected in the table" ),
wxITEM_CHECK );
menu.Check( 4207, cfg.selection_mode == 1 ); menu.Check( 4207, cfg.selection_mode == 1 );
// menu_id is the selected submenu id from the popup menu or wxID_NONE // menu_id is the selected submenu id from the popup menu or wxID_NONE

View File

@ -38,6 +38,7 @@
#include <lib_table_grid.h> #include <lib_table_grid.h>
#include <wildcards_and_files_ext.h> #include <wildcards_and_files_ext.h>
#include <env_paths.h> #include <env_paths.h>
#include <functional>
#include <eeschema_id.h> #include <eeschema_id.h>
#include <symbol_edit_frame.h> #include <symbol_edit_frame.h>
#include <symbol_viewer_frame.h> #include <symbol_viewer_frame.h>
@ -153,6 +154,13 @@ public:
{ {
} }
SYMBOL_GRID_TRICKS( DIALOG_EDIT_LIBRARY_TABLES* aParent, WX_GRID* aGrid,
std::function<void( wxCommandEvent& )> aAddHandler ) :
LIB_TABLE_GRID_TRICKS( aGrid, aAddHandler ),
m_dialog( aParent )
{
}
protected: protected:
DIALOG_EDIT_LIBRARY_TABLES* m_dialog; DIALOG_EDIT_LIBRARY_TABLES* m_dialog;
@ -224,8 +232,21 @@ protected:
} }
else else
{ {
// paste spreadsheet formatted text. wxString text = cb_text;
GRID_TRICKS::paste_text( cb_text );
if( !text.Contains( '\t' ) && text.Contains( ',' ) )
text.Replace( ',', '\t' );
if( text.Contains( '\t' ) )
{
int row = m_grid->GetGridCursorRow();
m_grid->ClearSelection();
m_grid->SelectRow( row );
m_grid->SetGridCursor( row, 0 );
getSelectedArea();
}
GRID_TRICKS::paste_text( text );
m_grid->AutoSizeColumns( false ); m_grid->AutoSizeColumns( false );
} }
@ -250,7 +271,8 @@ void PANEL_SYM_LIB_TABLE::setupGrid( WX_GRID* aGrid )
}; };
// add Cut, Copy, and Paste to wxGrids // add Cut, Copy, and Paste to wxGrids
aGrid->PushEventHandler( new SYMBOL_GRID_TRICKS( m_parent, aGrid ) ); aGrid->PushEventHandler( new SYMBOL_GRID_TRICKS( m_parent, aGrid,
[this]( wxCommandEvent& event ) { appendRowHandler( event ); } ) );
aGrid->SetSelectionMode( wxGrid::wxGridSelectRows ); aGrid->SetSelectionMode( wxGrid::wxGridSelectRows );

View File

@ -189,9 +189,6 @@ EESCHEMA_SETTINGS::EESCHEMA_SETTINGS() :
m_params.emplace_back( new PARAM<int>( "appearance.edit_label_height", m_params.emplace_back( new PARAM<int>( "appearance.edit_label_height",
&m_Appearance.edit_label_height, -1 ) ); &m_Appearance.edit_label_height, -1 ) );
m_params.emplace_back( new PARAM<int>( "appearance.erc_severities",
&m_Appearance.erc_severities, RPT_SEVERITY_ERROR | RPT_SEVERITY_WARNING ) );
m_params.emplace_back( new PARAM<bool>( "appearance.footprint_preview", m_params.emplace_back( new PARAM<bool>( "appearance.footprint_preview",
&m_Appearance.footprint_preview, true ) ); &m_Appearance.footprint_preview, true ) );
@ -591,6 +588,12 @@ EESCHEMA_SETTINGS::EESCHEMA_SETTINGS() :
m_params.emplace_back( new PARAM<int>( "symbol_chooser.sort_mode", m_params.emplace_back( new PARAM<int>( "symbol_chooser.sort_mode",
&m_SymChooserPanel.sort_mode, 0 ) ); &m_SymChooserPanel.sort_mode, 0 ) );
m_params.emplace_back( new PARAM<bool>( "ERC.crossprobe",
&m_ERCDialog.crossprobe, true ) );
m_params.emplace_back( new PARAM<bool>( "ERC.scroll_on_crossprobe",
&m_ERCDialog.scroll_on_crossprobe, true ) );
m_params.emplace_back( new PARAM<bool>( "import_graphics.interactive_placement", m_params.emplace_back( new PARAM<bool>( "import_graphics.interactive_placement",
&m_ImportGraphics.interactive_placement, true ) ); &m_ImportGraphics.interactive_placement, true ) );

View File

@ -68,7 +68,6 @@ public:
int edit_label_width; int edit_label_width;
int edit_label_height; int edit_label_height;
bool edit_label_multiple; bool edit_label_multiple;
int erc_severities;
bool footprint_preview; bool footprint_preview;
bool print_sheet_reference; bool print_sheet_reference;
wxString default_font; wxString default_font;
@ -265,6 +264,12 @@ public:
int sort_mode; int sort_mode;
}; };
struct DIALOG_ERC
{
bool crossprobe;
bool scroll_on_crossprobe;
};
struct DIALOG_IMPORT_GRAPHICS struct DIALOG_IMPORT_GRAPHICS
{ {
bool interactive_placement; bool interactive_placement;
@ -329,35 +334,26 @@ private:
public: public:
APPEARANCE m_Appearance; APPEARANCE m_Appearance;
AUTOPLACE_FIELDS m_AutoplaceFields;
AUI_PANELS m_AuiPanels; AUI_PANELS m_AuiPanels;
DRAWING m_Drawing; DRAWING m_Drawing;
FIND_REPLACE_EXTRA m_FindReplaceExtra;
INPUT m_Input; INPUT m_Input;
AUTOPLACE_FIELDS m_AutoplaceFields;
SELECTION m_Selection;
PAGE_SETTINGS m_PageSettings; PAGE_SETTINGS m_PageSettings;
PANEL_ANNOTATE m_AnnotatePanel; PANEL_ANNOTATE m_AnnotatePanel;
PANEL_BOM m_BomPanel; PANEL_BOM m_BomPanel;
PANEL_SYMBOL_FIELDS_TABLE m_FieldEditorPanel; PANEL_SYMBOL_FIELDS_TABLE m_FieldEditorPanel;
PANEL_LIB_VIEW m_LibViewPanel; PANEL_LIB_VIEW m_LibViewPanel;
PANEL_NETLIST m_NetlistPanel; PANEL_NETLIST m_NetlistPanel;
PANEL_SYM_CHOOSER m_SymChooserPanel; PANEL_SYM_CHOOSER m_SymChooserPanel;
FIND_REPLACE_EXTRA m_FindReplaceExtra;
DIALOG_ERC m_ERCDialog;
DIALOG_IMPORT_GRAPHICS m_ImportGraphics; DIALOG_IMPORT_GRAPHICS m_ImportGraphics;
SELECTION m_Selection;
SIMULATOR m_Simulator; SIMULATOR m_Simulator;
bool m_RescueNeverShow; bool m_RescueNeverShow;

View File

@ -2032,7 +2032,7 @@ bool SCH_EDIT_FRAME::GetShowAllPins() const
} }
void SCH_EDIT_FRAME::FocusOnItem( EDA_ITEM* aItem ) void SCH_EDIT_FRAME::FocusOnItem( EDA_ITEM* aItem, bool aAllowScroll )
{ {
// nullptr will clear the current focus // nullptr will clear the current focus
if( aItem != nullptr && !aItem->IsSCH_ITEM() ) if( aItem != nullptr && !aItem->IsSCH_ITEM() )
@ -2060,7 +2060,7 @@ void SCH_EDIT_FRAME::FocusOnItem( EDA_ITEM* aItem )
lastBrightenedItemID = aItem->m_Uuid; lastBrightenedItemID = aItem->m_Uuid;
} }
FocusOnLocation( aItem->GetFocusPosition() ); FocusOnLocation( aItem->GetFocusPosition(), aAllowScroll );
} }
} }

View File

@ -755,7 +755,7 @@ public:
int GetSchematicJunctionSize(); int GetSchematicJunctionSize();
double GetSchematicHopOverScale(); double GetSchematicHopOverScale();
void FocusOnItem( EDA_ITEM* aItem ) override; void FocusOnItem( EDA_ITEM* aItem, bool aAllowScroll = true ) override;
bool IsSyncingSelection() { return m_syncingPcbToSchSelection; } bool IsSyncingSelection() { return m_syncingPcbToSchSelection; }

View File

@ -34,6 +34,9 @@
#include <string_utils.h> #include <string_utils.h>
#include <geometry/geometry_utils.h> #include <geometry/geometry_utils.h>
#include <schematic.h> #include <schematic.h>
#include <sch_screen.h>
#include <sch_sheet.h>
#include <sch_sheet_pin.h>
#include <settings/color_settings.h> #include <settings/color_settings.h>
#include <sch_painter.h> #include <sch_painter.h>
#include <default_values.h> #include <default_values.h>
@ -314,6 +317,82 @@ COLOR4D SCH_LABEL_BASE::GetLabelColor() const
} }
void SCH_LABEL_BASE::SetLabelShape( LABEL_SHAPE aShape )
{
m_shape = (LABEL_FLAG_SHAPE) aShape;
static bool s_inUpdate = false;
if( s_inUpdate )
return;
s_inUpdate = true;
if( Type() == SCH_HIER_LABEL_T )
{
SCH_HIERLABEL* label = static_cast<SCH_HIERLABEL*>( this );
SCH_SCREEN* screen = static_cast<SCH_SCREEN*>( label->GetParent() );
if( screen )
{
const wxString& text = label->GetText();
for( SCH_ITEM* item : screen->Items().OfType( SCH_HIER_LABEL_T ) )
{
SCH_HIERLABEL* other = static_cast<SCH_HIERLABEL*>( item );
if( other != label && other->GetText() == text )
other->SetLabelShape( aShape );
}
for( const SCH_SHEET_PATH& sheetPath : screen->GetClientSheetPaths() )
{
SCH_SHEET* sheet = sheetPath.Last();
if( sheet )
{
for( SCH_SHEET_PIN* pin : sheet->GetPins() )
{
if( pin->GetText() == text )
pin->SetLabelShape( aShape );
}
}
}
}
}
else if( Type() == SCH_SHEET_PIN_T )
{
SCH_SHEET_PIN* pin = static_cast<SCH_SHEET_PIN*>( this );
SCH_SHEET* parent = pin->GetParent();
if( parent )
{
const wxString& text = pin->GetText();
SCH_SCREEN* screen = parent->GetScreen();
if( screen )
{
for( SCH_ITEM* item : screen->Items().OfType( SCH_HIER_LABEL_T ) )
{
SCH_HIERLABEL* hlabel = static_cast<SCH_HIERLABEL*>( item );
if( hlabel->GetText() == text )
hlabel->SetLabelShape( aShape );
}
}
for( SCH_SHEET_PIN* other : parent->GetPins() )
{
if( other != pin && other->GetText() == text )
other->SetLabelShape( aShape );
}
}
}
s_inUpdate = false;
}
void SCH_LABEL_BASE::SetSpinStyle( SPIN_STYLE aSpinStyle ) void SCH_LABEL_BASE::SetSpinStyle( SPIN_STYLE aSpinStyle )
{ {
// Assume "Right" and Left" mean which side of the anchor the text will be on // Assume "Right" and Left" mean which side of the anchor the text will be on

View File

@ -173,12 +173,19 @@ public:
bool HasConnectivityChanges( const SCH_ITEM* aItem, bool HasConnectivityChanges( const SCH_ITEM* aItem,
const SCH_SHEET_PATH* aInstance = nullptr ) const override; const SCH_SHEET_PATH* aInstance = nullptr ) const override;
LABEL_FLAG_SHAPE GetShape() const { return m_shape; }
void SetShape( LABEL_FLAG_SHAPE aShape ) { m_shape = aShape; }
// Type-specific versions for property manager // Type-specific versions for property manager
LABEL_SHAPE GetLabelShape() const { return (LABEL_SHAPE) m_shape; } LABEL_SHAPE GetLabelShape() const { return (LABEL_SHAPE) m_shape; }
void SetLabelShape( LABEL_SHAPE aShape ) { m_shape = (LABEL_FLAG_SHAPE) aShape; } void SetLabelShape( LABEL_SHAPE aShape );
LABEL_FLAG_SHAPE GetShape() const { return m_shape; }
void SetShape( LABEL_FLAG_SHAPE aShape )
{
// Set flags directly if a flag shape
if( aShape >= F_FIRST )
m_shape = aShape;
else
SetLabelShape( (LABEL_SHAPE) aShape );
}
COLOR4D GetLabelColor() const; COLOR4D GetLabelColor() const;

View File

@ -140,10 +140,9 @@ void SPICE_LIBRARY_PARSER::ReadFile( const wxString& aFilePath, REPORTER& aRepor
// Read all self-contained models in parallel // Read all self-contained models in parallel
thread_pool& tp = GetKiCadThreadPool(); thread_pool& tp = GetKiCadThreadPool();
auto results = tp.parallelize_loop( modelQueue.size(), auto results = tp.submit_loop( 0, modelQueue.size(),
[&]( const int a, const int b ) [&]( const int ii )
{ {
for( int ii = a; ii < b; ++ii )
createModel( ii, true ); createModel( ii, true );
} ); } );
results.wait(); results.wait();

View File

@ -1541,7 +1541,7 @@ const BOX2I SYMBOL_EDIT_FRAME::GetDocumentExtents( bool aIncludeAllVisible ) con
} }
void SYMBOL_EDIT_FRAME::FocusOnItem( EDA_ITEM* aItem ) void SYMBOL_EDIT_FRAME::FocusOnItem( EDA_ITEM* aItem, bool aAllowScroll )
{ {
static KIID lastBrightenedItemID( niluuid ); static KIID lastBrightenedItemID( niluuid );
@ -1587,7 +1587,7 @@ void SYMBOL_EDIT_FRAME::FocusOnItem( EDA_ITEM* aItem )
lastBrightenedItemID = aItem->m_Uuid; lastBrightenedItemID = aItem->m_Uuid;
} }
FocusOnLocation( VECTOR2I( aItem->GetFocusPosition().x, -aItem->GetFocusPosition().y ) ); FocusOnLocation( VECTOR2I( aItem->GetFocusPosition().x, -aItem->GetFocusPosition().y ), aAllowScroll );
} }
} }

View File

@ -377,7 +377,7 @@ public:
void KiwayMailIn( KIWAY_EXPRESS& mail ) override; void KiwayMailIn( KIWAY_EXPRESS& mail ) override;
void FocusOnItem( EDA_ITEM* aItem ) override; void FocusOnItem( EDA_ITEM* aItem, bool aAllowScroll = true ) override;
/** /**
* Load a symbol from the schematic to edit in place. * Load a symbol from the schematic to edit in place.

View File

@ -3097,6 +3097,7 @@ int SCH_DRAWING_TOOLS::DrawSheet( const TOOL_EVENT& aEvent )
KIGFX::VIEW_CONTROLS* controls = getViewControls(); KIGFX::VIEW_CONTROLS* controls = getViewControls();
EE_GRID_HELPER grid( m_toolMgr ); EE_GRID_HELPER grid( m_toolMgr );
VECTOR2I cursorPos; VECTOR2I cursorPos;
bool startedWithDrag = false; // Track if initial sheet placement started with a drag
m_toolMgr->RunAction( ACTIONS::selectionClear ); m_toolMgr->RunAction( ACTIONS::selectionClear );
@ -3188,7 +3189,8 @@ int SCH_DRAWING_TOOLS::DrawSheet( const TOOL_EVENT& aEvent )
} }
} }
else if( !sheet && ( evt->IsClick( BUT_LEFT ) || evt->IsDblClick( BUT_LEFT ) else if( !sheet && ( evt->IsClick( BUT_LEFT ) || evt->IsDblClick( BUT_LEFT )
|| evt->IsAction( &ACTIONS::cursorClick ) || evt->IsAction( &ACTIONS::cursorDblClick ) ) ) || evt->IsAction( &ACTIONS::cursorClick ) || evt->IsAction( &ACTIONS::cursorDblClick )
|| evt->IsDrag( BUT_LEFT ) ) )
{ {
SCH_SELECTION& selection = m_selectionTool->GetSelection(); SCH_SELECTION& selection = m_selectionTool->GetSelection();
@ -3211,7 +3213,15 @@ int SCH_DRAWING_TOOLS::DrawSheet( const TOOL_EVENT& aEvent )
m_toolMgr->RunAction( ACTIONS::selectionClear ); m_toolMgr->RunAction( ACTIONS::selectionClear );
sheet = new SCH_SHEET( m_frame->GetCurrentSheet().Last(), cursorPos ); VECTOR2I sheetPos = evt->IsDrag( BUT_LEFT ) ?
grid.Align( evt->DragOrigin(), GRID_HELPER_GRIDS::GRID_GRAPHICS ) :
cursorPos;
// Remember whether this sheet was initiated with a drag so we can treat mouse-up as
// the terminating (second) click.
startedWithDrag = evt->IsDrag( BUT_LEFT );
sheet = new SCH_SHEET( m_frame->GetCurrentSheet().Last(), sheetPos );
sheet->SetScreen( nullptr ); sheet->SetScreen( nullptr );
wxString ext = wxString( "." ) + FILEEXT::KiCadSchematicFileExtension; wxString ext = wxString( "." ) + FILEEXT::KiCadSchematicFileExtension;
@ -3268,7 +3278,8 @@ int SCH_DRAWING_TOOLS::DrawSheet( const TOOL_EVENT& aEvent )
else if( sheet && ( evt->IsClick( BUT_LEFT ) || evt->IsDblClick( BUT_LEFT ) else if( sheet && ( evt->IsClick( BUT_LEFT ) || evt->IsDblClick( BUT_LEFT )
|| isSyntheticClick || isSyntheticClick
|| evt->IsAction( &ACTIONS::cursorClick ) || evt->IsAction( &ACTIONS::cursorDblClick ) || evt->IsAction( &ACTIONS::cursorClick ) || evt->IsAction( &ACTIONS::cursorDblClick )
|| evt->IsAction( &ACTIONS::finishInteractive ) ) ) || evt->IsAction( &ACTIONS::finishInteractive )
|| ( startedWithDrag && evt->IsMouseUp( BUT_LEFT ) ) ) )
{ {
getViewControls()->SetAutoPan( false ); getViewControls()->SetAutoPan( false );
getViewControls()->CaptureCursor( false ); getViewControls()->CaptureCursor( false );
@ -3338,7 +3349,8 @@ int SCH_DRAWING_TOOLS::DrawSheet( const TOOL_EVENT& aEvent )
evt->SetPassEvent(); evt->SetPassEvent();
break; break;
} }
else if( sheet && ( evt->IsAction( &ACTIONS::refreshPreview ) || evt->IsMotion() ) ) else if( sheet && ( evt->IsAction( &ACTIONS::refreshPreview ) || evt->IsMotion()
|| evt->IsDrag( BUT_LEFT ) ) )
{ {
sizeSheet( sheet, cursorPos ); sizeSheet( sheet, cursorPos );
m_view->ClearPreview(); m_view->ClearPreview();

View File

@ -46,6 +46,9 @@
#include <pgm_base.h> #include <pgm_base.h>
#include <view/view_controls.h> #include <view/view_controls.h>
#include <settings/settings_manager.h> #include <settings/settings_manager.h>
#include <math/box2.h>
#include <base_units.h>
#include <sch_screen.h>
#include "sch_move_tool.h" #include "sch_move_tool.h"
@ -500,6 +503,7 @@ bool SCH_MOVE_TOOL::doMoveSelection( const TOOL_EVENT& aEvent, SCH_COMMIT* aComm
TOOL_EVENT* evt = &copy; TOOL_EVENT* evt = &copy;
VECTOR2I prevPos; VECTOR2I prevPos;
GRID_HELPER_GRIDS snapLayer = GRID_CURRENT; GRID_HELPER_GRIDS snapLayer = GRID_CURRENT;
SCH_SHEET* hoverSheet = nullptr;
m_cursor = controls->GetCursorPosition(); m_cursor = controls->GetCursorPosition();
@ -771,7 +775,65 @@ bool SCH_MOVE_TOOL::doMoveSelection( const TOOL_EVENT& aEvent, SCH_COMMIT* aComm
m_cursor = grid.BestSnapAnchor( controls->GetCursorPosition( false ), m_cursor = grid.BestSnapAnchor( controls->GetCursorPosition( false ),
snapLayer, selection ); snapLayer, selection );
// Determine potential target sheet.
SCH_SHEET* sheet = dynamic_cast<SCH_SHEET*>( m_frame->GetScreen()->GetItem( m_cursor, 0,
SCH_SHEET_T ) );
if( sheet && sheet->IsSelected() )
sheet = nullptr; // Never target a selected sheet
if( !sheet )
{
// Build current selection bounding box in its (already moved) position.
BOX2I selBBox;
for( EDA_ITEM* it : selection )
{
if( SCH_ITEM* schIt = dynamic_cast<SCH_ITEM*>( it ) )
selBBox.Merge( schIt->GetBoundingBox() );
}
if( selBBox.GetWidth() > 0 && selBBox.GetHeight() > 0 )
{
VECTOR2I selCenter( selBBox.GetX() + selBBox.GetWidth() / 2,
selBBox.GetY() + selBBox.GetHeight() / 2 );
// Find first non-selected sheet whose body fully contains the selection
// or at least contains its center point.
for( SCH_ITEM* it : m_frame->GetScreen()->Items().OfType( SCH_SHEET_T ) )
{
SCH_SHEET* candidate = static_cast<SCH_SHEET*>( it );
if( candidate->IsSelected() || candidate->IsRootSheet() )
continue;
BOX2I body = candidate->GetBodyBoundingBox();
if( body.Contains( selBBox ) || body.Contains( selCenter ) )
{
sheet = candidate;
break;
}
}
}
}
if( sheet != hoverSheet )
{
if( hoverSheet )
{
hoverSheet->ClearFlags( BRIGHTENED );
m_frame->UpdateItem( hoverSheet, false );
}
hoverSheet = sheet;
if( hoverSheet )
{
hoverSheet->SetFlags( BRIGHTENED );
m_frame->UpdateItem( hoverSheet, false );
}
}
m_frame->GetCanvas()->SetCurrentCursor( hoverSheet ? KICURSOR::PLACE
: KICURSOR::MOVING );
VECTOR2I delta( m_cursor - prevPos ); VECTOR2I delta( m_cursor - prevPos );
m_anchorPos = m_cursor; m_anchorPos = m_cursor;
@ -1032,6 +1094,22 @@ bool SCH_MOVE_TOOL::doMoveSelection( const TOOL_EVENT& aEvent, SCH_COMMIT* aComm
} while( ( evt = Wait() ) ); //Should be assignment not equality test } while( ( evt = Wait() ) ); //Should be assignment not equality test
SCH_SHEET* targetSheet = hoverSheet;
if( hoverSheet )
{
hoverSheet->ClearFlags( BRIGHTENED );
m_frame->UpdateItem( hoverSheet, false );
}
if( targetSheet )
{
moveSelectionToSheet( selection, targetSheet, aCommit );
m_toolMgr->RunAction( ACTIONS::selectionClear );
m_newDragLines.clear();
m_changedDragLines.clear();
}
// Create a selection of original selection, drag selected/changed items, and new // Create a selection of original selection, drag selected/changed items, and new
// bend lines for later before we clear them in the aCommit. We'll need these // bend lines for later before we clear them in the aCommit. We'll need these
// to check for new junctions needed, etc. // to check for new junctions needed, etc.
@ -1135,6 +1213,60 @@ bool SCH_MOVE_TOOL::doMoveSelection( const TOOL_EVENT& aEvent, SCH_COMMIT* aComm
} }
void SCH_MOVE_TOOL::moveSelectionToSheet( SCH_SELECTION& aSelection, SCH_SHEET* aTargetSheet,
SCH_COMMIT* aCommit )
{
SCH_SCREEN* destScreen = aTargetSheet->GetScreen();
SCH_SCREEN* srcScreen = m_frame->GetScreen();
BOX2I bbox;
for( EDA_ITEM* item : aSelection )
bbox.Merge( static_cast<SCH_ITEM*>( item )->GetBoundingBox() );
VECTOR2I offset = VECTOR2I( 0, 0 ) - bbox.GetPosition();
int step = schIUScale.MilsToIU( 50 );
bool overlap = false;
do
{
BOX2I moved = bbox;
moved.Move( offset );
overlap = false;
for( SCH_ITEM* existing : destScreen->Items() )
{
if( moved.Intersects( existing->GetBoundingBox() ) )
{
overlap = true;
break;
}
}
if( overlap )
offset += VECTOR2I( step, step );
} while( overlap );
for( EDA_ITEM* item : aSelection )
{
SCH_ITEM* schItem = static_cast<SCH_ITEM*>( item );
// Remove from current screen and view manually
m_frame->RemoveFromScreen( schItem, srcScreen );
// Move the item
schItem->Move( offset );
// Add to destination screen manually (won't add to view since it's not current)
destScreen->Append( schItem );
// Record in commit with CHT_DONE flag to bypass automatic screen/view operations
aCommit->Stage( schItem, CHT_REMOVE | CHT_DONE, srcScreen );
aCommit->Stage( schItem, CHT_ADD | CHT_DONE, destScreen );
}
}
void SCH_MOVE_TOOL::trimDanglingLines( SCH_COMMIT* aCommit ) void SCH_MOVE_TOOL::trimDanglingLines( SCH_COMMIT* aCommit )
{ {
// Need a local cleanup first to ensure we remove unneeded junctions // Need a local cleanup first to ensure we remove unneeded junctions
@ -1163,8 +1295,7 @@ void SCH_MOVE_TOOL::trimDanglingLines( SCH_COMMIT* aCommit )
{ {
line->SetFlags( STRUCT_DELETED ); line->SetFlags( STRUCT_DELETED );
aCommit->Removed( line, m_frame->GetScreen() ); aCommit->Removed( line, m_frame->GetScreen() );
updateItem( line, false ); // Update any cached visuals before commit processes
updateItem( line, false );
m_frame->RemoveFromScreen( line, m_frame->GetScreen() ); m_frame->RemoveFromScreen( line, m_frame->GetScreen() );
} }
} }

View File

@ -35,6 +35,9 @@ class SCH_LINE;
class SCH_LABEL_BASE; class SCH_LABEL_BASE;
class SCH_SHEET_PIN; class SCH_SHEET_PIN;
class SCH_JUNCTION; class SCH_JUNCTION;
class SCH_SELECTION;
class SCH_SHEET;
class SCH_COMMIT;
struct SPECIAL_CASE_LABEL_INFO struct SPECIAL_CASE_LABEL_INFO
@ -81,6 +84,8 @@ private:
void orthoLineDrag( SCH_COMMIT* aCommit, SCH_LINE* line, const VECTOR2I& splitDelta, void orthoLineDrag( SCH_COMMIT* aCommit, SCH_LINE* line, const VECTOR2I& splitDelta,
int& xBendCount, int& yBendCount, const EE_GRID_HELPER& grid ); int& xBendCount, int& yBendCount, const EE_GRID_HELPER& grid );
void moveSelectionToSheet( SCH_SELECTION& aSelection, SCH_SHEET* aTarget, SCH_COMMIT* aCommit );
///< Clears the new drag lines and removes them from the screen ///< Clears the new drag lines and removes them from the screen
void clearNewDragLines(); void clearNewDragLines();

View File

@ -548,9 +548,13 @@ void HIERARCHY_PANE::onCharHook( wxKeyEvent& aKeyStroke )
int mods = aKeyStroke.GetModifiers(); int mods = aKeyStroke.GetModifiers();
if( mods & wxMOD_ALTGR ) // the flag wxMOD_ALTGR is defined in wxWidgets as wxMOD_CONTROL|wxMOD_ALT
hotkey += MD_ALTGR; // So AltGr key cannot used as modifier key because it is the same as Alt key + Ctrl key.
#if CAN_USE_ALTGR_KEY
if( wxmods & wxMOD_ALTGR )
mods |= MD_ALTGR;
else else
#endif
{ {
if( mods & wxMOD_CONTROL ) if( mods & wxMOD_CONTROL )
hotkey += MD_CTRL; hotkey += MD_CTRL;

View File

@ -671,8 +671,7 @@ bool GERBER_FILE_IMAGE::ExecuteRS274XCommand( int aCommand, char* aBuff,
break; break;
case IMAGE_POLARITY: case IMAGE_POLARITY:
// These commands are deprecated since 2012. // Note: these commands IPPOS and IPNEG are deprecated since 2012.
// So do nothing and prompt the user about this command
if( strncasecmp( aText, "NEG", 3 ) == 0 ) if( strncasecmp( aText, "NEG", 3 ) == 0 )
{ {
m_ImageNegative = true; m_ImageNegative = true;
@ -688,7 +687,6 @@ bool GERBER_FILE_IMAGE::ExecuteRS274XCommand( int aCommand, char* aBuff,
// actual effect. Just skip it. // actual effect. Just skip it.
} }
ok = false;
break; break;
case LOAD_POLARITY: case LOAD_POLARITY:

View File

@ -306,14 +306,14 @@ public:
* *
* @param aPos is the point to go to. * @param aPos is the point to go to.
*/ */
void FocusOnLocation( const VECTOR2I& aPos ); void FocusOnLocation( const VECTOR2I& aPos, bool aAllowScroll = true );
/** /**
* Focus on a particular canvas item. * Focus on a particular canvas item.
* *
* @param aItem is the item to focus on. nullptr clears the focus. * @param aItem is the item to focus on. nullptr clears the focus.
*/ */
virtual void FocusOnItem( EDA_ITEM* aItem ) {} virtual void FocusOnItem( EDA_ITEM* aItem, bool aAllowScroll = true ) {}
virtual void ClearFocus() { FocusOnItem( nullptr ); } virtual void ClearFocus() { FocusOnItem( nullptr ); }

View File

@ -18,6 +18,7 @@
*/ */
#include "grid_tricks.h" #include "grid_tricks.h"
#include <functional>
class LIB_TABLE_GRID_TRICKS : public GRID_TRICKS class LIB_TABLE_GRID_TRICKS : public GRID_TRICKS
{ {
@ -33,6 +34,7 @@ class LIB_TABLE_GRID_TRICKS : public GRID_TRICKS
public: public:
explicit LIB_TABLE_GRID_TRICKS( WX_GRID* aGrid ); explicit LIB_TABLE_GRID_TRICKS( WX_GRID* aGrid );
LIB_TABLE_GRID_TRICKS( WX_GRID* aGrid, std::function<void( wxCommandEvent& )> aAddHandler );
virtual ~LIB_TABLE_GRID_TRICKS(){}; virtual ~LIB_TABLE_GRID_TRICKS(){};
@ -43,5 +45,7 @@ protected:
virtual void optionsEditor( int aRow ) = 0; virtual void optionsEditor( int aRow ) = 0;
bool handleDoubleClick( wxGridEvent& aEvent ) override; bool handleDoubleClick( wxGridEvent& aEvent ) override;
void onCharHook( wxKeyEvent& ev );
virtual bool supportsVisibilityColumn() { return false; } virtual bool supportsVisibilityColumn() { return false; }
}; };

View File

@ -220,9 +220,10 @@ public:
EDA_ITEM* ResolveItem( const KIID& aId, bool aAllowNullptrReturn = false ) const override; EDA_ITEM* ResolveItem( const KIID& aId, bool aAllowNullptrReturn = false ) const override;
void FocusOnItem( EDA_ITEM* aItem ) override; void FocusOnItem( EDA_ITEM* aItem, bool aAllowScroll = true ) override;
void FocusOnItem( BOARD_ITEM* aItem, PCB_LAYER_ID aLayer = UNDEFINED_LAYER ); void FocusOnItem( BOARD_ITEM* aItem, PCB_LAYER_ID aLayer = UNDEFINED_LAYER, bool aAllowScroll = true );
void FocusOnItems( std::vector<BOARD_ITEM*> aItems, PCB_LAYER_ID aLayer = UNDEFINED_LAYER ); void FocusOnItems( std::vector<BOARD_ITEM*> aItems, PCB_LAYER_ID aLayer = UNDEFINED_LAYER,
bool aAllowScroll = true );
void HideSolderMask(); void HideSolderMask();
void ShowSolderMask(); void ShowSolderMask();

View File

@ -110,7 +110,7 @@ public:
*/ */
void BuildArgvUtf8(); void BuildArgvUtf8();
BS::thread_pool& GetThreadPool() { return *m_singleton.m_ThreadPool; } BS::thread_pool<0>& GetThreadPool() { return *m_singleton.m_ThreadPool; }
GL_CONTEXT_MANAGER* GetGLContextManager() { return m_singleton.m_GLContextManager; } GL_CONTEXT_MANAGER* GetGLContextManager() { return m_singleton.m_GLContextManager; }

View File

@ -25,6 +25,7 @@
class GL_CONTEXT_MANAGER; class GL_CONTEXT_MANAGER;
namespace BS namespace BS
{ {
template <std::uint8_t>
class thread_pool; class thread_pool;
} }
@ -42,7 +43,7 @@ public:
void Init(); void Init();
public: public:
BS::thread_pool* m_ThreadPool; BS::thread_pool<0>* m_ThreadPool;
GL_CONTEXT_MANAGER* m_GLContextManager; GL_CONTEXT_MANAGER* m_GLContextManager;
}; };

View File

@ -0,0 +1,63 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright The KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef STARTUP_KEY_HANDLER_H
#define STARTUP_KEY_HANDLER_H
#include <kicommon.h>
#include <map>
#include <vector>
#include <wx/wx.h>
// A class to handle key press detection and execute multiple actions at startup
class KICOMMON_API StartupKeyHandler
{
public:
// Enum to define actions for key presses
enum class KEY_ACTION
{
RESET_TO_FACTORY_DEFAULTS
};
// Constructor to initialize key-action mappings
StartupKeyHandler();
~StartupKeyHandler();
// Function to handle the startup key check
void CheckStartupKeys();
private:
// Function to check if a ctrl key is pressed
static bool isKeyActionRequested( wxKeyCode aKeyCode );
// Function to perform actions if ctrl key pressed
void performKeyActions( const std::vector<KEY_ACTION>& aActions );
// Resets all user-configurable settings to their original factory default values.
// This operation will erase any customized settings or preferences.
void resetToFactoryDefaults();
private:
// A map to store the combination of keys and their corresponding list of actions
std::map<std::vector<wxKeyCode>, std::vector<KEY_ACTION>> m_keyActions;
};
#endif // STARTUP_KEY_HANDLER_H

View File

@ -28,7 +28,7 @@
#include <bs_thread_pool.hpp> #include <bs_thread_pool.hpp>
#include <import_export.h> #include <import_export.h>
using thread_pool = BS::thread_pool; using thread_pool = BS::thread_pool<0>;
/** /**
* Get a reference to the current thread pool. N.B., you cannot copy the thread pool * Get a reference to the current thread pool. N.B., you cannot copy the thread pool

View File

@ -84,38 +84,9 @@ private:
/// Returns the instance of VIEW, used by the application. /// Returns the instance of VIEW, used by the application.
KIGFX::VIEW* getView(); KIGFX::VIEW* getView();
/// Saves the state of key modifiers (Alt, Ctrl and so on). /// Returns the state of key modifiers (Alt, Ctrl and so on) as OR'ed list
static int decodeModifiers( const wxKeyboardState* aState ) /// of bits (MD_CTRL, MD_ALT ...)
{ static int decodeModifiers( const wxKeyboardState* aState );
int mods = 0;
int wxmods = aState->GetModifiers();
if( wxmods & wxMOD_ALTGR )
mods |= MD_ALTGR;
else
{
if( wxmods & wxMOD_CONTROL )
mods |= MD_CTRL;
if( wxmods & wxMOD_ALT )
mods |= MD_ALT;
}
if( wxmods & wxMOD_SHIFT )
mods |= MD_SHIFT;
#ifdef wxMOD_META
if( wxmods & wxMOD_META )
mods |= MD_META;
#endif
#ifdef wxMOD_WIN
if( wxmods & wxMOD_WIN )
mods |= MD_SUPER;
#endif
return mods;
}
private: private:
/// The time threshold for a mouse button press that distinguishes between a single mouse /// The time threshold for a mouse button press that distinguishes between a single mouse

View File

@ -327,7 +327,9 @@ class INFOBAR_REPORTER : public REPORTER
{ {
public: public:
INFOBAR_REPORTER( WX_INFOBAR* aInfoBar ) : INFOBAR_REPORTER( WX_INFOBAR* aInfoBar ) :
REPORTER(), m_messageSet( false ), m_infoBar( aInfoBar ), REPORTER(),
m_messageSet( false ),
m_infoBar( aInfoBar ),
m_severity( RPT_SEVERITY_UNDEFINED ) m_severity( RPT_SEVERITY_UNDEFINED )
{ {
} }

View File

@ -26,11 +26,14 @@
#include <bitmaps.h> #include <bitmaps.h>
#include <widgets/std_bitmap_button.h> #include <widgets/std_bitmap_button.h>
#include <widgets/ui_common.h> #include <widgets/ui_common.h>
#include <algorithm>
#include <wx_filename.h> #include <wx_filename.h>
#include <wx/dir.h> #include <wx/dir.h>
#include <wx/dirdlg.h> #include <wx/dirdlg.h>
#include <wx/settings.h> #include <wx/settings.h>
#include <wx/bitmap.h> #include <wx/bitmap.h>
#include <wx/image.h>
#include <wx/math.h>
#include "template_default_html.h" #include "template_default_html.h"
// Welcome / fallback HTML now provided by template_default_html.h // Welcome / fallback HTML now provided by template_default_html.h
@ -99,7 +102,24 @@ void TEMPLATE_WIDGET::SetTemplate( PROJECT_TEMPLATE* aTemplate )
wxBitmap* icon = aTemplate->GetIcon(); wxBitmap* icon = aTemplate->GetIcon();
if( icon && icon->IsOk() ) if( icon && icon->IsOk() )
{
wxSize maxSize = m_bitmapIcon->GetSize();
if( icon->GetWidth() > maxSize.x || icon->GetHeight() > maxSize.y )
{
double scale = std::min( (double) maxSize.x / icon->GetWidth(),
(double) maxSize.y / icon->GetHeight() );
wxImage image = icon->ConvertToImage();
int w = wxRound( icon->GetWidth() * scale );
int h = wxRound( icon->GetHeight() * scale );
image.Rescale( w, h, wxIMAGE_QUALITY_HIGH );
m_bitmapIcon->SetBitmap( wxBitmap( image ) );
}
else
{
m_bitmapIcon->SetBitmap( *icon ); m_bitmapIcon->SetBitmap( *icon );
}
}
else else
m_bitmapIcon->SetBitmap( KiBitmap( BITMAPS::icon_kicad ) ); m_bitmapIcon->SetBitmap( KiBitmap( BITMAPS::icon_kicad ) );
} }

View File

@ -63,6 +63,8 @@
#include <api/api_server.h> #include <api/api_server.h>
#endif #endif
#include "startup_key_handler.h"
// a dummy to quiet linking with EDA_BASE_FRAME::config(); // a dummy to quiet linking with EDA_BASE_FRAME::config();
#include <kiface_base.h> #include <kiface_base.h>
KIFACE_BASE& Kiface() KIFACE_BASE& Kiface()
@ -86,6 +88,9 @@ PGM_KICAD& PgmTop()
bool PGM_KICAD::OnPgmInit() bool PGM_KICAD::OnPgmInit()
{ {
StartupKeyHandler keyHandler;
keyHandler.CheckStartupKeys();
App().SetAppDisplayName( wxT( "KiCad" ) ); App().SetAppDisplayName( wxT( "KiCad" ) );
#if defined(DEBUG) #if defined(DEBUG)

View File

@ -636,7 +636,11 @@ void PROJECT_TREE_PANE::ReCreateTreePrj()
std::lock_guard<std::mutex> lock2( m_gitTreeCacheMutex ); std::lock_guard<std::mutex> lock2( m_gitTreeCacheMutex );
thread_pool& tp = GetKiCadThreadPool(); thread_pool& tp = GetKiCadThreadPool();
tp.wait_for_tasks(); while( tp.get_tasks_running() )
{
tp.wait_for( std::chrono::milliseconds( 250 ) );
}
m_gitStatusTimer.Stop(); m_gitStatusTimer.Stop();
m_gitSyncTimer.Stop(); m_gitSyncTimer.Stop();
m_gitTreeCache.clear(); m_gitTreeCache.clear();
@ -2293,8 +2297,7 @@ void PROJECT_TREE_PANE::onGitSyncTimer( wxTimerEvent& aEvent )
thread_pool& tp = GetKiCadThreadPool(); thread_pool& tp = GetKiCadThreadPool();
tp.push_task( tp.submit_task( [this]()
[this]()
{ {
KIGIT_COMMON* gitCommon = m_TreeProject->GitCommon(); KIGIT_COMMON* gitCommon = m_TreeProject->GitCommon();
@ -2307,10 +2310,7 @@ void PROJECT_TREE_PANE::onGitSyncTimer( wxTimerEvent& aEvent )
GIT_PULL_HANDLER handler( gitCommon ); GIT_PULL_HANDLER handler( gitCommon );
handler.PerformFetch(); handler.PerformFetch();
CallAfter( [this]() CallAfter( [this]() { gitStatusTimerHandler(); } );
{
gitStatusTimerHandler();
} );
} ); } );
if( gitSettings.updatInterval > 0 ) if( gitSettings.updatInterval > 0 )
@ -2327,11 +2327,7 @@ void PROJECT_TREE_PANE::gitStatusTimerHandler()
updateTreeCache(); updateTreeCache();
thread_pool& tp = GetKiCadThreadPool(); thread_pool& tp = GetKiCadThreadPool();
tp.push_task( tp.submit_task( [this]() { updateGitStatusIconMap(); } );
[this]()
{
updateGitStatusIconMap();
} );
} }
void PROJECT_TREE_PANE::onGitStatusTimer( wxTimerEvent& aEvent ) void PROJECT_TREE_PANE::onGitStatusTimer( wxTimerEvent& aEvent )

View File

@ -274,5 +274,5 @@ void UPDATE_MANAGER::CheckForUpdate( wxWindow* aNoticeParent )
}; };
thread_pool& tp = GetKiCadThreadPool(); thread_pool& tp = GetKiCadThreadPool();
m_updateTask = tp.submit( update_check ); m_updateTask = tp.submit_task( update_check );
} }

View File

@ -25,6 +25,7 @@
class wxChoice; class wxChoice;
class wxNonOwnedWindow; class wxNonOwnedWindow;
class wxTopLevelWindow;
class wxWindow; class wxWindow;
namespace KIPLATFORM namespace KIPLATFORM
@ -71,6 +72,8 @@ namespace KIPLATFORM
*/ */
void ReparentModal( wxNonOwnedWindow* aWindow ); void ReparentModal( wxNonOwnedWindow* aWindow );
void ReparentWindow( wxNonOwnedWindow* aWindow, wxTopLevelWindow* aParent );
/* /*
* An ugly hack to fix an issue on OSX: cmd+c closes the dialog instead of copying the * An ugly hack to fix an issue on OSX: cmd+c closes the dialog instead of copying the
* text if a button with wxID_CANCEL is used in a wxStdDialogButtonSizer created by * text if a button with wxID_CANCEL is used in a wxStdDialogButtonSizer created by

View File

@ -154,6 +154,12 @@ void KIPLATFORM::UI::ReparentModal( wxNonOwnedWindow* aWindow )
} }
void KIPLATFORM::UI::ReparentWindow( wxNonOwnedWindow* aWindow, wxTopLevelWindow* aParent )
{
// Not needed on this platform (only relevant for macOS child window ordering)
}
void KIPLATFORM::UI::FixupCancelButtonCmdKeyCollision( wxWindow *aWindow ) void KIPLATFORM::UI::FixupCancelButtonCmdKeyCollision( wxWindow *aWindow )
{ {
// Not needed on this platform // Not needed on this platform

View File

@ -88,6 +88,12 @@ void KIPLATFORM::UI::ReparentModal( wxNonOwnedWindow* aWindow )
} }
void KIPLATFORM::UI::ReparentWindow( wxNonOwnedWindow* aWindow, wxTopLevelWindow* aParent )
{
// Not needed on this platform (used only on macOS for child window ordering)
}
void KIPLATFORM::UI::FixupCancelButtonCmdKeyCollision( wxWindow *aWindow ) void KIPLATFORM::UI::FixupCancelButtonCmdKeyCollision( wxWindow *aWindow )
{ {
// Not needed on this platform // Not needed on this platform

View File

@ -103,24 +103,21 @@ void KIPLATFORM::UI::EnsureVisible( wxWindow* aWindow )
} }
void KIPLATFORM::UI::ReparentModal( wxNonOwnedWindow* aWindow ) void KIPLATFORM::UI::ReparentWindow( wxNonOwnedWindow* aWindow, wxTopLevelWindow* aParent )
{ {
wxTopLevelWindow* parent = NSWindow* parentWindow = aParent->GetWXWindow();
static_cast<wxTopLevelWindow*>( wxGetTopLevelParent( aWindow->GetParent() ) );
// Quietly return if no parent is found
if( !parent )
{
return;
}
NSWindow* parentWindow = parent->GetWXWindow();
NSWindow* theWindow = aWindow->GetWXWindow(); NSWindow* theWindow = aWindow->GetWXWindow();
if( parentWindow && theWindow ) if( parentWindow && theWindow )
{
[parentWindow addChildWindow:theWindow ordered:NSWindowAbove]; [parentWindow addChildWindow:theWindow ordered:NSWindowAbove];
} }
void KIPLATFORM::UI::ReparentModal( wxNonOwnedWindow* aWindow )
{
// Quietly return if no parent is found
if( wxTopLevelWindow* parent = static_cast<wxTopLevelWindow*>( wxGetTopLevelParent( aWindow->GetParent() ) ) )
ReparentWindow( aWindow, parent );
} }

View File

@ -1114,7 +1114,7 @@ void BOARD::CacheTriangulation( PROGRESS_REPORTER* aReporter, const std::vector<
}; };
for( ZONE* zone : zones ) for( ZONE* zone : zones )
returns.emplace_back( tp.submit( cache_zones, zone ) ); returns.emplace_back( tp.submit_task( [cache_zones, zone] { return cache_zones( zone ); } ) );
// Finalize the triangulation threads // Finalize the triangulation threads
for( const std::future<size_t>& ret : returns ) for( const std::future<size_t>& ret : returns )

View File

@ -270,24 +270,21 @@ void CN_CONNECTIVITY_ALGO::searchConnections()
{ {
std::vector<std::future<size_t>> returns( dirtyItems.size() ); std::vector<std::future<size_t>> returns( dirtyItems.size() );
auto conn_lambda = for( size_t ii = 0; ii < dirtyItems.size(); ++ii )
[&dirtyItems]( size_t aItem, CN_LIST* aItemList,
PROGRESS_REPORTER* aReporter) -> size_t
{ {
if( aReporter && aReporter->IsCancelled() ) returns[ii] = tp.submit_task(
[&dirtyItems, ii, this] () ->size_t {
if( m_progressReporter && m_progressReporter->IsCancelled() )
return 0; return 0;
CN_VISITOR visitor( dirtyItems[aItem] ); CN_VISITOR visitor( dirtyItems[ii] );
aItemList->FindNearby( dirtyItems[aItem], visitor ); m_itemList.FindNearby( dirtyItems[ii], visitor );
if( aReporter ) if( m_progressReporter )
aReporter->AdvanceProgress(); m_progressReporter->AdvanceProgress();
return 1; return 1; } );
}; }
for( size_t ii = 0; ii < dirtyItems.size(); ++ii )
returns[ii] = tp.submit( conn_lambda, ii, &m_itemList, m_progressReporter );
for( const std::future<size_t>& ret : returns ) for( const std::future<size_t>& ret : returns )
{ {
@ -490,7 +487,11 @@ void CN_CONNECTIVITY_ALGO::Build( BOARD* aBoard, PROGRESS_REPORTER* aReporter )
}; };
for( size_t ii = 0; ii < zitems.size(); ++ii ) for( size_t ii = 0; ii < zitems.size(); ++ii )
returns[ii] = tp.submit( cache_zones, zitems[ii] ); {
CN_ZONE_LAYER* ptr = zitems[ii];
returns[ii] = tp.submit_task(
[cache_zones, ptr] { return cache_zones( ptr ); } );
}
for( const std::future<size_t>& ret : returns ) for( const std::future<size_t>& ret : returns )
{ {

View File

@ -191,18 +191,16 @@ void CONNECTIVITY_DATA::updateRatsnest()
thread_pool& tp = GetKiCadThreadPool(); thread_pool& tp = GetKiCadThreadPool();
auto results = tp.parallelize_loop( dirty_nets.size(), auto results = tp.submit_loop( 0, dirty_nets.size(),
[&]( const int a, const int b ) [&]( const int ii )
{ {
for( int ii = a; ii < b; ++ii )
dirty_nets[ii]->UpdateNet(); dirty_nets[ii]->UpdateNet();
} ); } );
results.wait(); results.wait();
auto results2 = tp.parallelize_loop( dirty_nets.size(), auto results2 = tp.submit_loop( 0, dirty_nets.size(),
[&]( const int a, const int b ) [&]( const int ii )
{ {
for( int ii = a; ii < b; ++ii )
dirty_nets[ii]->OptimizeRNEdges(); dirty_nets[ii]->OptimizeRNEdges();
} ); } );
results2.wait(); results2.wait();
@ -370,10 +368,9 @@ void CONNECTIVITY_DATA::ComputeLocalRatsnest( const std::vector<BOARD_ITEM*>& aI
thread_pool& tp = GetKiCadThreadPool(); thread_pool& tp = GetKiCadThreadPool();
size_t num_nets = std::min( m_nets.size(), aDynamicData->m_nets.size() ); size_t num_nets = std::min( m_nets.size(), aDynamicData->m_nets.size() );
auto results = tp.parallelize_loop( 1, num_nets, auto results = tp.submit_loop( 1, num_nets,
[&]( const int a, const int b) [&]( const int ii )
{ {
for( int ii = a; ii < b; ++ii )
update_lambda( ii ); update_lambda( ii );
}); });
results.wait(); results.wait();

View File

@ -55,8 +55,8 @@
#define RESOLVE_PAGE( T, pageIndex ) static_cast<T*>( m_treebook->ResolvePage( pageIndex ) ) #define RESOLVE_PAGE( T, pageIndex ) static_cast<T*>( m_treebook->ResolvePage( pageIndex ) )
DIALOG_BOARD_SETUP::DIALOG_BOARD_SETUP( PCB_EDIT_FRAME* aFrame ) : DIALOG_BOARD_SETUP::DIALOG_BOARD_SETUP( PCB_EDIT_FRAME* aFrame, wxWindow* aParent ) :
PAGED_DIALOG( aFrame, _( "Board Setup" ), false, false, PAGED_DIALOG( aParent ? aParent : aFrame, _( "Board Setup" ), false, false,
_( "Import Settings from Another Board..." ), wxSize( 980, 600 ) ), _( "Import Settings from Another Board..." ), wxSize( 980, 600 ) ),
m_frame( aFrame ), m_frame( aFrame ),
m_layers( nullptr ), m_layers( nullptr ),

View File

@ -42,7 +42,7 @@ class PANEL_TEXT_VARIABLES;
class DIALOG_BOARD_SETUP : public PAGED_DIALOG class DIALOG_BOARD_SETUP : public PAGED_DIALOG
{ {
public: public:
DIALOG_BOARD_SETUP( PCB_EDIT_FRAME* aFrame ); DIALOG_BOARD_SETUP( PCB_EDIT_FRAME* aFrame, wxWindow* aWindow = nullptr );
~DIALOG_BOARD_SETUP(); ~DIALOG_BOARD_SETUP();
protected: protected:

View File

@ -46,8 +46,10 @@
#include <wx/wupdlock.h> #include <wx/wupdlock.h>
#include <widgets/appearance_controls.h> #include <widgets/appearance_controls.h>
#include <widgets/ui_common.h> #include <widgets/ui_common.h>
#include <widgets/std_bitmap_button.h>
#include <widgets/progress_reporter_base.h> #include <widgets/progress_reporter_base.h>
#include <widgets/wx_html_report_box.h> #include <widgets/wx_html_report_box.h>
#include <view/view_controls.h>
#include <dialogs/panel_setup_rules_base.h> #include <dialogs/panel_setup_rules_base.h>
#include <dialogs/dialog_text_entry.h> #include <dialogs/dialog_text_entry.h>
#include <tools/drc_tool.h> #include <tools/drc_tool.h>
@ -74,6 +76,9 @@ DIALOG_DRC::DIALOG_DRC( PCB_EDIT_FRAME* aEditorFrame, wxWindow* aParent ) :
m_running( false ), m_running( false ),
m_drcRun( false ), m_drcRun( false ),
m_footprintTestsRun( false ), m_footprintTestsRun( false ),
m_report_all_track_errors( false ),
m_crossprobe( true ),
m_scroll_on_crossprobe( true ),
m_markersTreeModel( nullptr ), m_markersTreeModel( nullptr ),
m_unconnectedTreeModel( nullptr ), m_unconnectedTreeModel( nullptr ),
m_fpWarningsTreeModel( nullptr ), m_fpWarningsTreeModel( nullptr ),
@ -85,6 +90,15 @@ DIALOG_DRC::DIALOG_DRC( PCB_EDIT_FRAME* aEditorFrame, wxWindow* aParent ) :
m_frame = aEditorFrame; m_frame = aEditorFrame;
m_currentBoard = m_frame->GetBoard(); m_currentBoard = m_frame->GetBoard();
m_bMenu->SetBitmap( KiBitmapBundle( BITMAPS::config ) );
if( PCBNEW_SETTINGS* cfg = m_frame->GetPcbNewSettings() )
{
m_report_all_track_errors = cfg->m_DRCDialog.report_all_track_errors;
m_crossprobe = cfg->m_DRCDialog.crossprobe;
m_scroll_on_crossprobe = cfg->m_DRCDialog.scroll_on_crossprobe;
}
m_messages->SetImmediateMode(); m_messages->SetImmediateMode();
m_markersProvider = std::make_shared<DRC_ITEMS_PROVIDER>( m_currentBoard, m_markersProvider = std::make_shared<DRC_ITEMS_PROVIDER>( m_currentBoard,
@ -147,6 +161,13 @@ DIALOG_DRC::DIALOG_DRC( PCB_EDIT_FRAME* aEditorFrame, wxWindow* aParent ) :
DIALOG_DRC::~DIALOG_DRC() DIALOG_DRC::~DIALOG_DRC()
{ {
if( PCBNEW_SETTINGS* cfg = m_frame->GetPcbNewSettings() )
{
cfg->m_DRCDialog.report_all_track_errors = m_report_all_track_errors;
cfg->m_DRCDialog.crossprobe = m_crossprobe;
cfg->m_DRCDialog.scroll_on_crossprobe = m_scroll_on_crossprobe;
}
m_frame->ClearFocus(); m_frame->ClearFocus();
g_lastDRCBoard = m_currentBoard; g_lastDRCBoard = m_currentBoard;
@ -240,9 +261,49 @@ int DIALOG_DRC::getSeverities()
} }
void DIALOG_DRC::OnMenu( wxCommandEvent& event )
{
// Build a pop menu:
wxMenu menu;
menu.Append( 4205, _( "Report All Errors for Each Track" ),
_( "If unchecked, only the first error will be reported for each track" ),
wxITEM_CHECK );
menu.Check( 4205, m_report_all_track_errors );
menu.AppendSeparator();
menu.Append( 4206, _( "Cross-probe Selected Items" ),
_( "Highlight corresponding items on canvas when selected in the DRC list" ),
wxITEM_CHECK );
menu.Check( 4206, m_crossprobe );
menu.Append( 4207, _( "Center on Cross-probe" ),
_( "When cross-probing, scroll the canvas so that the item is visible" ),
wxITEM_CHECK );
menu.Check( 4207, m_scroll_on_crossprobe );
// menu_id is the selected submenu id from the popup menu or wxID_NONE
int menu_id = m_bMenu->GetPopupMenuSelectionFromUser( menu );
if( menu_id == 0 || menu_id == 4205 )
{
m_report_all_track_errors = !m_report_all_track_errors;
}
else if( menu_id == 2 || menu_id == 4206 )
{
m_crossprobe = !m_crossprobe;
}
else if( menu_id == 3 || menu_id == 4207 )
{
m_scroll_on_crossprobe = !m_scroll_on_crossprobe;
}
}
void DIALOG_DRC::OnErrorLinkClicked( wxHtmlLinkEvent& event ) void DIALOG_DRC::OnErrorLinkClicked( wxHtmlLinkEvent& event )
{ {
m_frame->ShowBoardSetupDialog( _( "Custom Rules" ) ); m_frame->ShowBoardSetupDialog( _( "Custom Rules" ), this );
} }
@ -252,7 +313,6 @@ void DIALOG_DRC::OnRunDRCClick( wxCommandEvent& aEvent )
DRC_TOOL* drcTool = toolMgr->GetTool<DRC_TOOL>(); DRC_TOOL* drcTool = toolMgr->GetTool<DRC_TOOL>();
ZONE_FILLER_TOOL* zoneFillerTool = toolMgr->GetTool<ZONE_FILLER_TOOL>(); ZONE_FILLER_TOOL* zoneFillerTool = toolMgr->GetTool<ZONE_FILLER_TOOL>();
bool refillZones = m_cbRefillZones->GetValue(); bool refillZones = m_cbRefillZones->GetValue();
bool reportAllTrackErrors = m_cbReportAllTrackErrors->GetValue();
bool testFootprints = m_cbTestFootprints->GetValue(); bool testFootprints = m_cbTestFootprints->GetValue();
if( zoneFillerTool->IsBusy() ) if( zoneFillerTool->IsBusy() )
@ -326,7 +386,7 @@ void DIALOG_DRC::OnRunDRCClick( wxCommandEvent& aEvent )
{ {
wxBusyCursor dummy; wxBusyCursor dummy;
drcTool->RunTests( this, refillZones, reportAllTrackErrors, testFootprints ); drcTool->RunTests( this, refillZones, m_report_all_track_errors, testFootprints );
} }
if( m_cancelled ) if( m_cancelled )
@ -378,6 +438,12 @@ void DIALOG_DRC::UpdateData()
void DIALOG_DRC::OnDRCItemSelected( wxDataViewEvent& aEvent ) void DIALOG_DRC::OnDRCItemSelected( wxDataViewEvent& aEvent )
{ {
if( !m_crossprobe )
{
aEvent.Skip();
return;
}
BOARD* board = m_frame->GetBoard(); BOARD* board = m_frame->GetBoard();
RC_TREE_NODE* node = RC_TREE_MODEL::ToNode( aEvent.GetItem() ); RC_TREE_NODE* node = RC_TREE_MODEL::ToNode( aEvent.GetItem() );
@ -408,11 +474,8 @@ void DIALOG_DRC::OnDRCItemSelected( wxDataViewEvent& aEvent )
{ {
VECTOR2D selectedItemPos = aSelectedMarkerItem->GetPosition() / PCB_IU_PER_MM; VECTOR2D selectedItemPos = aSelectedMarkerItem->GetPosition() / PCB_IU_PER_MM;
VECTOR2D unSelectedItemPos = aUnSelectedMarkerItem->GetPosition() / PCB_IU_PER_MM; VECTOR2D unSelectedItemPos = aUnSelectedMarkerItem->GetPosition() / PCB_IU_PER_MM;
double dist = selectedItemPos.Distance( unSelectedItemPos ); double dist = selectedItemPos.Distance( unSelectedItemPos );
double minimumMarkerSeparationDistance = ADVANCED_CFG::GetCfg().m_MinimumMarkerSeparationDistance;
double minimumMarkerSeparationDistance =
ADVANCED_CFG::GetCfg().m_MinimumMarkerSeparationDistance;
return dist <= minimumMarkerSeparationDistance; return dist <= minimumMarkerSeparationDistance;
}; };
@ -430,7 +493,7 @@ void DIALOG_DRC::OnDRCItemSelected( wxDataViewEvent& aEvent )
if( rc_item->GetErrorCode() == DRCE_UNRESOLVED_VARIABLE if( rc_item->GetErrorCode() == DRCE_UNRESOLVED_VARIABLE
&& rc_item->GetParent()->GetMarkerType() == MARKER_BASE::MARKER_DRAWING_SHEET ) && rc_item->GetParent()->GetMarkerType() == MARKER_BASE::MARKER_DRAWING_SHEET )
{ {
m_frame->FocusOnLocation( node->m_RcItem->GetParent()->GetPos() ); m_frame->FocusOnLocation( node->m_RcItem->GetParent()->GetPos(), m_scroll_on_crossprobe );
aEvent.Skip(); aEvent.Skip();
return; return;
@ -512,7 +575,7 @@ void DIALOG_DRC::OnDRCItemSelected( wxDataViewEvent& aEvent )
if( item->Type() == PCB_ZONE_T ) if( item->Type() == PCB_ZONE_T )
{ {
m_frame->FocusOnItem( item, principalLayer ); m_frame->FocusOnItem( item, principalLayer, m_scroll_on_crossprobe );
m_frame->GetBoard()->GetConnectivity()->RunOnUnconnectedEdges( m_frame->GetBoard()->GetConnectivity()->RunOnUnconnectedEdges(
[&]( CN_EDGE& edge ) [&]( CN_EDGE& edge )
@ -541,7 +604,7 @@ void DIALOG_DRC::OnDRCItemSelected( wxDataViewEvent& aEvent )
: edge.GetTargetPos(); : edge.GetTargetPos();
} }
m_frame->FocusOnLocation( focusPos ); m_frame->FocusOnLocation( focusPos, m_scroll_on_crossprobe );
m_frame->RefreshCanvas(); m_frame->RefreshCanvas();
return false; return false;
@ -552,7 +615,7 @@ void DIALOG_DRC::OnDRCItemSelected( wxDataViewEvent& aEvent )
} }
else else
{ {
m_frame->FocusOnItem( item, principalLayer ); m_frame->FocusOnItem( item, principalLayer, m_scroll_on_crossprobe );
} }
} }
else if( rc_item->GetErrorCode() == DRCE_DIFF_PAIR_UNCOUPLED_LENGTH_TOO_LONG ) else if( rc_item->GetErrorCode() == DRCE_DIFF_PAIR_UNCOUPLED_LENGTH_TOO_LONG )
@ -579,7 +642,7 @@ void DIALOG_DRC::OnDRCItemSelected( wxDataViewEvent& aEvent )
items.push_back( item ); items.push_back( item );
} }
m_frame->FocusOnItems( items, principalLayer ); m_frame->FocusOnItems( items, principalLayer, m_scroll_on_crossprobe );
} }
else else
{ {
@ -594,11 +657,11 @@ void DIALOG_DRC::OnDRCItemSelected( wxDataViewEvent& aEvent )
} }
items.push_back( item ); items.push_back( item );
m_frame->FocusOnItems( items, principalLayer ); m_frame->FocusOnItems( items, principalLayer, m_scroll_on_crossprobe );
} }
else else
{ {
m_frame->FocusOnItem( item, principalLayer ); m_frame->FocusOnItem( item, principalLayer, m_scroll_on_crossprobe );
} }
} }
@ -930,7 +993,7 @@ void DIALOG_DRC::OnDRCItemRClick( wxDataViewEvent& aEvent )
} }
case ID_EDIT_SEVERITIES: case ID_EDIT_SEVERITIES:
m_frame->ShowBoardSetupDialog( _( "Violation Severity" ) ); m_frame->ShowBoardSetupDialog( _( "Violation Severity" ), this );
break; break;
} }
@ -972,7 +1035,7 @@ void DIALOG_DRC::OnIgnoredItemRClick( wxListEvent& event )
void DIALOG_DRC::OnEditViolationSeverities( wxHyperlinkEvent& aEvent ) void DIALOG_DRC::OnEditViolationSeverities( wxHyperlinkEvent& aEvent )
{ {
m_frame->ShowBoardSetupDialog( _( "Violation Severity" ) ); m_frame->ShowBoardSetupDialog( _( "Violation Severity" ), this );
} }

View File

@ -77,6 +77,7 @@ private:
bool TransferDataToWindow() override; bool TransferDataToWindow() override;
void OnMenu( wxCommandEvent& aEvent ) override;
void OnDRCItemSelected( wxDataViewEvent& aEvent ) override; void OnDRCItemSelected( wxDataViewEvent& aEvent ) override;
void OnDRCItemDClick( wxDataViewEvent& aEvent ) override; void OnDRCItemDClick( wxDataViewEvent& aEvent ) override;
void OnDRCItemRClick( wxDataViewEvent& aEvent ) override; void OnDRCItemRClick( wxDataViewEvent& aEvent ) override;
@ -117,6 +118,10 @@ private:
bool m_drcRun; bool m_drcRun;
bool m_footprintTestsRun; bool m_footprintTestsRun;
bool m_report_all_track_errors;
bool m_crossprobe;
bool m_scroll_on_crossprobe;
wxString m_markersTitleTemplate; wxString m_markersTitleTemplate;
wxString m_unconnectedTitleTemplate; wxString m_unconnectedTitleTemplate;
wxString m_footprintsTitleTemplate; wxString m_footprintsTitleTemplate;

View File

@ -5,6 +5,7 @@
// PLEASE DO *NOT* EDIT THIS FILE! // PLEASE DO *NOT* EDIT THIS FILE!
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
#include "widgets/std_bitmap_button.h"
#include "widgets/wx_html_report_box.h" #include "widgets/wx_html_report_box.h"
#include "dialog_drc_base.h" #include "dialog_drc_base.h"
@ -24,30 +25,43 @@ DIALOG_DRC_BASE::DIALOG_DRC_BASE( wxWindow* parent, wxWindowID id, const wxStrin
wxBoxSizer* bSizer12; wxBoxSizer* bSizer12;
bSizer12 = new wxBoxSizer( wxVERTICAL ); bSizer12 = new wxBoxSizer( wxVERTICAL );
m_cbRefillZones = new wxCheckBox( this, wxID_ANY, _("Refill all zones before performing DRC"), wxDefaultPosition, wxDefaultSize, 0 );
m_cbRefillZones->SetValue(true);
bSizer12->Add( m_cbRefillZones, 0, wxALL, 5 );
m_cbReportAllTrackErrors = new wxCheckBox( this, wxID_ANY, _("Report all errors for each track"), wxDefaultPosition, wxDefaultSize, 0 );
m_cbReportAllTrackErrors->SetToolTip( _("If selected, all DRC violations for tracks will be reported. This can be slow for complicated designs.\n\nIf unselected, only the first DRC violation will be reported for each track connection.") );
bSizer12->Add( m_cbReportAllTrackErrors, 0, wxBOTTOM|wxRIGHT|wxLEFT, 5 );
bSizerOptions->Add( bSizer12, 1, wxEXPAND|wxTOP|wxRIGHT|wxLEFT, 5 ); bSizerOptions->Add( bSizer12, 1, wxEXPAND|wxTOP|wxRIGHT|wxLEFT, 5 );
wxBoxSizer* bSizerOptSettings; wxBoxSizer* bSizerOptSettings;
bSizerOptSettings = new wxBoxSizer( wxVERTICAL ); bSizerOptSettings = new wxBoxSizer( wxVERTICAL );
m_cbTestFootprints = new wxCheckBox( this, wxID_ANY, _("Test for parity between PCB and schematic"), wxDefaultPosition, wxDefaultSize, 0 );
bSizerOptSettings->Add( m_cbTestFootprints, 0, wxALL, 5 );
bSizerOptions->Add( bSizerOptSettings, 1, wxEXPAND|wxTOP|wxRIGHT|wxLEFT, 5 ); bSizerOptions->Add( bSizerOptSettings, 1, wxEXPAND|wxTOP|wxRIGHT|wxLEFT, 5 );
m_MainSizer->Add( bSizerOptions, 0, wxEXPAND|wxTOP|wxBOTTOM|wxLEFT, 3 ); m_MainSizer->Add( bSizerOptions, 0, wxEXPAND|wxTOP|wxBOTTOM|wxLEFT, 3 );
wxGridBagSizer* gbSizerOptions;
gbSizerOptions = new wxGridBagSizer( 0, 0 );
gbSizerOptions->SetFlexibleDirection( wxBOTH );
gbSizerOptions->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED );
m_cbRefillZones = new wxCheckBox( this, wxID_ANY, _("Refill all zones before performing DRC"), wxDefaultPosition, wxDefaultSize, 0 );
m_cbRefillZones->SetValue(true);
gbSizerOptions->Add( m_cbRefillZones, wxGBPosition( 0, 0 ), wxGBSpan( 1, 1 ), wxALIGN_CENTER_VERTICAL|wxTOP|wxRIGHT|wxLEFT, 5 );
m_cbTestFootprints = new wxCheckBox( this, wxID_ANY, _("Test for parity between PCB and schematic"), wxDefaultPosition, wxDefaultSize, 0 );
gbSizerOptions->Add( m_cbTestFootprints, wxGBPosition( 0, 1 ), wxGBSpan( 1, 1 ), wxALIGN_CENTER_VERTICAL|wxTOP|wxRIGHT|wxLEFT, 5 );
m_bMenu = new STD_BITMAP_BUTTON( this, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxDefaultSize, wxBU_AUTODRAW|0 );
m_bMenu->SetMinSize( wxSize( 30,30 ) );
gbSizerOptions->Add( m_bMenu, wxGBPosition( 0, 2 ), wxGBSpan( 2, 1 ), wxALIGN_CENTER_VERTICAL|wxRIGHT, 5 );
gbSizerOptions->AddGrowableCol( 0 );
gbSizerOptions->AddGrowableCol( 1 );
gbSizerOptions->AddGrowableRow( 0 );
gbSizerOptions->AddGrowableRow( 1 );
m_MainSizer->Add( gbSizerOptions, 0, wxEXPAND|wxTOP|wxLEFT, 10 );
m_runningResultsBook = new wxSimplebook( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0 ); m_runningResultsBook = new wxSimplebook( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0 );
running = new wxPanel( m_runningResultsBook, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL ); running = new wxPanel( m_runningResultsBook, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL );
wxBoxSizer* bSizer14; wxBoxSizer* bSizer14;
@ -242,6 +256,7 @@ DIALOG_DRC_BASE::DIALOG_DRC_BASE( wxWindow* parent, wxWindowID id, const wxStrin
// Connect Events // Connect Events
this->Connect( wxEVT_ACTIVATE, wxActivateEventHandler( DIALOG_DRC_BASE::OnActivateDlg ) ); this->Connect( wxEVT_ACTIVATE, wxActivateEventHandler( DIALOG_DRC_BASE::OnActivateDlg ) );
this->Connect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( DIALOG_DRC_BASE::OnClose ) ); this->Connect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( DIALOG_DRC_BASE::OnClose ) );
m_bMenu->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_DRC_BASE::OnMenu ), NULL, this );
m_messages->Connect( wxEVT_COMMAND_HTML_LINK_CLICKED, wxHtmlLinkEventHandler( DIALOG_DRC_BASE::OnErrorLinkClicked ), NULL, this ); m_messages->Connect( wxEVT_COMMAND_HTML_LINK_CLICKED, wxHtmlLinkEventHandler( DIALOG_DRC_BASE::OnErrorLinkClicked ), NULL, this );
m_Notebook->Connect( wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED, wxNotebookEventHandler( DIALOG_DRC_BASE::OnChangingNotebookPage ), NULL, this ); m_Notebook->Connect( wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED, wxNotebookEventHandler( DIALOG_DRC_BASE::OnChangingNotebookPage ), NULL, this );
m_markerDataView->Connect( wxEVT_COMMAND_DATAVIEW_ITEM_ACTIVATED, wxDataViewEventHandler( DIALOG_DRC_BASE::OnDRCItemDClick ), NULL, this ); m_markerDataView->Connect( wxEVT_COMMAND_DATAVIEW_ITEM_ACTIVATED, wxDataViewEventHandler( DIALOG_DRC_BASE::OnDRCItemDClick ), NULL, this );
@ -271,6 +286,7 @@ DIALOG_DRC_BASE::~DIALOG_DRC_BASE()
// Disconnect Events // Disconnect Events
this->Disconnect( wxEVT_ACTIVATE, wxActivateEventHandler( DIALOG_DRC_BASE::OnActivateDlg ) ); this->Disconnect( wxEVT_ACTIVATE, wxActivateEventHandler( DIALOG_DRC_BASE::OnActivateDlg ) );
this->Disconnect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( DIALOG_DRC_BASE::OnClose ) ); this->Disconnect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( DIALOG_DRC_BASE::OnClose ) );
m_bMenu->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_DRC_BASE::OnMenu ), NULL, this );
m_messages->Disconnect( wxEVT_COMMAND_HTML_LINK_CLICKED, wxHtmlLinkEventHandler( DIALOG_DRC_BASE::OnErrorLinkClicked ), NULL, this ); m_messages->Disconnect( wxEVT_COMMAND_HTML_LINK_CLICKED, wxHtmlLinkEventHandler( DIALOG_DRC_BASE::OnErrorLinkClicked ), NULL, this );
m_Notebook->Disconnect( wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED, wxNotebookEventHandler( DIALOG_DRC_BASE::OnChangingNotebookPage ), NULL, this ); m_Notebook->Disconnect( wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED, wxNotebookEventHandler( DIALOG_DRC_BASE::OnChangingNotebookPage ), NULL, this );
m_markerDataView->Disconnect( wxEVT_COMMAND_DATAVIEW_ITEM_ACTIVATED, wxDataViewEventHandler( DIALOG_DRC_BASE::OnDRCItemDClick ), NULL, this ); m_markerDataView->Disconnect( wxEVT_COMMAND_DATAVIEW_ITEM_ACTIVATED, wxDataViewEventHandler( DIALOG_DRC_BASE::OnDRCItemDClick ), NULL, this );

View File

@ -84,10 +84,43 @@
<property name="name">bSizer12</property> <property name="name">bSizer12</property>
<property name="orient">wxVERTICAL</property> <property name="orient">wxVERTICAL</property>
<property name="permission">none</property> <property name="permission">none</property>
<object class="sizeritem" expanded="false"> </object>
</object>
<object class="sizeritem" expanded="true">
<property name="border">5</property> <property name="border">5</property>
<property name="flag">wxALL</property> <property name="flag">wxEXPAND|wxTOP|wxRIGHT|wxLEFT</property>
<property name="proportion">1</property>
<object class="wxBoxSizer" expanded="true">
<property name="minimum_size"></property>
<property name="name">bSizerOptSettings</property>
<property name="orient">wxVERTICAL</property>
<property name="permission">none</property>
</object>
</object>
</object>
</object>
<object class="sizeritem" expanded="true">
<property name="border">10</property>
<property name="flag">wxEXPAND|wxTOP|wxLEFT</property>
<property name="proportion">0</property> <property name="proportion">0</property>
<object class="wxGridBagSizer" expanded="true">
<property name="empty_cell_size"></property>
<property name="flexible_direction">wxBOTH</property>
<property name="growablecols">0,1</property>
<property name="growablerows">0,1</property>
<property name="hgap">0</property>
<property name="minimum_size"></property>
<property name="name">gbSizerOptions</property>
<property name="non_flexible_grow_mode">wxFLEX_GROWMODE_SPECIFIED</property>
<property name="permission">none</property>
<property name="vgap">0</property>
<object class="gbsizeritem" expanded="true">
<property name="border">5</property>
<property name="colspan">1</property>
<property name="column">0</property>
<property name="flag">wxALIGN_CENTER_VERTICAL|wxTOP|wxRIGHT|wxLEFT</property>
<property name="row">0</property>
<property name="rowspan">1</property>
<object class="wxCheckBox" expanded="false"> <object class="wxCheckBox" expanded="false">
<property name="BottomDockable">1</property> <property name="BottomDockable">1</property>
<property name="LeftDockable">1</property> <property name="LeftDockable">1</property>
@ -149,86 +182,13 @@
<property name="window_style"></property> <property name="window_style"></property>
</object> </object>
</object> </object>
<object class="sizeritem" expanded="false"> <object class="gbsizeritem" expanded="true">
<property name="border">5</property> <property name="border">5</property>
<property name="flag">wxBOTTOM|wxRIGHT|wxLEFT</property> <property name="colspan">1</property>
<property name="proportion">0</property> <property name="column">1</property>
<object class="wxCheckBox" expanded="false"> <property name="flag">wxALIGN_CENTER_VERTICAL|wxTOP|wxRIGHT|wxLEFT</property>
<property name="BottomDockable">1</property> <property name="row">0</property>
<property name="LeftDockable">1</property> <property name="rowspan">1</property>
<property name="RightDockable">1</property>
<property name="TopDockable">1</property>
<property name="aui_layer">0</property>
<property name="aui_name"></property>
<property name="aui_position">0</property>
<property name="aui_row">0</property>
<property name="best_size"></property>
<property name="bg"></property>
<property name="caption"></property>
<property name="caption_visible">1</property>
<property name="center_pane">0</property>
<property name="checked">0</property>
<property name="close_button">1</property>
<property name="context_help"></property>
<property name="context_menu">1</property>
<property name="default_pane">0</property>
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="drag_accept_files">0</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
<property name="font"></property>
<property name="gripper">0</property>
<property name="hidden">0</property>
<property name="id">wxID_ANY</property>
<property name="label">Report all errors for each track</property>
<property name="max_size"></property>
<property name="maximize_button">0</property>
<property name="maximum_size"></property>
<property name="min_size"></property>
<property name="minimize_button">0</property>
<property name="minimum_size"></property>
<property name="moveable">1</property>
<property name="name">m_cbReportAllTrackErrors</property>
<property name="pane_border">1</property>
<property name="pane_position"></property>
<property name="pane_size"></property>
<property name="permission">protected</property>
<property name="pin_button">1</property>
<property name="pos"></property>
<property name="resize">Resizable</property>
<property name="show">1</property>
<property name="size"></property>
<property name="style"></property>
<property name="subclass">; forward_declare</property>
<property name="toolbar_pane">0</property>
<property name="tooltip">If selected, all DRC violations for tracks will be reported. This can be slow for complicated designs.&#x0A;&#x0A;If unselected, only the first DRC violation will be reported for each track connection.</property>
<property name="validator_data_type"></property>
<property name="validator_style">wxFILTER_NONE</property>
<property name="validator_type">wxDefaultValidator</property>
<property name="validator_variable"></property>
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style"></property>
</object>
</object>
</object>
</object>
<object class="sizeritem" expanded="true">
<property name="border">5</property>
<property name="flag">wxEXPAND|wxTOP|wxRIGHT|wxLEFT</property>
<property name="proportion">1</property>
<object class="wxBoxSizer" expanded="true">
<property name="minimum_size"></property>
<property name="name">bSizerOptSettings</property>
<property name="orient">wxVERTICAL</property>
<property name="permission">none</property>
<object class="sizeritem" expanded="false">
<property name="border">5</property>
<property name="flag">wxALL</property>
<property name="proportion">0</property>
<object class="wxCheckBox" expanded="false"> <object class="wxCheckBox" expanded="false">
<property name="BottomDockable">1</property> <property name="BottomDockable">1</property>
<property name="LeftDockable">1</property> <property name="LeftDockable">1</property>
@ -290,6 +250,82 @@
<property name="window_style"></property> <property name="window_style"></property>
</object> </object>
</object> </object>
<object class="gbsizeritem" expanded="true">
<property name="border">5</property>
<property name="colspan">1</property>
<property name="column">2</property>
<property name="flag">wxALIGN_CENTER_VERTICAL|wxRIGHT</property>
<property name="row">0</property>
<property name="rowspan">2</property>
<object class="wxBitmapButton" expanded="true">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
<property name="TopDockable">1</property>
<property name="aui_layer">0</property>
<property name="aui_name"></property>
<property name="aui_position">0</property>
<property name="aui_row">0</property>
<property name="auth_needed">0</property>
<property name="best_size"></property>
<property name="bg"></property>
<property name="bitmap"></property>
<property name="caption"></property>
<property name="caption_visible">1</property>
<property name="center_pane">0</property>
<property name="close_button">1</property>
<property name="context_help"></property>
<property name="context_menu">1</property>
<property name="current"></property>
<property name="default">0</property>
<property name="default_pane">0</property>
<property name="disabled"></property>
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="drag_accept_files">0</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
<property name="focus"></property>
<property name="font"></property>
<property name="gripper">0</property>
<property name="hidden">0</property>
<property name="id">wxID_ANY</property>
<property name="label">Refresh Grouping</property>
<property name="margins"></property>
<property name="markup">0</property>
<property name="max_size"></property>
<property name="maximize_button">0</property>
<property name="maximum_size"></property>
<property name="min_size"></property>
<property name="minimize_button">0</property>
<property name="minimum_size">30,30</property>
<property name="moveable">1</property>
<property name="name">m_bMenu</property>
<property name="pane_border">1</property>
<property name="pane_position"></property>
<property name="pane_size"></property>
<property name="permission">protected</property>
<property name="pin_button">1</property>
<property name="pos"></property>
<property name="position"></property>
<property name="pressed"></property>
<property name="resize">Resizable</property>
<property name="show">1</property>
<property name="size"></property>
<property name="style"></property>
<property name="subclass">STD_BITMAP_BUTTON; widgets/std_bitmap_button.h; forward_declare</property>
<property name="toolbar_pane">0</property>
<property name="tooltip"></property>
<property name="validator_data_type"></property>
<property name="validator_style">wxFILTER_NONE</property>
<property name="validator_type">wxDefaultValidator</property>
<property name="validator_variable"></property>
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style"></property>
<event name="OnButtonClick">OnMenu</event>
</object> </object>
</object> </object>
</object> </object>

View File

@ -10,22 +10,26 @@
#include <wx/artprov.h> #include <wx/artprov.h>
#include <wx/xrc/xmlres.h> #include <wx/xrc/xmlres.h>
#include <wx/intl.h> #include <wx/intl.h>
class STD_BITMAP_BUTTON;
class WX_HTML_REPORT_BOX; class WX_HTML_REPORT_BOX;
#include "dialog_shim.h" #include "dialog_shim.h"
#include <wx/sizer.h>
#include <wx/gdicmn.h>
#include <wx/string.h> #include <wx/string.h>
#include <wx/checkbox.h> #include <wx/checkbox.h>
#include <wx/gdicmn.h>
#include <wx/font.h> #include <wx/font.h>
#include <wx/colour.h> #include <wx/colour.h>
#include <wx/settings.h> #include <wx/settings.h>
#include <wx/sizer.h> #include <wx/bmpbuttn.h>
#include <wx/html/htmlwin.h>
#include <wx/gauge.h>
#include <wx/panel.h>
#include <wx/bitmap.h> #include <wx/bitmap.h>
#include <wx/image.h> #include <wx/image.h>
#include <wx/icon.h> #include <wx/icon.h>
#include <wx/button.h>
#include <wx/gbsizer.h>
#include <wx/html/htmlwin.h>
#include <wx/gauge.h>
#include <wx/panel.h>
#include <wx/notebook.h> #include <wx/notebook.h>
#include <wx/dataview.h> #include <wx/dataview.h>
#include <wx/listctrl.h> #include <wx/listctrl.h>
@ -33,7 +37,6 @@ class WX_HTML_REPORT_BOX;
#include <wx/simplebook.h> #include <wx/simplebook.h>
#include <wx/stattext.h> #include <wx/stattext.h>
#include <widgets/number_badge.h> #include <widgets/number_badge.h>
#include <wx/button.h>
#include <wx/dialog.h> #include <wx/dialog.h>
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
@ -48,8 +51,8 @@ class DIALOG_DRC_BASE : public DIALOG_SHIM
protected: protected:
wxCheckBox* m_cbRefillZones; wxCheckBox* m_cbRefillZones;
wxCheckBox* m_cbReportAllTrackErrors;
wxCheckBox* m_cbTestFootprints; wxCheckBox* m_cbTestFootprints;
STD_BITMAP_BUTTON* m_bMenu;
wxSimplebook* m_runningResultsBook; wxSimplebook* m_runningResultsBook;
wxPanel* running; wxPanel* running;
wxNotebook* m_runningNotebook; wxNotebook* m_runningNotebook;
@ -85,6 +88,7 @@ class DIALOG_DRC_BASE : public DIALOG_SHIM
// Virtual event handlers, override them in your derived class // Virtual event handlers, override them in your derived class
virtual void OnActivateDlg( wxActivateEvent& event ) { event.Skip(); } virtual void OnActivateDlg( wxActivateEvent& event ) { event.Skip(); }
virtual void OnClose( wxCloseEvent& event ) { event.Skip(); } virtual void OnClose( wxCloseEvent& event ) { event.Skip(); }
virtual void OnMenu( wxCommandEvent& event ) { event.Skip(); }
virtual void OnErrorLinkClicked( wxHtmlLinkEvent& event ) { event.Skip(); } virtual void OnErrorLinkClicked( wxHtmlLinkEvent& event ) { event.Skip(); }
virtual void OnChangingNotebookPage( wxNotebookEvent& event ) { event.Skip(); } virtual void OnChangingNotebookPage( wxNotebookEvent& event ) { event.Skip(); }
virtual void OnDRCItemDClick( wxDataViewEvent& event ) { event.Skip(); } virtual void OnDRCItemDClick( wxDataViewEvent& event ) { event.Skip(); }

View File

@ -425,7 +425,7 @@ void DIALOG_EXPORT_ODBPP::GenerateODBPPFiles( const JOB_EXPORT_PCB_ODB& aJob, BO
}; };
thread_pool& tp = GetKiCadThreadPool(); thread_pool& tp = GetKiCadThreadPool();
auto ret = tp.submit( saveFile ); auto ret = tp.submit_task( saveFile );
std::future_status status = ret.wait_for( std::chrono::milliseconds( 250 ) ); std::future_status status = ret.wait_for( std::chrono::milliseconds( 250 ) );

View File

@ -674,6 +674,7 @@ bool DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR::Validate()
// Check that the user isn't trying to remove a layer that is used by the footprint // Check that the user isn't trying to remove a layer that is used by the footprint
usedLayers &= ~getCustomLayersFromControls(); usedLayers &= ~getCustomLayersFromControls();
usedLayers &= ~LSET::AllTechMask(); usedLayers &= ~LSET::AllTechMask();
usedLayers &= ~LSET::UserMask();
if( usedLayers.any() ) if( usedLayers.any() )
{ {

View File

@ -38,6 +38,7 @@
#include <wx/dirdlg.h> #include <wx/dirdlg.h>
#include <wx/filedlg.h> #include <wx/filedlg.h>
#include <wx/msgdlg.h> #include <wx/msgdlg.h>
#include <functional>
#include <project.h> #include <project.h>
#include <env_vars.h> #include <env_vars.h>
@ -147,6 +148,12 @@ public:
m_dialog( aParent ) m_dialog( aParent )
{ } { }
FP_GRID_TRICKS( DIALOG_EDIT_LIBRARY_TABLES* aParent, WX_GRID* aGrid,
std::function<void( wxCommandEvent& )> aAddHandler ) :
LIB_TABLE_GRID_TRICKS( aGrid, aAddHandler ),
m_dialog( aParent )
{ }
protected: protected:
DIALOG_EDIT_LIBRARY_TABLES* m_dialog; DIALOG_EDIT_LIBRARY_TABLES* m_dialog;
@ -217,8 +224,21 @@ protected:
} }
else else
{ {
// paste spreadsheet formatted text. wxString text = cb_text;
GRID_TRICKS::paste_text( cb_text );
if( !text.Contains( '\t' ) && text.Contains( ',' ) )
text.Replace( ',', '\t' );
if( text.Contains( '\t' ) )
{
int row = m_grid->GetGridCursorRow();
m_grid->ClearSelection();
m_grid->SelectRow( row );
m_grid->SetGridCursor( row, 0 );
getSelectedArea();
}
GRID_TRICKS::paste_text( text );
m_grid->AutoSizeColumns( false ); m_grid->AutoSizeColumns( false );
} }
@ -254,7 +274,8 @@ void PANEL_FP_LIB_TABLE::setupGrid( WX_GRID* aGrid )
aGrid->SetRowSize( ii, aGrid->GetDefaultRowSize() + 4 ); aGrid->SetRowSize( ii, aGrid->GetDefaultRowSize() + 4 );
// add Cut, Copy, and Paste to wxGrids // add Cut, Copy, and Paste to wxGrids
aGrid->PushEventHandler( new FP_GRID_TRICKS( m_parent, aGrid ) ); aGrid->PushEventHandler( new FP_GRID_TRICKS( m_parent, aGrid,
[this]( wxCommandEvent& event ) { appendRowHandler( event ); } ) );
aGrid->SetSelectionMode( wxGrid::wxGridSelectRows ); aGrid->SetSelectionMode( wxGrid::wxGridSelectRows );

View File

@ -158,7 +158,7 @@ bool DRC_CACHE_GENERATOR::Run()
forEachGeometryItem( itemTypes, boardCopperLayers, countItems ); forEachGeometryItem( itemTypes, boardCopperLayers, countItems );
std::future<void> retn = tp.submit( std::future<void> retn = tp.submit_task(
[&]() [&]()
{ {
std::unique_lock<std::shared_mutex> writeLock( m_board->m_CachesMutex ); std::unique_lock<std::shared_mutex> writeLock( m_board->m_CachesMutex );
@ -225,7 +225,7 @@ bool DRC_CACHE_GENERATOR::Run()
}; };
for( ZONE* zone : allZones ) for( ZONE* zone : allZones )
returns.emplace_back( tp.submit( cache_zones, zone ) ); returns.emplace_back( tp.submit_task( [cache_zones, zone] { return cache_zones( zone ); } ) );
done.store( 1 ); done.store( 1 );

View File

@ -2317,9 +2317,7 @@ void CREEPAGE_GRAPH::GeneratePaths( double aMaxWeight, PCB_LAYER_ID aLayer )
} }
} }
auto processWorkItems = [&]( size_t start_idx, size_t end_idx ) -> bool auto processWorkItems = [&]( size_t idx ) -> bool
{
for( size_t idx = start_idx; idx < end_idx; ++idx )
{ {
auto [gn1, gn2] = work_items[idx]; auto [gn1, gn2] = work_items[idx];
@ -2366,7 +2364,7 @@ void CREEPAGE_GRAPH::GeneratePaths( double aMaxWeight, PCB_LAYER_ID aLayer )
AddConnection( connect1, connect2, pc ); AddConnection( connect1, connect2, pc );
} }
}
return true; return true;
}; };
@ -2374,15 +2372,16 @@ void CREEPAGE_GRAPH::GeneratePaths( double aMaxWeight, PCB_LAYER_ID aLayer )
// has already parallelized the work, so we can process all items in one go. // has already parallelized the work, so we can process all items in one go.
if( tp.get_tasks_total() >= tp.get_thread_count() - 4 ) if( tp.get_tasks_total() >= tp.get_thread_count() - 4 )
{ {
processWorkItems( 0, work_items.size() ); for( size_t ii = 0; ii < work_items.size(); ii++ )
processWorkItems( ii );
} }
else else
{ {
auto ret = tp.parallelize_loop( work_items.size(), processWorkItems ); auto ret = tp.submit_loop( 0, work_items.size(), processWorkItems );
for( size_t ii = 0; ii < ret.size(); ii++ ) for( size_t ii = 0; ii < ret.size(); ii++ )
{ {
std::future<bool>& r = ret[ii]; auto& r = ret[ii];
if( !r.valid() ) if( !r.valid() )
continue; continue;

View File

@ -527,10 +527,9 @@ void DRC_ENGINE::loadRules( const wxFileName& aPath )
void DRC_ENGINE::compileRules() void DRC_ENGINE::compileRules()
{ {
if( m_logReporter ) if( m_logReporter )
{ m_logReporter->Report( wxT( "Compiling Rules" ) );
m_logReporter->Report( ( wxString::Format( wxT( "Compiling Rules (%d rules): " ),
(int) m_rules.size() ) ) ); REPORTER error_semaphore;
}
for( std::shared_ptr<DRC_RULE>& rule : m_rules ) for( std::shared_ptr<DRC_RULE>& rule : m_rules )
{ {
@ -539,9 +538,12 @@ void DRC_ENGINE::compileRules()
if( rule->m_Condition && !rule->m_Condition->GetExpression().IsEmpty() ) if( rule->m_Condition && !rule->m_Condition->GetExpression().IsEmpty() )
{ {
condition = rule->m_Condition; condition = rule->m_Condition;
condition->Compile( nullptr ); condition->Compile( &error_semaphore );
} }
if( error_semaphore.HasMessageOfSeverity( RPT_SEVERITY_ERROR ) )
THROW_PARSE_ERROR( wxT( "Parse error" ), rule->m_Name, rule->m_Condition->GetExpression(), 0, 0 );
for( const DRC_CONSTRAINT& constraint : rule->m_Constraints ) for( const DRC_CONSTRAINT& constraint : rule->m_Constraints )
{ {
if( !m_constraintMap.count( constraint.m_Type ) ) if( !m_constraintMap.count( constraint.m_Type ) )
@ -594,6 +596,8 @@ void DRC_ENGINE::InitEngine( const wxFileName& aRulePath )
} }
catch( PARSE_ERROR& original_parse_error ) catch( PARSE_ERROR& original_parse_error )
{ {
m_rules.clear();
try // try again with just our implicit rules try // try again with just our implicit rules
{ {
loadImplicitRules(); loadImplicitRules();

View File

@ -505,7 +505,6 @@ bool DRC_TEST_PROVIDER_CONNECTION_WIDTH::Run()
} }
thread_pool& tp = GetKiCadThreadPool(); thread_pool& tp = GetKiCadThreadPool();
std::vector<std::future<size_t>> returns;
size_t total_effort = 0; size_t total_effort = 0;
for( const auto& [ netLayer, itemsPoly ] : dataset ) for( const auto& [ netLayer, itemsPoly ] : dataset )
@ -513,14 +512,16 @@ bool DRC_TEST_PROVIDER_CONNECTION_WIDTH::Run()
total_effort += std::max( (size_t) 1, total_effort ) * distinctMinWidths.size(); total_effort += std::max( (size_t) 1, total_effort ) * distinctMinWidths.size();
std::vector<std::future<size_t>> returns;
returns.reserve( dataset.size() ); returns.reserve( dataset.size() );
for( const auto& [ netLayer, itemsPoly ] : dataset ) for( const auto& [ netLayer, itemsPoly ] : dataset )
{ {
returns.emplace_back( tp.submit( build_netlayer_polys, netLayer.Netcode, netLayer.Layer ) ); int netcode = netLayer.Netcode;
PCB_LAYER_ID layer = netLayer.Layer;
returns.emplace_back( tp.submit_task( [&, netcode, layer]() { return build_netlayer_polys( netcode, layer ); } ) );
} }
for( std::future<size_t>& ret : returns ) for( auto& ret : returns )
{ {
std::future_status status = ret.wait_for( std::chrono::milliseconds( 250 ) ); std::future_status status = ret.wait_for( std::chrono::milliseconds( 250 ) );
@ -541,11 +542,13 @@ bool DRC_TEST_PROVIDER_CONNECTION_WIDTH::Run()
if( minWidth - epsilon <= 0 ) if( minWidth - epsilon <= 0 )
continue; continue;
returns.emplace_back( tp.submit( min_checker, itemsPoly, netLayer.Layer, minWidth ) ); returns.emplace_back( tp.submit_task( [min_checker, &itemsPoly, &netLayer, minWidth]() {
return min_checker( itemsPoly, netLayer.Layer, minWidth );
} ) );
} }
} }
for( std::future<size_t>& ret : returns ) for( auto& ret : returns )
{ {
std::future_status status = ret.wait_for( std::chrono::milliseconds( 250 ) ); std::future_status status = ret.wait_for( std::chrono::milliseconds( 250 ) );

View File

@ -594,9 +594,7 @@ void DRC_TEST_PROVIDER_COPPER_CLEARANCE::testTrackClearances()
LSET boardCopperLayers = LSET::AllCuMask( m_board->GetCopperLayerCount() ); LSET boardCopperLayers = LSET::AllCuMask( m_board->GetCopperLayerCount() );
auto testTrack = [&]( const int start_idx, const int end_idx ) auto testTrack = [&]( const int trackIdx )
{
for( int trackIdx = start_idx; trackIdx < end_idx; ++trackIdx )
{ {
PCB_TRACK* track = m_board->Tracks()[trackIdx]; PCB_TRACK* track = m_board->Tracks()[trackIdx];
@ -697,12 +695,11 @@ void DRC_TEST_PROVIDER_COPPER_CLEARANCE::testTrackClearances()
} }
done.fetch_add( 1 ); done.fetch_add( 1 );
}
}; };
thread_pool& tp = GetKiCadThreadPool(); thread_pool& tp = GetKiCadThreadPool();
tp.push_loop( m_board->Tracks().size(), testTrack ); auto track_futures = tp.submit_loop( 0, m_board->Tracks().size(), testTrack );
while( done < count ) while( done < count )
{ {
@ -710,7 +707,8 @@ void DRC_TEST_PROVIDER_COPPER_CLEARANCE::testTrackClearances()
if( m_drcEngine->IsCancelled() ) if( m_drcEngine->IsCancelled() )
{ {
tp.wait_for_tasks(); // Wait for the submitted loop tasks to finish
track_futures.wait();
break; break;
} }
@ -967,9 +965,7 @@ void DRC_TEST_PROVIDER_COPPER_CLEARANCE::testPadClearances( )
LSET boardCopperLayers = LSET::AllCuMask( m_board->GetCopperLayerCount() ); LSET boardCopperLayers = LSET::AllCuMask( m_board->GetCopperLayerCount() );
const auto fp_check = [&]( size_t aFromIdx, size_t aToIdx ) const auto fp_check = [&]( size_t ii )
{
for( size_t ii = aFromIdx; ii < aToIdx; ++ii )
{ {
FOOTPRINT* footprint = m_board->Footprints()[ ii ]; FOOTPRINT* footprint = m_board->Footprints()[ ii ];
@ -1038,11 +1034,10 @@ void DRC_TEST_PROVIDER_COPPER_CLEARANCE::testPadClearances( )
} }
done.fetch_add( 1 ); done.fetch_add( 1 );
}
}; };
size_t numFootprints = m_board->Footprints().size(); size_t numFootprints = m_board->Footprints().size();
auto returns = tp.parallelize_loop( numFootprints, fp_check ); auto returns = tp.submit_loop( 0, numFootprints, fp_check );
// Wait for all threads to finish // Wait for all threads to finish
for( size_t ii = 0; ii < returns.size(); ++ii ) for( size_t ii = 0; ii < returns.size(); ++ii )
@ -1152,7 +1147,7 @@ void DRC_TEST_PROVIDER_COPPER_CLEARANCE::testGraphicClearances()
m_board->m_DRCMaxClearance ); m_board->m_DRCMaxClearance );
}; };
std::future<void> retn = tp.submit( std::future<void> retn = tp.submit_task(
[&]() [&]()
{ {
for( BOARD_ITEM* item : m_board->Drawings() ) for( BOARD_ITEM* item : m_board->Drawings() )
@ -1370,7 +1365,7 @@ void DRC_TEST_PROVIDER_COPPER_CLEARANCE::testZonesToZones()
continue; continue;
count++; count++;
tp.push_task( checkZones, ia, ia2, sameNet, layer ); tp.submit_task( [checkZones, ia, ia2, sameNet, layer]() { checkZones(ia, ia2, sameNet, layer); } );
} }
} }
} }
@ -1382,7 +1377,7 @@ void DRC_TEST_PROVIDER_COPPER_CLEARANCE::testZonesToZones()
if( m_drcEngine->IsCancelled() ) if( m_drcEngine->IsCancelled() )
break; break;
if( tp.wait_for_tasks_duration( std::chrono::milliseconds( 250 ) ) ) if( tp.wait_for( std::chrono::milliseconds( 250 ) ) )
break; break;
} }

View File

@ -110,11 +110,11 @@ bool DRC_TEST_PROVIDER_DISALLOW::Run()
} }
auto query_areas = auto query_areas =
[&]( std::pair<ZONE* /* rule area */, ZONE* /* copper zone */> areaZonePair ) -> size_t [&]( const int idx ) -> size_t
{ {
if( m_drcEngine->IsCancelled() ) if( m_drcEngine->IsCancelled() )
return 0; return 0;
const auto& areaZonePair = toCache[idx];
ZONE* ruleArea = areaZonePair.first; ZONE* ruleArea = areaZonePair.first;
ZONE* copperZone = areaZonePair.second; ZONE* copperZone = areaZonePair.second;
BOX2I areaBBox = ruleArea->GetBoundingBox(); BOX2I areaBBox = ruleArea->GetBoundingBox();
@ -169,14 +169,9 @@ bool DRC_TEST_PROVIDER_DISALLOW::Run()
}; };
thread_pool& tp = GetKiCadThreadPool(); thread_pool& tp = GetKiCadThreadPool();
std::vector<std::future<size_t>> returns; auto futures = tp.submit_loop( 0, toCache.size(), query_areas );
returns.reserve( toCache.size() ); for( auto& ret : futures )
for( const std::pair<ZONE*, ZONE*>& areaZonePair : toCache )
returns.emplace_back( tp.submit( query_areas, areaZonePair ) );
for( const std::future<size_t>& ret : returns )
{ {
std::future_status status = ret.wait_for( std::chrono::milliseconds( 250 ) ); std::future_status status = ret.wait_for( std::chrono::milliseconds( 250 ) );

View File

@ -149,14 +149,10 @@ bool DRC_TEST_PROVIDER_SLIVER_CHECKER::Run()
}; };
thread_pool& tp = GetKiCadThreadPool(); thread_pool& tp = GetKiCadThreadPool();
std::vector<std::future<size_t>> returns;
returns.reserve( copperLayers.size() ); auto returns = tp.submit_loop( 0, copperLayers.size(), build_layer_polys );
for( size_t ii = 0; ii < copperLayers.size(); ++ii ) for( auto& ret : returns )
returns.emplace_back( tp.submit( build_layer_polys, ii ) );
for( const std::future<size_t>& ret : returns )
{ {
std::future_status status = ret.wait_for( std::chrono::milliseconds( 250 ) ); std::future_status status = ret.wait_for( std::chrono::milliseconds( 250 ) );

View File

@ -737,9 +737,7 @@ void DRC_TEST_PROVIDER_SOLDER_MASK::testMaskBridges()
thread_pool& tp = GetKiCadThreadPool(); thread_pool& tp = GetKiCadThreadPool();
auto returns = tp.parallelize_loop( test_items.size(), [&]( size_t a, size_t b ) -> bool auto returns = tp.submit_loop( 0, test_items.size(), [&]( size_t i ) -> bool
{
for( size_t i = a; i < b; ++i )
{ {
BOARD_ITEM* item = test_items[ i ]; BOARD_ITEM* item = test_items[ i ];
@ -777,7 +775,6 @@ void DRC_TEST_PROVIDER_SOLDER_MASK::testMaskBridges()
} }
++count; ++count;
}
return true; return true;
} ); } );

View File

@ -70,13 +70,15 @@ bool DRC_TEST_PROVIDER_TRACK_ANGLE::Run()
return false; // DRC cancelled return false; // DRC cancelled
auto checkTrackAngle = auto checkTrackAngle =
[&]( PCB_TRACK* item ) -> bool [&]( const int ind ) -> bool
{ {
if( m_drcEngine->IsErrorLimitExceeded( DRCE_TRACK_ANGLE ) ) if( m_drcEngine->IsErrorLimitExceeded( DRCE_TRACK_ANGLE ) )
{ {
return false; return false;
} }
PCB_TRACK* item = m_drcEngine->GetBoard()->Tracks()[ind];
if( item->Type() != PCB_TRACE_T ) if( item->Type() != PCB_TRACE_T )
{ {
return true; return true;
@ -196,16 +198,9 @@ bool DRC_TEST_PROVIDER_TRACK_ANGLE::Run()
int ii = 0; int ii = 0;
thread_pool& tp = GetKiCadThreadPool(); thread_pool& tp = GetKiCadThreadPool();
std::vector<std::future<bool>> returns; auto futures = tp.submit_loop( 0, m_drcEngine->GetBoard()->Tracks().size(), checkTrackAngle );
returns.reserve( m_drcEngine->GetBoard()->Tracks().size() ); for( auto& ret : futures )
for( PCB_TRACK* item : m_drcEngine->GetBoard()->Tracks() )
{
returns.emplace_back( tp.submit( checkTrackAngle, item ) );
}
for( std::future<bool>& ret : returns )
{ {
std::future_status status = ret.wait_for( std::chrono::milliseconds( 250 ) ); std::future_status status = ret.wait_for( std::chrono::milliseconds( 250 ) );

View File

@ -67,8 +67,9 @@ bool DRC_TEST_PROVIDER_TRACK_SEGMENT_LENGTH::Run()
return false; // DRC cancelled return false; // DRC cancelled
auto checkTrackSegmentLength = auto checkTrackSegmentLength =
[&]( BOARD_ITEM* item ) -> bool [&]( const int idx ) -> bool
{ {
BOARD_ITEM* item = m_drcEngine->GetBoard()->Tracks()[idx];
if( m_drcEngine->IsErrorLimitExceeded( DRCE_TRACK_SEGMENT_LENGTH ) ) if( m_drcEngine->IsErrorLimitExceeded( DRCE_TRACK_SEGMENT_LENGTH ) )
return false; return false;
@ -153,16 +154,9 @@ bool DRC_TEST_PROVIDER_TRACK_SEGMENT_LENGTH::Run()
int ii = 0; int ii = 0;
thread_pool& tp = GetKiCadThreadPool(); thread_pool& tp = GetKiCadThreadPool();
std::vector<std::future<bool>> returns; auto futures = tp.submit_loop( 0, m_drcEngine->GetBoard()->Tracks().size(), checkTrackSegmentLength );
returns.reserve( m_drcEngine->GetBoard()->Tracks().size() ); for( auto& ret : futures )
for( PCB_TRACK* item : m_drcEngine->GetBoard()->Tracks() )
{
returns.emplace_back( tp.submit( checkTrackSegmentLength, item ) );
}
for( std::future<bool>& ret : returns )
{ {
std::future_status status = ret.wait_for( std::chrono::milliseconds( 250 ) ); std::future_status status = ret.wait_for( std::chrono::milliseconds( 250 ) );

View File

@ -319,27 +319,17 @@ bool DRC_TEST_PROVIDER_ZONE_CONNECTIONS::Run()
total_effort = std::max( (size_t) 1, total_effort ); total_effort = std::max( (size_t) 1, total_effort );
thread_pool& tp = GetKiCadThreadPool(); thread_pool& tp = GetKiCadThreadPool();
std::vector<std::future<int>> returns; auto returns = tp.submit_loop( 0, zoneLayers.size(),
[&]( const int ii )
returns.reserve( zoneLayers.size() );
for( const std::pair<ZONE*, PCB_LAYER_ID>& zonelayer : zoneLayers )
{
returns.emplace_back( tp.submit(
[&]( ZONE* aZone, PCB_LAYER_ID aLayer ) -> int
{ {
if( !m_drcEngine->IsCancelled() ) if( !m_drcEngine->IsCancelled() )
{ {
testZoneLayer( aZone, aLayer ); testZoneLayer( zoneLayers[ii].first, zoneLayers[ii].second );
done.fetch_add( aZone->GetFilledPolysList( aLayer )->FullPointCount() ); done.fetch_add( zoneLayers[ii].first->GetFilledPolysList( zoneLayers[ii].second )->FullPointCount() );
} }
} );
return 0; for( auto& ret : returns )
},
zonelayer.first, zonelayer.second ) );
}
for( const std::future<int>& ret : returns )
{ {
std::future_status status = ret.wait_for( std::chrono::milliseconds( 250 ) ); std::future_status status = ret.wait_for( std::chrono::milliseconds( 250 ) );

View File

@ -2026,9 +2026,7 @@ bool STEP_PCB_MODEL::CreatePCB( SHAPE_POLY_SET& aOutline, const VECTOR2D& aOrigi
{ {
std::mutex mutex; std::mutex mutex;
auto subtractLoopFn = [&]( const int a, const int b ) auto subtractLoopFn = [&]( const int shapeId )
{
for( int shapeId = a; shapeId < b; shapeId++ )
{ {
TopoDS_Shape& shape = vec[shapeId]; TopoDS_Shape& shape = vec[shapeId];
@ -2047,7 +2045,7 @@ bool STEP_PCB_MODEL::CreatePCB( SHAPE_POLY_SET& aOutline, const VECTOR2D& aOrigi
} }
if( holelist.IsEmpty() ) if( holelist.IsEmpty() )
continue; return; // nothing to cut for this shape
TopTools_ListOfShape cutArgs; TopTools_ListOfShape cutArgs;
cutArgs.Append( shape ); cutArgs.Append( shape );
@ -2092,10 +2090,9 @@ bool STEP_PCB_MODEL::CreatePCB( SHAPE_POLY_SET& aOutline, const VECTOR2D& aOrigi
} }
shape = cut.Shape(); shape = cut.Shape();
}
}; };
tp.parallelize_loop( vec.size(), subtractLoopFn ).wait(); tp.submit_loop( 0, vec.size(), subtractLoopFn ).wait();
} }
}; };
@ -2172,7 +2169,7 @@ bool STEP_PCB_MODEL::CreatePCB( SHAPE_POLY_SET& aOutline, const VECTOR2D& aOrigi
BS::multi_future<void> mf; BS::multi_future<void> mf;
for( const auto& [netname, _] : shapesToFuseMap ) for( const auto& [netname, _] : shapesToFuseMap )
mf.push_back( tp.submit( fuseLoopFn, netname ) ); mf.push_back( tp.submit_task( [&, netname]() { fuseLoopFn( netname ); } ) );
mf.wait(); mf.wait();
} }

View File

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

View File

@ -253,27 +253,27 @@ EDA_ITEM* PCB_BASE_FRAME::ResolveItem( const KIID& aId, bool aAllowNullptrReturn
return GetBoard()->ResolveItem( aId, aAllowNullptrReturn ); return GetBoard()->ResolveItem( aId, aAllowNullptrReturn );
} }
void PCB_BASE_FRAME::FocusOnItem( EDA_ITEM* aItem ) void PCB_BASE_FRAME::FocusOnItem( EDA_ITEM* aItem, bool aAllowScroll )
{ {
// nullptr will clear the current focus // nullptr will clear the current focus
if( aItem != nullptr && !aItem->IsBOARD_ITEM() ) if( aItem != nullptr && !aItem->IsBOARD_ITEM() )
return; return;
FocusOnItem( static_cast<BOARD_ITEM*>( aItem ), UNDEFINED_LAYER ); FocusOnItem( static_cast<BOARD_ITEM*>( aItem ), UNDEFINED_LAYER, aAllowScroll );
} }
void PCB_BASE_FRAME::FocusOnItem( BOARD_ITEM* aItem, PCB_LAYER_ID aLayer ) void PCB_BASE_FRAME::FocusOnItem( BOARD_ITEM* aItem, PCB_LAYER_ID aLayer, bool aAllowScroll )
{ {
std::vector<BOARD_ITEM*> items; std::vector<BOARD_ITEM*> items;
if( aItem ) if( aItem )
items.push_back( aItem ); items.push_back( aItem );
FocusOnItems( items, aLayer ); FocusOnItems( items, aLayer, aAllowScroll );
} }
void PCB_BASE_FRAME::FocusOnItems( std::vector<BOARD_ITEM*> aItems, PCB_LAYER_ID aLayer ) void PCB_BASE_FRAME::FocusOnItems( std::vector<BOARD_ITEM*> aItems, PCB_LAYER_ID aLayer, bool aAllowScroll )
{ {
static std::vector<KIID> lastBrightenedItemIDs; static std::vector<KIID> lastBrightenedItemIDs;
@ -361,7 +361,7 @@ void PCB_BASE_FRAME::FocusOnItems( std::vector<BOARD_ITEM*> aItems, PCB_LAYER_ID
case PCB_PAD_T: case PCB_PAD_T:
case PCB_MARKER_T: case PCB_MARKER_T:
case PCB_VIA_T: case PCB_VIA_T:
FocusOnLocation( item->GetFocusPosition() ); FocusOnLocation( item->GetFocusPosition(), aAllowScroll );
GetCanvas()->Refresh(); GetCanvas()->Refresh();
return; return;
@ -449,7 +449,7 @@ void PCB_BASE_FRAME::FocusOnItems( std::vector<BOARD_ITEM*> aItems, PCB_LAYER_ID
} }
} }
FocusOnLocation( focusPt ); FocusOnLocation( focusPt, aAllowScroll );
GetCanvas()->Refresh(); GetCanvas()->Refresh();
} }

View File

@ -109,6 +109,7 @@
#include <widgets/pcb_net_inspector_panel.h> #include <widgets/pcb_net_inspector_panel.h>
#include <widgets/wx_aui_utils.h> #include <widgets/wx_aui_utils.h>
#include <kiplatform/app.h> #include <kiplatform/app.h>
#include <kiplatform/ui.h>
#include <core/profile.h> #include <core/profile.h>
#include <math/box2_minmax.h> #include <math/box2_minmax.h>
#include <view/wx_view_controls.h> #include <view/wx_view_controls.h>
@ -1466,7 +1467,7 @@ void PCB_EDIT_FRAME::ActivateGalCanvas()
} }
void PCB_EDIT_FRAME::ShowBoardSetupDialog( const wxString& aInitialPage ) void PCB_EDIT_FRAME::ShowBoardSetupDialog( const wxString& aInitialPage, wxWindow* aParent )
{ {
static std::mutex dialogMutex; // Local static mutex static std::mutex dialogMutex; // Local static mutex
@ -1486,7 +1487,7 @@ void PCB_EDIT_FRAME::ShowBoardSetupDialog( const wxString& aInitialPage )
// Make sure everything's up-to-date // Make sure everything's up-to-date
GetBoard()->BuildListOfNets(); GetBoard()->BuildListOfNets();
DIALOG_BOARD_SETUP dlg( this ); DIALOG_BOARD_SETUP dlg( this, aParent );
if( !aInitialPage.IsEmpty() ) if( !aInitialPage.IsEmpty() )
dlg.SetInitialPage( aInitialPage, wxEmptyString ); dlg.SetInitialPage( aInitialPage, wxEmptyString );

View File

@ -301,7 +301,7 @@ public:
///< @copydoc EDA_DRAW_FRAME::UseGalCanvas() ///< @copydoc EDA_DRAW_FRAME::UseGalCanvas()
void ActivateGalCanvas() override; void ActivateGalCanvas() override;
void ShowBoardSetupDialog( const wxString& aInitialPage = wxEmptyString ); void ShowBoardSetupDialog( const wxString& aInitialPage = wxEmptyString, wxWindow* aParent = nullptr );
void PrepareLayerIndicator( bool aForceRebuild = false ); void PrepareLayerIndicator( bool aForceRebuild = false );

View File

@ -349,6 +349,15 @@ PCBNEW_SETTINGS::PCBNEW_SETTINGS()
m_params.emplace_back( new PARAM<wxString>( "system.last_footprint3d_dir", m_params.emplace_back( new PARAM<wxString>( "system.last_footprint3d_dir",
&m_LastFootprint3dDir, "" ) ); &m_LastFootprint3dDir, "" ) );
m_params.emplace_back( new PARAM<bool>( "DRC.report_all_track_errors",
&m_DRCDialog.report_all_track_errors, false ) );
m_params.emplace_back( new PARAM<bool>( "DRC.crossprobe",
&m_DRCDialog.crossprobe, true ) );
m_params.emplace_back( new PARAM<bool>( "DRC.scroll_on_crossprobe",
&m_DRCDialog.scroll_on_crossprobe, true ) );
registerMigration( 0, 1, registerMigration( 0, 1,
[&]() [&]()
{ {

View File

@ -168,6 +168,13 @@ public:
bool doNotExportUnconnectedPads; bool doNotExportUnconnectedPads;
}; };
struct DIALOG_DRC
{
bool report_all_track_errors;
bool crossprobe;
bool scroll_on_crossprobe;
};
struct FOOTPRINT_CHOOSER struct FOOTPRINT_CHOOSER
{ {
// Footprint chooser is a FRAME, so there's no DIALOG_SHIM to save/restore control state // Footprint chooser is a FRAME, so there's no DIALOG_SHIM to save/restore control state
@ -227,6 +234,7 @@ public:
AUI_PANELS m_AuiPanels; AUI_PANELS m_AuiPanels;
DIALOG_EXPORT_D356 m_ExportD356; DIALOG_EXPORT_D356 m_ExportD356;
DIALOG_DRC m_DRCDialog;
FOOTPRINT_CHOOSER m_FootprintChooser; FOOTPRINT_CHOOSER m_FootprintChooser;
ZONES m_Zones; ZONES m_Zones;

View File

@ -27,6 +27,7 @@
#include <tools/pcb_selection_tool.h> #include <tools/pcb_selection_tool.h>
#include <tools/pcb_picker_tool.h> #include <tools/pcb_picker_tool.h>
#include <tools/edit_tool.h> #include <tools/edit_tool.h>
#include <tools/drc_tool.h>
#include <pcb_painter.h> #include <pcb_painter.h>
#include <connectivity/connectivity_data.h> #include <connectivity/connectivity_data.h>
#include <drc/drc_engine.h> #include <drc/drc_engine.h>
@ -34,11 +35,12 @@
#include <dialogs/dialog_book_reporter.h> #include <dialogs/dialog_book_reporter.h>
#include <dialogs/panel_setup_rules_base.h> #include <dialogs/panel_setup_rules_base.h>
#include <dialogs/dialog_footprint_associations.h> #include <dialogs/dialog_footprint_associations.h>
#include <dialogs/dialog_drc.h>
#include <kiplatform/ui.h>
#include <string_utils.h> #include <string_utils.h>
#include <tools/board_inspection_tool.h> #include <tools/board_inspection_tool.h>
#include <fp_lib_table.h> #include <fp_lib_table.h>
#include <pcb_shape.h> #include <pcb_shape.h>
#include <pcbnew_settings.h>
#include <widgets/appearance_controls.h> #include <widgets/appearance_controls.h>
#include <widgets/wx_html_report_box.h> #include <widgets/wx_html_report_box.h>
#include <widgets/footprint_diff_widget.h> #include <widgets/footprint_diff_widget.h>
@ -338,7 +340,9 @@ wxString BOARD_INSPECTION_TOOL::InspectDRCErrorMenuText( const std::shared_ptr<R
void BOARD_INSPECTION_TOOL::InspectDRCError( const std::shared_ptr<RC_ITEM>& aDRCItem ) void BOARD_INSPECTION_TOOL::InspectDRCError( const std::shared_ptr<RC_ITEM>& aDRCItem )
{ {
wxCHECK( m_frame, /* void */ ); DRC_TOOL* drcTool = m_toolMgr->GetTool<DRC_TOOL>();
wxCHECK( drcTool && m_frame, /* void */ );
BOARD_ITEM* a = m_frame->GetBoard()->ResolveItem( aDRCItem->GetMainItemID() ); BOARD_ITEM* a = m_frame->GetBoard()->ResolveItem( aDRCItem->GetMainItemID() );
BOARD_ITEM* b = m_frame->GetBoard()->ResolveItem( aDRCItem->GetAuxItemID() ); BOARD_ITEM* b = m_frame->GetBoard()->ResolveItem( aDRCItem->GetAuxItemID() );
@ -349,7 +353,7 @@ void BOARD_INSPECTION_TOOL::InspectDRCError( const std::shared_ptr<RC_ITEM>& aDR
if( aDRCItem->GetErrorCode() == DRCE_LIB_FOOTPRINT_MISMATCH ) if( aDRCItem->GetErrorCode() == DRCE_LIB_FOOTPRINT_MISMATCH )
{ {
if( FOOTPRINT* footprint = dynamic_cast<FOOTPRINT*>( a ) ) if( FOOTPRINT* footprint = dynamic_cast<FOOTPRINT*>( a ) )
DiffFootprint( footprint ); DiffFootprint( footprint, drcTool->GetDRCDialog() );
return; return;
} }
@ -698,7 +702,7 @@ void BOARD_INSPECTION_TOOL::InspectDRCError( const std::shared_ptr<RC_ITEM>& aDR
r->Flush(); r->Flush();
dialog->Raise(); KIPLATFORM::UI::ReparentWindow( dialog, drcTool->GetDRCDialog() );
dialog->Show( true ); dialog->Show( true );
} }
@ -1613,7 +1617,7 @@ int BOARD_INSPECTION_TOOL::ShowFootprintLinks( const TOOL_EVENT& aEvent )
} }
void BOARD_INSPECTION_TOOL::DiffFootprint( FOOTPRINT* aFootprint ) void BOARD_INSPECTION_TOOL::DiffFootprint( FOOTPRINT* aFootprint, wxTopLevelWindow* aReparentTo )
{ {
DIALOG_BOOK_REPORTER* dialog = m_frame->GetFootprintDiffDialog(); DIALOG_BOOK_REPORTER* dialog = m_frame->GetFootprintDiffDialog();
@ -1694,7 +1698,11 @@ void BOARD_INSPECTION_TOOL::DiffFootprint( FOOTPRINT* aFootprint )
r->Flush(); r->Flush();
if( aReparentTo )
KIPLATFORM::UI::ReparentWindow( dialog, aReparentTo );
else
dialog->Raise(); dialog->Raise();
dialog->Show( true ); dialog->Show( true );
} }

View File

@ -90,7 +90,7 @@ public:
int ShowFootprintLinks( const TOOL_EVENT& aEvent ); int ShowFootprintLinks( const TOOL_EVENT& aEvent );
int DiffFootprint( const TOOL_EVENT& aEvent ); int DiffFootprint( const TOOL_EVENT& aEvent );
void DiffFootprint( FOOTPRINT* aFootprint ); void DiffFootprint( FOOTPRINT* aFootprint, wxTopLevelWindow* aReparentTo = nullptr );
/** /**
* @return true if a net or nets to highlight have been set * @return true if a net or nets to highlight have been set

View File

@ -60,6 +60,8 @@ public:
int ShowDRCDialog( const TOOL_EVENT& aEvent ); int ShowDRCDialog( const TOOL_EVENT& aEvent );
DIALOG_DRC* GetDRCDialog() { return m_drcDialog; }
/** /**
* Check to see if the DRC_TOOL dialog is currently shown * Check to see if the DRC_TOOL dialog is currently shown
*/ */

View File

@ -581,7 +581,7 @@ void TRACKS_CLEANER::cleanup( bool aDeleteDuplicateVias, bool aDeleteNullSegment
// and extract all of the pairs of segments that might be merged. Then, perform // and extract all of the pairs of segments that might be merged. Then, perform
// the actual merge in the main loop. // the actual merge in the main loop.
thread_pool& tp = GetKiCadThreadPool(); thread_pool& tp = GetKiCadThreadPool();
auto merge_returns = tp.parallelize_loop( 0, m_brd->Tracks().size(), track_loop ); auto merge_returns = tp.submit_blocks( 0, m_brd->Tracks().size(), track_loop );
bool retval = false; bool retval = false;
for( size_t ii = 0; ii < merge_returns.size(); ++ii ) for( size_t ii = 0; ii < merge_returns.size(); ++ii )

View File

@ -654,11 +654,9 @@ PCB_NET_INSPECTOR_PANEL::calculateNets( const std::vector<NETINFO_ITEM*>& aNetCo
std::mutex resultsMutex; std::mutex resultsMutex;
thread_pool& tp = GetKiCadThreadPool(); thread_pool& tp = GetKiCadThreadPool();
auto resultsFuture = tp.parallelize_loop( auto resultsFuture = tp.submit_loop(
0, foundNets.size(), 0, foundNets.size(),
[&, this, calc]( const int start, const int end ) [&, this, calc]( const int i )
{
for( int i = start; i < end; ++i )
{ {
int netCode = foundNets[i]->GetNetCode(); int netCode = foundNets[i]->GetNetCode();
@ -695,7 +693,6 @@ PCB_NET_INSPECTOR_PANEL::calculateNets( const std::vector<NETINFO_ITEM*>& aNetCo
std::scoped_lock lock( resultsMutex ); std::scoped_lock lock( resultsMutex );
results.emplace_back( std::move( new_item ) ); results.emplace_back( std::move( new_item ) );
} }
}
} ); } );
resultsFuture.get(); resultsFuture.get();

View File

@ -611,7 +611,7 @@ bool ZONE_FILLER::Fill( const std::vector<ZONE*>& aZones, bool aCheck, wxWindow*
thread_pool& tp = GetKiCadThreadPool(); thread_pool& tp = GetKiCadThreadPool();
for( const std::pair<ZONE*, PCB_LAYER_ID>& fillItem : toFill ) for( const std::pair<ZONE*, PCB_LAYER_ID>& fillItem : toFill )
returns.emplace_back( std::make_pair( tp.submit( fill_lambda, fillItem ), 0 ) ); returns.emplace_back( std::make_pair( tp.submit_task( [&, fillItem]() { return fill_lambda( fillItem ); } ), 0 ) );
while( !cancelled && finished != 2 * toFill.size() ) while( !cancelled && finished != 2 * toFill.size() )
{ {
@ -636,9 +636,9 @@ bool ZONE_FILLER::Fill( const std::vector<ZONE*>& aZones, bool aCheck, wxWindow*
{ {
// Queue the next step (will re-queue the existing step if it didn't complete) // Queue the next step (will re-queue the existing step if it didn't complete)
if( ret.second == 0 ) if( ret.second == 0 )
returns[ii].first = tp.submit( fill_lambda, toFill[ii] ); returns[ii].first = tp.submit_task( [&, idx = ii]() { return fill_lambda( toFill[idx] ); } );
else if( ret.second == 1 ) else if( ret.second == 1 )
returns[ii].first = tp.submit( tesselate_lambda, toFill[ii] ); returns[ii].first = tp.submit_task( [&, idx = ii]() { return tesselate_lambda( toFill[idx] ); } );
} }
} }
} }
@ -827,7 +827,7 @@ bool ZONE_FILLER::Fill( const std::vector<ZONE*>& aZones, bool aCheck, wxWindow*
return retval; return retval;
}; };
auto island_returns = tp.parallelize_loop( 0, polys_to_check.size(), island_lambda ); auto island_returns = tp.submit_blocks( 0, polys_to_check.size(), island_lambda );
cancelled = false; cancelled = false;
// Allow island removal threads to finish // Allow island removal threads to finish

View File

@ -147,7 +147,7 @@ long PYTHON_MANAGER::Execute( const std::vector<wxString>& aArgs,
if( !aSaveOutput ) if( !aSaveOutput )
{ {
thread_pool& tp = GetKiCadThreadPool(); thread_pool& tp = GetKiCadThreadPool();
auto ret = tp.submit( monitor, process ); auto ret = tp.submit_task( [monitor, process] { monitor( process ); } );
} }
} }

View File

@ -5,21 +5,20 @@
# All rights reserved. Use of this source code is governed by a # All rights reserved. Use of this source code is governed by a
# BSD-style license that can be found in the LICENSE file. # BSD-style license that can be found in the LICENSE file.
#cmake_minimum_required(VERSION 3.4) # Propagate this policy (FindPythonInterp removal) so it can be detected later
if(NOT CMAKE_VERSION VERSION_LESS "3.27")
cmake_policy(GET CMP0148 _pybind11_cmp0148)
endif()
# The `cmake_minimum_required(VERSION 3.4...3.22)` syntax does not work with cmake_minimum_required(VERSION 3.15...4.0)
# some versions of VS that have a patched CMake 3.11. This forces us to emulate
# the behavior using the following workaround: if(_pybind11_cmp0148)
if(${CMAKE_VERSION} VERSION_LESS 3.22) cmake_policy(SET CMP0148 ${_pybind11_cmp0148})
cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}) unset(_pybind11_cmp0148)
else()
cmake_policy(VERSION 3.22)
endif() endif()
# Avoid infinite recursion if tests include this as a subdirectory # Avoid infinite recursion if tests include this as a subdirectory
if(DEFINED PYBIND11_MASTER_PROJECT) include_guard(GLOBAL)
return()
endif()
# Extract project version from source # Extract project version from source
file(STRINGS "${CMAKE_CURRENT_SOURCE_DIR}/include/pybind11/detail/common.h" file(STRINGS "${CMAKE_CURRENT_SOURCE_DIR}/include/pybind11/detail/common.h"
@ -64,16 +63,15 @@ if(CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR)
set(PYBIND11_MASTER_PROJECT ON) set(PYBIND11_MASTER_PROJECT ON)
if(OSX AND CMAKE_VERSION VERSION_LESS 3.7)
# Bug in macOS CMake < 3.7 is unable to download catch
message(WARNING "CMAKE 3.7+ needed on macOS to download catch, and newer HIGHLY recommended")
elseif(WINDOWS AND CMAKE_VERSION VERSION_LESS 3.8)
# Only tested with 3.8+ in CI.
message(WARNING "CMAKE 3.8+ tested on Windows, previous versions untested")
endif()
message(STATUS "CMake ${CMAKE_VERSION}") message(STATUS "CMake ${CMAKE_VERSION}")
if(DEFINED SKBUILD AND DEFINED ENV{PYBIND11_GLOBAL_SDIST})
message(
FATAL_ERROR
"PYBIND11_GLOBAL_SDIST is not supported, use nox -s build_global or a pybind11-global SDist instead."
)
endif()
if(CMAKE_CXX_STANDARD) if(CMAKE_CXX_STANDARD)
set(CMAKE_CXX_EXTENSIONS OFF) set(CMAKE_CXX_EXTENSIONS OFF)
set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_STANDARD_REQUIRED ON)
@ -82,59 +80,160 @@ if(CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR)
set(pybind11_system "") set(pybind11_system "")
set_property(GLOBAL PROPERTY USE_FOLDERS ON) set_property(GLOBAL PROPERTY USE_FOLDERS ON)
if(CMAKE_VERSION VERSION_LESS "3.18")
set(_pybind11_findpython_default OFF)
else()
set(_pybind11_findpython_default ON)
endif()
else() else()
set(PYBIND11_MASTER_PROJECT OFF) set(PYBIND11_MASTER_PROJECT OFF)
set(pybind11_system SYSTEM) set(pybind11_system SYSTEM)
set(_pybind11_findpython_default COMPAT)
endif() endif()
# Options # Options
option(PYBIND11_INSTALL "Install pybind11 header files?" ${PYBIND11_MASTER_PROJECT}) option(PYBIND11_INSTALL "Install pybind11 header files?" ${PYBIND11_MASTER_PROJECT})
option(PYBIND11_TEST "Build pybind11 test suite?" ${PYBIND11_MASTER_PROJECT}) option(PYBIND11_TEST "Build pybind11 test suite?" ${PYBIND11_MASTER_PROJECT})
option(PYBIND11_NOPYTHON "Disable search for Python" OFF) option(PYBIND11_NOPYTHON "Disable search for Python" OFF)
option(PYBIND11_DISABLE_HANDLE_TYPE_NAME_DEFAULT_IMPLEMENTATION
"To enforce that a handle_type_name<> specialization exists" OFF)
option(PYBIND11_SIMPLE_GIL_MANAGEMENT
"Use simpler GIL management logic that does not support disassociation" OFF)
set(PYBIND11_INTERNALS_VERSION set(PYBIND11_INTERNALS_VERSION
"" ""
CACHE STRING "Override the ABI version, may be used to enable the unstable ABI.") CACHE STRING "Override the ABI version, may be used to enable the unstable ABI.")
option(PYBIND11_USE_CROSSCOMPILING "Respect CMAKE_CROSSCOMPILING" OFF)
if(PYBIND11_DISABLE_HANDLE_TYPE_NAME_DEFAULT_IMPLEMENTATION)
add_compile_definitions(PYBIND11_DISABLE_HANDLE_TYPE_NAME_DEFAULT_IMPLEMENTATION)
endif()
if(PYBIND11_SIMPLE_GIL_MANAGEMENT)
add_compile_definitions(PYBIND11_SIMPLE_GIL_MANAGEMENT)
endif()
cmake_dependent_option( cmake_dependent_option(
USE_PYTHON_INCLUDE_DIR USE_PYTHON_INCLUDE_DIR
"Install pybind11 headers in Python include directory instead of default installation prefix" "Install pybind11 headers in Python include directory instead of default installation prefix"
OFF "PYBIND11_INSTALL" OFF) OFF "PYBIND11_INSTALL" OFF)
cmake_dependent_option(PYBIND11_FINDPYTHON "Force new FindPython" OFF set(PYBIND11_FINDPYTHON
"NOT CMAKE_VERSION VERSION_LESS 3.12" OFF) ${_pybind11_findpython_default}
CACHE STRING "Force new FindPython - NEW, OLD, COMPAT")
if(PYBIND11_MASTER_PROJECT)
# Allow PYTHON_EXECUTABLE if in FINDPYTHON mode and building pybind11's tests
# (makes transition easier while we support both modes).
if(PYBIND11_FINDPYTHON
AND DEFINED PYTHON_EXECUTABLE
AND NOT DEFINED Python_EXECUTABLE)
set(Python_EXECUTABLE "${PYTHON_EXECUTABLE}")
endif()
# This is a shortcut that is primarily for the venv cmake preset,
# but can be used to quickly setup tests manually, too
set(PYBIND11_CREATE_WITH_UV
""
CACHE STRING "Create a virtualenv if it doesn't exist")
if(NOT PYBIND11_CREATE_WITH_UV STREQUAL "")
set(Python_ROOT_DIR "${CMAKE_CURRENT_BINARY_DIR}/.venv")
if(EXISTS "${Python_ROOT_DIR}")
if(EXISTS "${CMAKE_BINARY_DIR}/CMakeCache.txt")
message(STATUS "Using existing venv at ${Python_ROOT_DIR}, remove or --fresh to recreate")
else()
# --fresh used to remove the cache
file(REMOVE_RECURSE "${CMAKE_CURRENT_BINARY_DIR}/.venv")
endif()
endif()
if(NOT EXISTS "${Python_ROOT_DIR}")
find_program(UV uv REQUIRED)
# CMake 3.19+ would be able to use COMMAND_ERROR_IS_FATAL
message(
STATUS "Creating venv with ${UV} venv -p ${PYBIND11_CREATE_WITH_UV} '${Python_ROOT_DIR}'")
execute_process(COMMAND ${UV} venv -p ${PYBIND11_CREATE_WITH_UV} "${Python_ROOT_DIR}"
RESULT_VARIABLE _venv_result)
if(_venv_result AND NOT _venv_result EQUAL 0)
message(FATAL_ERROR "uv venv failed with '${_venv_result}'")
endif()
message(
STATUS
"Installing deps with ${UV} pip install -p '${Python_ROOT_DIR}' -r tests/requirements.txt"
)
execute_process(
COMMAND ${UV} pip install -p "${Python_ROOT_DIR}" -r
"${CMAKE_CURRENT_SOURCE_DIR}/tests/requirements.txt" RESULT_VARIABLE _pip_result)
if(_pip_result AND NOT _pip_result EQUAL 0)
message(FATAL_ERROR "uv pip install failed with '${_pip_result}'")
endif()
endif()
else()
if(NOT DEFINED Python3_EXECUTABLE
AND NOT DEFINED Python_EXECUTABLE
AND NOT DEFINED Python_ROOT_DIR
AND NOT DEFINED ENV{VIRTUALENV}
AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/.venv")
message(STATUS "Autodetecting Python in virtual environment")
set(Python_ROOT_DIR "${CMAKE_CURRENT_SOURCE_DIR}/.venv")
endif()
endif()
endif()
# NB: when adding a header don't forget to also add it to setup.py
set(PYBIND11_HEADERS set(PYBIND11_HEADERS
include/pybind11/detail/class.h include/pybind11/detail/class.h
include/pybind11/detail/common.h include/pybind11/detail/common.h
include/pybind11/detail/cpp_conduit.h
include/pybind11/detail/descr.h include/pybind11/detail/descr.h
include/pybind11/detail/dynamic_raw_ptr_cast_if_possible.h
include/pybind11/detail/exception_translation.h
include/pybind11/detail/function_record_pyobject.h
include/pybind11/detail/init.h include/pybind11/detail/init.h
include/pybind11/detail/internals.h include/pybind11/detail/internals.h
include/pybind11/detail/native_enum_data.h
include/pybind11/detail/pybind11_namespace_macros.h
include/pybind11/detail/struct_smart_holder.h
include/pybind11/detail/type_caster_base.h include/pybind11/detail/type_caster_base.h
include/pybind11/detail/typeid.h include/pybind11/detail/typeid.h
include/pybind11/detail/using_smart_holder.h
include/pybind11/detail/value_and_holder.h
include/pybind11/attr.h include/pybind11/attr.h
include/pybind11/buffer_info.h include/pybind11/buffer_info.h
include/pybind11/cast.h include/pybind11/cast.h
include/pybind11/chrono.h include/pybind11/chrono.h
include/pybind11/common.h include/pybind11/common.h
include/pybind11/complex.h include/pybind11/complex.h
include/pybind11/conduit/pybind11_conduit_v1.h
include/pybind11/conduit/pybind11_platform_abi_id.h
include/pybind11/conduit/wrap_include_python_h.h
include/pybind11/critical_section.h
include/pybind11/options.h include/pybind11/options.h
include/pybind11/eigen.h include/pybind11/eigen.h
include/pybind11/eigen/common.h
include/pybind11/eigen/matrix.h
include/pybind11/eigen/tensor.h
include/pybind11/embed.h include/pybind11/embed.h
include/pybind11/eval.h include/pybind11/eval.h
include/pybind11/gil.h include/pybind11/gil.h
include/pybind11/gil_safe_call_once.h
include/pybind11/gil_simple.h
include/pybind11/iostream.h include/pybind11/iostream.h
include/pybind11/functional.h include/pybind11/functional.h
include/pybind11/native_enum.h
include/pybind11/numpy.h include/pybind11/numpy.h
include/pybind11/operators.h include/pybind11/operators.h
include/pybind11/pybind11.h include/pybind11/pybind11.h
include/pybind11/pytypes.h include/pybind11/pytypes.h
include/pybind11/subinterpreter.h
include/pybind11/stl.h include/pybind11/stl.h
include/pybind11/stl_bind.h include/pybind11/stl_bind.h
include/pybind11/stl/filesystem.h) include/pybind11/stl/filesystem.h
include/pybind11/trampoline_self_life_support.h
include/pybind11/type_caster_pyobject_ptr.h
include/pybind11/typing.h
include/pybind11/warnings.h)
# Compare with grep and warn if mismatched # Compare with grep and warn if mismatched
if(PYBIND11_MASTER_PROJECT AND NOT CMAKE_VERSION VERSION_LESS 3.12) if(PYBIND11_MASTER_PROJECT)
file( file(
GLOB_RECURSE _pybind11_header_check GLOB_RECURSE _pybind11_header_check
LIST_DIRECTORIES false LIST_DIRECTORIES false
@ -152,10 +251,7 @@ if(PYBIND11_MASTER_PROJECT AND NOT CMAKE_VERSION VERSION_LESS 3.12)
endif() endif()
endif() endif()
# CMake 3.12 added list(TRANSFORM <list> PREPEND list(TRANSFORM PYBIND11_HEADERS PREPEND "${CMAKE_CURRENT_SOURCE_DIR}/")
# But we can't use it yet
string(REPLACE "include/" "${CMAKE_CURRENT_SOURCE_DIR}/include/" PYBIND11_HEADERS
"${PYBIND11_HEADERS}")
# Cache variable so this can be used in parent projects # Cache variable so this can be used in parent projects
set(pybind11_INCLUDE_DIR set(pybind11_INCLUDE_DIR
@ -198,6 +294,9 @@ else()
endif() endif()
include("${CMAKE_CURRENT_SOURCE_DIR}/tools/pybind11Common.cmake") include("${CMAKE_CURRENT_SOURCE_DIR}/tools/pybind11Common.cmake")
# https://github.com/jtojnar/cmake-snips/#concatenating-paths-when-building-pkg-config-files
# TODO: cmake 3.20 adds the cmake_path() function, which obsoletes this snippet
include("${CMAKE_CURRENT_SOURCE_DIR}/tools/JoinPaths.cmake")
# Relative directory setting # Relative directory setting
if(USE_PYTHON_INCLUDE_DIR AND DEFINED Python_INCLUDE_DIRS) if(USE_PYTHON_INCLUDE_DIR AND DEFINED Python_INCLUDE_DIRS)
@ -207,6 +306,9 @@ elseif(USE_PYTHON_INCLUDE_DIR AND DEFINED PYTHON_INCLUDE_DIR)
endif() endif()
if(PYBIND11_INSTALL) if(PYBIND11_INSTALL)
if(DEFINED SKBUILD_PROJECT_NAME AND SKBUILD_PROJECT_NAME STREQUAL "pybind11_global")
install(DIRECTORY ${pybind11_INCLUDE_DIR}/pybind11 DESTINATION "${SKBUILD_HEADERS_DIR}")
endif()
install(DIRECTORY ${pybind11_INCLUDE_DIR}/pybind11 DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) install(DIRECTORY ${pybind11_INCLUDE_DIR}/pybind11 DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
set(PYBIND11_CMAKECONFIG_INSTALL_DIR set(PYBIND11_CMAKECONFIG_INSTALL_DIR
"${CMAKE_INSTALL_DATAROOTDIR}/cmake/${PROJECT_NAME}" "${CMAKE_INSTALL_DATAROOTDIR}/cmake/${PROJECT_NAME}"
@ -222,25 +324,11 @@ if(PYBIND11_INSTALL)
tools/${PROJECT_NAME}Config.cmake.in "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake" tools/${PROJECT_NAME}Config.cmake.in "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake"
INSTALL_DESTINATION ${PYBIND11_CMAKECONFIG_INSTALL_DIR}) INSTALL_DESTINATION ${PYBIND11_CMAKECONFIG_INSTALL_DIR})
if(CMAKE_VERSION VERSION_LESS 3.14) # CMake natively supports header-only libraries
# Remove CMAKE_SIZEOF_VOID_P from ConfigVersion.cmake since the library does
# not depend on architecture specific settings or libraries.
set(_PYBIND11_CMAKE_SIZEOF_VOID_P ${CMAKE_SIZEOF_VOID_P})
unset(CMAKE_SIZEOF_VOID_P)
write_basic_package_version_file(
${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake
VERSION ${PROJECT_VERSION}
COMPATIBILITY AnyNewerVersion)
set(CMAKE_SIZEOF_VOID_P ${_PYBIND11_CMAKE_SIZEOF_VOID_P})
else()
# CMake 3.14+ natively supports header-only libraries
write_basic_package_version_file( write_basic_package_version_file(
${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake
VERSION ${PROJECT_VERSION} VERSION ${PROJECT_VERSION}
COMPATIBILITY AnyNewerVersion ARCH_INDEPENDENT) COMPATIBILITY AnyNewerVersion ARCH_INDEPENDENT)
endif()
install( install(
FILES ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake FILES ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake
@ -249,6 +337,7 @@ if(PYBIND11_INSTALL)
tools/pybind11Common.cmake tools/pybind11Common.cmake
tools/pybind11Tools.cmake tools/pybind11Tools.cmake
tools/pybind11NewTools.cmake tools/pybind11NewTools.cmake
tools/pybind11GuessPythonExtSuffix.cmake
DESTINATION ${PYBIND11_CMAKECONFIG_INSTALL_DIR}) DESTINATION ${PYBIND11_CMAKECONFIG_INSTALL_DIR})
if(NOT PYBIND11_EXPORT_NAME) if(NOT PYBIND11_EXPORT_NAME)
@ -262,6 +351,41 @@ if(PYBIND11_INSTALL)
NAMESPACE "pybind11::" NAMESPACE "pybind11::"
DESTINATION ${PYBIND11_CMAKECONFIG_INSTALL_DIR}) DESTINATION ${PYBIND11_CMAKECONFIG_INSTALL_DIR})
# pkg-config support
if(NOT prefix_for_pc_file)
if(IS_ABSOLUTE "${CMAKE_INSTALL_DATAROOTDIR}")
set(prefix_for_pc_file "${CMAKE_INSTALL_PREFIX}")
else()
set(pc_datarootdir "${CMAKE_INSTALL_DATAROOTDIR}")
if(CMAKE_VERSION VERSION_LESS 3.20)
set(prefix_for_pc_file "\${pcfiledir}/..")
while(pc_datarootdir)
get_filename_component(pc_datarootdir "${pc_datarootdir}" DIRECTORY)
string(APPEND prefix_for_pc_file "/..")
endwhile()
else()
cmake_path(RELATIVE_PATH CMAKE_INSTALL_PREFIX BASE_DIRECTORY CMAKE_INSTALL_DATAROOTDIR
OUTPUT_VARIABLE prefix_for_pc_file)
endif()
endif()
endif()
join_paths(includedir_for_pc_file "\${prefix}" "${CMAKE_INSTALL_INCLUDEDIR}")
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/tools/pybind11.pc.in"
"${CMAKE_CURRENT_BINARY_DIR}/pybind11.pc" @ONLY)
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/pybind11.pc"
DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/pkgconfig/")
# When building a wheel, include __init__.py's for modules
# (see https://github.com/pybind/pybind11/pull/5552)
if(DEFINED SKBUILD_PROJECT_NAME AND SKBUILD_PROJECT_NAME STREQUAL "pybind11")
file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/empty")
file(TOUCH "${CMAKE_CURRENT_BINARY_DIR}/empty/__init__.py")
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/empty/__init__.py"
DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/")
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/empty/__init__.py"
DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/pkgconfig/")
endif()
# Uninstall target # Uninstall target
if(PYBIND11_MASTER_PROJECT) if(PYBIND11_MASTER_PROJECT)
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/tools/cmake_uninstall.cmake.in" configure_file("${CMAKE_CURRENT_SOURCE_DIR}/tools/cmake_uninstall.cmake.in"

View File

@ -1,6 +0,0 @@
recursive-include pybind11/include/pybind11 *.h
recursive-include pybind11 *.py
recursive-include pybind11 py.typed
recursive-include pybind11 *.pyi
include pybind11/share/cmake/pybind11/*.cmake
include LICENSE README.rst pyproject.toml setup.py setup.cfg

View File

@ -1,9 +1,11 @@
.. figure:: https://github.com/pybind/pybind11/raw/master/docs/pybind11-logo.png .. figure:: https://github.com/pybind/pybind11/raw/master/docs/pybind11-logo.png
:alt: pybind11 logo :alt: pybind11 logo
**pybind11 — Seamless operability between C++11 and Python** **pybind11 (v3) — Seamless interoperability between C++ and Python**
|Latest Documentation Status| |Stable Documentation Status| |Gitter chat| |GitHub Discussions| |CI| |Build status| |Latest Documentation Status| |Stable Documentation Status| |Gitter chat| |GitHub Discussions|
|CI| |Build status| |SPEC 4 — Using and Creating Nightly Wheels|
|Repology| |PyPI package| |Conda-forge| |Python Versions| |Repology| |PyPI package| |Conda-forge| |Python Versions|
@ -32,14 +34,14 @@ this heavy machinery has become an excessively large and unnecessary
dependency. dependency.
Think of this library as a tiny self-contained version of Boost.Python Think of this library as a tiny self-contained version of Boost.Python
with everything stripped away that isnt relevant for binding with everything stripped away that isn't relevant for binding
generation. Without comments, the core header files only require ~4K generation. Without comments, the core header files only require ~4K
lines of code and depend on Python (2.7 or 3.5+, or PyPy) and the C++ lines of code and depend on Python (CPython 3.8+, PyPy, or GraalPy) and the C++
standard library. This compact implementation was possible thanks to standard library. This compact implementation was possible thanks to some C++11
some of the new C++11 language features (specifically: tuples, lambda language features (specifically: tuples, lambda functions and variadic
functions and variadic templates). Since its creation, this library has templates). Since its creation, this library has grown beyond Boost.Python in
grown beyond Boost.Python in many ways, leading to dramatically simpler many ways, leading to dramatically simpler binding code in many common
binding code in many common situations. situations.
Tutorial and reference documentation is provided at Tutorial and reference documentation is provided at
`pybind11.readthedocs.io <https://pybind11.readthedocs.io/en/latest>`_. `pybind11.readthedocs.io <https://pybind11.readthedocs.io/en/latest>`_.
@ -71,6 +73,7 @@ pybind11 can map the following core C++ features to Python:
- Internal references with correct reference counting - Internal references with correct reference counting
- C++ classes with virtual (and pure virtual) methods can be extended - C++ classes with virtual (and pure virtual) methods can be extended
in Python in Python
- Integrated NumPy support (NumPy 2 requires pybind11 2.12+)
Goodies Goodies
------- -------
@ -78,8 +81,9 @@ Goodies
In addition to the core functionality, pybind11 provides some extra In addition to the core functionality, pybind11 provides some extra
goodies: goodies:
- Python 2.7, 3.5+, and PyPy/PyPy3 7.3 are supported with an - CPython 3.8+, PyPy3 7.3.17+, and GraalPy 24.1+ are supported with an
implementation-agnostic interface. implementation-agnostic interface (see older versions for older CPython
and PyPy versions).
- It is possible to bind C++11 lambda functions with captured - It is possible to bind C++11 lambda functions with captured
variables. The lambda capture data is stored inside the resulting variables. The lambda capture data is stored inside the resulting
@ -88,8 +92,8 @@ goodies:
- pybind11 uses C++11 move constructors and move assignment operators - pybind11 uses C++11 move constructors and move assignment operators
whenever possible to efficiently transfer custom data types. whenever possible to efficiently transfer custom data types.
- Its easy to expose the internal storage of custom data types through - It's easy to expose the internal storage of custom data types through
Pythons buffer protocols. This is handy e.g. for fast conversion Pythons' buffer protocols. This is handy e.g. for fast conversion
between C++ matrix classes like Eigen and NumPy without expensive between C++ matrix classes like Eigen and NumPy without expensive
copy operations. copy operations.
@ -119,25 +123,55 @@ goodies:
Supported compilers Supported compilers
------------------- -------------------
1. Clang/LLVM 3.3 or newer (for Apple Xcodes clang, this is 5.0.0 or 1. Clang/LLVM 3.3 or newer (for Apple Xcode's clang, this is 5.0.0 or
newer) newer)
2. GCC 4.8 or newer 2. GCC 4.8 or newer
3. Microsoft Visual Studio 2015 Update 3 or newer 3. Microsoft Visual Studio 2022 or newer (2019 probably works, but was dropped in CI)
4. Intel classic C++ compiler 18 or newer (ICC 20.2 tested in CI) 4. Intel classic C++ compiler 18 or newer (ICC 20.2 tested in CI)
5. Cygwin/GCC (previously tested on 2.5.1) 5. Cygwin/GCC (previously tested on 2.5.1)
6. NVCC (CUDA 11.0 tested in CI) 6. NVCC (CUDA 11.0 tested in CI)
7. NVIDIA PGI (20.9 tested in CI) 7. NVIDIA PGI (20.9 tested in CI)
Supported Platforms
-------------------
* Windows, Linux, macOS, and iOS
* CPython 3.8+, Pyodide, PyPy, and GraalPy
* C++11, C++14, C++17, C++20, and C++23
About About
----- -----
This project was created by `Wenzel This project was created by `Wenzel
Jakob <http://rgl.epfl.ch/people/wjakob>`_. Significant features and/or Jakob <http://rgl.epfl.ch/people/wjakob>`_. Significant features and/or
improvements to the code were contributed by Jonas Adler, Lori A. Burns, improvements to the code were contributed by
Sylvain Corlay, Eric Cousineau, Aaron Gokaslan, Ralf Grosse-Kunstleve, Trent Houliston, Axel Jonas Adler,
Huebl, @hulucc, Yannick Jadoul, Sergey Lyskov Johan Mabille, Tomasz Miąsko, Lori A. Burns,
Dean Moldovan, Ben Pritchard, Jason Rhinelander, Boris Schäling, Pim Sylvain Corlay,
Schellart, Henry Schreiner, Ivan Smirnov, Boris Staletic, and Patrick Stewart. Eric Cousineau,
Aaron Gokaslan,
Ralf Grosse-Kunstleve,
Trent Houliston,
Axel Huebl,
@hulucc,
Yannick Jadoul,
Sergey Lyskov,
Johan Mabille,
Tomasz Miąsko,
Dean Moldovan,
Ben Pritchard,
Jason Rhinelander,
Boris Schäling,
Pim Schellart,
Henry Schreiner,
Ivan Smirnov,
Dustin Spicuzza,
Boris Staletic,
Ethan Steinberg,
Patrick Stewart,
Ivor Wanders,
and
Xiaofei Wang.
We thank Google for a generous financial contribution to the continuous We thank Google for a generous financial contribution to the continuous
integration infrastructure used by this project. integration infrastructure used by this project.
@ -178,3 +212,5 @@ to the terms and conditions of this license.
:target: https://pypi.org/project/pybind11/ :target: https://pypi.org/project/pybind11/
.. |GitHub Discussions| image:: https://img.shields.io/static/v1?label=Discussions&message=Ask&color=blue&logo=github .. |GitHub Discussions| image:: https://img.shields.io/static/v1?label=Discussions&message=Ask&color=blue&logo=github
:target: https://github.com/pybind/pybind11/discussions :target: https://github.com/pybind/pybind11/discussions
.. |SPEC 4 — Using and Creating Nightly Wheels| image:: https://img.shields.io/badge/SPEC-4-green?labelColor=%23004811&color=%235CA038
:target: https://scientific-python.org/specs/spec-0004/

13
thirdparty/pybind11/SECURITY.md vendored Normal file
View File

@ -0,0 +1,13 @@
# Security Policy
## Supported Versions
Security updates are applied only to the latest release.
## Reporting a Vulnerability
If you have discovered a security vulnerability in this project, please report it privately. **Do not disclose it as a public issue.** This gives us time to work with you to fix the issue before public exposure, reducing the chance that the exploit will be used before a patch is released.
Please disclose it at [security advisory](https://github.com/pybind/pybind11/security/advisories/new).
This project is maintained by a team of volunteers on a reasonable-effort basis. As such, please give us at least 90 days to work on a fix before public exposure.

View File

@ -18,5 +18,4 @@ ALIASES += "endrst=\endverbatim"
QUIET = YES QUIET = YES
WARNINGS = YES WARNINGS = YES
WARN_IF_UNDOCUMENTED = NO WARN_IF_UNDOCUMENTED = NO
PREDEFINED = PY_MAJOR_VERSION=3 \ PREDEFINED = PYBIND11_NOINLINE
PYBIND11_NOINLINE

View File

@ -0,0 +1,3 @@
.highlight .go {
color: #707070;
}

View File

@ -1,11 +0,0 @@
.wy-table-responsive table td,
.wy-table-responsive table th {
white-space: initial !important;
}
.rst-content table.docutils td {
vertical-align: top !important;
}
div[class^='highlight'] pre {
white-space: pre;
white-space: pre-wrap;
}

View File

@ -1,35 +1,55 @@
.. _custom_type_caster:
Custom type casters Custom type casters
=================== ===================
In very rare cases, applications may require custom type casters that cannot be Some applications may prefer custom type casters that convert between existing
expressed using the abstractions provided by pybind11, thus requiring raw Python types and C++ types, similar to the ``list````std::vector``
Python C API calls. This is fairly advanced usage and should only be pursued by and ``dict````std::map`` conversions which are built into pybind11.
experts who are familiar with the intricacies of Python reference counting. Implementing custom type casters is fairly advanced usage.
While it is recommended to use the pybind11 API as much as possible, more complex examples may
require familiarity with the intricacies of the Python C API.
You can refer to the `Python/C API Reference Manual <https://docs.python.org/3/c-api/index.html>`_
for more information.
The following snippets demonstrate how this works for a very simple ``inty`` The following snippets demonstrate how this works for a very simple ``Point2D`` type.
type that that should be convertible from Python types that provide a We want this type to be convertible to C++ from Python types implementing the
``__int__(self)`` method. ``Sequence`` protocol and having two elements of type ``float``.
When returned from C++ to Python, it should be converted to a Python ``tuple[float, float]``.
For this type we could provide Python bindings for different arithmetic functions implemented
in C++ (here demonstrated by a simple ``negate`` function).
..
PLEASE KEEP THE CODE BLOCKS IN SYNC WITH
tests/test_docs_advanced_cast_custom.cpp
tests/test_docs_advanced_cast_custom.py
Ideally, change the test, run pre-commit (incl. clang-format),
then copy the changed code back here.
Also use TEST_SUBMODULE in tests, but PYBIND11_MODULE in docs.
.. code-block:: cpp .. code-block:: cpp
struct inty { long long_value; }; namespace user_space {
void print(inty s) { struct Point2D {
std::cout << s.long_value << std::endl; double x;
} double y;
};
The following Python snippet demonstrates the intended usage from the Python side: Point2D negate(const Point2D &point) { return Point2D{-point.x, -point.y}; }
} // namespace user_space
The following Python snippet demonstrates the intended usage of ``negate`` from the Python side:
.. code-block:: python .. code-block:: python
class A: from my_math_module import docs_advanced_cast_custom as m
def __int__(self):
return 123
point1 = [1.0, -1.0]
from example import print point2 = m.negate(point1)
assert point2 == (-1.0, 1.0)
print(A())
To register the necessary conversion routines, it is necessary to add an To register the necessary conversion routines, it is necessary to add an
instantiation of the ``pybind11::detail::type_caster<T>`` template. instantiation of the ``pybind11::detail::type_caster<T>`` template.
@ -38,47 +58,57 @@ type is explicitly allowed.
.. code-block:: cpp .. code-block:: cpp
namespace pybind11 { namespace detail { namespace pybind11 {
template <> struct type_caster<inty> { namespace detail {
public:
/**
* This macro establishes the name 'inty' in
* function signatures and declares a local variable
* 'value' of type inty
*/
PYBIND11_TYPE_CASTER(inty, const_name("inty"));
/** template <>
* Conversion part 1 (Python->C++): convert a PyObject into a inty struct type_caster<user_space::Point2D> {
* instance or return false upon failure. The second argument // This macro inserts a lot of boilerplate code and sets the type hint.
* indicates whether implicit conversions should be applied. // `io_name` is used to specify different type hints for arguments and return values.
*/ // The signature of our negate function would then look like:
bool load(handle src, bool) { // `negate(Sequence[float]) -> tuple[float, float]`
/* Extract PyObject from handle */ PYBIND11_TYPE_CASTER(user_space::Point2D, io_name("Sequence[float]", "tuple[float, float]"));
PyObject *source = src.ptr();
/* Try converting into a Python integer value */ // C++ -> Python: convert `Point2D` to `tuple[float, float]`. The second and third arguments
PyObject *tmp = PyNumber_Long(source); // are used to indicate the return value policy and parent object (for
if (!tmp) // return_value_policy::reference_internal) and are often ignored by custom casters.
return false; // The return value should reflect the type hint specified by the second argument of `io_name`.
/* Now try to convert into a C++ int */ static handle
value.long_value = PyLong_AsLong(tmp); cast(const user_space::Point2D &number, return_value_policy /*policy*/, handle /*parent*/) {
Py_DECREF(tmp); return py::make_tuple(number.x, number.y).release();
/* Ensure return code was OK (to avoid out-of-range errors etc) */
return !(value.long_value == -1 && !PyErr_Occurred());
} }
/** // Python -> C++: convert a `PyObject` into a `Point2D` and return false upon failure. The
* Conversion part 2 (C++ -> Python): convert an inty instance into // second argument indicates whether implicit conversions should be allowed.
* a Python object. The second and third arguments are used to // The accepted types should reflect the type hint specified by the first argument of
* indicate the return value policy and parent object (for // `io_name`.
* ``return_value_policy::reference_internal``) and are generally bool load(handle src, bool /*convert*/) {
* ignored by implicit casters. // Check if handle is a Sequence
*/ if (!py::isinstance<py::sequence>(src)) {
static handle cast(inty src, return_value_policy /* policy */, handle /* parent */) { return false;
return PyLong_FromLong(src.long_value); }
auto seq = py::reinterpret_borrow<py::sequence>(src);
// Check if exactly two values are in the Sequence
if (seq.size() != 2) {
return false;
}
// Check if each element is either a float or an int
for (auto item : seq) {
if (!py::isinstance<py::float_>(item) && !py::isinstance<py::int_>(item)) {
return false;
}
}
value.x = seq[0].cast<double>();
value.y = seq[1].cast<double>();
return true;
} }
}; };
}} // namespace pybind11::detail
} // namespace detail
} // namespace pybind11
// Bind the negate function
PYBIND11_MODULE(docs_advanced_cast_custom, m, py::mod_gil_not_used()) { m.def("negate", user_space::negate); }
.. note:: .. note::
@ -86,8 +116,22 @@ type is explicitly allowed.
that ``T`` is default-constructible (``value`` is first default constructed that ``T`` is default-constructible (``value`` is first default constructed
and then ``load()`` assigns to it). and then ``load()`` assigns to it).
.. note::
For further information on the ``return_value_policy`` argument of ``cast`` refer to :ref:`return_value_policies`.
To learn about the ``convert`` argument of ``load`` see :ref:`nonconverting_arguments`.
.. warning:: .. warning::
When using custom type casters, it's important to declare them consistently When using custom type casters, it's important to declare them consistently
in every compilation unit of the Python extension module. Otherwise, in every compilation unit of the Python extension module to satisfy the C++ One Definition Rule
(`ODR <https://en.cppreference.com/w/cpp/language/definition>`_). Otherwise,
undefined behavior can ensue. undefined behavior can ensue.
.. note::
Using the type hint ``Sequence[float]`` signals to static type checkers, that not only tuples may be
passed, but any type implementing the Sequence protocol, e.g., ``list[float]``.
Unfortunately, that loses the length information ``tuple[float, float]`` provides.
One way of still providing some length information in type hints is using ``typing.Annotated``, e.g.,
``Annotated[Sequence[float], 2]``, or further add libraries like
`annotated-types <https://github.com/annotated-types/annotated-types>`_.

View File

@ -259,7 +259,7 @@ copying to take place:
"small"_a // <- This one can be copied if needed "small"_a // <- This one can be copied if needed
); );
With the above binding code, attempting to call the the ``some_method(m)`` With the above binding code, attempting to call the ``some_method(m)``
method on a ``MyClass`` object, or attempting to call ``some_function(m, m2)`` method on a ``MyClass`` object, or attempting to call ``some_function(m, m2)``
will raise a ``RuntimeError`` rather than making a temporary copy of the array. will raise a ``RuntimeError`` rather than making a temporary copy of the array.
It will, however, allow the ``m2`` argument to be copied into a temporary if It will, however, allow the ``m2`` argument to be copied into a temporary if

View File

@ -56,7 +56,7 @@ trivial to generate binding code for all of these functions.
#include <pybind11/functional.h> #include <pybind11/functional.h>
PYBIND11_MODULE(example, m) { PYBIND11_MODULE(example, m, py::mod_gil_not_used()) {
m.def("func_arg", &func_arg); m.def("func_arg", &func_arg);
m.def("func_ret", &func_ret); m.def("func_ret", &func_ret);
m.def("func_cpp", &func_cpp); m.def("func_cpp", &func_cpp);

View File

@ -151,7 +151,7 @@ as arguments and return values, refer to the section on binding :ref:`classes`.
+------------------------------------+---------------------------+-----------------------------------+ +------------------------------------+---------------------------+-----------------------------------+
| ``std::variant<...>`` | Type-safe union (C++17) | :file:`pybind11/stl.h` | | ``std::variant<...>`` | Type-safe union (C++17) | :file:`pybind11/stl.h` |
+------------------------------------+---------------------------+-----------------------------------+ +------------------------------------+---------------------------+-----------------------------------+
| ``std::filesystem::path<T>`` | STL path (C++17) [#]_ | :file:`pybind11/stl/filesystem.h` | | ``std::filesystem::path`` | STL path (C++17) [#]_ | :file:`pybind11/stl/filesystem.h` |
+------------------------------------+---------------------------+-----------------------------------+ +------------------------------------+---------------------------+-----------------------------------+
| ``std::function<...>`` | STL polymorphic function | :file:`pybind11/functional.h` | | ``std::function<...>`` | STL polymorphic function | :file:`pybind11/functional.h` |
+------------------------------------+---------------------------+-----------------------------------+ +------------------------------------+---------------------------+-----------------------------------+
@ -167,5 +167,4 @@ as arguments and return values, refer to the section on binding :ref:`classes`.
+------------------------------------+---------------------------+-----------------------------------+ +------------------------------------+---------------------------+-----------------------------------+
.. [#] ``std::filesystem::path`` is converted to ``pathlib.Path`` and .. [#] ``std::filesystem::path`` is converted to ``pathlib.Path`` and
``os.PathLike`` is converted to ``std::filesystem::path``, but this requires can be loaded from ``os.PathLike``, ``str``, and ``bytes``.
Python 3.6 (for ``__fspath__`` support).

View File

@ -42,7 +42,7 @@ types:
.. code-block:: cpp .. code-block:: cpp
// `boost::optional` as an example -- can be any `std::optional`-like container // `boost::optional` as an example -- can be any `std::optional`-like container
namespace pybind11 { namespace detail { namespace PYBIND11_NAMESPACE { namespace detail {
template <typename T> template <typename T>
struct type_caster<boost::optional<T>> : optional_caster<boost::optional<T>> {}; struct type_caster<boost::optional<T>> : optional_caster<boost::optional<T>> {};
}} }}
@ -54,7 +54,7 @@ for custom variant types:
.. code-block:: cpp .. code-block:: cpp
// `boost::variant` as an example -- can be any `std::variant`-like container // `boost::variant` as an example -- can be any `std::variant`-like container
namespace pybind11 { namespace detail { namespace PYBIND11_NAMESPACE { namespace detail {
template <typename... Ts> template <typename... Ts>
struct type_caster<boost::variant<Ts...>> : variant_caster<boost::variant<Ts...>> {}; struct type_caster<boost::variant<Ts...>> : variant_caster<boost::variant<Ts...>> {};
@ -66,7 +66,7 @@ for custom variant types:
return boost::apply_visitor(args...); return boost::apply_visitor(args...);
} }
}; };
}} // namespace pybind11::detail }} // namespace PYBIND11_NAMESPACE::detail
The ``visit_helper`` specialization is not required if your ``name::variant`` provides The ``visit_helper`` specialization is not required if your ``name::variant`` provides
a ``name::visit()`` function. For any other function name, the specialization must be a ``name::visit()`` function. For any other function name, the specialization must be
@ -87,8 +87,6 @@ included to tell pybind11 how to visit the variant.
pybind11 only supports the modern implementation of ``boost::variant`` pybind11 only supports the modern implementation of ``boost::variant``
which makes use of variadic templates. This requires Boost 1.56 or newer. which makes use of variadic templates. This requires Boost 1.56 or newer.
Additionally, on Windows, MSVC 2017 is required because ``boost::variant``
falls back to the old non-variadic implementation on MSVC 2015.
.. _opaque: .. _opaque:
@ -164,15 +162,15 @@ the declaration
.. code-block:: cpp .. code-block:: cpp
PYBIND11_MAKE_OPAQUE(std::vector<int>); PYBIND11_MAKE_OPAQUE(std::vector<int>)
before any binding code (e.g. invocations to ``class_::def()``, etc.). This before any binding code (e.g. invocations to ``class_::def()``, etc.). This
macro must be specified at the top level (and outside of any namespaces), since macro must be specified at the top level (and outside of any namespaces), since
it adds a template instantiation of ``type_caster``. If your binding code consists of it adds a template instantiation of ``type_caster``. If your binding code consists of
multiple compilation units, it must be present in every file (typically via a multiple compilation units, it must be present in every file (typically via a
common header) preceding any usage of ``std::vector<int>``. Opaque types must common header) preceding any usage of ``std::vector<int>``. Opaque types must
also have a corresponding ``class_`` declaration to associate them with a name also have a corresponding ``py::class_`` declaration to associate them with a
in Python, and to define a set of available operations, e.g.: name in Python, and to define a set of available operations, e.g.:
.. code-block:: cpp .. code-block:: cpp
@ -209,8 +207,8 @@ The following example showcases usage of :file:`pybind11/stl_bind.h`:
// Don't forget this // Don't forget this
#include <pybind11/stl_bind.h> #include <pybind11/stl_bind.h>
PYBIND11_MAKE_OPAQUE(std::vector<int>); PYBIND11_MAKE_OPAQUE(std::vector<int>)
PYBIND11_MAKE_OPAQUE(std::map<std::string, double>); PYBIND11_MAKE_OPAQUE(std::map<std::string, double>)
// ... // ...

View File

@ -1,14 +1,6 @@
Strings, bytes and Unicode conversions Strings, bytes and Unicode conversions
###################################### ######################################
.. note::
This section discusses string handling in terms of Python 3 strings. For
Python 2.7, replace all occurrences of ``str`` with ``unicode`` and
``bytes`` with ``str``. Python 2.7 users may find it best to use ``from
__future__ import unicode_literals`` to avoid unintentionally using ``str``
instead of ``unicode``.
Passing Python strings to C++ Passing Python strings to C++
============================= =============================
@ -58,9 +50,9 @@ Passing bytes to C++
-------------------- --------------------
A Python ``bytes`` object will be passed to C++ functions that accept A Python ``bytes`` object will be passed to C++ functions that accept
``std::string`` or ``char*`` *without* conversion. On Python 3, in order to ``std::string`` or ``char*`` *without* conversion. In order to make a function
make a function *only* accept ``bytes`` (and not ``str``), declare it as taking *only* accept ``bytes`` (and not ``str``), declare it as taking a ``py::bytes``
a ``py::bytes`` argument. argument.
Returning C++ strings to Python Returning C++ strings to Python
@ -109,8 +101,11 @@ conversion has the same overhead as implicit conversion.
m.def("str_output", m.def("str_output",
[]() { []() {
std::string s = "Send your r\xe9sum\xe9 to Alice in HR"; // Latin-1 std::string s = "Send your r\xe9sum\xe9 to Alice in HR"; // Latin-1
py::str py_s = PyUnicode_DecodeLatin1(s.data(), s.length()); py::handle py_s = PyUnicode_DecodeLatin1(s.data(), s.length(), nullptr);
return py_s; if (!py_s) {
throw py::error_already_set();
}
return py::reinterpret_steal<py::str>(py_s);
} }
); );
@ -121,7 +116,8 @@ conversion has the same overhead as implicit conversion.
The `Python C API The `Python C API
<https://docs.python.org/3/c-api/unicode.html#built-in-codecs>`_ provides <https://docs.python.org/3/c-api/unicode.html#built-in-codecs>`_ provides
several built-in codecs. several built-in codecs. Note that these all return *new* references, so
use :cpp:func:`reinterpret_steal` when converting them to a :cpp:class:`str`.
One could also use a third party encoding library such as libiconv to transcode One could also use a third party encoding library such as libiconv to transcode
@ -204,11 +200,6 @@ decoded to Python ``str``.
} }
); );
.. warning::
Wide character strings may not work as described on Python 2.7 or Python
3.3 compiled with ``--enable-unicode=ucs2``.
Strings in multibyte encodings such as Shift-JIS must transcoded to a Strings in multibyte encodings such as Shift-JIS must transcoded to a
UTF-8/16/32 before being returned to Python. UTF-8/16/32 before being returned to Python.

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