KiCad PCB EDA Suite
zone_filler_tool.cpp
Go to the documentation of this file.
1 /*
2  * This program source code file is part of KiCad, a free EDA CAD application.
3  *
4  * Copyright (C) 2014-2017 CERN
5  * Copyright (C) 2014-2018 KiCad Developers, see AUTHORS.txt for contributors.
6  * @author Maciej Suminski <maciej.suminski@cern.ch>
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License
10  * as published by the Free Software Foundation; either version 2
11  * of the License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, you may find one here:
20  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
21  * or you may search the http://www.gnu.org website for the version 2 license,
22  * or you may write to the Free Software Foundation, Inc.,
23  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
24  */
25 #include <cstdint>
26 #include <thread>
27 #include <zone.h>
29 #include <board_commit.h>
30 #include <board_design_settings.h>
32 #include <widgets/infobar.h>
33 #include <wx/event.h>
34 #include <wx/hyperlink.h>
35 #include <tool/tool_manager.h>
36 #include "pcb_actions.h"
37 #include "zone_filler_tool.h"
38 #include "zone_filler.h"
39 
40 
42  PCB_TOOL_BASE( "pcbnew.ZoneFiller" ),
43  m_fillInProgress( false )
44 {
45 }
46 
47 
49 {
50 }
51 
52 
54 {
55 }
56 
57 
58 void ZONE_FILLER_TOOL::CheckAllZones( wxWindow* aCaller, PROGRESS_REPORTER* aReporter )
59 {
60  if( !getEditFrame<PCB_EDIT_FRAME>()->m_ZoneFillsDirty || m_fillInProgress )
61  return;
62 
63  m_fillInProgress = true;
64 
65  std::vector<ZONE*> toFill;
66 
67  for( ZONE* zone : board()->Zones() )
68  toFill.push_back(zone);
69 
70  BOARD_COMMIT commit( this );
71 
72  ZONE_FILLER filler( frame()->GetBoard(), &commit );
73 
74  if( aReporter )
75  filler.SetProgressReporter( aReporter );
76  else
77  filler.InstallNewProgressReporter( aCaller, _( "Checking Zones" ), 4 );
78 
79  std::lock_guard<KISPINLOCK> lock( board()->GetConnectivity()->GetLock() );
80 
81  if( filler.Fill( toFill, true, aCaller ) )
82  {
83  commit.Push( _( "Fill Zone(s)" ), false );
84  getEditFrame<PCB_EDIT_FRAME>()->m_ZoneFillsDirty = false;
85  }
86  else
87  {
88  commit.Revert();
89  }
90 
91  canvas()->Refresh();
92  m_fillInProgress = false;
93 }
94 
95 
97 {
98  canvas()->SetFocus();
99  canvas()->Unbind( wxEVT_IDLE, &ZONE_FILLER_TOOL::singleShotRefocus, this );
100 }
101 
102 
103 void ZONE_FILLER_TOOL::FillAllZones( wxWindow* aCaller, PROGRESS_REPORTER* aReporter )
104 {
105  PCB_EDIT_FRAME* frame = getEditFrame<PCB_EDIT_FRAME>();
106  BOARD_COMMIT commit( this );
107  std::vector<ZONE*> toFill;
108 
109  if( m_fillInProgress )
110  return;
111 
112  m_fillInProgress = true;
113 
114  for( ZONE* zone : board()->Zones() )
115  toFill.push_back( zone );
116 
117  board()->IncrementTimeStamp(); // Clear caches
118 
119  ZONE_FILLER filler( board(), &commit );
120 
121  if( !board()->GetDesignSettings().m_DRCEngine->RulesValid() )
122  {
123  WX_INFOBAR* infobar = frame->GetInfoBar();
124  wxHyperlinkCtrl* button = new wxHyperlinkCtrl( infobar, wxID_ANY, _("Show DRC rules"),
125  wxEmptyString );
126 
127  button->Bind( wxEVT_COMMAND_HYPERLINK,
128  std::function<void( wxHyperlinkEvent& aEvent )>(
129  [frame]( wxHyperlinkEvent& aEvent )
130  {
131  frame->ShowBoardSetupDialog( _( "Rules" ) );
132  } ) );
133 
134  infobar->RemoveAllButtons();
135  infobar->AddButton( button );
136 
137  infobar->ShowMessageFor( _( "Zone fills may be inaccurate. DRC rules contain errors." ),
138  10000, wxICON_WARNING );
139  }
140 
141  if( aReporter )
142  filler.SetProgressReporter( aReporter );
143  else
144  filler.InstallNewProgressReporter( aCaller, _( "Fill All Zones" ), 3 );
145 
146  std::lock_guard<KISPINLOCK> lock( board()->GetConnectivity()->GetLock() );
147 
148  if( filler.Fill( toFill ) )
149  {
150  commit.Push( _( "Fill Zone(s)" ), true ); // Allow undoing zone fill
151  frame->m_ZoneFillsDirty = false;
152  }
153  else
154  {
155  commit.Revert();
156  }
157 
158  if( filler.IsDebug() )
159  frame->UpdateUserInterface();
160 
161  canvas()->Refresh();
162  m_fillInProgress = false;
163 
164  // wxWidgets has keyboard focus issues after the progress reporter. Re-setting the focus
165  // here doesn't work, so we delay it to an idle event.
166  canvas()->Bind( wxEVT_IDLE, &ZONE_FILLER_TOOL::singleShotRefocus, this );
167 }
168 
169 
171 {
172  if( m_fillInProgress )
173  {
174  wxBell();
175  return -1;
176  }
177 
178  m_fillInProgress = true;
179 
180  std::vector<ZONE*> toFill;
181 
182  BOARD_COMMIT commit( this );
183 
184  if( ZONE* passedZone = aEvent.Parameter<ZONE*>() )
185  {
186  toFill.push_back( passedZone );
187  }
188  else
189  {
190  for( EDA_ITEM* item : selection() )
191  {
192  if( ZONE* zone = dynamic_cast<ZONE*>( item ) )
193  toFill.push_back( zone );
194  }
195  }
196 
197  ZONE_FILLER filler( board(), &commit );
198  filler.InstallNewProgressReporter( frame(), _( "Fill Zone" ), 4 );
199 
200  std::lock_guard<KISPINLOCK> lock( board()->GetConnectivity()->GetLock() );
201 
202  if( filler.Fill( toFill ) )
203  commit.Push( _( "Fill Zone(s)" ), true ); // Allow undoing zone fill
204  else
205  commit.Revert();
206 
207  canvas()->Refresh();
208  m_fillInProgress = false;
209  return 0;
210 }
211 
212 
214 {
215  FillAllZones( frame() );
216  return 0;
217 }
218 
219 
221 {
222  BOARD_COMMIT commit( this );
223 
224  for( EDA_ITEM* item : selection() )
225  {
226  assert( item->Type() == PCB_ZONE_T || item->Type() == PCB_FP_ZONE_T );
227 
228  ZONE* zone = static_cast<ZONE*>( item );
229 
230  commit.Modify( zone );
231 
232  zone->UnFill();
233  }
234 
235  commit.Push( _( "Unfill Zone" ) );
236  canvas()->Refresh();
237 
238  return 0;
239 }
240 
241 
243 {
244  BOARD_COMMIT commit( this );
245 
246  for( ZONE* zone : board()->Zones() )
247  {
248  commit.Modify( zone );
249 
250  zone->UnFill();
251  }
252 
253  commit.Push( _( "Unfill All Zones" ) );
254  canvas()->Refresh();
255 
256  return 0;
257 }
258 
259 
261 {
262  // Zone actions
267 }
void ShowMessageFor(const wxString &aMessage, int aTime, int aFlags=wxICON_INFORMATION)
Show the infobar with the provided message and icon for a specific period of time.
Definition: infobar.cpp:123
COMMIT & Modify(EDA_ITEM *aItem)
Create an undo entry for an item that has been already modified.
Definition: commit.h:103
void AddButton(wxButton *aButton)
Add an already created button to the infobar.
Definition: infobar.cpp:246
BOARD * board() const
int ZoneUnfill(const TOOL_EVENT &aEvent)
static TOOL_ACTION zoneFillAll
Definition: pcb_actions.h:306
A progress reporter for use in multi-threaded environments.
virtual void Revert() override
int ZoneUnfillAll(const TOOL_EVENT &aEvent)
void singleShotRefocus(wxIdleEvent &)
< Refocus on an idle event (used after the Progress Reporter messes up the focus).
void Go(int(T::*aStateFunc)(const TOOL_EVENT &), const TOOL_EVENT_LIST &aConditions=TOOL_EVENT(TC_ANY, TA_ANY))
Define which state (aStateFunc) to go when a certain event arrives (aConditions).
static TOOL_ACTION zoneFill
Definition: pcb_actions.h:305
void InstallNewProgressReporter(wxWindow *aParent, const wxString &aTitle, int aNumPhases)
Definition: zone_filler.cpp:72
PCB_BASE_EDIT_FRAME * frame() const
bool Fill(std::vector< ZONE * > &aZones, bool aCheck=false, wxWindow *aParent=nullptr)
Fills the given list of zones.
Definition: zone_filler.cpp:87
void FillAllZones(wxWindow *aCaller, PROGRESS_REPORTER *aReporter=nullptr)
void CheckAllZones(wxWindow *aCaller, PROGRESS_REPORTER *aReporter=nullptr)
int ZoneFill(const TOOL_EVENT &aEvent)
const PCB_SELECTION & selection() const
void SetProgressReporter(PROGRESS_REPORTER *aReporter)
Definition: zone_filler.cpp:80
T Parameter() const
Return a non-standard parameter assigned to the event.
Definition: tool_event.h:427
Generic, UI-independent tool event.
Definition: tool_event.h:152
#define _(s)
virtual void SetFocus() override
Handle a list of polygons defining a copper zone.
Definition: zone.h:57
class ZONE, a copper pour area
Definition: typeinfo.h:105
void IncrementTimeStamp()
Definition: board.cpp:191
bool IsDebug() const
Definition: zone_filler.h:56
static TOOL_ACTION zoneUnfillAll
Definition: pcb_actions.h:308
void RemoveAllButtons()
Remove all the buttons that have been added by the user.
Definition: infobar.cpp:287
virtual void Refresh(bool aEraseBackground=true, const wxRect *aRect=NULL) override
Update the board display after modifying it by a python script (note: it is automatically called by a...
static TOOL_ACTION zoneUnfill
Definition: pcb_actions.h:307
BOARD * GetBoard()
void Reset(RESET_REASON aReason) override
Bring the tool to a known, initial state.
A modified version of the wxInfoBar class that allows us to:
Definition: infobar.h:73
void setTransitions() override
This method is meant to be overridden in order to specify handlers for events.
class ZONE, managed by a footprint
Definition: typeinfo.h:94
The main frame for Pcbnew.
A base class for most all the KiCad significant classes used in schematics and boards.
Definition: eda_item.h:100
virtual void Push(const wxString &aMessage=wxT("A commit"), bool aCreateUndoEntry=true, bool aSetDirtyBit=true) override
Revert the commit by restoring the modified items state.
RESET_REASON
Determine the reason of reset for a tool.
Definition: tool_base.h:77
WX_INFOBAR * GetInfoBar()
PCB_DRAW_PANEL_GAL * canvas() const
int ZoneFillAll(const TOOL_EVENT &aEvent)