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>
31 #include <progress_reporter.h>
32 #include <widgets/infobar.h>
34 #include <wx/event.h>
35 #include <wx/hyperlink.h>
36 #include <tool/tool_manager.h>
37 #include "pcb_actions.h"
38 #include "zone_filler_tool.h"
39 #include "zone_filler.h"
40 
41 
43  PCB_TOOL_BASE( "pcbnew.ZoneFiller" ),
44  m_fillInProgress( false )
45 {
46 }
47 
48 
50 {
51 }
52 
53 
55 {
56 }
57 
58 
59 void ZONE_FILLER_TOOL::CheckAllZones( wxWindow* aCaller, PROGRESS_REPORTER* aReporter )
60 {
61  if( !getEditFrame<PCB_EDIT_FRAME>()->m_ZoneFillsDirty || m_fillInProgress )
62  return;
63 
64  m_fillInProgress = true;
65 
66  std::vector<ZONE*> toFill;
67 
68  for( ZONE* zone : board()->Zones() )
69  toFill.push_back(zone);
70 
71  BOARD_COMMIT commit( this );
72  std::unique_ptr<WX_PROGRESS_REPORTER> reporter;
73  ZONE_FILLER filler( frame()->GetBoard(), &commit );
74 
75  if( aReporter )
76  {
77  filler.SetProgressReporter( aReporter );
78  }
79  else
80  {
81  reporter = std::make_unique<WX_PROGRESS_REPORTER>( aCaller, _( "Checking Zones" ), 4 );
82  filler.SetProgressReporter( reporter.get() );
83  }
84 
85  std::lock_guard<KISPINLOCK> lock( board()->GetConnectivity()->GetLock() );
86 
87  if( filler.Fill( toFill, true, aCaller ) )
88  {
89  commit.Push( _( "Fill Zone(s)" ), false );
90  getEditFrame<PCB_EDIT_FRAME>()->m_ZoneFillsDirty = false;
91  }
92  else
93  {
94  commit.Revert();
95  }
96 
97  canvas()->Refresh();
98  m_fillInProgress = false;
99 }
100 
101 
103 {
104  canvas()->SetFocus();
105  canvas()->Unbind( wxEVT_IDLE, &ZONE_FILLER_TOOL::singleShotRefocus, this );
106 }
107 
108 
109 void ZONE_FILLER_TOOL::FillAllZones( wxWindow* aCaller, PROGRESS_REPORTER* aReporter )
110 {
111  PCB_EDIT_FRAME* frame = getEditFrame<PCB_EDIT_FRAME>();
112  std::vector<ZONE*> toFill;
113 
114  if( m_fillInProgress )
115  return;
116 
117  m_fillInProgress = true;
118 
119  for( ZONE* zone : board()->Zones() )
120  toFill.push_back( zone );
121 
122  board()->IncrementTimeStamp(); // Clear caches
123 
124  BOARD_COMMIT commit( this );
125  std::unique_ptr<WX_PROGRESS_REPORTER> reporter;
126  ZONE_FILLER filler( board(), &commit );
127 
128  if( !board()->GetDesignSettings().m_DRCEngine->RulesValid() )
129  {
130  WX_INFOBAR* infobar = frame->GetInfoBar();
131  wxHyperlinkCtrl* button = new wxHyperlinkCtrl( infobar, wxID_ANY, _("Show DRC rules"),
132  wxEmptyString );
133 
134  button->Bind( wxEVT_COMMAND_HYPERLINK,
135  std::function<void( wxHyperlinkEvent& aEvent )>(
136  [frame]( wxHyperlinkEvent& aEvent )
137  {
138  frame->ShowBoardSetupDialog( _( "Rules" ) );
139  } ) );
140 
141  infobar->RemoveAllButtons();
142  infobar->AddButton( button );
143 
144  infobar->ShowMessageFor( _( "Zone fills may be inaccurate. DRC rules contain errors." ),
145  10000, wxICON_WARNING );
146  }
147 
148  if( aReporter )
149  {
150  filler.SetProgressReporter( aReporter );
151  }
152  else
153  {
154  reporter = std::make_unique<WX_PROGRESS_REPORTER>( aCaller, _( "Fill All Zones" ), 3 );
155  filler.SetProgressReporter( reporter.get() );
156  }
157 
158  std::lock_guard<KISPINLOCK> lock( board()->GetConnectivity()->GetLock() );
159 
160  if( filler.Fill( toFill ) )
161  {
162  commit.Push( _( "Fill Zone(s)" ), true ); // Allow undoing zone fill
163  frame->m_ZoneFillsDirty = false;
164  }
165  else
166  {
167  commit.Revert();
168  }
169 
170  if( filler.IsDebug() )
171  frame->UpdateUserInterface();
172 
173  canvas()->Refresh();
174  m_fillInProgress = false;
175 
176  // wxWidgets has keyboard focus issues after the progress reporter. Re-setting the focus
177  // here doesn't work, so we delay it to an idle event.
178  canvas()->Bind( wxEVT_IDLE, &ZONE_FILLER_TOOL::singleShotRefocus, this );
179 }
180 
181 
183 {
184  if( m_fillInProgress )
185  {
186  wxBell();
187  return -1;
188  }
189 
190  m_fillInProgress = true;
191 
192  std::vector<ZONE*> toFill;
193 
194  if( ZONE* passedZone = aEvent.Parameter<ZONE*>() )
195  {
196  toFill.push_back( passedZone );
197  }
198  else
199  {
200  for( EDA_ITEM* item : selection() )
201  {
202  if( ZONE* zone = dynamic_cast<ZONE*>( item ) )
203  toFill.push_back( zone );
204  }
205  }
206 
207  BOARD_COMMIT commit( this );
208  std::unique_ptr<WX_PROGRESS_REPORTER> reporter;
209  ZONE_FILLER filler( board(), &commit );
210 
211  reporter = std::make_unique<WX_PROGRESS_REPORTER>( frame(), _( "Fill Zone" ), 4 );
212  filler.SetProgressReporter( reporter.get() );
213 
214  std::lock_guard<KISPINLOCK> lock( board()->GetConnectivity()->GetLock() );
215 
216  if( filler.Fill( toFill ) )
217  commit.Push( _( "Fill Zone(s)" ), true ); // Allow undoing zone fill
218  else
219  commit.Revert();
220 
221  canvas()->Refresh();
222  m_fillInProgress = false;
223  return 0;
224 }
225 
226 
228 {
229  FillAllZones( frame() );
230  return 0;
231 }
232 
233 
235 {
236  BOARD_COMMIT commit( this );
237 
238  for( EDA_ITEM* item : selection() )
239  {
240  assert( item->Type() == PCB_ZONE_T || item->Type() == PCB_FP_ZONE_T );
241 
242  ZONE* zone = static_cast<ZONE*>( item );
243 
244  commit.Modify( zone );
245 
246  zone->UnFill();
247  }
248 
249  commit.Push( _( "Unfill Zone" ) );
250  canvas()->Refresh();
251 
252  return 0;
253 }
254 
255 
257 {
258  BOARD_COMMIT commit( this );
259 
260  for( ZONE* zone : board()->Zones() )
261  {
262  commit.Modify( zone );
263 
264  zone->UnFill();
265  }
266 
267  commit.Push( _( "Unfill All Zones" ) );
268  canvas()->Refresh();
269 
270  return 0;
271 }
272 
273 
275 {
276  // Zone actions
281 }
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:245
BOARD * board() const
int ZoneUnfill(const TOOL_EVENT &aEvent)
static TOOL_ACTION zoneFillAll
Definition: pcb_actions.h:303
A progress reporter interface 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 ShowMessageFor(const wxString &aMessage, int aTime, int aFlags=wxICON_INFORMATION, MESSAGE_TYPE aType=WX_INFOBAR::MESSAGE_TYPE::GENERIC)
Show the infobar with the provided message and icon for a specific period of time.
Definition: infobar.cpp:128
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:302
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:79
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:72
T Parameter() const
Return a non-standard parameter assigned to the event.
Definition: tool_event.h:432
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:56
class ZONE, a copper pour area
Definition: typeinfo.h:105
void IncrementTimeStamp()
Definition: board.cpp:191
bool IsDebug() const
Definition: zone_filler.h:55
static TOOL_ACTION zoneUnfillAll
Definition: pcb_actions.h:305
void RemoveAllButtons()
Remove all the buttons that have been added by the user.
Definition: infobar.cpp:286
static TOOL_ACTION zoneUnfill
Definition: pcb_actions.h:304
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
virtual void Refresh(bool aEraseBackground=true, const wxRect *aRect=nullptr) override
Update the board display after modifying it by a python script (note: it is automatically called by a...
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)