ADDED: automatic zone refilling.

This is for the out-of-box experience for novice users.  It is presumed
that folks with larger more complicated boards will turn it off.

Fixes https://gitlab.com/kicad/code/kicad/issues/6413
This commit is contained in:
Jeff Young 2022-02-24 09:59:54 +00:00
parent f076d07e9e
commit d465eb6425
16 changed files with 289 additions and 109 deletions

View File

@ -561,7 +561,7 @@ void TOOL_MANAGER::ResetTools( TOOL_BASE::RESET_REASON aReason )
void TOOL_MANAGER::InitTools()
{
for( TOOL_VEC::iterator it = m_toolOrder.begin(); it != m_toolOrder.end(); /* iter inside */ )
for( auto it = m_toolOrder.begin(); it != m_toolOrder.end(); /* iter inside */ )
{
TOOL_BASE* tool = *it;
wxASSERT( m_toolState.count( tool ) );

View File

@ -133,7 +133,7 @@ public:
///< Execute the changes.
virtual void Push( const wxString& aMessage = wxT( "A commit" ),
bool aCreateUndoEntry = true, bool aSetDirtyBit = true,
bool aUpdateConnectivity = true ) = 0;
bool aUpdateConnectivity = true, bool aZoneFillOp = false ) = 0;
///< Revert the commit by restoring the modified items state.
virtual void Revert() = 0;

View File

@ -66,7 +66,6 @@ public:
typedef std::map<std::string, TOOL_STATE*> NAME_STATE_MAP;
typedef std::map<TOOL_ID, TOOL_STATE*> ID_STATE_MAP;
typedef std::list<TOOL_ID> ID_LIST;
typedef std::vector<TOOL_BASE*> TOOL_VEC;
/**
* Generates a unique ID from for a tool with given name.
@ -226,6 +225,11 @@ public:
return nullptr;
}
/*
* Return all registered tools.
*/
std::vector<TOOL_BASE*> Tools() { return m_toolOrder; }
/**
* Deactivate the currently active tool.
*/
@ -531,7 +535,7 @@ private:
void setActiveState( TOOL_STATE* aState );
///< List of tools in the order they were registered
TOOL_VEC m_toolOrder;
std::vector<TOOL_BASE*> m_toolOrder;
///< Index of registered tools current states, associated by tools' objects.
TOOL_STATE_MAP m_toolState;

View File

@ -2,7 +2,7 @@
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2016 CERN
* Copyright (C) 2020-2021 KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 2020-2022 KiCad Developers, see AUTHORS.txt for contributors.
* @author Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
*
* This program is free software; you can redistribute it and/or
@ -28,6 +28,7 @@
#include <pcb_group.h>
#include <tool/tool_manager.h>
#include <tools/pcb_selection_tool.h>
#include <tools/zone_filler_tool.h>
#include <view/view.h>
#include <board_commit.h>
#include <tools/pcb_tool_base.h>
@ -42,6 +43,7 @@ using namespace std::placeholders;
BOARD_COMMIT::BOARD_COMMIT( TOOL_MANAGER* aToolMgr ) :
m_toolMgr( aToolMgr ),
m_isFootprintEditor( false ),
m_isBoardEditor( false ),
m_resolveNetConflicts( false )
{
}
@ -52,6 +54,7 @@ BOARD_COMMIT::BOARD_COMMIT( PCB_TOOL_BASE* aTool ) :
{
m_toolMgr = aTool->GetManager();
m_isFootprintEditor = aTool->IsFootprintEditor();
m_isBoardEditor = aTool->IsBoardEditor();
}
@ -60,6 +63,7 @@ BOARD_COMMIT::BOARD_COMMIT( EDA_DRAW_FRAME* aFrame ) :
{
m_toolMgr = aFrame->GetToolManager();
m_isFootprintEditor = aFrame->IsType( FRAME_FOOTPRINT_EDITOR );
m_isBoardEditor = aFrame->IsType( FRAME_PCB_EDITOR );
}
@ -96,18 +100,59 @@ COMMIT& BOARD_COMMIT::Stage( const PICKED_ITEMS_LIST& aItems, UNDO_REDO aModFlag
}
void BOARD_COMMIT::dirtyIntersectingZones( BOARD_ITEM* item )
{
if( item->Type() == PCB_FOOTPRINT_T )
{
static_cast<FOOTPRINT*>( item )->RunOnChildren(
[&]( BOARD_ITEM* child )
{
dirtyIntersectingZones( child );
} );
}
else if( item->Type() == PCB_GROUP_T )
{
static_cast<PCB_GROUP*>( item )->RunOnChildren(
[&]( BOARD_ITEM* child )
{
dirtyIntersectingZones( child );
} );
}
else
{
ZONE_FILLER_TOOL* zoneFillerTool = m_toolMgr->GetTool<ZONE_FILLER_TOOL>();
BOARD* board = static_cast<BOARD*>( m_toolMgr->GetModel() );
EDA_RECT bbox = item->GetBoundingBox();
LSET layers = item->GetLayerSet();
for( ZONE* zone : board->Zones() )
{
if( zone->GetIsRuleArea() )
continue;
if( ( zone->GetLayerSet() & layers ).any()
&& zone->GetCachedBoundingBox().Intersects( bbox ) )
{
zoneFillerTool->DirtyZone( zone );
}
}
}
}
void BOARD_COMMIT::Push( const wxString& aMessage, bool aCreateUndoEntry, bool aSetDirtyBit,
bool aUpdateConnectivity )
bool aUpdateConnectivity, bool aZoneFillOp )
{
// Objects potentially interested in changes:
PICKED_ITEMS_LIST undoList;
KIGFX::VIEW* view = m_toolMgr->GetView();
BOARD* board = (BOARD*) m_toolMgr->GetModel();
BOARD* board = static_cast<BOARD*>( m_toolMgr->GetModel() );
PCB_BASE_FRAME* frame = dynamic_cast<PCB_BASE_FRAME*>( m_toolMgr->GetToolHolder() );
std::set<EDA_ITEM*> savedModules;
PCB_SELECTION_TOOL* selTool = m_toolMgr->GetTool<PCB_SELECTION_TOOL>();
bool itemsDeselected = false;
bool solderMaskDirty = false;
bool autofillZones = false;
std::vector<BOARD_ITEM*> bulkAddedItems;
std::vector<BOARD_ITEM*> bulkRemovedItems;
@ -116,6 +161,14 @@ void BOARD_COMMIT::Push( const wxString& aMessage, bool aCreateUndoEntry, bool a
if( Empty() )
return;
if( m_isBoardEditor && !aZoneFillOp && frame->GetPcbNewSettings()->m_AutoRefillZones )
{
autofillZones = true;
for( ZONE* zone : board->Zones() )
zone->CacheBoundingBox();
}
for( COMMIT_LINE& ent : m_changes )
{
int changeType = ent.m_type & CHT_TYPE;
@ -205,6 +258,9 @@ void BOARD_COMMIT::Push( const wxString& aMessage, bool aCreateUndoEntry, bool a
}
}
if( autofillZones )
dirtyIntersectingZones( boardItem );
if( view && boardItem->Type() != PCB_NETINFO_T )
view->Add( boardItem );
@ -224,6 +280,9 @@ void BOARD_COMMIT::Push( const wxString& aMessage, bool aCreateUndoEntry, bool a
itemsDeselected = true;
}
if( autofillZones )
dirtyIntersectingZones( boardItem );
switch( boardItem->Type() )
{
// Footprint items
@ -334,7 +393,7 @@ void BOARD_COMMIT::Push( const wxString& aMessage, bool aCreateUndoEntry, bool a
bulkRemovedItems.push_back( boardItem );
break;
default: // other types do not need to (or should not) be handled
default: // other types do not need to (or should not) be handled
wxASSERT( false );
break;
}
@ -362,6 +421,12 @@ void BOARD_COMMIT::Push( const wxString& aMessage, bool aCreateUndoEntry, bool a
connectivity->Update( boardItem );
}
if( autofillZones )
{
dirtyIntersectingZones( static_cast<BOARD_ITEM*>( ent.m_copy )); // before
dirtyIntersectingZones( boardItem ); // after
}
if( view )
{
view->Update( boardItem );
@ -400,7 +465,7 @@ void BOARD_COMMIT::Push( const wxString& aMessage, bool aCreateUndoEntry, bool a
if( itemsChanged.size() > 0 )
board->OnItemsChanged( itemsChanged );
if( !m_isFootprintEditor )
if( m_isBoardEditor )
{
size_t num_changes = m_changes.size();
@ -415,42 +480,38 @@ void BOARD_COMMIT::Push( const wxString& aMessage, bool aCreateUndoEntry, bool a
connectivity->ClearDynamicRatsnest();
}
if( frame && solderMaskDirty )
if( solderMaskDirty )
frame->HideSolderMask();
if( frame )
frame->GetCanvas()->RedrawRatsnest();
frame->GetCanvas()->RedrawRatsnest();
if( m_changes.size() > num_changes )
// Log undo items for any connectivity changes
for( size_t i = num_changes; i < m_changes.size(); ++i )
{
for( size_t i = num_changes; i < m_changes.size(); ++i )
COMMIT_LINE& ent = m_changes[i];
wxASSERT( ( ent.m_type & CHT_TYPE ) == CHT_MODIFY );
BOARD_ITEM* boardItem = static_cast<BOARD_ITEM*>( ent.m_item );
if( aCreateUndoEntry )
{
COMMIT_LINE& ent = m_changes[i];
// This should only be modifications from the connectivity algo
wxASSERT( ( ent.m_type & CHT_TYPE ) == CHT_MODIFY );
BOARD_ITEM* boardItem = static_cast<BOARD_ITEM*>( ent.m_item );
if( aCreateUndoEntry )
{
ITEM_PICKER itemWrapper( nullptr, boardItem, UNDO_REDO::CHANGED );
wxASSERT( ent.m_copy );
itemWrapper.SetLink( ent.m_copy );
undoList.PushItem( itemWrapper );
}
else
{
delete ent.m_copy;
}
if( view )
view->Update( boardItem );
ITEM_PICKER itemWrapper( nullptr, boardItem, UNDO_REDO::CHANGED );
wxASSERT( ent.m_copy );
itemWrapper.SetLink( ent.m_copy );
undoList.PushItem( itemWrapper );
}
else
{
delete ent.m_copy;
}
if( view )
view->Update( boardItem );
}
}
if( !m_isFootprintEditor && aCreateUndoEntry && frame )
if( m_isBoardEditor && aCreateUndoEntry )
frame->SaveCopyInUndoList( undoList, UNDO_REDO::UNSPECIFIED );
m_toolMgr->PostEvent( { TC_MESSAGE, TA_MODEL_CHANGE, AS_GLOBAL } );
@ -458,6 +519,9 @@ void BOARD_COMMIT::Push( const wxString& aMessage, bool aCreateUndoEntry, bool a
if( itemsDeselected )
m_toolMgr->PostEvent( EVENTS::UnselectedEvent );
if( autofillZones )
m_toolMgr->RunAction( PCB_ACTIONS::zoneFillDirty );
if( frame )
{
if( aSetDirtyBit )

View File

@ -2,6 +2,7 @@
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2016 CERN
* Copyright (C) 2016-2022 KiCad Developers, see AUTHORS.txt for contributors.
* @author Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
*
* This program is free software; you can redistribute it and/or
@ -22,8 +23,8 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#ifndef __BOARD_COMMIT_H
#define __BOARD_COMMIT_H
#ifndef BOARD_COMMIT_H
#define BOARD_COMMIT_H
#include <commit.h>
@ -45,7 +46,7 @@ public:
virtual void Push( const wxString& aMessage = wxT( "A commit" ),
bool aCreateUndoEntry = true, bool aSetDirtyBit = true,
bool aUpdateConnectivity = true ) override;
bool aUpdateConnectivity = true, bool aZoneFillOp = false ) override;
virtual void Revert() override;
COMMIT& Stage( EDA_ITEM* aItem, CHANGE_TYPE aChangeType ) override;
@ -66,10 +67,13 @@ public:
private:
virtual EDA_ITEM* parentObject( EDA_ITEM* aItem ) const override;
void dirtyIntersectingZones( BOARD_ITEM* item );
private:
TOOL_MANAGER* m_toolMgr;
bool m_isFootprintEditor;
bool m_resolveNetConflicts;
TOOL_MANAGER* m_toolMgr;
bool m_isFootprintEditor;
bool m_isBoardEditor;
bool m_resolveNetConflicts;
};
#endif

View File

@ -363,7 +363,7 @@ PANEL_EDIT_OPTIONS_BASE::PANEL_EDIT_OPTIONS_BASE( wxWindow* parent, wxWindowID i
sbSizerPcbGraphics = new wxStaticBoxSizer( new wxStaticBox( pcbPage, wxID_ANY, _("Graphics Editing") ), wxVERTICAL );
m_cbPcbGraphic45Mode = new wxCheckBox( sbSizerPcbGraphics->GetStaticBox(), wxID_ANY, _("Limit actions to 45 degrees from start"), wxDefaultPosition, wxDefaultSize, 0 );
sbSizerPcbGraphics->Add( m_cbPcbGraphic45Mode, 0, wxALL, 5 );
sbSizerPcbGraphics->Add( m_cbPcbGraphic45Mode, 0, wxBOTTOM|wxRIGHT|wxLEFT, 5 );
pcbOptionsSizer->Add( sbSizerPcbGraphics, 0, wxEXPAND|wxTOP, 5 );
@ -377,11 +377,11 @@ PANEL_EDIT_OPTIONS_BASE::PANEL_EDIT_OPTIONS_BASE( wxWindow* parent, wxWindowID i
sbSizer4->Add( m_showPageLimits, 0, wxBOTTOM|wxRIGHT|wxLEFT, 5 );
m_autoRefillZones = new wxCheckBox( sbSizer4->GetStaticBox(), wxID_ANY, _("Refill zones after Zone Properties dialog"), wxDefaultPosition, wxDefaultSize, 0 );
m_autoRefillZones = new wxCheckBox( sbSizer4->GetStaticBox(), wxID_ANY, _("Auto-refill zones"), wxDefaultPosition, wxDefaultSize, 0 );
m_autoRefillZones->SetValue(true);
m_autoRefillZones->SetToolTip( _("If checked, zones will be re-filled after editing the properties of the zone using the Zone Properties dialog") );
sbSizer4->Add( m_autoRefillZones, 0, wxALL, 5 );
sbSizer4->Add( m_autoRefillZones, 0, wxBOTTOM|wxRIGHT|wxLEFT, 5 );
pcbOptionsSizer->Add( sbSizer4, 1, wxEXPAND|wxTOP, 5 );

View File

@ -3313,7 +3313,7 @@
<property name="permission">none</property>
<object class="sizeritem" expanded="1">
<property name="border">5</property>
<property name="flag">wxALL</property>
<property name="flag">wxBOTTOM|wxRIGHT|wxLEFT</property>
<property name="proportion">0</property>
<object class="wxCheckBox" expanded="1">
<property name="BottomDockable">1</property>
@ -3455,7 +3455,7 @@
</object>
<object class="sizeritem" expanded="1">
<property name="border">5</property>
<property name="flag">wxALL</property>
<property name="flag">wxBOTTOM|wxRIGHT|wxLEFT</property>
<property name="proportion">0</property>
<object class="wxCheckBox" expanded="1">
<property name="BottomDockable">1</property>
@ -3486,7 +3486,7 @@
<property name="gripper">0</property>
<property name="hidden">0</property>
<property name="id">wxID_ANY</property>
<property name="label">Refill zones after Zone Properties dialog</property>
<property name="label">Auto-refill zones</property>
<property name="max_size"></property>
<property name="maximize_button">0</property>
<property name="maximum_size"></property>

View File

@ -2,7 +2,7 @@
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2012 Jean-Pierre Charras, jean-pierre.charras@ujf-grenoble.fr
* Copyright (C) 1992-2012 KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 1992-2022 KiCad Developers, see AUTHORS.txt for contributors.
*
* Some code comes from FreePCB.
*
@ -33,8 +33,6 @@
#include <zones.h>
#include <zones_functions_for_undo_redo.h>
#include <connectivity/connectivity_data.h>
#include <widgets/wx_progress_reporters.h>
#include <zone_filler.h>
void PCB_EDIT_FRAME::Edit_Zone_Params( ZONE* aZone )
@ -103,43 +101,8 @@ void PCB_EDIT_FRAME::Edit_Zone_Params( ZONE* aZone )
UpdateCopyOfZonesList( pickedList, deletedList, GetBoard() );
// refill zones with the new properties applied
std::vector<ZONE*> zones_to_refill;
for( unsigned i = 0; i < pickedList.GetCount(); ++i )
{
ZONE* zone = dyn_cast<ZONE*>( pickedList.GetPickedItem( i ) );
if( zone == nullptr )
{
wxASSERT_MSG( false, wxT( "Expected a zone after zone properties edit" ) );
continue;
}
// aZone won't be filled if the layer set was modified, but it needs to be updated
if( zone->IsFilled() || zone == aZone )
zones_to_refill.push_back( zone );
}
commit.Stage( pickedList );
// Only auto-refill zones here if in user preferences
if( Settings().m_AutoRefillZones )
{
if( zones_to_refill.size() )
{
ZONE_FILLER filler( GetBoard(), &commit );
wxString title = wxString::Format( _( "Refill %d Zones" ),
(int) zones_to_refill.size() );
std::unique_ptr<WX_PROGRESS_REPORTER> reporter;
reporter = std::make_unique<WX_PROGRESS_REPORTER>( this, title, 4 );
filler.SetProgressReporter( reporter.get() );
(void) filler.Fill( zones_to_refill );
}
}
commit.Push( _( "Modify zone properties" ), true, true, false );
GetBoard()->GetConnectivity()->Build( GetBoard() );

View File

@ -1020,16 +1020,11 @@ void FOOTPRINT_EDIT_FRAME::setupTools()
m_toolManager->RegisterTool( new CONVERT_TOOL );
m_toolManager->RegisterTool( new SCRIPTING_TOOL );
m_toolManager->GetTool<PCB_SELECTION_TOOL>()->SetIsFootprintEditor( true );
m_toolManager->GetTool<EDIT_TOOL>()->SetIsFootprintEditor( true );
m_toolManager->GetTool<PAD_TOOL>()->SetIsFootprintEditor( true );
m_toolManager->GetTool<DRAWING_TOOL>()->SetIsFootprintEditor( true );
m_toolManager->GetTool<PCB_POINT_EDITOR>()->SetIsFootprintEditor( true );
m_toolManager->GetTool<PCB_CONTROL>()->SetIsFootprintEditor( true );
m_toolManager->GetTool<PCB_PICKER_TOOL>()->SetIsFootprintEditor( true );
m_toolManager->GetTool<POSITION_RELATIVE_TOOL>()->SetIsFootprintEditor( true );
m_toolManager->GetTool<GROUP_TOOL>()->SetIsFootprintEditor( true );
m_toolManager->GetTool<SCRIPTING_TOOL>()->SetIsFootprintEditor( true );
for( TOOL_BASE* tool : m_toolManager->Tools() )
{
if( PCB_TOOL_BASE* pcbTool = dynamic_cast<PCB_TOOL_BASE*>( tool ) )
pcbTool->SetIsFootprintEditor( true );
}
m_toolManager->GetTool<PCB_VIEWER_TOOLS>()->SetFootprintFrame( true );
m_toolManager->InitTools();

View File

@ -568,6 +568,12 @@ void PCB_EDIT_FRAME::setupTools()
m_toolManager->RegisterTool( new SCRIPTING_TOOL );
m_toolManager->InitTools();
for( TOOL_BASE* tool : m_toolManager->Tools() )
{
if( PCB_TOOL_BASE* pcbTool = dynamic_cast<PCB_TOOL_BASE*>( tool ) )
pcbTool->SetIsBoardEditor( true );
}
// Run the selection tool, it is supposed to be always active
m_toolManager->InvokeTool( "pcbnew.InteractiveSelection" );
}

View File

@ -1300,6 +1300,9 @@ TOOL_ACTION PCB_ACTIONS::zoneFillAll( "pcbnew.ZoneFiller.zoneFillAll",
_( "Fill All Zones" ), _( "Update copper fill of all zones" ),
BITMAPS::fill_zone );
TOOL_ACTION PCB_ACTIONS::zoneFillDirty( "pcbnew.ZoneFiller.zoneFillDirty",
AS_CONTEXT );
TOOL_ACTION PCB_ACTIONS::zoneUnfill( "pcbnew.ZoneFiller.zoneUnfill",
AS_GLOBAL, 0, "",
_( "Unfill Zone" ), _( "Remove copper fill from selected zone(s)" ),

View File

@ -309,6 +309,7 @@ public:
// Zone actions
static TOOL_ACTION zoneFill;
static TOOL_ACTION zoneFillAll;
static TOOL_ACTION zoneFillDirty;
static TOOL_ACTION zoneUnfill;
static TOOL_ACTION zoneUnfillAll;
static TOOL_ACTION zoneMerge;

View File

@ -76,7 +76,8 @@ public:
* Creates a tool with given id & name. The name must be unique. */
PCB_TOOL_BASE( TOOL_ID aId, const std::string& aName ) :
TOOL_INTERACTIVE ( aId, aName ),
m_isFootprintEditor( false )
m_isFootprintEditor( false ),
m_isBoardEditor( false )
{};
/**
@ -85,7 +86,8 @@ public:
* Creates a tool with given name. The name must be unique. */
PCB_TOOL_BASE( const std::string& aName ) :
TOOL_INTERACTIVE ( aName ),
m_isFootprintEditor( false )
m_isFootprintEditor( false ),
m_isBoardEditor( false )
{};
virtual ~PCB_TOOL_BASE() {};
@ -103,6 +105,9 @@ public:
void SetIsFootprintEditor( bool aEnabled ) { m_isFootprintEditor = aEnabled; }
bool IsFootprintEditor() const { return m_isFootprintEditor; }
void SetIsBoardEditor( bool aEnabled ) { m_isBoardEditor = aEnabled; }
bool IsBoardEditor() const { return m_isBoardEditor; }
/**
* Should the tool use its 45° mode option?
* @return True if set to use 45°
@ -179,6 +184,7 @@ protected:
protected:
bool m_isFootprintEditor;
bool m_isBoardEditor;
};
#endif

View File

@ -27,6 +27,8 @@
#include <zone.h>
#include <connectivity/connectivity_data.h>
#include <board_commit.h>
#include <footprint.h>
#include <pcb_group.h>
#include <board_design_settings.h>
#include <progress_reporter.h>
#include <widgets/infobar.h>
@ -66,7 +68,7 @@ void ZONE_FILLER_TOOL::CheckAllZones( wxWindow* aCaller, PROGRESS_REPORTER* aRep
std::vector<ZONE*> toFill;
for( ZONE* zone : board()->Zones() )
toFill.push_back(zone);
toFill.push_back( zone );
BOARD_COMMIT commit( this );
std::unique_ptr<WX_PROGRESS_REPORTER> reporter;
@ -84,7 +86,7 @@ void ZONE_FILLER_TOOL::CheckAllZones( wxWindow* aCaller, PROGRESS_REPORTER* aRep
if( filler.Fill( toFill, true, aCaller ) )
{
commit.Push( _( "Fill Zone(s)" ), true, true, false );
commit.Push( _( "Fill Zone(s)" ), true, true, false, true );
getEditFrame<PCB_EDIT_FRAME>()->m_ZoneFillsDirty = false;
}
else
@ -159,7 +161,7 @@ void ZONE_FILLER_TOOL::FillAllZones( wxWindow* aCaller, PROGRESS_REPORTER* aRepo
{
filler.GetProgressReporter()->AdvancePhase();
commit.Push( _( "Fill Zone(s)" ), true, true, false );
commit.Push( _( "Fill Zone(s)" ), true, true, false, true );
frame->m_ZoneFillsDirty = false;
}
else
@ -181,6 +183,105 @@ void ZONE_FILLER_TOOL::FillAllZones( wxWindow* aCaller, PROGRESS_REPORTER* aRepo
}
int ZONE_FILLER_TOOL::ZoneFillDirty( const TOOL_EVENT& aEvent )
{
PCB_EDIT_FRAME* frame = getEditFrame<PCB_EDIT_FRAME>();
std::vector<ZONE*> toFill;
for( ZONE* zone : board()->Zones() )
{
if( m_dirtyZoneIDs.count( zone->m_Uuid ) )
toFill.push_back( zone );
}
if( toFill.empty() )
return 0;
if( m_fillInProgress )
return 0;
m_fillInProgress = true;
m_dirtyZoneIDs.clear();
board()->IncrementTimeStamp(); // Clear caches
BOARD_COMMIT commit( this );
std::unique_ptr<WX_PROGRESS_REPORTER> reporter;
ZONE_FILLER filler( board(), &commit );
int pts = 0;
if( !board()->GetDesignSettings().m_DRCEngine->RulesValid() )
{
WX_INFOBAR* infobar = frame->GetInfoBar();
wxHyperlinkCtrl* button = new wxHyperlinkCtrl( infobar, wxID_ANY, _( "Show DRC rules" ),
wxEmptyString );
button->Bind( wxEVT_COMMAND_HYPERLINK,
std::function<void( wxHyperlinkEvent& aEvent )>(
[frame]( wxHyperlinkEvent& aEvent )
{
frame->ShowBoardSetupDialog( _( "Rules" ) );
} ) );
infobar->RemoveAllButtons();
infobar->AddButton( button );
infobar->ShowMessageFor( _( "Zone fills may be inaccurate. DRC rules contain errors." ),
10000, wxICON_WARNING );
}
for( ZONE* zone : toFill )
{
for( PCB_LAYER_ID layer : zone->GetLayerSet().Seq() )
pts += zone->GetFilledPolysList( layer )->FullPointCount();
if( pts > 1000 )
{
wxString title = wxString::Format( _( "Refill %d Zones" ), (int) toFill.size() );
reporter = std::make_unique<WX_PROGRESS_REPORTER>( frame, title, 5 );
filler.SetProgressReporter( reporter.get() );
break;
}
}
if( filler.Fill( toFill ) )
commit.Push( _( "Auto-fill Zone(s)" ), false, false, false, true );
else
commit.Revert();
board()->GetConnectivity()->Build( board(), reporter.get() );
if( filler.IsDebug() )
frame->UpdateUserInterface();
canvas()->Refresh();
m_fillInProgress = false;
for( ZONE* zone : toFill )
{
int outlines = 0;
for( PCB_LAYER_ID layer : zone->GetLayerSet().Seq() )
outlines += zone->GetFilledPolysList( layer )->OutlineCount();
if( outlines == 0 )
{
// TODO: why does this trash memory?
// frame->ShowInfoBarWarning( _( "Zone has no connections." ) );
break;
}
}
// wxWidgets has keyboard focus issues after the progress reporter. Re-setting the focus
// here doesn't work, so we delay it to an idle event.
canvas()->Bind( wxEVT_IDLE, &ZONE_FILLER_TOOL::singleShotRefocus, this );
return 0;
}
int ZONE_FILLER_TOOL::ZoneFill( const TOOL_EVENT& aEvent )
{
if( m_fillInProgress )
@ -216,7 +317,7 @@ int ZONE_FILLER_TOOL::ZoneFill( const TOOL_EVENT& aEvent )
if( filler.Fill( toFill ) )
{
reporter->AdvancePhase();
commit.Push( _( "Fill Zone(s)" ), true, true, false );
commit.Push( _( "Fill Zone(s)" ), true, true, false, true );
}
else
{
@ -253,7 +354,7 @@ int ZONE_FILLER_TOOL::ZoneUnfill( const TOOL_EVENT& aEvent )
zone->UnFill();
}
commit.Push( _( "Unfill Zone" ) );
commit.Push( _( "Unfill Zone" ), true, true, true, true );
canvas()->Refresh();
return 0;
@ -271,7 +372,7 @@ int ZONE_FILLER_TOOL::ZoneUnfillAll( const TOOL_EVENT& aEvent )
zone->UnFill();
}
commit.Push( _( "Unfill All Zones" ) );
commit.Push( _( "Unfill All Zones" ), true, true, true, true );
canvas()->Refresh();
return 0;
@ -281,8 +382,9 @@ int ZONE_FILLER_TOOL::ZoneUnfillAll( const TOOL_EVENT& aEvent )
void ZONE_FILLER_TOOL::setTransitions()
{
// Zone actions
Go( &ZONE_FILLER_TOOL::ZoneFill, PCB_ACTIONS::zoneFill.MakeEvent() );
Go( &ZONE_FILLER_TOOL::ZoneFillAll, PCB_ACTIONS::zoneFillAll.MakeEvent() );
Go( &ZONE_FILLER_TOOL::ZoneUnfill, PCB_ACTIONS::zoneUnfill.MakeEvent() );
Go( &ZONE_FILLER_TOOL::ZoneUnfillAll, PCB_ACTIONS::zoneUnfillAll.MakeEvent() );
Go( &ZONE_FILLER_TOOL::ZoneFill, PCB_ACTIONS::zoneFill.MakeEvent() );
Go( &ZONE_FILLER_TOOL::ZoneFillAll, PCB_ACTIONS::zoneFillAll.MakeEvent() );
Go( &ZONE_FILLER_TOOL::ZoneFillDirty, PCB_ACTIONS::zoneFillDirty.MakeEvent() );
Go( &ZONE_FILLER_TOOL::ZoneUnfill, PCB_ACTIONS::zoneUnfill.MakeEvent() );
Go( &ZONE_FILLER_TOOL::ZoneUnfillAll, PCB_ACTIONS::zoneUnfillAll.MakeEvent() );
}

View File

@ -2,7 +2,7 @@
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2014 CERN
* Copyright (C) 2021 KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 2021-2022 KiCad Developers, see AUTHORS.txt for contributors.
*
* @author Maciej Suminski <maciej.suminski@cern.ch>
*
@ -28,6 +28,7 @@
#define ZONE_FILLER_TOOL_H
#include <tools/pcb_tool_base.h>
#include <zone.h>
class PCB_EDIT_FRAME;
@ -52,11 +53,17 @@ public:
int ZoneFill( const TOOL_EVENT& aEvent );
int ZoneFillAll( const TOOL_EVENT& aEvent );
int ZoneFillDirty( const TOOL_EVENT& aEvent );
int ZoneUnfill( const TOOL_EVENT& aEvent );
int ZoneUnfillAll( const TOOL_EVENT& aEvent );
bool IsBusy() { return m_fillInProgress; }
void DirtyZone( ZONE* aZone )
{
m_dirtyZoneIDs.insert( aZone->m_Uuid );
}
private:
///< Refocus on an idle event (used after the Progress Reporter messes up the focus).
void singleShotRefocus( wxIdleEvent& );
@ -66,6 +73,8 @@ private:
private:
bool m_fillInProgress;
std::set<KIID> m_dirtyZoneIDs;
};
#endif

View File

@ -35,6 +35,7 @@
#include <footprint_wizard_frame.h>
#include <footprint.h>
#include <tools/pcb_actions.h>
#include <tools/zone_filler_tool.h>
#include <router/router_tool.h>
#include <dialog_find.h>
#include <dialog_filter_selection.h>
@ -619,6 +620,28 @@ bool PCB_TOOL_BASE::Is45Limited() const
}
ZONE_FILLER_TOOL::ZONE_FILLER_TOOL() :
PCB_TOOL_BASE( "pcbnew.ZoneFiller" ),
m_fillInProgress( false )
{
}
ZONE_FILLER_TOOL::~ZONE_FILLER_TOOL()
{
}
void ZONE_FILLER_TOOL::Reset( RESET_REASON aReason )
{
}
void ZONE_FILLER_TOOL::setTransitions()
{
}
PCBNEW_SETTINGS::DISPLAY_OPTIONS& PCB_TOOL_BASE::displayOptions() const
{
static PCBNEW_SETTINGS::DISPLAY_OPTIONS disp;