Work around EnsureVisible bug in wxWidgets during DRC cross-probe.

Also adds double-click-marker to open DRC dialog and select marker
in list.

Fixes https://gitlab.com/kicad/code/kicad/issues/7246
This commit is contained in:
Jeff Young 2021-10-05 23:33:30 +01:00
parent 95f841a037
commit 1bb5fc3fd6
7 changed files with 71 additions and 21 deletions

View File

@ -594,7 +594,7 @@ void RC_TREE_MODEL::NextMarker()
} }
void RC_TREE_MODEL::SelectMarker( MARKER_BASE* aMarker ) void RC_TREE_MODEL::SelectMarker( const MARKER_BASE* aMarker )
{ {
for( RC_TREE_NODE* candidate : m_tree ) for( RC_TREE_NODE* candidate : m_tree )
{ {
@ -607,6 +607,19 @@ void RC_TREE_MODEL::SelectMarker( MARKER_BASE* aMarker )
} }
void RC_TREE_MODEL::CenterMarker( const MARKER_BASE* aMarker )
{
for( RC_TREE_NODE* candidate : m_tree )
{
if( candidate->m_RcItem->GetParent() == aMarker )
{
m_view->EnsureVisible( ToItem( candidate ) );
break;
}
}
}
void RC_TREE_MODEL::onSizeView( wxSizeEvent& aEvent ) void RC_TREE_MODEL::onSizeView( wxSizeEvent& aEvent )
{ {
int width = m_view->GetMainWindow()->GetRect().GetWidth() - WX_DATAVIEW_WINDOW_PADDING; int width = m_view->GetMainWindow()->GetRect().GetWidth() - WX_DATAVIEW_WINDOW_PADDING;

View File

@ -227,7 +227,8 @@ public:
void PrevMarker(); void PrevMarker();
void NextMarker(); void NextMarker();
void SelectMarker( MARKER_BASE* aMarker ); void SelectMarker( const MARKER_BASE* aMarker );
void CenterMarker( const MARKER_BASE* aMarker );
bool IsContainer( wxDataViewItem const& aItem ) const override; bool IsContainer( wxDataViewItem const& aItem ) const override;

View File

@ -395,7 +395,15 @@ void DIALOG_DRC::OnDRCItemSelected( wxDataViewEvent& aEvent )
if( board->GetVisibleLayers().test( principalLayer ) ) if( board->GetVisibleLayers().test( principalLayer ) )
m_frame->SetActiveLayer( principalLayer ); m_frame->SetActiveLayer( principalLayer );
m_frame->FocusOnItem( item, principalLayer ); if( m_centerMarkerOnIdle )
{
// we already came from a cross-probe of the marker in the document; don't go
// around in circles
}
else
{
m_frame->FocusOnItem( item, principalLayer );
}
} }
aEvent.Skip(); aEvent.Skip();
@ -743,16 +751,28 @@ void DIALOG_DRC::NextMarker()
} }
void DIALOG_DRC::SelectMarker( PCB_MARKER* aMarker ) void DIALOG_DRC::SelectMarker( const PCB_MARKER* aMarker )
{ {
if( m_Notebook->IsShown() ) if( m_Notebook->IsShown() )
{ {
m_Notebook->SetSelection( 0 ); m_Notebook->SetSelection( 0 );
m_markersTreeModel->SelectMarker( aMarker ); m_markersTreeModel->SelectMarker( aMarker );
// wxWidgets on some platforms fails to correctly ensure that a selected item is
// visible, so we have to do it in a separate idle event.
m_centerMarkerOnIdle = aMarker;
Bind( wxEVT_IDLE, &DIALOG_DRC::centerMarkerIdleHandler, this );
} }
} }
void DIALOG_DRC::centerMarkerIdleHandler( wxIdleEvent& aEvent )
{
m_markersTreeModel->CenterMarker( m_centerMarkerOnIdle );
Unbind( wxEVT_IDLE, &DIALOG_DRC::centerMarkerIdleHandler, this );
}
void DIALOG_DRC::ExcludeMarker() void DIALOG_DRC::ExcludeMarker()
{ {
if( !m_Notebook->IsShown() || m_Notebook->GetSelection() != 0 ) if( !m_Notebook->IsShown() || m_Notebook->GetSelection() != 0 )

View File

@ -57,7 +57,7 @@ public:
void PrevMarker(); void PrevMarker();
void NextMarker(); void NextMarker();
void SelectMarker( PCB_MARKER* aMarker ); void SelectMarker( const PCB_MARKER* aMarker );
void ExcludeMarker(); void ExcludeMarker();
@ -97,6 +97,8 @@ private:
void OnChangingNotebookPage( wxNotebookEvent& aEvent ) override; void OnChangingNotebookPage( wxNotebookEvent& aEvent ) override;
void centerMarkerIdleHandler( wxIdleEvent& aEvent );
void deleteAllMarkers( bool aIncludeExclusions ); void deleteAllMarkers( bool aIncludeExclusions );
void refreshEditor(); void refreshEditor();
@ -126,7 +128,9 @@ private:
RC_ITEMS_PROVIDER* m_footprintWarningsProvider; RC_ITEMS_PROVIDER* m_footprintWarningsProvider;
RC_TREE_MODEL* m_footprintWarningsTreeModel; RC_TREE_MODEL* m_footprintWarningsTreeModel;
int m_severities; const PCB_MARKER* m_centerMarkerOnIdle;
int m_severities; // A mask of SEVERITY flags
}; };
#endif // _DIALOG_DRC_H_ #endif // _DIALOG_DRC_H_

