From 6ad37972c069bb451d033542ff07481053569be4 Mon Sep 17 00:00:00 2001 From: Jeff Young Date: Tue, 30 Jan 2018 06:45:53 +0000 Subject: [PATCH] Don't center objects behind the DRC dialog. (cherry picked from commit d5bb39f) --- common/view/view.cpp | 37 +++++++++++++++++++++++++++++++++ include/math/box2.h | 34 ++++++++++++++++++++++++++++++ include/view/view.h | 9 ++++++++ pcbnew/class_module.cpp | 2 +- pcbnew/class_track.cpp | 2 +- pcbnew/pcb_base_frame.cpp | 26 ++++++++++++++++++++++- pcbnew/tools/selection_tool.cpp | 2 +- 7 files changed, 108 insertions(+), 4 deletions(-) diff --git a/common/view/view.cpp b/common/view/view.cpp index 84f848cd41..df44d5c199 100644 --- a/common/view/view.cpp +++ b/common/view/view.cpp @@ -609,6 +609,43 @@ void VIEW::SetCenter( const VECTOR2D& aCenter ) } +void VIEW::SetCenter( VECTOR2D aCenter, const BOX2D& occultingScreenRect ) +{ + BOX2D screenRect( VECTOR2D( 0, 0 ), m_gal->GetScreenPixelSize() ); + + if( !screenRect.Intersects( occultingScreenRect ) ) + { + SetCenter( aCenter ); + return; + } + + BOX2D occultedRect = screenRect.Intersect( occultingScreenRect ); + VECTOR2D offset( occultedRect.GetWidth() / 2, occultedRect.GetHeight() / 2 ); + + double topExposed = occultedRect.GetTop() - screenRect.GetTop(); + 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 ) ) + { + if( topExposed > bottomExposed ) + aCenter.y += ToWorld( occultedRect.GetHeight() / 2 ); + else + aCenter.y -= ToWorld( occultedRect.GetHeight() / 2 ); + } + else + { + if( leftExposed > rightExposed ) + aCenter.x += ToWorld( occultedRect.GetWidth() / 2 ); + else + aCenter.x -= ToWorld( occultedRect.GetWidth() / 2 ); + } + + SetCenter( aCenter ); +} + + void VIEW::SetLayerOrder( int aLayer, int aRenderingOrder ) { m_layers[aLayer].renderingOrder = aRenderingOrder; diff --git a/include/math/box2.h b/include/math/box2.h index f76392181b..b3369242cd 100644 --- a/include/math/box2.h +++ b/include/math/box2.h @@ -58,6 +58,16 @@ public: Normalize(); } +#ifdef WX_COMPATIBILITY + /// Constructor with a wxRect as argument + BOX2( const wxRect& aRect ) : + m_Pos( aRect.GetPosition() ), + m_Size( aRect.GetSize() ) + { + Normalize(); + } +#endif + void SetMaximum() { m_Pos.x = m_Pos.y = coord_limits::lowest() / 2 + coord_limits::epsilon(); @@ -249,6 +259,30 @@ public: return rc; } + /** + * Function Intersect + * Returns the intersection of this with another rectangle. + */ + BOX2 Intersect( const BOX2& aRect ) + { + BOX2 me( *this ); + BOX2 rect( aRect ); + me.Normalize(); // ensure size is >= 0 + rect.Normalize(); // ensure size is >= 0 + + Vec topLeft, bottomRight; + + topLeft.x = std::max( me.m_Pos.x, rect.m_Pos.x ); + bottomRight.x = std::min( me.m_Pos.x + me.m_Size.x, rect.m_Pos.x + rect.m_Size.x ); + topLeft.y = std::max( me.m_Pos.y, rect.m_Pos.y ); + bottomRight.y = std::min( me.m_Pos.y + me.m_Size.y, rect.m_Pos.y + rect.m_Size.y ); + + if ( topLeft.x < bottomRight.x && topLeft.y < bottomRight.y ) + return BOX2( topLeft, bottomRight - topLeft ); + else + return BOX2( Vec( 0, 0 ), Vec( 0, 0 ) ); + } + const std::string Format() const { std::stringstream ss; diff --git a/include/view/view.h b/include/view/view.h index 7a242b3fbc..ad8635fefd 100644 --- a/include/view/view.h +++ b/include/view/view.h @@ -308,6 +308,15 @@ public: */ void SetCenter( const VECTOR2D& aCenter ); + /** + * Function SetCenter() + * Sets the center point of the VIEW, attempting to avoid \a occultingScreenRect (for + * instance, the screen rect of a modeless dialog in front of the VIEW). + * @param aCenter: the new center point, in world space coordinates. + * @param occultingScreenRect: the occulting rect, in screen space coordinates. + */ + void SetCenter( VECTOR2D aCenter, const BOX2D& occultingScreenRect ); + /** * Function GetCenter() * Returns the center point of this VIEW (in world space coordinates) diff --git a/pcbnew/class_module.cpp b/pcbnew/class_module.cpp index 327f0a8c08..cb4101eec0 100644 --- a/pcbnew/class_module.cpp +++ b/pcbnew/class_module.cpp @@ -1017,7 +1017,7 @@ const BOX2I MODULE::ViewBBox() const } - return BOX2I( area ); + return area; } diff --git a/pcbnew/class_track.cpp b/pcbnew/class_track.cpp index 54f831b3c8..92ecee080a 100644 --- a/pcbnew/class_track.cpp +++ b/pcbnew/class_track.cpp @@ -807,7 +807,7 @@ unsigned int TRACK::ViewGetLOD( int aLayer, KIGFX::VIEW* aView ) const const BOX2I TRACK::ViewBBox() const { - BOX2I bbox( GetBoundingBox() ); + BOX2I bbox = GetBoundingBox(); bbox.Inflate( 2 * GetClearance() ); return bbox; } diff --git a/pcbnew/pcb_base_frame.cpp b/pcbnew/pcb_base_frame.cpp index 237c515dfe..bbc92cffff 100644 --- a/pcbnew/pcb_base_frame.cpp +++ b/pcbnew/pcb_base_frame.cpp @@ -362,13 +362,37 @@ double PCB_BASE_FRAME::BestZoom() } +// Find the first child dialog. +wxWindow* findDialog( wxWindowList& aList ) +{ + for( wxWindowList::iterator iter = aList.begin(); iter != aList.end(); ++iter ) + { + if( dynamic_cast( *iter ) ) + return *iter; + } + return NULL; +} + + void PCB_BASE_FRAME::FocusOnLocation( const wxPoint& aPos, bool aWarpMouseCursor, bool aCenterView ) { if( IsGalCanvasActive() ) { if( aCenterView ) - GetGalCanvas()->GetView()->SetCenter( aPos ); + { + wxWindow* dialog = findDialog( GetChildren() ); + + // If a dialog partly obscures the window, then center on the uncovered area. + if( dialog ) + { + wxRect dialogRect( GetGalCanvas()->ScreenToClient( dialog->GetScreenPosition() ), + dialog->GetSize() ); + GetGalCanvas()->GetView()->SetCenter( aPos, dialogRect ); + } + else + GetGalCanvas()->GetView()->SetCenter( aPos ); + } if( aWarpMouseCursor ) GetGalCanvas()->GetViewControls()->SetCursorPosition( aPos ); diff --git a/pcbnew/tools/selection_tool.cpp b/pcbnew/tools/selection_tool.cpp index b86fa984cf..6d14e4799c 100644 --- a/pcbnew/tools/selection_tool.cpp +++ b/pcbnew/tools/selection_tool.cpp @@ -628,7 +628,7 @@ bool SELECTION_TOOL::selectMultiple() if( windowSelection ) { - BOX2I bbox( item->GetBoundingBox() ); + BOX2I bbox = item->GetBoundingBox(); if( selectionBox.Contains( bbox ) ) {