diff --git a/common/widgets/net_selector.cpp b/common/widgets/net_selector.cpp index 2e54c70adf..f52985ff31 100644 --- a/common/widgets/net_selector.cpp +++ b/common/widgets/net_selector.cpp @@ -201,9 +201,17 @@ public: { // Remove the first character ':' and all whitespace remainingName = remainingName.Mid( 1 ).Trim().Trim( false ); + + BOARD* board = m_netinfoList->GetParent(); NETINFO_ITEM *newnet = new NETINFO_ITEM( m_board, remainingName, 0 ); - m_netinfoList->AppendNet( newnet ); + // add the new netinfo through the board's function so that + // board listeners get notified and things stay in sync. + if( board != nullptr ) + board->Add( newnet ); + else + m_netinfoList->AppendNet( newnet ); + rebuildList(); if( newnet->GetNet() > 0 ) @@ -215,6 +223,11 @@ public: { // This indicates that the NETINFO_ITEM was not successfully appended // to the list for unknown reasons + if( board != nullptr ) + board->Remove( newnet ); + else + m_netinfoList->RemoveNet( newnet ); + delete newnet; } } diff --git a/pcbnew/board_commit.cpp b/pcbnew/board_commit.cpp index 047829690a..42039ac1c9 100644 --- a/pcbnew/board_commit.cpp +++ b/pcbnew/board_commit.cpp @@ -262,6 +262,7 @@ void BOARD_COMMIT::Push( const wxString& aMessage, bool aCreateUndoEntry, bool a connectivity->Update( boardItem ); view->Update( boardItem ); + board->OnItemChanged( boardItem ); // if no undo entry is needed, the copy would create a memory leak if( !aCreateUndoEntry ) @@ -395,6 +396,7 @@ void BOARD_COMMIT::Revert() view->Add( item ); connectivity->Add( item ); + board->OnItemChanged( item ); delete copy; break; } diff --git a/pcbnew/class_board.cpp b/pcbnew/class_board.cpp index 268de28855..33c5712180 100644 --- a/pcbnew/class_board.cpp +++ b/pcbnew/class_board.cpp @@ -601,6 +601,8 @@ void BOARD::Add( BOARD_ITEM* aBoardItem, ADD_MODE aMode ) aBoardItem->SetParent( this ); aBoardItem->ClearEditFlags(); m_connectivity->Add( aBoardItem ); + + InvokeListeners( &BOARD_LISTENER::OnBoardItemAdded, *this, aBoardItem ); } @@ -679,6 +681,8 @@ void BOARD::Remove( BOARD_ITEM* aBoardItem ) } m_connectivity->Remove( aBoardItem ); + + InvokeListeners( &BOARD_LISTENER::OnBoardItemRemoved, *this, aBoardItem ); } @@ -1429,6 +1433,9 @@ void BOARD::GetSortedPadListByXthenYCoord( std::vector& aVector, int aNe void BOARD::PadDelete( D_PAD* aPad ) { GetConnectivity()->Remove( aPad ); + + InvokeListeners( &BOARD_LISTENER::OnBoardItemRemoved, *this, aPad ); + aPad->DeleteStructure(); } @@ -1799,3 +1806,54 @@ void BOARD::SanitizeNetcodes() item->SetNetCode( NETINFO_LIST::ORPHANED ); } } + +void BOARD::AddListener( BOARD_LISTENER* aListener ) +{ + if( std::find( m_listeners.begin(), m_listeners.end(), aListener ) == m_listeners.end() ) + m_listeners.push_back( aListener ); +} + +void BOARD::RemoveListener( BOARD_LISTENER* aListener ) +{ + auto i = std::find( m_listeners.begin(), m_listeners.end(), aListener ); + + if( i != m_listeners.end() ) + { + std::iter_swap( i, m_listeners.end() - 1 ); + m_listeners.pop_back(); + } +} + +void BOARD::OnItemChanged( BOARD_ITEM* aItem ) +{ + InvokeListeners( &BOARD_LISTENER::OnBoardItemChanged, *this, aItem ); +} + + +void BOARD::ResetNetHighLight() +{ + m_highLight.Clear(); + m_highLightPrevious.Clear(); + + InvokeListeners( &BOARD_LISTENER::OnBoardHighlightNetChanged, *this ); +} + + +void BOARD::SetHighLightNet( int aNetCode ) +{ + if( m_highLight.m_netCode != aNetCode ) + { + m_highLight.m_netCode = aNetCode; + InvokeListeners( &BOARD_LISTENER::OnBoardHighlightNetChanged, *this ); + } +} + + +void BOARD::HighLightON( bool aValue ) +{ + if( m_highLight.m_highLightOn != aValue ) + { + m_highLight.m_highLightOn = aValue; + InvokeListeners( &BOARD_LISTENER::OnBoardHighlightNetChanged, *this ); + } +} diff --git a/pcbnew/class_board.h b/pcbnew/class_board.h index b24bac242a..f562bcb852 100644 --- a/pcbnew/class_board.h +++ b/pcbnew/class_board.h @@ -151,6 +151,25 @@ protected: } }; +/** + * BOARD_LISTENER + * provides an interface to hook into board modifications and get callbacks + * on certain modifications that are made to the board. This allows updating + * auxiliary views other than the primary board editor view. + */ +class BOARD; + +class BOARD_LISTENER +{ +public: + virtual ~BOARD_LISTENER() { } + virtual void OnBoardItemAdded( BOARD& aBoard, BOARD_ITEM* aBoardItem ) { } + virtual void OnBoardItemRemoved( BOARD& aBoard, BOARD_ITEM* aBoardItem ) { } + virtual void OnBoardNetSettingsChanged( BOARD& aBoard ) { } + virtual void OnBoardItemChanged( BOARD& aBoard, BOARD_ITEM* aBoardItem ) { } + virtual void OnBoardHighlightNetChanged( BOARD& aBoard ) { } +}; + DECL_VEC_FOR_SWIG( MARKERS, MARKER_PCB* ) DECL_VEC_FOR_SWIG( ZONE_CONTAINERS, ZONE_CONTAINER* ) @@ -202,6 +221,7 @@ private: NETINFO_LIST m_NetInfo; // net info list (name, design constraints .. PROJECT* m_project; // project this board is a part of (if any) + std::vector m_listeners; // The default copy constructor & operator= are inadequate, // either write one or do not use it at all @@ -209,6 +229,13 @@ private: BOARD& operator=( const BOARD& aOther ) = delete; + template + void InvokeListeners( Func&& aFunc, Args&&... args ) + { + for( auto&& l : m_listeners ) + ( l->*aFunc )( std::forward( args )... ); + } + public: static inline bool ClassOf( const EDA_ITEM* aItem ) { @@ -347,18 +374,19 @@ public: * Function ResetNetHighLight * Reset all high light data to the init state */ - void ResetNetHighLight() - { - m_highLight.Clear(); - m_highLightPrevious.Clear(); - } + void ResetNetHighLight(); /** * Function GetHighLightNetCode * @return netcode of net to highlight (-1 when no net selected) */ int GetHighLightNetCode() const { return m_highLight.m_netCode; } - void SetHighLightNet( int aNetCode) { m_highLight.m_netCode = aNetCode; } + + /** + * Function SetHighLightNet + * Select the netcode to be highlighted. + */ + void SetHighLightNet( int aNetCode ); /** * Function IsHighLightNetON @@ -368,11 +396,19 @@ public: /** * Function HighLightON - * Enable highlight. + * Enable net highlight. * if m_highLight_NetCode >= 0, this net will be highlighted */ - void HighLightON() { m_highLight.m_highLightOn = true; } - void HighLightOFF() { m_highLight.m_highLightOn = false; } + void HighLightON( bool aValue = true ); + + /** + * Function HighLightOFF + * Disable net highlight. + */ + void HighLightOFF() + { + HighLightON( false ); + } /** * Function GetCopperLayerCount @@ -1119,6 +1155,28 @@ public: void MapNets( const BOARD* aDestBoard ); void SanitizeNetcodes(); + + /** + * Add a listener to the board to receive calls whenever something on the + * board has been modified. The board does not take ownership of the + * listener object. Make sure to call RemoveListener before deleing the + * listener object. The order of listener invocations is not guaranteed. + * If the specified listener object has been added before, it will not be + * added again. + */ + void AddListener( BOARD_LISTENER* aListener ); + + /** + * Remove the specified listener. If it has not been added before, it + * will do nothing. + */ + void RemoveListener( BOARD_LISTENER* aListener ); + + /** + * Notify the board and its listeners that an item on the board has + * been modified in some way. + */ + void OnItemChanged( BOARD_ITEM* aItem ); }; #endif // CLASS_BOARD_H_ diff --git a/pcbnew/dialogs/dialog_global_edit_tracks_and_vias.cpp b/pcbnew/dialogs/dialog_global_edit_tracks_and_vias.cpp index 39a31e5281..db281fff1d 100644 --- a/pcbnew/dialogs/dialog_global_edit_tracks_and_vias.cpp +++ b/pcbnew/dialogs/dialog_global_edit_tracks_and_vias.cpp @@ -299,6 +299,8 @@ void DIALOG_GLOBAL_EDIT_TRACKS_AND_VIAS::processItem( PICKED_ITEMS_LIST* aUndoLi if( m_parent->SetTrackSegmentWidth( aItem, aUndoList, true ) == TRACK_ACTION_DRC_ERROR ) m_failedDRC = true; } + + m_brd->OnItemChanged( aItem ); } diff --git a/pcbnew/netclass.cpp b/pcbnew/netclass.cpp index 71c3e72833..a2edb1d172 100644 --- a/pcbnew/netclass.cpp +++ b/pcbnew/netclass.cpp @@ -225,6 +225,8 @@ void BOARD::SynchronizeNetsAndNetClasses() m_designSettings.SetCustomDiffPairWidth( defaultNetClass->GetDiffPairWidth() ); m_designSettings.SetCustomDiffPairGap( defaultNetClass->GetDiffPairGap() ); m_designSettings.SetCustomDiffPairViaGap( defaultNetClass->GetDiffPairViaGap() ); + + InvokeListeners( &BOARD_LISTENER::OnBoardNetSettingsChanged, *this ); } diff --git a/pcbnew/undo_redo.cpp b/pcbnew/undo_redo.cpp index 4cbdf37c62..b8e4ad5c7f 100644 --- a/pcbnew/undo_redo.cpp +++ b/pcbnew/undo_redo.cpp @@ -475,6 +475,7 @@ void PCB_BASE_EDIT_FRAME::PutDataInPreviousState( PICKED_ITEMS_LIST* aList, bool view->Add( eda_item ); connectivity->Add( item ); + item->GetBoard()->OnItemChanged( item ); } break; @@ -496,6 +497,7 @@ void PCB_BASE_EDIT_FRAME::PutDataInPreviousState( PICKED_ITEMS_LIST* aList, bool item->Move( aRedoCommand ? aList->m_TransformPoint : -aList->m_TransformPoint ); view->Update( item, KIGFX::GEOMETRY ); connectivity->Update( item ); + item->GetBoard()->OnItemChanged( item ); } break; @@ -506,6 +508,7 @@ void PCB_BASE_EDIT_FRAME::PutDataInPreviousState( PICKED_ITEMS_LIST* aList, bool aRedoCommand ? m_rotationAngle : -m_rotationAngle ); view->Update( item, KIGFX::GEOMETRY ); connectivity->Update( item ); + item->GetBoard()->OnItemChanged( item ); } break; @@ -516,6 +519,7 @@ void PCB_BASE_EDIT_FRAME::PutDataInPreviousState( PICKED_ITEMS_LIST* aList, bool aRedoCommand ? -m_rotationAngle : m_rotationAngle ); view->Update( item, KIGFX::GEOMETRY ); connectivity->Update( item ); + item->GetBoard()->OnItemChanged( item ); } break; @@ -525,6 +529,7 @@ void PCB_BASE_EDIT_FRAME::PutDataInPreviousState( PICKED_ITEMS_LIST* aList, bool item->Flip( aList->m_TransformPoint, m_Settings->m_FlipLeftRight ); view->Update( item, KIGFX::LAYERS ); connectivity->Update( item ); + item->GetBoard()->OnItemChanged( item ); } break;