Improve obscuring dialog algorithm to handle multiple dialogs.
Fixes https://gitlab.com/kicad/code/kicad/issues/8970
This commit is contained in:
parent
5c402a64ab
commit
11c91c7179
|
@ -836,15 +836,17 @@ void EDA_DRAW_FRAME::Zoom_Automatique( bool aWarpPointer )
|
||||||
|
|
||||||
|
|
||||||
// Find the first child dialog.
|
// Find the first child dialog.
|
||||||
wxWindow* EDA_DRAW_FRAME::findDialog()
|
std::vector<wxWindow*> EDA_DRAW_FRAME::findDialogs()
|
||||||
{
|
{
|
||||||
|
std::vector<wxWindow*> dialogs;
|
||||||
|
|
||||||
for( wxWindow* window : GetChildren() )
|
for( wxWindow* window : GetChildren() )
|
||||||
{
|
{
|
||||||
if( dynamic_cast<DIALOG_SHIM*>( window ) )
|
if( dynamic_cast<DIALOG_SHIM*>( window ) )
|
||||||
return window;
|
dialogs.push_back( window );
|
||||||
}
|
}
|
||||||
|
|
||||||
return nullptr;
|
return dialogs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -859,33 +861,25 @@ void EDA_DRAW_FRAME::FocusOnLocation( const wxPoint& aPos )
|
||||||
if( !r.Contains( aPos ) )
|
if( !r.Contains( aPos ) )
|
||||||
centerView = true;
|
centerView = true;
|
||||||
|
|
||||||
// Center if we're behind an obscuring dialog, or within 10% of its edge
|
std::vector<BOX2D> dialogScreenRects;
|
||||||
wxWindow* dialog = findDialog();
|
|
||||||
|
|
||||||
if( dialog )
|
for( wxWindow* dialog : findDialogs() )
|
||||||
{
|
{
|
||||||
wxRect dialogRect( GetCanvas()->ScreenToClient( dialog->GetScreenPosition() ),
|
dialogScreenRects.emplace_back( GetCanvas()->ScreenToClient( dialog->GetScreenPosition() ),
|
||||||
dialog->GetSize() );
|
dialog->GetSize() );
|
||||||
dialogRect.Inflate( dialogRect.GetWidth() / 10 );
|
}
|
||||||
|
|
||||||
if( dialogRect.Contains( (wxPoint) GetCanvas()->GetView()->ToScreen( aPos ) ) )
|
// Center if we're behind an obscuring dialog, or within 10% of its edge
|
||||||
|
for( BOX2D rect : dialogScreenRects )
|
||||||
|
{
|
||||||
|
rect.Inflate( rect.GetWidth() / 10 );
|
||||||
|
|
||||||
|
if( rect.Contains( GetCanvas()->GetView()->ToScreen( aPos ) ) )
|
||||||
centerView = true;
|
centerView = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( centerView )
|
if( centerView )
|
||||||
{
|
GetCanvas()->GetView()->SetCenter( aPos, dialogScreenRects );
|
||||||
// If a dialog partly obscures the window, then center on the uncovered area.
|
|
||||||
if( dialog )
|
|
||||||
{
|
|
||||||
BOX2D dialogRect( GetCanvas()->ScreenToClient( dialog->GetScreenPosition() ),
|
|
||||||
dialog->GetSize() );
|
|
||||||
GetCanvas()->GetView()->SetCenter( aPos, dialogRect );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
GetCanvas()->GetView()->SetCenter( aPos );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
GetCanvas()->GetViewControls()->SetCrossHairCursorPosition( aPos );
|
GetCanvas()->GetViewControls()->SetCrossHairCursorPosition( aPos );
|
||||||
}
|
}
|
||||||
|
|
|
@ -603,39 +603,35 @@ void VIEW::SetCenter( const VECTOR2D& aCenter )
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void VIEW::SetCenter( const VECTOR2D& aCenter, const BOX2D& occultingScreenRect )
|
void VIEW::SetCenter( const VECTOR2D& aCenter, const std::vector<BOX2D>& obscuringScreenRects )
|
||||||
{
|
{
|
||||||
VECTOR2D center( aCenter );
|
if( obscuringScreenRects.empty() )
|
||||||
BOX2D screenRect( VECTOR2D( 0, 0 ), m_gal->GetScreenPixelSize() );
|
return SetCenter( aCenter );
|
||||||
|
|
||||||
if( !screenRect.Intersects( occultingScreenRect ) )
|
BOX2D screenRect( { 0, 0 }, m_gal->GetScreenPixelSize() );
|
||||||
|
SHAPE_POLY_SET unobscuredPoly( screenRect );
|
||||||
|
VECTOR2D unobscuredCenter = screenRect.Centre();
|
||||||
|
|
||||||
|
for( const BOX2D& obscuringScreenRect : obscuringScreenRects )
|
||||||
{
|
{
|
||||||
SetCenter( aCenter );
|
SHAPE_POLY_SET obscuringPoly( obscuringScreenRect );
|
||||||
return;
|
unobscuredPoly.BooleanSubtract( obscuringPoly, SHAPE_POLY_SET::PM_FAST );
|
||||||
}
|
}
|
||||||
|
|
||||||
BOX2D occultedRect = screenRect.Intersect( occultingScreenRect );
|
/*
|
||||||
double topExposed = occultedRect.GetTop() - screenRect.GetTop();
|
* Perform a step-wise deflate to find the center of the largest unobscured area
|
||||||
double bottomExposed = screenRect.GetBottom() - occultedRect.GetBottom();
|
*/
|
||||||
double leftExposed = occultedRect.GetLeft() - screenRect.GetLeft();
|
|
||||||
double rightExposed = screenRect.GetRight() - occultedRect.GetRight();
|
|
||||||
|
|
||||||
if( std::max( topExposed, bottomExposed ) > std::max( leftExposed, rightExposed ) )
|
BOX2I bbox = unobscuredPoly.BBox();
|
||||||
|
int step = std::min( bbox.GetWidth(), bbox.GetHeight() ) / 10;
|
||||||
|
|
||||||
|
while( !unobscuredPoly.IsEmpty() )
|
||||||
{
|
{
|
||||||
if( topExposed > bottomExposed )
|
unobscuredCenter = (wxPoint) unobscuredPoly.BBox().Centre();
|
||||||
center.y += ToWorld( screenRect.GetHeight() / 2 - topExposed / 2 );
|
unobscuredPoly.Deflate( step, 4 );
|
||||||
else
|
|
||||||
center.y -= ToWorld( screenRect.GetHeight() / 2 - bottomExposed / 2 );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if( leftExposed > rightExposed )
|
|
||||||
center.x += ToWorld( screenRect.GetWidth() / 2 - leftExposed / 2 );
|
|
||||||
else
|
|
||||||
center.x -= ToWorld( screenRect.GetWidth() / 2 - rightExposed / 2 );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SetCenter( center );
|
SetCenter( aCenter - ToWorld( unobscuredCenter - screenRect.Centre(), false ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -462,7 +462,7 @@ protected:
|
||||||
|
|
||||||
void setupUnits( APP_SETTINGS_BASE* aCfg );
|
void setupUnits( APP_SETTINGS_BASE* aCfg );
|
||||||
|
|
||||||
wxWindow* findDialog();
|
std::vector<wxWindow*> findDialogs();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determines the Canvas type to load (with prompt if required) and initializes m_canvasType
|
* Determines the Canvas type to load (with prompt if required) and initializes m_canvasType
|
||||||
|
|
|
@ -318,13 +318,13 @@ public:
|
||||||
void SetCenter( const VECTOR2D& aCenter );
|
void SetCenter( const VECTOR2D& aCenter );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the center point of the VIEW, attempting to avoid \a occultingScreenRect (for
|
* Set the center point of the VIEW, attempting to avoid \a obscuringScreenRects (for
|
||||||
* instance, the screen rect of a modeless dialog in front of the VIEW).
|
* instance, the screen rect of a modeless dialog in front of the VIEW).
|
||||||
*
|
*
|
||||||
* @param aCenter: the new center point, in world space coordinates.
|
* @param aCenter: the new center point, in world space coordinates.
|
||||||
* @param occultingScreenRect: the occulting rect, in screen space coordinates.
|
* @param obscuringScreenRects: the obscuring rects, in screen space coordinates.
|
||||||
*/
|
*/
|
||||||
void SetCenter( const VECTOR2D& aCenter, const BOX2D& occultingScreenRect );
|
void SetCenter( const VECTOR2D& aCenter, const std::vector<BOX2D>& obscuringScreenRects );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the center point of this VIEW (in world space coordinates).
|
* Return the center point of this VIEW (in world space coordinates).
|
||||||
|
|
|
@ -271,15 +271,14 @@ void PCB_BASE_FRAME::FocusOnItem( BOARD_ITEM* aItem, PCB_LAYER_ID aLayer )
|
||||||
GetCanvas()->GetView()->Update( aItem );
|
GetCanvas()->GetView()->Update( aItem );
|
||||||
lastBrightenedItemID = aItem->m_Uuid;
|
lastBrightenedItemID = aItem->m_Uuid;
|
||||||
|
|
||||||
// Focus on the object's location. Prefer a visible part of the object to its anhcor
|
// Focus on the object's location. Prefer a visible part of the object to its anchor
|
||||||
// in order to keep from scrolling around.
|
// in order to keep from scrolling around.
|
||||||
|
|
||||||
wxPoint focusPt = aItem->GetFocusPosition();
|
wxPoint focusPt = aItem->GetFocusPosition();
|
||||||
KIGFX::VIEW* view = GetCanvas()->GetView();
|
KIGFX::VIEW* view = GetCanvas()->GetView();
|
||||||
SHAPE_POLY_SET viewportPoly( view->GetViewport() );
|
SHAPE_POLY_SET viewportPoly( view->GetViewport() );
|
||||||
wxWindow* dialog = findDialog();
|
|
||||||
|
|
||||||
if( dialog )
|
for( wxWindow* dialog : findDialogs() )
|
||||||
{
|
{
|
||||||
wxPoint dialogPos = GetCanvas()->ScreenToClient( dialog->GetScreenPosition() );
|
wxPoint dialogPos = GetCanvas()->ScreenToClient( dialog->GetScreenPosition() );
|
||||||
SHAPE_POLY_SET dialogPoly( BOX2D( view->ToWorld( dialogPos, true ),
|
SHAPE_POLY_SET dialogPoly( BOX2D( view->ToWorld( dialogPos, true ),
|
||||||
|
@ -335,6 +334,10 @@ void PCB_BASE_FRAME::FocusOnItem( BOARD_ITEM* aItem, PCB_LAYER_ID aLayer )
|
||||||
if( !clippedPoly.IsEmpty() )
|
if( !clippedPoly.IsEmpty() )
|
||||||
itemPoly = clippedPoly;
|
itemPoly = clippedPoly;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Perform a step-wise deflate to find the visual-center-of-mass
|
||||||
|
*/
|
||||||
|
|
||||||
BOX2I bbox = itemPoly.BBox();
|
BOX2I bbox = itemPoly.BBox();
|
||||||
int step = std::min( bbox.GetWidth(), bbox.GetHeight() ) / 10;
|
int step = std::min( bbox.GetWidth(), bbox.GetHeight() ) / 10;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue