KiCad PCB EDA Suite
Loading...
Searching...
No Matches
dialog_zone_manager.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) 2023 Ethan Chien <[email protected]>
5 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, you may find one here:
19 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
20 * or you may search the http://www.gnu.org website for the version 2 license,
21 * or you may write to the Free Software Foundation, Inc.,
22 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
23 */
24
25#include <memory>
26#include <optional>
27#include <wx/dataview.h>
28#include <wx/debug.h>
29#include <wx/event.h>
30#include <wx/gdicmn.h>
31#include <wx/wupdlock.h>
32#include <pcb_edit_frame.h>
33#include <wx/string.h>
34#include <board_commit.h>
37#include <zone.h>
38#include <zone_settings_bag.h>
39#include <board.h>
40#include <bitmaps.h>
41#include <string_utils.h>
42#include <zone_filler.h>
43
47#include "dialog_zone_manager.h"
48
49
51 DIALOG_ZONE_MANAGER_BASE( aParent ),
52 m_pcbFrame( aParent ),
53 m_zoneInfo( aZoneInfo ),
54 m_zoneSettingsBag( aParent->GetBoard() ),
56 m_needZoomGAL( true ),
57 m_isFillingZones( false ),
58 m_zoneFillComplete( false )
59{
60#ifdef __APPLE__
61 m_sizerZoneOP->InsertSpacer( m_sizerZoneOP->GetItemCount(), 5 );
62#endif
63
64 m_btnMoveUp->SetBitmap( KiBitmapBundle( BITMAPS::small_up ) );
65 m_btnMoveDown->SetBitmap( KiBitmapBundle( BITMAPS::small_down ) );
66
67 m_panelZoneProperties = new PANEL_ZONE_PROPERTIES( m_zonePanel, aParent, m_zoneSettingsBag );
68 m_sizerProperties->Add( m_panelZoneProperties, 0, wxEXPAND, 5 );
69
70 m_zonePreviewNotebook = new ZONE_PREVIEW_NOTEBOOK( m_zonePanel, aParent );
71 m_sizerPreview->Add( m_zonePreviewNotebook, 1, wxALL | wxEXPAND, 5 );
72
73 for( const auto& [k, v] : MODEL_ZONES_OVERVIEW::GetColumnNames() )
74 {
76 m_viewZonesOverview->AppendIconTextColumn( v, k, wxDATAVIEW_CELL_INERT, 140 );
77 else
78 m_viewZonesOverview->AppendTextColumn( v, k, wxDATAVIEW_CELL_INERT, 160 );
79 }
80
81 m_modelZonesOverview = new MODEL_ZONES_OVERVIEW( m_zoneSettingsBag.GetManagedZones(), aParent->GetBoard(),
82 aParent, this );
83 m_viewZonesOverview->AssociateModel( m_modelZonesOverview.get() );
84
85#if wxUSE_DRAG_AND_DROP
86 m_viewZonesOverview->EnableDragSource( wxDF_UNICODETEXT );
87 m_viewZonesOverview->EnableDropTarget( wxDF_UNICODETEXT );
88
89 int id = m_viewZonesOverview->GetId();
90 Bind( wxEVT_DATAVIEW_ITEM_BEGIN_DRAG, &DIALOG_ZONE_MANAGER::OnBeginDrag, this, id );
91 Bind( wxEVT_DATAVIEW_ITEM_DROP_POSSIBLE, &DIALOG_ZONE_MANAGER::OnDropPossible, this, id );
92 Bind( wxEVT_DATAVIEW_ITEM_DROP, &DIALOG_ZONE_MANAGER::OnDrop, this, id );
93#endif // wxUSE_DRAG_AND_DROP
94
95 Bind( EVT_ZONE_NAME_UPDATE, &DIALOG_ZONE_MANAGER::OnZoneNameUpdate, this );
96 Bind( EVT_ZONE_NET_UPDATE, &DIALOG_ZONE_MANAGER::OnZoneNetUpdate, this );
97 Bind( EVT_ZONES_OVERVIEW_COUNT_CHANGE, &DIALOG_ZONE_MANAGER::OnZonesTableRowCountChange, this );
98 Bind( wxEVT_CHECKBOX, &DIALOG_ZONE_MANAGER::OnCheckBoxClicked, this );
99 Bind( wxEVT_IDLE, &DIALOG_ZONE_MANAGER::OnIdle, this );
100 Bind( wxEVT_BOOKCTRL_PAGE_CHANGED,
101 [this]( wxNotebookEvent& aEvent )
102 {
103 Layout();
104 },
105 m_zonePreviewNotebook->GetId() );
106
107 if( m_modelZonesOverview->GetCount() )
108 SelectZoneTableItem( m_modelZonesOverview->GetItem( 0 ) );
109
110 Layout();
111 m_MainBoxSizer->Fit( this );
112 finishDialogSettings();
113
114 //NOTE - Works on Windows and MacOS , need further handling in IDLE on Ubuntu
115 FitCanvasToScreen();
116}
117
118
120
121
123{
124 m_zonePreviewNotebook->FitCanvasToScreen();
125}
126
127
128void DIALOG_ZONE_MANAGER::PostProcessZoneViewSelChange( wxDataViewItem const& aItem )
129{
130 bool textCtrlHasFocus = m_filterCtrl->HasFocus();
131 long filterInsertPos = m_filterCtrl->GetInsertionPoint();
132
133 if( aItem.IsOk() )
134 {
135 m_viewZonesOverview->Select( aItem );
136 m_viewZonesOverview->EnsureVisible( aItem );
137 }
138 else
139 {
140 if( m_modelZonesOverview->GetCount() )
141 {
142 wxDataViewItem first_item = m_modelZonesOverview->GetItem( 0 );
143 m_viewZonesOverview->Select( first_item );
144 m_viewZonesOverview->EnsureVisible( first_item );
145 m_zonePreviewNotebook->OnZoneSelectionChanged( m_modelZonesOverview->GetZone( first_item ) );
146 }
147 else
148 {
149 m_zonePreviewNotebook->OnZoneSelectionChanged( nullptr );
150 }
151 }
152
153 if( textCtrlHasFocus )
154 {
155 m_filterCtrl->SetFocus();
156 m_filterCtrl->SetInsertionPoint( filterInsertPos );
157 }
158}
159
160
162{
163 aEvent.Skip();
164
165 if( aEvent.GetKeyCode() == WXK_DOWN || aEvent.GetKeyCode() == WXK_UP )
166 Bind( wxEVT_IDLE, &DIALOG_ZONE_MANAGER::OnIdle, this );
167}
168
169
170void DIALOG_ZONE_MANAGER::OnTableChar( wxKeyEvent& aEvent )
171{
172 GenericProcessChar( aEvent );
173}
174
175
176void DIALOG_ZONE_MANAGER::OnTableCharHook( wxKeyEvent& aEvent )
177{
178 GenericProcessChar( aEvent );
179}
180
181
182void DIALOG_ZONE_MANAGER::OnIdle( wxIdleEvent& aEvent )
183{
184 WXUNUSED( aEvent )
185 m_viewZonesOverview->SetFocus();
186 Unbind( wxEVT_IDLE, &DIALOG_ZONE_MANAGER::OnIdle, this );
187
188 if( !m_needZoomGAL )
189 return;
190
191 m_needZoomGAL = false;
193}
194
195
196void DIALOG_ZONE_MANAGER::onDialogResize( wxSizeEvent& event )
197{
198 event.Skip();
200}
201
202
204{
205 wxWindowUpdateLocker updateLock( this );
206
207 m_panelZoneProperties->SetZone( zone );
208 m_zonePreviewNotebook->OnZoneSelectionChanged( zone );
209
210 Layout();
211}
212
213
215{
216 Bind( wxEVT_IDLE, &DIALOG_ZONE_MANAGER::OnIdle, this );
217}
218
219
221{
222 SelectZoneTableItem( aEvent.GetItem() );
223}
224
225
226void DIALOG_ZONE_MANAGER::SelectZoneTableItem( wxDataViewItem const& aItem )
227{
228 ZONE* zone = m_modelZonesOverview->GetZone( aItem );
229
230 if( !zone )
231 return;
232
234}
235
236
237void DIALOG_ZONE_MANAGER::OnOk( wxCommandEvent& aEvt )
238{
239 m_panelZoneProperties->TransferZoneSettingsFromWindow();
240 m_zoneSettingsBag.OnUserConfirmChange();
241
242 if( m_zoneInfo )
243 {
244 if( std::shared_ptr<ZONE_SETTINGS> zone = m_panelZoneProperties->GetZoneSettings() )
245 m_zoneInfo->CopyFrom( *zone, false );
246 }
247
248 aEvt.Skip();
249}
250
251
252#if wxUSE_DRAG_AND_DROP
253
254void DIALOG_ZONE_MANAGER::OnBeginDrag( wxDataViewEvent& aEvent )
255{
256 wxTextDataObject* obj = new wxTextDataObject;
257 obj->SetText( "42" ); //FIXME - Workaround for drop on GTK
258 aEvent.SetDataObject( obj );
259 aEvent.SetDragFlags( wxDrag_AllowMove );
260 const wxDataViewItem it = aEvent.GetItem();
261
262 if( it.IsOk() )
264}
265
266
267void DIALOG_ZONE_MANAGER::OnDropPossible( wxDataViewEvent& aEvent )
268{
269 aEvent.SetDropEffect( wxDragMove ); // check 'move' drop effect
270}
271
272
273void DIALOG_ZONE_MANAGER::OnDrop( wxDataViewEvent& aEvent )
274{
275 if( aEvent.GetDataFormat() != wxDF_UNICODETEXT )
276 {
277 aEvent.Veto();
278 return;
279 }
280
281 if( !m_priorityDragIndex.has_value() )
282 return;
283
284 const wxDataViewItem it = aEvent.GetItem();
285
286 if( !it.IsOk() )
287 {
288 aEvent.Veto();
289 return;
290 }
291
292 unsigned int drop_index = m_modelZonesOverview->GetRow( it );
293 const std::optional<unsigned> rtn = m_modelZonesOverview->SwapZonePriority( *m_priorityDragIndex, drop_index );
294
295 if( rtn.has_value() )
296 {
297 const wxDataViewItem item = m_modelZonesOverview->GetItem( *rtn );
298
299 if( item.IsOk() )
300 m_viewZonesOverview->Select( item );
301 }
302}
303
304#endif // wxUSE_DRAG_AND_DROP
305
306
311
312
317
318
319void DIALOG_ZONE_MANAGER::OnFilterCtrlCancel( wxCommandEvent& aEvent )
320{
322 aEvent.Skip();
323}
324
325
326void DIALOG_ZONE_MANAGER::OnFilterCtrlSearch( wxCommandEvent& aEvent )
327{
328 PostProcessZoneViewSelChange( m_modelZonesOverview->ApplyFilter( aEvent.GetString(),
329 m_viewZonesOverview->GetSelection() ) );
330 aEvent.Skip();
331}
332
333
335{
336 PostProcessZoneViewSelChange( m_modelZonesOverview->ApplyFilter( aEvent.GetString(),
337 m_viewZonesOverview->GetSelection() ) );
338 aEvent.Skip();
339}
340
341
342void DIALOG_ZONE_MANAGER::OnFilterCtrlEnter( wxCommandEvent& aEvent )
343{
344 PostProcessZoneViewSelChange( m_modelZonesOverview->ApplyFilter( aEvent.GetString(),
345 m_viewZonesOverview->GetSelection() ) );
346 aEvent.Skip();
347}
348
349
351{
352 if( m_isFillingZones )
353 return;
354
355 m_isFillingZones = true;
356 m_panelZoneProperties->TransferZoneSettingsFromWindow();
357 m_zoneSettingsBag.FlushZoneSettingsChange();
358 m_zoneSettingsBag.FlushPriorityChange();
359
360 BOARD* board = m_pcbFrame->GetBoard();
361 board->IncrementTimeStamp();
362
363 auto commit = std::make_unique<BOARD_COMMIT>( m_pcbFrame );
364 m_filler = std::make_unique<ZONE_FILLER>( board, commit.get() );
365 auto reporter = std::make_unique<WX_PROGRESS_REPORTER>( this, _( "Fill All Zones" ), 5, PR_CAN_ABORT );
366 m_filler->SetProgressReporter( reporter.get() );
367
368 // TODO: replace these const_cast calls with a different solution that avoids mutating the
369 // container of the board. This is relatively safe as-is because the original zones list is
370 // swapped back in below, but still should be changed to avoid invalidating the board state
371 // in case this code is refactored to be a non-modal dialog in the future.
372 const_cast<ZONES&>( board->Zones() ) = m_zoneSettingsBag.GetClonedZoneList();
373
374 //NOTE - Nether revert nor commit is needed here , cause the cloned zones are not owned by
375 // the pcb frame.
376 m_zoneFillComplete = m_filler->Fill( board->Zones() );
377 board->BuildConnectivity();
378
379 m_zonePreviewNotebook->OnZoneSelectionChanged( m_panelZoneProperties->GetZone() );
380
381 //NOTE - But the connectivity need to be rebuild, otherwise if cancelling, it may
382 // segfault.
383 const_cast<ZONES&>( board->Zones() ) = m_zoneSettingsBag.GetOriginalZoneList();
384 board->BuildConnectivity();
385
386 m_isFillingZones = false;
387}
388
389
390void DIALOG_ZONE_MANAGER::OnZoneNameUpdate( wxCommandEvent& aEvent )
391{
392 if( ZONE* zone = m_panelZoneProperties->GetZone() )
393 {
394 zone->SetZoneName( aEvent.GetString() );
395 m_modelZonesOverview->RowChanged( m_modelZonesOverview->GetRow( m_modelZonesOverview->GetItemByZone( zone ) ) );
396 }
397}
398
399
400void DIALOG_ZONE_MANAGER::OnZoneNetUpdate( wxCommandEvent& aEvent )
401{
402 if( ZONE* zone = m_panelZoneProperties->GetZone() )
403 {
404 zone->SetNetCode( aEvent.GetId() );
405 m_modelZonesOverview->RowChanged( m_modelZonesOverview->GetRow( m_modelZonesOverview->GetItemByZone( zone ) ) );
406 }
407}
408
409
411{
412 unsigned count = aEvent.GetInt();
413
415 btn->Enable( count == m_modelZonesOverview->GetAllZonesCount() );
416}
417
418
419void DIALOG_ZONE_MANAGER::OnCheckBoxClicked( wxCommandEvent& aEvent )
420{
421 const wxObject* sender = aEvent.GetEventObject();
422
423 if( aEvent.GetEventObject() == m_checkName )
424 m_modelZonesOverview->EnableFitterByName( aEvent.IsChecked() );
425 else if( aEvent.GetEventObject() == m_checkNet )
426 m_modelZonesOverview->EnableFitterByNet( aEvent.IsChecked() );
427
428 if( ( sender == m_checkName || sender == m_checkNet ) && !m_filterCtrl->IsEmpty() )
429 m_modelZonesOverview->ApplyFilter( m_filterCtrl->GetValue(), m_viewZonesOverview->GetSelection() );
430}
431
432
434{
435 if( !m_viewZonesOverview->HasSelection() )
436 return;
437
438 const wxDataViewItem selectedItem = m_viewZonesOverview->GetSelection();
439
440 if( !selectedItem.IsOk() )
441 return;
442
443 const unsigned int selectedRow = m_modelZonesOverview->GetRow( selectedItem );
444 const std::optional<unsigned> new_index = m_modelZonesOverview->MoveZoneIndex( selectedRow, aMove );
445
446 if( new_index.has_value() )
447 {
448 wxDataViewItem new_item = m_modelZonesOverview->GetItem( *new_index );
450 }
451}
wxBitmapBundle KiBitmapBundle(BITMAPS aBitmap, int aMinHeight)
Definition bitmap.cpp:110
Information pertinent to a Pcbnew printed circuit board.
Definition board.h:322
const ZONES & Zones() const
Definition board.h:367
bool BuildConnectivity(PROGRESS_REPORTER *aReporter=nullptr)
Build or rebuild the board connectivity database for the board, especially the list of connected item...
Definition board.cpp:192
void IncrementTimeStamp()
Definition board.cpp:260
DIALOG_ZONE_MANAGER_BASE(wxWindow *parent, wxWindowID id=wxID_ANY, const wxString &title=_("Zone Manager"), const wxPoint &pos=wxDefaultPosition, const wxSize &size=wxSize(-1,-1), long style=wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER)
void OnZoneNameUpdate(wxCommandEvent &aEvent)
void OnViewZonesOverviewOnLeftUp(wxMouseEvent &aEvent) override
~DIALOG_ZONE_MANAGER() override
void GenericProcessChar(wxKeyEvent &event)
PCB_BASE_FRAME * m_pcbFrame
wxObjectDataPtr< MODEL_ZONES_OVERVIEW > m_modelZonesOverview
PANEL_ZONE_PROPERTIES * m_panelZoneProperties
void OnMoveDownClick(wxCommandEvent &aEvent) override
void PostProcessZoneViewSelChange(wxDataViewItem const &aItem)
std::unique_ptr< ZONE_FILLER > m_filler
void OnTableChar(wxKeyEvent &event) override
void onDialogResize(wxSizeEvent &event) override
void OnMoveUpClick(wxCommandEvent &aEvent) override
void OnUpdateDisplayedZonesClick(wxCommandEvent &aEvent) override
void MoveSelectedZonePriority(ZONE_INDEX_MOVEMENT aMove)
ZONE_SETTINGS_BAG m_zoneSettingsBag
void OnDataViewCtrlSelectionChanged(wxDataViewEvent &event) override
std::optional< unsigned > m_priorityDragIndex
DIALOG_ZONE_MANAGER(PCB_BASE_FRAME *aParent, ZONE_SETTINGS *aZoneInfo)
void OnTableCharHook(wxKeyEvent &event) override
void OnIdle(wxIdleEvent &aEvent)
void OnZoneNetUpdate(wxCommandEvent &aEvent)
void OnCheckBoxClicked(wxCommandEvent &aEvent)
void OnFilterCtrlTextChange(wxCommandEvent &aEvent) override
ZONE_PREVIEW_NOTEBOOK * m_zonePreviewNotebook
void SelectZoneTableItem(wxDataViewItem const &aItem)
void OnOk(wxCommandEvent &aEvt) override
void OnFilterCtrlCancel(wxCommandEvent &aEvent) override
void OnFilterCtrlEnter(wxCommandEvent &aEvent) override
void OnZoneSelectionChanged(ZONE *aZone)
void OnZonesTableRowCountChange(wxCommandEvent &aEvent)
void OnFilterCtrlSearch(wxCommandEvent &aEvent) override
static std::map< int, wxString > GetColumnNames()
Base PCB main window class for Pcbnew, Gerbview, and CvPcb footprint viewer.
A bitmap button widget that behaves like a standard dialog button except with an icon.
ZONE_SETTINGS handles zones parameters.
Handle a list of polygons defining a copper zone.
Definition zone.h:74
#define _(s)
ZONE_INDEX_MOVEMENT
std::vector< ZONE * > ZONES
BOARD * GetBoard()
#define PR_CAN_ABORT