View File

@ -40,6 +40,7 @@
#include <connectivity/connectivity_data.h> #include <connectivity/connectivity_data.h>
#include <tool/tool_manager.h> #include <tool/tool_manager.h>
#include <tools/pcb_actions.h> #include <tools/pcb_actions.h>
#include <tools/drc_tool.h>
#include <dialogs/dialog_dimension_properties.h> #include <dialogs/dialog_dimension_properties.h>
// Handles the selection of command events. // Handles the selection of command events.
@ -157,6 +158,10 @@ void PCB_EDIT_FRAME::OnEditItemRequest( BOARD_ITEM* aItem )
m_toolManager->RunAction( PCB_ACTIONS::groupProperties, true, aItem ); m_toolManager->RunAction( PCB_ACTIONS::groupProperties, true, aItem );
break; break;
case PCB_MARKER_T:
m_toolManager->GetTool<DRC_TOOL>()->CrossProbe( static_cast<PCB_MARKER*>( aItem ) );
break;
default: default:
break; break;
} }

View File

@ -275,7 +275,9 @@ int DRC_TOOL::CrossProbe( const TOOL_EVENT& aEvent )
if( selection.GetSize() == 1 && selection.Front()->Type() == PCB_MARKER_T ) if( selection.GetSize() == 1 && selection.Front()->Type() == PCB_MARKER_T )
{ {
m_drcDialog->Show( true ); if( !m_drcDialog->IsShown() )
m_drcDialog->Show( true );
m_drcDialog->Raise(); m_drcDialog->Raise();
m_drcDialog->SelectMarker( static_cast<PCB_MARKER*>( selection.Front() ) ); m_drcDialog->SelectMarker( static_cast<PCB_MARKER*>( selection.Front() ) );
} }
@ -285,6 +287,16 @@ int DRC_TOOL::CrossProbe( const TOOL_EVENT& aEvent )
} }
void DRC_TOOL::CrossProbe( const PCB_MARKER* aMarker )
{
if( !IsDRCDialogShown() )
ShowDRCDialog( nullptr );
m_drcDialog->Raise();
m_drcDialog->SelectMarker( aMarker );
}
int DRC_TOOL::ExcludeMarker( const TOOL_EVENT& aEvent ) int DRC_TOOL::ExcludeMarker( const TOOL_EVENT& aEvent )
{ {
if( m_drcDialog ) if( m_drcDialog )

View File

@ -51,17 +51,10 @@ public:
void Reset( RESET_REASON aReason ) override; void Reset( RESET_REASON aReason ) override;
/** /**
* Open a dialog and prompts the user, then if a test run button is * Opens the DRC dialog. The dialog is only created if it is not already in existence.
* clicked, runs the test(s) and creates the MARKERS. The dialog is only
* created if it is not already in existence.
* *
* @param aParent is the parent window for wxWidgets. Usually the PCB editor frame * @param aParent is the parent window for modal invocations. If nullptr, the parent will
* but can be another dialog * be the PCB_EDIT_FRAME and the dialog will be modeless.
* if aParent == NULL (default), the parent will be the PCB editor frame
* and the dialog will be not modal (just float on parent
* if aParent is specified, the dialog will be modal.
* The modal mode is mandatory if the dialog is created from another dialog, not
* from the PCB editor frame
*/ */
void ShowDRCDialog( wxWindow* aParent ); void ShowDRCDialog( wxWindow* aParent );
@ -69,15 +62,11 @@ public:
/** /**
* Check to see if the DRC_TOOL dialog is currently shown * Check to see if the DRC_TOOL dialog is currently shown
*
* @return true if the dialog is shown
*/ */
bool IsDRCDialogShown(); bool IsDRCDialogShown();
/** /**
* Check to see if the DRC engine is running the tests * Check to see if the DRC engine is running the tests
*
* @return true if the DRC engine is running the tests
*/ */
bool IsDRCRunning() const { return m_drcRunning; } bool IsDRCRunning() const { return m_drcRunning; }
@ -98,6 +87,12 @@ public:
int NextMarker( const TOOL_EVENT& aEvent ); int NextMarker( const TOOL_EVENT& aEvent );
int CrossProbe( const TOOL_EVENT& aEvent ); int CrossProbe( const TOOL_EVENT& aEvent );
/**
* A more "active" CrossProbe which will open the DRC dialog if it is closed. Used when
* double-clicking on a marker.
*/
void CrossProbe( const PCB_MARKER* aMarker );
int ExcludeMarker( const TOOL_EVENT& aEvent ); int ExcludeMarker( const TOOL_EVENT& aEvent );
private: private: