KiCad PCB EDA Suite
Loading...
Searching...
No Matches
panel_setup_buses.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) 2018 CERN
5 * Copyright (C) 2021-2024 KiCad Developers, see AUTHORS.txt for contributors.
6 * @author Jon Evans <[email protected]>
7 *
8 * This program is free software: you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation, either version 3 of the License, or (at your
11 * option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License along
19 * with this program. If not, see <http://www.gnu.org/licenses/>.
20 */
21
22#include <widgets/wx_grid.h>
24#include <confirm.h>
25#include <sch_edit_frame.h>
26#include <schematic.h>
28#include "grid_tricks.h"
29
31 PANEL_SETUP_BUSES_BASE( aWindow ),
32 m_frame( aFrame ),
33 m_lastAlias( 0 ),
34 m_membersGridDirty( false ),
35 m_errorGrid( nullptr ),
36 m_errorRow( -1 )
37{
39
40 m_addAlias->SetBitmap( KiBitmapBundle( BITMAPS::small_plus ) );
41 m_deleteAlias->SetBitmap( KiBitmapBundle( BITMAPS::small_trash ) );
42 m_addMember->SetBitmap( KiBitmapBundle( BITMAPS::small_plus ) );
43 m_removeMember->SetBitmap( KiBitmapBundle( BITMAPS::small_trash ) );
44
45 m_source->SetFont( KIUI::GetInfoFont( aWindow ) );
46
47 m_aliasesGrid->SetSelectionMode( wxGrid::wxGridSelectRows );
48 m_membersGrid->SetSelectionMode( wxGrid::wxGridSelectRows );
49
50 m_aliasesGrid->PushEventHandler( new GRID_TRICKS( m_aliasesGrid,
51 [this]( wxCommandEvent& aEvent )
52 {
53 OnAddAlias( aEvent );
54 } ) );
55
56 m_membersGrid->PushEventHandler( new GRID_TRICKS( m_membersGrid,
57 [this]( wxCommandEvent& aEvent )
58 {
59 OnAddMember( aEvent );
60 } ) );
61
62 m_aliasesGrid->SetUseNativeColLabels();
63 m_membersGrid->SetUseNativeColLabels();
64
65 // wxFormBuilder doesn't include this event...
66 m_aliasesGrid->Connect( wxEVT_GRID_CELL_CHANGING,
68 nullptr, this );
69 m_membersGrid->Connect( wxEVT_GRID_CELL_CHANGING,
71 nullptr, this );
72
73 Layout();
74}
75
76
78{
79 // Delete the GRID_TRICKS.
80 m_aliasesGrid->PopEventHandler( true );
81 m_membersGrid->PopEventHandler( true );
82
83 m_aliasesGrid->Disconnect( wxEVT_GRID_CELL_CHANGING,
85 nullptr, this );
86 m_membersGrid->Disconnect( wxEVT_GRID_CELL_CHANGING,
88 nullptr, this );
89}
90
91
93{
94 auto contains =
95 [&]( const std::shared_ptr<BUS_ALIAS>& alias ) -> bool
96 {
97 wxString aName = alias->GetName();
98 std::vector<wxString> aMembers = alias->Members();
99
100 std::sort( aMembers.begin(), aMembers.end() );
101
102 for( const std::shared_ptr<BUS_ALIAS>& candidate : m_aliases )
103 {
104 wxString bName = candidate->GetName();
105 std::vector<wxString> bMembers = candidate->Members();
106
107 std::sort( bMembers.begin(), bMembers.end() );
108
109 if( aName == bName && aMembers == bMembers )
110 return true;
111 }
112
113 return false;
114 };
115
116 SCH_SCREENS screens( aSchematic.Root() );
117
118 // collect aliases from each open sheet
119 for( SCH_SCREEN* screen = screens.GetFirst(); screen != nullptr; screen = screens.GetNext() )
120 {
121 for( const std::shared_ptr<BUS_ALIAS>& alias : screen->GetBusAliases() )
122 {
123 if( !contains( alias ) )
124 m_aliases.push_back( alias->Clone() );
125 }
126 }
127
128 int ii = 0;
129
131 m_aliasesGrid->AppendRows( m_aliases.size() );
132
133 for( const std::shared_ptr<BUS_ALIAS>& alias : m_aliases )
134 m_aliasesGrid->SetCellValue( ii++, 0, alias->GetName() );
135
136 m_membersBook->SetSelection( 1 );
137}
138
139
141{
143 return true;
144}
145
146
148{
150 return false;
151
152 // Copy names back just in case they didn't get caught on the GridCellChanging event
153 for( int ii = 0; ii < m_aliasesGrid->GetNumberRows(); ++ii )
154 m_aliases[ii]->SetName( m_aliasesGrid->GetCellValue( ii, 0 ) );
155
156 SCH_SCREENS screens( m_frame->Schematic().Root() );
157
158 for( SCH_SCREEN* screen = screens.GetFirst(); screen != nullptr; screen = screens.GetNext() )
159 screen->ClearBusAliases();
160
161 for( const std::shared_ptr<BUS_ALIAS>& alias : m_aliases )
162 alias->GetParent()->AddBusAlias( alias );
163
164 return true;
165}
166
167
168void PANEL_SETUP_BUSES::OnAddAlias( wxCommandEvent& aEvent )
169{
171 return;
172
173 // New aliases get stored on the currently visible sheet
174 m_aliases.push_back( std::make_shared<BUS_ALIAS>( m_frame->GetScreen() ) );
175
176 int row = m_aliasesGrid->GetNumberRows();
177 m_aliasesGrid->AppendRows();
178
179 m_aliasesGrid->MakeCellVisible( row, 0 );
180 m_aliasesGrid->SetGridCursor( row, 0 );
181
182 m_aliasesGrid->EnableCellEditControl( true );
183 m_aliasesGrid->ShowCellEditControl();
184}
185
186
187void PANEL_SETUP_BUSES::OnDeleteAlias( wxCommandEvent& aEvent )
188{
190 return;
191
192 int curRow = m_aliasesGrid->GetGridCursorRow();
193
194 if( curRow < 0 )
195 return;
196
197 // Clear the members grid first so we don't try to write it back to a deleted alias
199 m_lastAlias = -1;
200 m_lastAliasName = wxEmptyString;
201
202 m_aliases.erase( m_aliases.begin() + curRow );
203
204 m_aliasesGrid->DeleteRows( curRow, 1 );
205
206 if( m_aliasesGrid->GetNumberRows() > 0 )
207 {
208 m_aliasesGrid->MakeCellVisible( std::max( 0, curRow-1 ), 0 );
209 m_aliasesGrid->SelectRow( std::max( 0, curRow-1 ) );
210 }
211}
212
213
214void PANEL_SETUP_BUSES::OnAddMember( wxCommandEvent& aEvent )
215{
217 return;
218
219 int row = m_membersGrid->GetNumberRows();
220 m_membersGrid->AppendRows();
221
222 m_membersGrid->MakeCellVisible( row, 0 );
223 m_membersGrid->SetGridCursor( row, 0 );
224
225 m_membersGrid->EnableCellEditControl( true );
226 m_membersGrid->ShowCellEditControl();
227}
228
229
230void PANEL_SETUP_BUSES::OnRemoveMember( wxCommandEvent& aEvent )
231{
233 return;
234
235 int curRow = m_membersGrid->GetGridCursorRow();
236
237 if( curRow < 0 )
238 return;
239
240 m_membersGrid->DeleteRows( curRow, 1 );
241
242 // Update the member list of the current bus alias from the members grid
243 const std::shared_ptr<BUS_ALIAS>& alias = m_aliases[ m_lastAlias ];
244 alias->Members().clear();
245
246 for( int ii = 0; ii < m_membersGrid->GetNumberRows(); ++ii )
247 alias->Members().push_back( m_membersGrid->GetCellValue( ii, 0 ) );
248
249 if( m_membersGrid->GetNumberRows() > 0 )
250 {
251 m_membersGrid->MakeCellVisible( std::max( 0, curRow-1 ), 0 );
252 m_membersGrid->SelectRow( std::max( 0, curRow-1 ) );
253 }
254}
255
256
258{
259 int row = event.GetRow();
260
261 if( row >= 0 )
262 {
263 wxString name = event.GetString();
264
265 for( int ii = 0; ii < m_aliasesGrid->GetNumberRows(); ++ii )
266 {
267 if( ii == event.GetRow() )
268 continue;
269
270 if( name == m_aliasesGrid->GetCellValue( ii, 0 )
271 && m_aliases[ row ]->GetParent() == m_aliases[ ii ]->GetParent() )
272 {
273 m_errorMsg = wxString::Format( _( "Alias name '%s' already in use." ), name );
275 m_errorRow = row;
276
277 event.Veto();
278 return;
279 }
280 }
281
282 m_aliases[ row ]->SetName( name );
283 }
284}
285
286
288{
289 int row = event.GetRow();
290
291 if( row >= 0 )
292 {
293 wxString name = event.GetString();
294
295 if( name.IsEmpty() )
296 {
297 m_errorMsg = _( "Member net/alias name cannot be empty." );
299 m_errorRow = event.GetRow();
300
301 event.Veto();
302 return;
303 }
304
305 const std::shared_ptr<BUS_ALIAS>& alias = m_aliases[ m_lastAlias ];
306
307 alias->Members().clear();
308
309 for( int ii = 0; ii < m_membersGrid->GetNumberRows(); ++ii )
310 {
311 if( ii == row )
312 {
313 // Parse a space-separated list and add each one
314 wxStringTokenizer tok( name, " " );
315
316 if( tok.CountTokens() > 1 )
317 {
318 m_membersGridDirty = true;
319 Bind( wxEVT_IDLE, &PANEL_SETUP_BUSES::reloadMembersGridOnIdle, this );
320 }
321
322 while( tok.HasMoreTokens() )
323 alias->Members().push_back( tok.GetNextToken() );
324 }
325 else
326 {
327 alias->Members().push_back( m_membersGrid->GetCellValue( ii, 0 ) );
328 }
329 }
330 }
331}
332
333
335{
336 if( m_lastAlias >= 0 && m_lastAlias < m_aliasesGrid->GetNumberRows() )
337 {
338 const std::shared_ptr<BUS_ALIAS>& alias = m_aliases[ m_lastAlias ];
339 wxString source;
340 wxString membersLabel;
341
342 if( alias->GetParent() )
343 {
344 wxFileName sheet_name( alias->GetParent()->GetFileName() );
345 source.Printf( wxS( "(" ) + sheet_name.GetFullName() + wxS( ")" ) );
346 }
347
348 membersLabel.Printf( m_membersLabelTemplate, m_lastAliasName );
349
350 m_source->SetLabel( source );
351 m_membersLabel->SetLabel( membersLabel );
352
354 m_membersGrid->AppendRows( alias->Members().size() );
355
356 int ii = 0;
357
358 for( const wxString& member : alias->Members() )
359 m_membersGrid->SetCellValue( ii++, 0, member );
360 }
361
362 m_membersGridDirty = false;
363}
364
365
367{
370
371 Unbind( wxEVT_IDLE, &PANEL_SETUP_BUSES::reloadMembersGridOnIdle, this );
372}
373
374
375
376void PANEL_SETUP_BUSES::OnSizeGrid( wxSizeEvent& event )
377{
378 auto setColSize =
379 []( WX_GRID* grid )
380 {
381 int colSize = std::max( grid->GetClientSize().x, grid->GetVisibleWidth( 0 ) );
382
383 if( grid->GetColSize( 0 ) != colSize )
384 grid->SetColSize( 0, colSize );
385 };
386
387 setColSize( m_aliasesGrid );
388 setColSize( m_membersGrid );
389
390 // Always propagate for a grid repaint (needed if the height changes, as well as width)
391 event.Skip();
392}
393
394
395void PANEL_SETUP_BUSES::OnUpdateUI( wxUpdateUIEvent& event )
396{
397 // Handle a grid error. This is delayed to OnUpdateUI so that we can change focus
398 // even when the original validation was triggered from a killFocus event.
399 if( !m_errorMsg.IsEmpty() )
400 {
401 // We will re-enter this routine when the error dialog is displayed, so make
402 // sure we don't keep putting up more dialogs.
403 wxString errorMsg = m_errorMsg;
404 m_errorMsg = wxEmptyString;
405
406 wxWindow* topLevelParent = wxGetTopLevelParent( this );
407
408 DisplayErrorMessage( topLevelParent, errorMsg );
409
410 m_errorGrid->SetFocus();
411 m_errorGrid->MakeCellVisible( m_errorRow, 0 );
412 m_errorGrid->SetGridCursor( m_errorRow, 0 );
413
414 m_errorGrid->EnableCellEditControl( true );
415 m_errorGrid->ShowCellEditControl();
416
417 return;
418 }
419
420 if( !m_membersGrid->IsCellEditControlShown() )
421 {
422 int row = -1;
423 wxString aliasName;
424
425 if( m_aliasesGrid->IsCellEditControlShown() )
426 {
427 row = m_aliasesGrid->GetGridCursorRow();
428 wxGridCellEditor* cellEditor = m_aliasesGrid->GetCellEditor( row, 0 );
429
430 if( wxTextEntry* txt = dynamic_cast<wxTextEntry*>( cellEditor->GetControl() ) )
431 aliasName = txt->GetValue();
432
433 cellEditor->DecRef();
434 }
435 else if( m_aliasesGrid->GetGridCursorRow() >= 0 )
436 {
437 row = m_aliasesGrid->GetGridCursorRow();
438 aliasName = m_aliasesGrid->GetCellValue( row, 0 );
439 }
440 else if( m_lastAlias >= 0 && m_lastAlias < m_aliasesGrid->GetNumberRows() )
441 {
442 row = m_lastAlias;
443 aliasName = m_lastAliasName;
444 }
445
446 if( row < 0 )
447 {
448 m_membersBook->SetSelection( 1 );
449 }
450 else if( row != m_lastAlias || aliasName != m_lastAliasName )
451 {
452 m_lastAlias = row;
453 m_lastAliasName = aliasName;
454
455 m_membersBook->SetSelection( 0 );
456 m_membersBook->GetPage( 0 )->Layout();
457
458 const std::shared_ptr<BUS_ALIAS>& alias = m_aliases[ row ];
459 alias->SetName( aliasName );
460
461 m_membersGridDirty = true;
462 Bind( wxEVT_IDLE, &PANEL_SETUP_BUSES::reloadMembersGridOnIdle, this );
463 }
464 }
465}
466
467
469{
470 loadAliases( aOtherSchematic );
471
472 // New aliases get stored on the currently visible sheet
473 for( const std::shared_ptr<BUS_ALIAS>& alias : m_aliases )
474 alias->SetParent( m_frame->GetScreen() );
475}
const char * name
Definition: DXF_plotter.cpp:57
wxBitmapBundle KiBitmapBundle(BITMAPS aBitmap)
Definition: bitmap.cpp:110
Add mouse and command handling (such as cut, copy, and paste) to a WX_GRID instance.
Definition: grid_tricks.h:61
Class PANEL_SETUP_BUSES_BASE.
STD_BITMAP_BUTTON * m_addAlias
STD_BITMAP_BUTTON * m_addMember
STD_BITMAP_BUTTON * m_deleteAlias
STD_BITMAP_BUTTON * m_removeMember
void OnAliasesGridCellChanging(wxGridEvent &event)
std::vector< std::shared_ptr< BUS_ALIAS > > m_aliases
void reloadMembersGridOnIdle(wxIdleEvent &aEvent)
void OnDeleteAlias(wxCommandEvent &aEvent) override
void OnUpdateUI(wxUpdateUIEvent &event) override
void loadAliases(const SCHEMATIC &aSchematic)
SCH_EDIT_FRAME * m_frame
void OnSizeGrid(wxSizeEvent &event) override
PANEL_SETUP_BUSES(wxWindow *aWindow, SCH_EDIT_FRAME *aFrame)
bool TransferDataToWindow() override
void ImportSettingsFrom(const SCHEMATIC &aOtherSchematic)
wxString m_membersLabelTemplate
void OnRemoveMember(wxCommandEvent &aEvent) override
void OnMemberGridCellChanging(wxGridEvent &event)
bool TransferDataFromWindow() override
void OnAddMember(wxCommandEvent &aEvent) override
void OnAddAlias(wxCommandEvent &aEvent) override
Holds all the data relating to one schematic.
Definition: schematic.h:76
SCH_SHEET & Root() const
Definition: schematic.h:113
Schematic editor (Eeschema) main window.
SCH_SCREEN * GetScreen() const override
Return a pointer to a BASE_SCREEN or one of its derivatives.
SCHEMATIC & Schematic() const
Container class that holds multiple SCH_SCREEN objects in a hierarchy.
Definition: sch_screen.h:710
SCH_SCREEN * GetNext()
SCH_SCREEN * GetFirst()
void SetBitmap(const wxBitmapBundle &aBmp)
void ClearRows()
wxWidgets recently added an ASSERT which fires if the position is greater than or equal to the number...
Definition: wx_grid.h:184
bool CommitPendingChanges(bool aQuietMode=false)
Close any open cell edit controls.
Definition: wx_grid.cpp:637
void DisplayErrorMessage(wxWindow *aParent, const wxString &aText, const wxString &aExtraInfo)
Display an error message with aMessage.
Definition: confirm.cpp:195
This file is part of the common library.
#define _(s)
KICOMMON_API wxFont GetInfoFont(wxWindow *aWindow)
Definition: ui_common.cpp:154