From 3f320e4d68595799de9edba698d2244390cbb127 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Fri, 27 Sep 2013 16:23:43 +0200 Subject: [PATCH] Some more comments and code formatting. --- common/drawpanel_gal.cpp | 11 - common/geometry/seg.cpp | 120 ++++---- common/geometry/shape_collisions.cpp | 119 ++++---- common/geometry/shape_index.cpp | 1 - common/geometry/shape_line_chain.cpp | 401 +++++++++++++++------------ common/tool/action_manager.cpp | 7 +- common/tool/context_menu.cpp | 14 +- common/tool/tool_dispatcher.cpp | 38 ++- common/tool/tool_event.cpp | 2 +- common/tool/tool_manager.cpp | 10 +- include/geometry/shape_index.h | 134 +++++---- include/geometry/shape_line_chain.h | 238 ++++++++-------- include/tool/action_manager.h | 15 +- include/tool/context_menu.h | 58 +++- include/tool/tool_base.h | 59 +++- include/tool/tool_dispatcher.h | 41 ++- include/tool/tool_event.h | 60 +++- include/tool/tool_interactive.h | 20 +- pcbnew/tools/move_tool.cpp | 16 +- pcbnew/tools/selection_area.h | 1 + pcbnew/tools/selection_tool.cpp | 27 +- 21 files changed, 853 insertions(+), 539 deletions(-) diff --git a/common/drawpanel_gal.cpp b/common/drawpanel_gal.cpp index fd907a1ca6..fcdf12bae3 100644 --- a/common/drawpanel_gal.cpp +++ b/common/drawpanel_gal.cpp @@ -121,11 +121,6 @@ void EDA_DRAW_PANEL_GAL::onPaint( wxPaintEvent& WXUNUSED( aEvent ) ) m_pendingRefresh = false; m_lastRefresh = wxGetLocalTimeMillis(); -#ifdef __WXDEBUG__ - prof_counter time; - prof_start( &time, false ); -#endif /* __WXDEBUG__ */ - m_gal->BeginDrawing(); m_gal->SetBackgroundColor( KiGfx::COLOR4D( 0.0, 0.0, 0.0, 1.0 ) ); m_gal->ClearScreen(); @@ -138,12 +133,6 @@ void EDA_DRAW_PANEL_GAL::onPaint( wxPaintEvent& WXUNUSED( aEvent ) ) m_gal->DrawCursor( m_viewControls->GetCursorPosition() ); m_gal->EndDrawing(); - -#ifdef __WXDEBUG__ - prof_end( &time ); - wxLogDebug( wxT( "EDA_DRAW_PANEL_GAL::Refresh: %.0f ms (%.0f fps)" ), - static_cast( time.value ) / 1000.0, 1000000.0 / static_cast( time.value ) ); -#endif /* __WXDEBUG__ */ } diff --git a/common/geometry/seg.cpp b/common/geometry/seg.cpp index abc80688ca..68dda76675 100644 --- a/common/geometry/seg.cpp +++ b/common/geometry/seg.cpp @@ -25,126 +25,128 @@ #include -template int sgn(T val) { - return (T(0) < val) - (val < T(0)); +template int sgn( T val ) { + return ( T( 0 ) < val ) - ( val < T( 0 ) ); } -bool SEG::PointCloserThan (const VECTOR2I& aP, int dist) const + +bool SEG::PointCloserThan( const VECTOR2I& aP, int dist ) const { VECTOR2I d = b - a; ecoord dist_sq = (ecoord) dist * dist; - SEG::ecoord l_squared = d.Dot(d); - SEG::ecoord t = d.Dot(aP - a); - + SEG::ecoord l_squared = d.Dot( d ); + SEG::ecoord t = d.Dot( aP - a ); if( t <= 0 || !l_squared ) - return (aP - a).SquaredEuclideanNorm() < dist_sq; + return ( aP - a ).SquaredEuclideanNorm() < dist_sq; else if( t >= l_squared ) - return (aP - b).SquaredEuclideanNorm() < dist_sq; + return ( aP - b ).SquaredEuclideanNorm() < dist_sq; + int dxdy = abs( d.x ) - abs( d.y ); - int dxdy = abs(d.x) - abs(d.y); - - if( (dxdy >= -1 && dxdy <= 1) || abs(d.x) <= 1 || abs(d.y) <= 1) + if( ( dxdy >= -1 && dxdy <= 1 ) || abs( d.x ) <= 1 || abs( d.y ) <= 1 ) { - int ca = -sgn(d.y); - int cb = sgn(d.x); + int ca = -sgn( d.y ); + int cb = sgn( d.x ); int cc = -ca * a.x - cb * a.y; ecoord num = ca * aP.x + cb * aP.y + cc; num *= num; - if(ca && cb) + if( ca && cb ) num >>= 1; - if(num > (dist_sq + 100)) + if( num > ( dist_sq + 100 ) ) return false; - else if(num < (dist_sq - 100)) + else if( num < ( dist_sq - 100 ) ) return true; } VECTOR2I nearest; - nearest.x = a.x + rescale(t, (ecoord)d.x, l_squared); - nearest.y = a.y + rescale(t, (ecoord)d.y, l_squared); + nearest.x = a.x + rescale( t, (ecoord)d.x, l_squared ); + nearest.y = a.y + rescale( t, (ecoord)d.y, l_squared ); - return (nearest - aP).SquaredEuclideanNorm() <= dist_sq; + return ( nearest - aP ).SquaredEuclideanNorm() <= dist_sq; } + SEG::ecoord SEG::SquaredDistance( const SEG& aSeg ) const { - // fixme: rather inefficient.... - if(Intersect(aSeg)) - return 0; + // fixme: rather inefficient.... + if( Intersect( aSeg ) ) + return 0; - const VECTOR2I pts[4] = - { - aSeg.NearestPoint(a) - a, - aSeg.NearestPoint(b) - b, - NearestPoint(aSeg.a) - aSeg.a, - NearestPoint(aSeg.b) - aSeg.b - }; + const VECTOR2I pts[4] = + { + aSeg.NearestPoint( a ) - a, + aSeg.NearestPoint( b ) - b, + NearestPoint( aSeg.a ) - aSeg.a, + NearestPoint( aSeg.b ) - aSeg.b + }; - ecoord m = VECTOR2I::ECOORD_MAX; - for (int i = 0; i<4 ; i++) - m = std::min(m, pts[i].SquaredEuclideanNorm()); - return m; + ecoord m = VECTOR2I::ECOORD_MAX; + for( int i = 0; i < 4; i++ ) + m = std::min( m, pts[i].SquaredEuclideanNorm() ); + + return m; } + OPT_VECTOR2I SEG::Intersect( const SEG& aSeg, bool aIgnoreEndpoints, bool aLines ) const { - const VECTOR2I e (b - a); - const VECTOR2I f (aSeg.b - aSeg.a); - const VECTOR2I ac (aSeg.a - a); + const VECTOR2I e ( b - a ); + const VECTOR2I f ( aSeg.b - aSeg.a ); + const VECTOR2I ac ( aSeg.a - a ); - ecoord d = f.Cross(e); - ecoord p = f.Cross(ac); - ecoord q = e.Cross(ac); + ecoord d = f.Cross( e ); + ecoord p = f.Cross( ac ); + ecoord q = e.Cross( ac ); - if(d == 0) + if( d == 0 ) return OPT_VECTOR2I(); - if (!aLines && d > 0 && (q < 0 || q > d || p < 0 || p > d)) + if ( !aLines && d > 0 && ( q < 0 || q > d || p < 0 || p > d ) ) return OPT_VECTOR2I(); - if (!aLines && d < 0 && (q < d || p < d || p > 0 || q > 0)) + if ( !aLines && d < 0 && ( q < d || p < d || p > 0 || q > 0 ) ) return OPT_VECTOR2I(); - if (!aLines && aIgnoreEndpoints && (q == 0 || q == d) && (p == 0 || p == d)) + if ( !aLines && aIgnoreEndpoints && ( q == 0 || q == d ) && ( p == 0 || p == d ) ) return OPT_VECTOR2I(); - - VECTOR2I ip ( aSeg.a.x + rescale(q, (ecoord)f.x, d), - aSeg.a.y + rescale(q, (ecoord)f.y, d) ); + VECTOR2I ip( aSeg.a.x + rescale( q, (ecoord)f.x, d ), + aSeg.a.y + rescale( q, (ecoord)f.y, d ) ); return ip; } -bool SEG::ccw ( const VECTOR2I& a, const VECTOR2I& b, const VECTOR2I &c ) const +bool SEG::ccw( const VECTOR2I& a, const VECTOR2I& b, const VECTOR2I& c ) const { - return (ecoord)(c.y - a.y) * (b.x - a.x) > (ecoord)(b.y - a.y) * (c.x - a.x); + return (ecoord)( c.y - a.y ) * ( b.x - a.x ) > (ecoord)( b.y - a.y ) * ( c.x - a.x ); } + bool SEG::Collide( const SEG& aSeg, int aClearance ) const { // check for intersection // fixme: move to a method - if( ccw(a,aSeg.a,aSeg.b) != ccw(b,aSeg.a,aSeg.b) && ccw(a,b,aSeg.a) != ccw(a,b,aSeg.b) ) + if( ccw( a, aSeg.a, aSeg.b ) != ccw( b, aSeg.a, aSeg.b ) && + ccw( a, b, aSeg.a ) != ccw( a, b, aSeg.b ) ) return true; #define CHK(_seg, _pt) \ if( (_seg).PointCloserThan (_pt, aClearance ) ) return true; - CHK(*this, aSeg.a); - CHK(*this, aSeg.b); - CHK(aSeg, a); - CHK(aSeg, b); - + CHK( *this, aSeg.a ); + CHK( *this, aSeg.b ); + CHK( aSeg, a ); + CHK( aSeg, b ); #undef CHK return false; } - -bool SEG::Contains(const VECTOR2I& aP) const -{ - return PointCloserThan(aP, 1); -} + +bool SEG::Contains( const VECTOR2I& aP ) const +{ + return PointCloserThan( aP, 1 ); +} diff --git a/common/geometry/shape_collisions.cpp b/common/geometry/shape_collisions.cpp index c67a371e68..b678e0faa2 100644 --- a/common/geometry/shape_collisions.cpp +++ b/common/geometry/shape_collisions.cpp @@ -31,7 +31,8 @@ typedef VECTOR2I::extended_type ecoord; -static inline bool Collide( const SHAPE_CIRCLE& a, const SHAPE_CIRCLE& b, int clearance, bool needMTV, VECTOR2I& aMTV ) +static inline bool Collide( const SHAPE_CIRCLE& a, const SHAPE_CIRCLE& b, int clearance, + bool needMTV, VECTOR2I& aMTV ) { ecoord min_dist = clearance + a.GetRadius() + b.GetRadius(); ecoord min_dist_sq = min_dist * min_dist; @@ -44,12 +45,13 @@ static inline bool Collide( const SHAPE_CIRCLE& a, const SHAPE_CIRCLE& b, int cl return false; if ( needMTV ) - aMTV = delta.Resize( sqrt (abs(min_dist_sq - dist_sq)) + 1); + aMTV = delta.Resize( sqrt ( abs( min_dist_sq - dist_sq ) ) + 1 ); return true; } -static inline bool Collide( const SHAPE_RECT& a, const SHAPE_CIRCLE& b, int clearance, bool needMTV, VECTOR2I& aMTV ) +static inline bool Collide( const SHAPE_RECT& a, const SHAPE_CIRCLE& b, int clearance, + bool needMTV, VECTOR2I& aMTV ) { const VECTOR2I c = b.GetCenter(); const VECTOR2I p0 = a.GetPosition(); @@ -58,7 +60,7 @@ static inline bool Collide( const SHAPE_RECT& a, const SHAPE_CIRCLE& b, int cle const ecoord min_dist = clearance + r; const ecoord min_dist_sq = min_dist * min_dist; - if (a.BBox(0).Contains(c)) + if ( a.BBox( 0 ).Contains( c ) ) return true; const VECTOR2I vts[] = { @@ -71,73 +73,77 @@ static inline bool Collide( const SHAPE_RECT& a, const SHAPE_CIRCLE& b, int cle ecoord nearest_seg_dist_sq = VECTOR2I::ECOORD_MAX; VECTOR2I nearest; - bool inside = c.x >= p0.x && c.x <= (p0.x + size.x) - && c.y >= p0.y && c.y <= (p0.y + size.y); + bool inside = c.x >= p0.x && c.x <= ( p0.x + size.x ) + && c.y >= p0.y && c.y <= ( p0.y + size.y ); - if(!inside) + if( !inside ) { - for (int i = 0; i < 4; i++) + for( int i = 0; i < 4; i++ ) { - const SEG seg (vts[i], vts[i+1]); - ecoord dist_sq = seg.SquaredDistance ( c ); + const SEG seg( vts[i], vts[i+1] ); + ecoord dist_sq = seg.SquaredDistance( c ); - - if(dist_sq < min_dist_sq) + if( dist_sq < min_dist_sq ) { - if(!needMTV) + if( !needMTV ) return true; else { - nearest = seg.NearestPoint ( c ); + nearest = seg.NearestPoint( c ); nearest_seg_dist_sq = dist_sq; } } } } - if(nearest_seg_dist_sq >= min_dist_sq && !inside) + if( nearest_seg_dist_sq >= min_dist_sq && !inside ) return false; VECTOR2I delta = c - nearest; - if(!needMTV) + if( !needMTV ) return true; - if(inside) - aMTV = -delta.Resize(sqrt(abs(r * r + nearest_seg_dist_sq) + 1)); + if( inside ) + aMTV = -delta.Resize( sqrt( abs( r * r + nearest_seg_dist_sq ) + 1 ) ); else - aMTV = delta.Resize(sqrt(abs(r * r - nearest_seg_dist_sq) + 1)); + aMTV = delta.Resize( sqrt( abs( r * r - nearest_seg_dist_sq ) + 1 ) ); return true; } -static inline bool Collide( const SHAPE_CIRCLE& a, const SHAPE_LINE_CHAIN& b, int clearance, bool needMTV, VECTOR2I& aMTV ) + +static inline bool Collide( const SHAPE_CIRCLE& a, const SHAPE_LINE_CHAIN& b, int clearance, + bool needMTV, VECTOR2I& aMTV ) { - for (int s = 0; s < b.SegmentCount(); s++) + for( int s = 0; s < b.SegmentCount(); s++ ) { - if ( a.Collide (b.CSegment(s), clearance)) + if ( a.Collide( b.CSegment( s ), clearance ) ) return true; } return false; } -static inline bool Collide( const SHAPE_LINE_CHAIN& a, const SHAPE_LINE_CHAIN& b, int clearance, bool needMTV, VECTOR2I& aMTV ) + +static inline bool Collide( const SHAPE_LINE_CHAIN& a, const SHAPE_LINE_CHAIN& b, int clearance, + bool needMTV, VECTOR2I& aMTV ) { - for( int i = 0; i < b.SegmentCount() ;i++) - if(a.Collide(b.CSegment(i), clearance)) + for( int i = 0; i < b.SegmentCount(); i++ ) + if( a.Collide( b.CSegment(i), clearance ) ) return true; return false; } -static inline bool Collide( const SHAPE_RECT& a, const SHAPE_LINE_CHAIN& b, int clearance, bool needMTV, VECTOR2I& aMTV ) +static inline bool Collide( const SHAPE_RECT& a, const SHAPE_LINE_CHAIN& b, int clearance, + bool needMTV, VECTOR2I& aMTV ) { - for (int s = 0; s < b.SegmentCount(); s++) + for( int s = 0; s < b.SegmentCount(); s++ ) { - SEG seg = b.CSegment(s); - if ( a.Collide (seg, clearance)) + SEG seg = b.CSegment( s ); + if( a.Collide( seg, clearance ) ) return true; } @@ -145,66 +151,83 @@ static inline bool Collide( const SHAPE_RECT& a, const SHAPE_LINE_CHAIN& b, int } - -bool CollideShapes ( const SHAPE *a, const SHAPE *b, int clearance, bool needMTV, VECTOR2I& aMTV ) +bool CollideShapes( const SHAPE* a, const SHAPE* b, int clearance, bool needMTV, VECTOR2I& aMTV ) { - switch(a->Type()) + switch( a->Type() ) { case SH_RECT: - switch(b->Type()) + switch( b->Type() ) { case SH_CIRCLE: - return Collide( *static_cast (a), *static_cast (b), clearance, needMTV, aMTV ); + return Collide( *static_cast( a ), + *static_cast( b ), clearance, needMTV, aMTV ); + case SH_LINE_CHAIN: - return Collide( *static_cast (a), *static_cast (b), clearance, needMTV, aMTV ); + return Collide( *static_cast( a ), + *static_cast( b ), clearance, needMTV, aMTV ); + default: break; } case SH_CIRCLE: - switch(b->Type()) + switch( b->Type() ) { case SH_RECT: - return Collide( *static_cast (b), *static_cast (a), clearance, needMTV, aMTV ); + return Collide( *static_cast( b ), + *static_cast( a ), clearance, needMTV, aMTV ); + case SH_CIRCLE: - return Collide( *static_cast (a), *static_cast (b), clearance, needMTV, aMTV ); + return Collide( *static_cast( a ), + *static_cast( b ), clearance, needMTV, aMTV ); + case SH_LINE_CHAIN: - return Collide( *static_cast (a), *static_cast (b), clearance, needMTV, aMTV ); + return Collide( *static_cast( a ), + *static_cast( b ), clearance, needMTV, aMTV ); + default: break; } case SH_LINE_CHAIN: - switch(b->Type()) + switch( b->Type() ) { case SH_RECT: - return Collide( *static_cast (b), *static_cast (a), clearance, needMTV, aMTV ); + return Collide( *static_cast( b ), + *static_cast( a ), clearance, needMTV, aMTV ); + case SH_CIRCLE: - return Collide( *static_cast (b), *static_cast (a), clearance, needMTV, aMTV ); + return Collide( *static_cast( b ), + *static_cast( a ), clearance, needMTV, aMTV ); + case SH_LINE_CHAIN: - return Collide( *static_cast (a), *static_cast (b), clearance, needMTV, aMTV ); + return Collide( *static_cast( a ), + *static_cast( b ), clearance, needMTV, aMTV ); + default: break; } + default: break; } bool unsupported_collision = true; - assert(unsupported_collision == false); + assert( unsupported_collision == false ); + return false; } -bool SHAPE::Collide ( const SHAPE *aShape, int aClerance, VECTOR2I& aMTV ) const +bool SHAPE::Collide( const SHAPE* aShape, int aClerance, VECTOR2I& aMTV ) const { return CollideShapes( this, aShape, aClerance, true, aMTV); } -bool SHAPE::Collide ( const SHAPE *aShape, int aClerance ) const + +bool SHAPE::Collide ( const SHAPE* aShape, int aClerance ) const { VECTOR2I dummy; - return CollideShapes( this, aShape, aClerance, false, dummy); + return CollideShapes( this, aShape, aClerance, false, dummy ); } - diff --git a/common/geometry/shape_index.cpp b/common/geometry/shape_index.cpp index 4552881082..986dd0c0bd 100644 --- a/common/geometry/shape_index.cpp +++ b/common/geometry/shape_index.cpp @@ -30,4 +30,3 @@ const SHAPE* shapeFunctor( SHAPE* aItem ) { return aItem; } - diff --git a/common/geometry/shape_line_chain.cpp b/common/geometry/shape_line_chain.cpp index 6edc0d2b14..909a1832a0 100644 --- a/common/geometry/shape_line_chain.cpp +++ b/common/geometry/shape_line_chain.cpp @@ -28,43 +28,46 @@ using namespace std; using boost::optional; -bool SHAPE_LINE_CHAIN::Collide ( const VECTOR2I& aP, int aClearance ) const +bool SHAPE_LINE_CHAIN::Collide( const VECTOR2I& aP, int aClearance ) const { - assert(false); + assert( false ); return false; } -bool SHAPE_LINE_CHAIN::Collide ( const BOX2I& aBox, int aClearance ) const + +bool SHAPE_LINE_CHAIN::Collide( const BOX2I& aBox, int aClearance ) const { - assert(false); + assert( false ); return false; } -bool SHAPE_LINE_CHAIN::Collide ( const SEG& aSeg, int aClearance ) const + +bool SHAPE_LINE_CHAIN::Collide( const SEG& aSeg, int aClearance ) const { - BOX2I box_a(aSeg.a, aSeg.b - aSeg.a); + BOX2I box_a( aSeg.a, aSeg.b - aSeg.a ); BOX2I::ecoord_type dist_sq = (BOX2I::ecoord_type) aClearance * aClearance; - for( int i = 0; i < SegmentCount() ;i++) + for( int i = 0; i < SegmentCount() ;i++ ) { - const SEG& s = CSegment(i); - BOX2I box_b(s.a, s.b - s.a); + const SEG& s = CSegment( i ); + BOX2I box_b( s.a, s.b - s.a ); BOX2I::ecoord_type d = box_a.SquaredDistance ( box_b ); - if(d < dist_sq) + if( d < dist_sq ) { - if(s.Collide(aSeg, aClearance)) + if( s.Collide( aSeg, aClearance ) ) return true; } } + return false; } const SHAPE_LINE_CHAIN SHAPE_LINE_CHAIN::Reverse() const { - SHAPE_LINE_CHAIN a (*this); - reverse(a.m_points.begin(), a.m_points.end()); + SHAPE_LINE_CHAIN a( *this ); + reverse( a.m_points.begin(), a.m_points.end() ); a.m_closed = m_closed; return a; @@ -74,176 +77,195 @@ const SHAPE_LINE_CHAIN SHAPE_LINE_CHAIN::Reverse() const int SHAPE_LINE_CHAIN::Length() const { int l = 0; - for (int i = 0; i < SegmentCount(); i++) - l += CSegment(i).Length(); + for( int i = 0; i < SegmentCount(); i++ ) + l += CSegment( i ).Length(); + return l; } -void SHAPE_LINE_CHAIN::Replace( int start_index, int end_index, const VECTOR2I& aP) -{ - if(end_index < 0) - end_index += PointCount(); - if(start_index < 0) - start_index += PointCount(); - if (start_index == end_index) - m_points [start_index] = aP; - else { - m_points.erase (m_points.begin() + start_index + 1, m_points.begin() + end_index + 1); - m_points [start_index] = aP; +void SHAPE_LINE_CHAIN::Replace( int aStartIndex, int aEndIndex, const VECTOR2I& aP ) +{ + if( aEndIndex < 0 ) + aEndIndex += PointCount(); + if( aStartIndex < 0 ) + aStartIndex += PointCount(); + + if( aStartIndex == aEndIndex ) + m_points [aStartIndex] = aP; + else + { + m_points.erase( m_points.begin() + aStartIndex + 1, m_points.begin() + aEndIndex + 1 ); + m_points[aStartIndex] = aP; } } -void SHAPE_LINE_CHAIN::Replace( int start_index, int end_index, const SHAPE_LINE_CHAIN& aLine) -{ - if(end_index < 0) - end_index += PointCount(); - if(start_index < 0) - start_index += PointCount(); - m_points.erase (m_points.begin() + start_index, m_points.begin() + end_index + 1); - m_points.insert (m_points.begin() + start_index, aLine.m_points.begin(), aLine.m_points.end()); +void SHAPE_LINE_CHAIN::Replace( int aStartIndex, int aEndIndex, const SHAPE_LINE_CHAIN& aLine ) +{ + if( aEndIndex < 0 ) + aEndIndex += PointCount(); + if( aStartIndex < 0 ) + aStartIndex += PointCount(); + + m_points.erase( m_points.begin() + aStartIndex, m_points.begin() + aEndIndex + 1 ); + m_points.insert( m_points.begin() + aStartIndex, aLine.m_points.begin(), aLine.m_points.end() ); } -void SHAPE_LINE_CHAIN::Remove( int start_index, int end_index) -{ - if(end_index < 0) - end_index += PointCount(); - if(start_index < 0) - start_index += PointCount(); - m_points.erase (m_points.begin() + start_index, m_points.begin() + end_index + 1); +void SHAPE_LINE_CHAIN::Remove( int aStartIndex, int aEndIndex ) +{ + if(aEndIndex < 0) + aEndIndex += PointCount(); + if(aStartIndex < 0) + aStartIndex += PointCount(); + + m_points.erase( m_points.begin() + aStartIndex, m_points.begin() + aEndIndex + 1 ); } -int SHAPE_LINE_CHAIN::Distance( const VECTOR2I & aP ) const + +int SHAPE_LINE_CHAIN::Distance( const VECTOR2I& aP ) const { int d = INT_MAX; - for (int s = 0; s < SegmentCount(); s++) - d = min (d, CSegment(s).Distance(aP)); + for( int s = 0; s < SegmentCount(); s++ ) + d = min( d, CSegment( s ).Distance( aP ) ); + return d; } - -int SHAPE_LINE_CHAIN::Split( const VECTOR2I & aP ) + + +int SHAPE_LINE_CHAIN::Split( const VECTOR2I& aP ) { int ii = -1; int min_dist = 2; - ii = Find(aP); + ii = Find( aP ); - if(ii >= 0) + if( ii >= 0 ) return ii; - for (int s = 0; s < SegmentCount(); s++) + for( int s = 0; s < SegmentCount(); s++ ) { - const SEG seg = CSegment(s); - int dist = seg.Distance(aP); + const SEG seg = CSegment( s ); + int dist = seg.Distance( aP ); // make sure we are not producing a 'slightly concave' primitive. This might happen // if aP lies very close to one of already existing points. - if(dist < min_dist && seg.a != aP && seg.b != aP) + if( dist < min_dist && seg.a != aP && seg.b != aP ) { min_dist = dist; ii = s; } } - if(ii >= 0) + if( ii >= 0 ) { - m_points.insert(m_points.begin() + ii + 1, aP); + m_points.insert( m_points.begin() + ii + 1, aP ); + return ii + 1; } return -1; } -int SHAPE_LINE_CHAIN::Find ( const VECTOR2I& aP ) const + +int SHAPE_LINE_CHAIN::Find( const VECTOR2I& aP ) const { - for (int s = 0; s< PointCount(); s++) - if(CPoint(s) == aP) + for( int s = 0; s< PointCount(); s++ ) + if( CPoint( s ) == aP ) return s; + return -1; } -const SHAPE_LINE_CHAIN SHAPE_LINE_CHAIN::Slice( int start_index, int end_index ) const + +const SHAPE_LINE_CHAIN SHAPE_LINE_CHAIN::Slice( int aStartIndex, int aEndIndex ) const { SHAPE_LINE_CHAIN rv; - if(end_index < 0) - end_index += PointCount(); - if(start_index < 0) - start_index += PointCount(); + if( aEndIndex < 0 ) + aEndIndex += PointCount(); + if( aStartIndex < 0 ) + aStartIndex += PointCount(); + + for( int i = aStartIndex; i <= aEndIndex; i++ ) + rv.Append( m_points[i] ); - for(int i = start_index; i<= end_index; i++) - rv.Append(m_points[i]); return rv; } -struct compareOriginDistance { - compareOriginDistance( VECTOR2I& aOrigin ): - m_origin(aOrigin) {}; - bool operator()(const SHAPE_LINE_CHAIN::Intersection &a, const SHAPE_LINE_CHAIN::Intersection& b) +struct compareOriginDistance +{ + compareOriginDistance( VECTOR2I& aOrigin ): + m_origin( aOrigin ) {}; + + bool operator()( const SHAPE_LINE_CHAIN::Intersection& aA, + const SHAPE_LINE_CHAIN::Intersection& aB ) { - return (m_origin - a.p).EuclideanNorm() < (m_origin - b.p).EuclideanNorm(); + return ( m_origin - aA.p ).EuclideanNorm() < ( m_origin - aB.p ).EuclideanNorm(); } VECTOR2I m_origin; }; -int SHAPE_LINE_CHAIN::Intersect ( const SEG& aSeg, Intersections& aIp ) const +int SHAPE_LINE_CHAIN::Intersect( const SEG& aSeg, Intersections& aIp ) const { - for (int s = 0; s < SegmentCount(); s++) + for( int s = 0; s < SegmentCount(); s++ ) { - OPT_VECTOR2I p = CSegment(s).Intersect(aSeg); - if(p) + OPT_VECTOR2I p = CSegment( s ).Intersect( aSeg ); + if( p ) { Intersection is; - is.our = CSegment(s); + is.our = CSegment( s ); is.their = aSeg; is.p = *p; - aIp.push_back(is); + aIp.push_back( is ); } } - compareOriginDistance comp(aSeg.a); - sort(aIp.begin(), aIp.end(), comp); + compareOriginDistance comp( aSeg.a ); + sort( aIp.begin(), aIp.end(), comp ); + return aIp.size(); -}; +} -int SHAPE_LINE_CHAIN::Intersect( const SHAPE_LINE_CHAIN &aChain, Intersections& aIp ) const + +int SHAPE_LINE_CHAIN::Intersect( const SHAPE_LINE_CHAIN& aChain, Intersections& aIp ) const { -BOX2I bb_other = aChain.BBox(); + BOX2I bb_other = aChain.BBox(); - for (int s1 = 0; s1 < SegmentCount(); s1++) + for ( int s1 = 0; s1 < SegmentCount(); s1++ ) { - const SEG& a = CSegment(s1); - const BOX2I bb_cur (a.a, a.b - a.a); + const SEG& a = CSegment( s1 ); + const BOX2I bb_cur( a.a, a.b - a.a ); - if(! bb_other.Intersects( bb_cur )) + if( !bb_other.Intersects( bb_cur ) ) continue; - for (int s2 = 0; s2 < aChain.SegmentCount(); s2++) + for( int s2 = 0; s2 < aChain.SegmentCount(); s2++ ) { - const SEG& b = aChain.CSegment(s2); + const SEG& b = aChain.CSegment( s2 ); Intersection is; - - if(a.Collinear(b)) + if( a.Collinear( b ) ) { - if(a.Contains(b.a)) { is.p = b.a; aIp.push_back(is); } - if(a.Contains(b.b)) { is.p = b.b; aIp.push_back(is); } - if(b.Contains(a.a)) { is.p = a.a; aIp.push_back(is); } - if(b.Contains(a.b)) { is.p = a.b; aIp.push_back(is); } - } else { - OPT_VECTOR2I p = a.Intersect(b); + if( a.Contains( b.a ) ) { is.p = b.a; aIp.push_back( is ); } + if( a.Contains( b.b ) ) { is.p = b.b; aIp.push_back( is ); } + if( b.Contains( a.a ) ) { is.p = a.a; aIp.push_back( is ); } + if( b.Contains( a.b ) ) { is.p = a.b; aIp.push_back( is ); } + } + else + { + OPT_VECTOR2I p = a.Intersect( b ); - if(p) + if( p ) { is.p = *p; is.our = a; is.their = b; - aIp.push_back(is); + aIp.push_back( is ); } } } @@ -251,130 +273,152 @@ BOX2I bb_other = aChain.BBox(); return aIp.size(); - for (int s1 = 0; s1 < SegmentCount(); s1++) - for (int s2 = 0; s2 < aChain.SegmentCount(); s2++) + for( int s1 = 0; s1 < SegmentCount(); s1++ ) + { + for( int s2 = 0; s2 < aChain.SegmentCount(); s2++ ) { - const SEG& a = CSegment(s1); - const SEG& b = aChain.CSegment(s2); - OPT_VECTOR2I p = a.Intersect(b); + const SEG& a = CSegment( s1 ); + const SEG& b = aChain.CSegment( s2 ); + OPT_VECTOR2I p = a.Intersect( b ); Intersection is; - if(p) + if( p ) { is.p = *p; is.our = a; is.their = b; - aIp.push_back(is); - } else if (a.Collinear(b)) + aIp.push_back( is ); + } + else if( a.Collinear( b ) ) { - if(a.a != b.a && a.a != b.b && b.Contains(a.a) ) + if( a.a != b.a && a.a != b.b && b.Contains( a.a ) ) { is.p = a.a; is.our = a; is.their = b; - aIp.push_back(is); + aIp.push_back( is ); } - else if(a.b != b.a && a.b != b.b && b.Contains(a.b) ) + else if( a.b != b.a && a.b != b.b && b.Contains( a.b ) ) { is.p = a.b; is.our = a; is.their = b; - aIp.push_back(is); + aIp.push_back( is ); } } } + } + return aIp.size(); } - -int SHAPE_LINE_CHAIN::PathLength (const VECTOR2I& aP ) const + + +int SHAPE_LINE_CHAIN::PathLength( const VECTOR2I& aP ) const { int sum = 0; - for (int i = 0; i < SegmentCount(); i++) + for( int i = 0; i < SegmentCount(); i++ ) { - const SEG seg = CSegment(i); - int d = seg.Distance(aP); - if (d <= 1) + const SEG seg = CSegment( i ); + int d = seg.Distance( aP ); + + if( d <= 1 ) { - sum += (aP - seg.a).EuclideanNorm(); + sum += ( aP - seg.a ).EuclideanNorm(); return sum; } else sum += seg.Length(); } + return -1; } - -bool SHAPE_LINE_CHAIN::PointInside( const VECTOR2I& aP) const + + +bool SHAPE_LINE_CHAIN::PointInside( const VECTOR2I& aP ) const { - if(!m_closed || SegmentCount() < 3) + if( !m_closed || SegmentCount() < 3 ) return false; - int cur = CSegment(0).Side(aP); - if(cur == 0) + int cur = CSegment(0).Side( aP ); + + if( cur == 0 ) return false; - for( int i = 1; i < SegmentCount(); i++) + for( int i = 1; i < SegmentCount(); i++ ) { - const SEG s = CSegment(i); - if(aP == s.a || aP == s.b) // edge does not belong to the interior! + const SEG s = CSegment( i ); + + if( aP == s.a || aP == s.b ) // edge does not belong to the interior! return false; - if (s.Side(aP) != cur) + + if( s.Side(aP) != cur ) return false; - } + } + return true; } -bool SHAPE_LINE_CHAIN::PointOnEdge( const VECTOR2I& aP) const + +bool SHAPE_LINE_CHAIN::PointOnEdge( const VECTOR2I& aP ) const { - if(SegmentCount() < 1) + if( SegmentCount() < 1 ) return m_points[0] == aP; - - for( int i = 1; i < SegmentCount(); i++) + + for( int i = 1; i < SegmentCount(); i++ ) { - const SEG s = CSegment(i); - if(s.a == aP || s.b == aP) + const SEG s = CSegment( i ); + + if( s.a == aP || s.b == aP ) return true; - if(s.Distance(aP) <= 1) + if( s.Distance(aP) <= 1 ) return true; } + return false; } + const optional SHAPE_LINE_CHAIN::SelfIntersecting() const { - for (int s1 = 0; s1 < SegmentCount(); s1++) - for (int s2 = s1 + 1; s2 < SegmentCount(); s2++) + for( int s1 = 0; s1 < SegmentCount(); s1++ ) + { + for( int s2 = s1 + 1; s2 < SegmentCount(); s2++ ) { - const VECTOR2I s2a = CSegment(s2).a, s2b = CSegment(s2).b; - if(s1 + 1 != s2 && CSegment(s1).Contains(s2a)) + const VECTOR2I s2a = CSegment( s2 ).a, s2b = CSegment( s2 ).b; + if( s1 + 1 != s2 && CSegment( s1 ).Contains( s2a ) ) { Intersection is; - is.our = CSegment(s1); - is.their = CSegment(s2); + is.our = CSegment( s1 ); + is.their = CSegment( s2 ); is.p = s2a; return is; - } else if (CSegment(s1).Contains(s2b)) { + } + else if( CSegment( s1 ).Contains(s2b ) ) + { Intersection is; - is.our = CSegment(s1); - is.their = CSegment(s2); + is.our = CSegment( s1 ); + is.their = CSegment( s2 ); is.p = s2b; return is; - - } else { - OPT_VECTOR2I p = CSegment(s1).Intersect(CSegment(s2), true); + } + else + { + OPT_VECTOR2I p = CSegment( s1 ).Intersect( CSegment( s2 ), true ); - if(p) + if( p ) { Intersection is; - is.our = CSegment(s1); - is.their = CSegment(s2); + is.our = CSegment( s1 ); + is.their = CSegment( s2 ); is.p = *p; return is; } } } + } + return optional(); } @@ -383,12 +427,15 @@ SHAPE_LINE_CHAIN& SHAPE_LINE_CHAIN::Simplify() { vector pts_unique; - if (PointCount() < 2) + if( PointCount() < 2 ) { return *this; - } else if (PointCount() == 2) { - if(m_points[0] == m_points[1]) - m_points.erase(m_points.end()); + } + else if( PointCount() == 2 ) + { + if( m_points[0] == m_points[1] ) + m_points.erase( m_points.end() ); + return *this; } @@ -398,10 +445,11 @@ SHAPE_LINE_CHAIN& SHAPE_LINE_CHAIN::Simplify() // stage 1: eliminate duplicate vertices while ( i < np ) { - int j = i+1; - while(j < np && CPoint(i) == CPoint(j)) - j ++; - pts_unique.push_back(CPoint(i)); + int j = i + 1; + while( j < np && CPoint(i) == CPoint( j ) ) + j++; + + pts_unique.push_back( CPoint( i ) ); i = j; } @@ -410,56 +458,63 @@ SHAPE_LINE_CHAIN& SHAPE_LINE_CHAIN::Simplify() i = 0; // stage 1: eliminate collinear segments - while (i < np - 2) + while( i < np - 2 ) { const VECTOR2I p0 = pts_unique[i]; const VECTOR2I p1 = pts_unique[i+1]; int n = i; - while(n < np - 2 && SEG(p0, p1).LineDistance(pts_unique[n + 2]) <= 1) + + while( n < np - 2 && SEG( p0, p1 ).LineDistance( pts_unique[n + 2] ) <= 1 ) n++; - m_points.push_back(p0); - if (n > i) + m_points.push_back( p0 ); + if( n > i ) i = n; - if (n == np) + + if( n == np ) { - m_points.push_back(pts_unique[n-1]); + m_points.push_back( pts_unique[n - 1] ); return *this; } - i ++; + + i++; } - if(np > 1) - m_points.push_back(pts_unique[np-2]); - m_points.push_back(pts_unique[np-1]); + if( np > 1 ) + m_points.push_back( pts_unique[np - 2] ); + + m_points.push_back( pts_unique[np - 1] ); return *this; } -const VECTOR2I SHAPE_LINE_CHAIN::NearestPoint(const VECTOR2I& aP) const + +const VECTOR2I SHAPE_LINE_CHAIN::NearestPoint( const VECTOR2I& aP ) const { int min_d = INT_MAX; int nearest = 0; - for ( int i = 0; i < SegmentCount() ; i++ ) + for ( int i = 0; i < SegmentCount(); i++ ) { - int d = CSegment(i).Distance(aP); + int d = CSegment( i ).Distance( aP ); if( d < min_d ) { min_d = d; nearest = i; } } - return CSegment(nearest).NearestPoint(aP); + + return CSegment( nearest ).NearestPoint( aP ); } - + + const string SHAPE_LINE_CHAIN::Format() const { stringstream ss; - ss << m_points.size() << " " << (m_closed ? 1 : 0) << " " ; + ss << m_points.size() << " " << ( m_closed ? 1 : 0 ) << " " ; - for(int i = 0; isetActionMgr( NULL ); + aAction->setId( -1 ); m_actionNameIndex.erase( aAction->m_name ); m_actionIdIndex.erase( aAction->m_id ); @@ -75,7 +76,7 @@ bool ACTION_MANAGER::RunAction( const std::string& aActionName ) const std::map::const_iterator it = m_actionNameIndex.find( aActionName ); if( it == m_actionNameIndex.end() ) - return false; + return false; // no action with given name found runAction( it->second ); @@ -88,7 +89,7 @@ bool ACTION_MANAGER::RunHotKey( int aHotKey ) const std::map::const_iterator it = m_actionHotKeys.find( aHotKey ); if( it == m_actionHotKeys.end() ) - return false; + return false; // no appropriate action found for the hotkey runAction( it->second ); diff --git a/common/tool/context_menu.cpp b/common/tool/context_menu.cpp index 25ef5b0a0f..d01bc3f0ef 100644 --- a/common/tool/context_menu.cpp +++ b/common/tool/context_menu.cpp @@ -62,13 +62,15 @@ CONTEXT_MENU::CONTEXT_MENU( const CONTEXT_MENU& aMenu ) : wxEmptyString, wxITEM_NORMAL ) ); } - // Copy tool actions that are available to choose from menu + // Copy tool actions that are available to choose from context menu m_toolActions = aMenu.m_toolActions; } void CONTEXT_MENU::SetTitle( const wxString& aTitle ) { + // TODO handle an empty string (remove title and separator) + // Unfortunately wxMenu::SetTitle() does nothing.. if( m_titleSet ) { @@ -85,12 +87,18 @@ void CONTEXT_MENU::SetTitle( const wxString& aTitle ) void CONTEXT_MENU::Add( const wxString& aLabel, int aId ) { +#ifdef DEBUG + if( m_menu.FindItem( aId ) != NULL ) + wxLogWarning( wxT( "Adding more than one menu entry with the same ID may result in" + "undefined behaviour" ) ); +#endif m_menu.Append( new wxMenuItem( &m_menu, aId, aLabel, wxEmptyString, wxITEM_NORMAL ) ); } void CONTEXT_MENU::Add( const TOOL_ACTION& aAction ) { + /// ID numbers for tool actions need to have a value higher than m_actionId int id = m_actionId + aAction.GetId(); wxString menuEntry; @@ -110,6 +118,7 @@ void CONTEXT_MENU::Clear() { m_titleSet = false; + // Remove all the entries from context menu for( unsigned i = 0; i < m_menu.GetMenuItemCount(); ++i ) m_menu.Destroy( m_menu.FindItemByPosition( 0 ) ); @@ -144,15 +153,18 @@ void CONTEXT_MENU::CMEventHandler::onEvent( wxEvent& aEvent ) if( type == wxEVT_MENU_HIGHLIGHT ) evt = TOOL_EVENT( TC_Command, TA_ContextMenuUpdate, aEvent.GetId() ); + else if( type == wxEVT_COMMAND_MENU_SELECTED ) { if( aEvent.GetId() > m_actionId ) { + // Handling TOOL_ACTIONs if( m_menu->m_toolActions.count( aEvent.GetId() ) == 1 ) evt = m_menu->m_toolActions[aEvent.GetId()]->GetEvent(); } else { + // Handling common menu entries evt = TOOL_EVENT( TC_Command, TA_ContextMenuChoice, aEvent.GetId() ); } } diff --git a/common/tool/tool_dispatcher.cpp b/common/tool/tool_dispatcher.cpp index 638f9d0dd5..09847b8518 100644 --- a/common/tool/tool_dispatcher.cpp +++ b/common/tool/tool_dispatcher.cpp @@ -42,28 +42,41 @@ using boost::optional; struct TOOL_DISPATCHER::ButtonState { ButtonState( TOOL_MouseButtons aButton, const wxEventType& aDownEvent, - const wxEventType& aUpEvent, bool aTriggerMenu = false ) : + const wxEventType& aUpEvent ) : button( aButton ), downEvent( aDownEvent ), - upEvent( aUpEvent ), - triggerContextMenu( aTriggerMenu ) + upEvent( aUpEvent ) {}; + ///> Flag indicating that dragging is active for the given button. bool dragging; + + ///> Flag indicating that the given button is pressed. bool pressed; + ///> Point where dragging has started (in world coordinates). VECTOR2D dragOrigin; + + ///> Point where click event has occurred. VECTOR2D downPosition; + ///> Difference between drag origin point and current mouse position (expressed as distance in + ///> pixels). double dragMaxDelta; + ///> Determines the mouse button for which information are stored. TOOL_MouseButtons button; + + ///> The type of wxEvent that determines mouse button press. wxEventType downEvent; + + ///> The type of wxEvent that determines mouse button release. wxEventType upEvent; - bool triggerContextMenu; - + + ///> Time stamp for the last mouse button press event. wxLongLong downTimestamp; + ///> Restores initial state. void Reset() { dragging = false; @@ -76,7 +89,7 @@ TOOL_DISPATCHER::TOOL_DISPATCHER( TOOL_MANAGER* aToolMgr, PCB_BASE_FRAME* aEditF m_toolMgr( aToolMgr ), m_editFrame( aEditFrame ) { m_buttons.push_back( new ButtonState( MB_Left, wxEVT_LEFT_DOWN, wxEVT_LEFT_UP ) ); - m_buttons.push_back( new ButtonState( MB_Right, wxEVT_RIGHT_DOWN, wxEVT_RIGHT_UP, true ) ); + m_buttons.push_back( new ButtonState( MB_Right, wxEVT_RIGHT_DOWN, wxEVT_RIGHT_UP ) ); m_buttons.push_back( new ButtonState( MB_Middle, wxEVT_MIDDLE_DOWN, wxEVT_MIDDLE_UP ) ); ResetState(); @@ -124,14 +137,14 @@ bool TOOL_DISPATCHER::handleMouseButton( wxEvent& aEvent, int aIndex, bool aMoti wxEventType type = aEvent.GetEventType(); optional evt; bool isClick = false; - + bool up = type == st->upEvent; bool down = type == st->downEvent; - + int mods = decodeModifiers( static_cast( &aEvent ) ); int args = st->button | mods; - if( down ) + if( down ) // Handle mouse button press { st->downTimestamp = wxGetLocalTimeMillis(); st->dragOrigin = m_lastMousePos; @@ -140,7 +153,7 @@ bool TOOL_DISPATCHER::handleMouseButton( wxEvent& aEvent, int aIndex, bool aMoti st->pressed = true; evt = TOOL_EVENT( TC_Mouse, TA_MouseDown, args ); } - else if( up ) + else if( up ) // Handle mouse button release { st->pressed = false; @@ -148,6 +161,7 @@ bool TOOL_DISPATCHER::handleMouseButton( wxEvent& aEvent, int aIndex, bool aMoti { wxLongLong t = wxGetLocalTimeMillis(); + // Determine if it was just a single click or beginning of dragging if( t - st->downTimestamp < DragTimeThreshold && st->dragMaxDelta < DragDistanceThreshold ) isClick = true; @@ -156,7 +170,6 @@ bool TOOL_DISPATCHER::handleMouseButton( wxEvent& aEvent, int aIndex, bool aMoti } else isClick = true; - if( isClick ) evt = TOOL_EVENT( TC_Mouse, TA_MouseClick, args ); @@ -208,6 +221,7 @@ void TOOL_DISPATCHER::DispatchWxEvent( wxEvent& aEvent ) { VECTOR2D screenPos = m_toolMgr->GetViewControls()->GetCursorPosition(); VECTOR2D pos = getView()->ToWorld( screenPos ); + if( pos != m_lastMousePos || type == KiGfx::WX_VIEW_CONTROLS::EVT_REFRESH_MOUSE ) { motion = true; @@ -251,7 +265,7 @@ void TOOL_DISPATCHER::DispatchWxEvent( wxEvent& aEvent ) } -void TOOL_DISPATCHER::DispatchWxCommand( wxCommandEvent& aEvent ) +void TOOL_DISPATCHER::DispatchWxCommand( const wxCommandEvent& aEvent ) { bool activateTool = false; std::string toolName; diff --git a/common/tool/tool_event.cpp b/common/tool/tool_event.cpp index cf40310534..00397f8ee4 100644 --- a/common/tool/tool_event.cpp +++ b/common/tool/tool_event.cpp @@ -25,7 +25,7 @@ #include #include -#include +//#include #include #include diff --git a/common/tool/tool_manager.cpp b/common/tool/tool_manager.cpp index e261e37c2c..4e4985ad52 100644 --- a/common/tool/tool_manager.cpp +++ b/common/tool/tool_manager.cpp @@ -288,10 +288,7 @@ void TOOL_MANAGER::dispatchInternal( TOOL_EVENT& aEvent ) st->pendingWait = false; st->waitEvents.clear(); if( st->cofunc && !st->cofunc->Resume() ) - { - // The couroutine has finished - finishTool( st ); - } + finishTool( st ); // The couroutine has finished // If the tool did not request to propagate // the event to other tools, we should stop it now @@ -303,6 +300,7 @@ void TOOL_MANAGER::dispatchInternal( TOOL_EVENT& aEvent ) BOOST_FOREACH( TOOL_STATE* st, m_toolState | boost::adaptors::map_values ) { + // the tool state handler is waiting for events (i.e. called Wait() method) if( !st->pendingWait ) { // no state handler in progress - check if there are any transitions (defined by @@ -324,9 +322,7 @@ void TOOL_MANAGER::dispatchInternal( TOOL_EVENT& aEvent ) st->cofunc->Call( aEvent ); if( !st->cofunc->Running() ) - { - finishTool( st ); - } + finishTool( st ); // The couroutine has finished } } } diff --git a/include/geometry/shape_index.h b/include/geometry/shape_index.h index 6f505fb574..578c237685 100644 --- a/include/geometry/shape_index.h +++ b/include/geometry/shape_index.h @@ -93,28 +93,27 @@ void acceptVisitor( T object, V visitor ) * @param minDistance minimum collision distance * @return if object and anotherObject collide */ -template +template bool collide( T object, U anotherObject, int minDistance ) { - return shapeFunctor(object)->Collide( anotherObject, minDistance ); + return shapeFunctor( object )->Collide( anotherObject, minDistance ); } template -bool queryCallback(T shape, void* context) { +bool queryCallback(T shape, void* context) +{ V* visitor = (V*) context; - acceptVisitor(shape, *visitor); + acceptVisitor( shape, *visitor ); + return true; } -template +template class SHAPE_INDEX { - public: - class Iterator { private: - typedef typename RTree::Iterator RTreeIterator; RTreeIterator iterator; @@ -124,20 +123,21 @@ class SHAPE_INDEX { * Setup the internal tree iterator. * @param tree pointer to a RTREE object */ - void Init(RTree* tree) { - tree->GetFirst(iterator); + void Init( RTree* tree ) + { + tree->GetFirst( iterator ); } public: - /** * Iterator constructor * * Creates an iterator for the index object * @param index SHAPE_INDEX object to iterate */ - Iterator(SHAPE_INDEX* index) { - Init(index->m_tree); + Iterator( SHAPE_INDEX* index ) + { + Init( index->m_tree ); } /** @@ -145,7 +145,8 @@ class SHAPE_INDEX { * * Returns the next data element. */ - T operator*() { + T operator*() + { return *iterator; } @@ -154,7 +155,8 @@ class SHAPE_INDEX { * * Shifts the iterator to the next element. */ - bool operator++() { + bool operator++() + { return ++iterator; } @@ -163,7 +165,8 @@ class SHAPE_INDEX { * * Shifts the iterator to the next element. */ - bool operator++(int) { + bool operator++( int ) + { return ++iterator; } @@ -173,7 +176,8 @@ class SHAPE_INDEX { * Checks if the iterator has reached the end. * @return true if it is in an invalid position (data finished) */ - bool IsNull() { + bool IsNull() + { return iterator.IsNull(); } @@ -183,7 +187,8 @@ class SHAPE_INDEX { * Checks if the iterator has not reached the end. * @return true if it is in an valid position (data not finished) */ - bool IsNotNull() { + bool IsNotNull() + { return iterator.IsNotNull(); } @@ -192,12 +197,13 @@ class SHAPE_INDEX { * * Returns the current element of the iterator and moves to the next * position. - * @return SHAPE object pointed by the iterator before moving to the - * next position. + * @return SHAPE object pointed by the iterator before moving to the next position. */ - T Next() { + T Next() + { T object = *iterator; ++iterator; + return object; } }; @@ -210,17 +216,17 @@ class SHAPE_INDEX { * Function Add() * * Adds a SHAPE to the index. - * @param shape the new SHAPE + * @param aShape is the new SHAPE. */ - void Add( T shape ); + void Add( T aShape ); /** * Function Remove() * * Removes a SHAPE to the index. - * @param shape the new SHAPE + * @param aShape is the new SHAPE. */ - void Remove( T shape ); + void Remove( T aShape ); /** * Function RemoveAll() @@ -236,12 +242,14 @@ class SHAPE_INDEX { * @param visitor Visitor object to be run */ template - void Accept( V visitor ) + void Accept( V aVisitor ) { Iterator iter = this->Begin(); - while(!iter.IsNull()) { + + while( !iter.IsNull() ) + { T shape = *iter; - acceptVisitor(shape, visitor); + acceptVisitor( shape, aVisitor ); iter++; } } @@ -262,17 +270,16 @@ class SHAPE_INDEX { * @param minDistance distance threshold * @param visitor object to be invoked on every object contained in the search area. */ - - template - int Query( const SHAPE *shape, int minDistance, V& visitor, bool aExact ) + template + int Query( const SHAPE *aShape, int aMinDistance, V& aVisitor, bool aExact ) { - BOX2I box = shape->BBox(); - box.Inflate(minDistance); + BOX2I box = aShape->BBox(); + box.Inflate( aMinDistance ); - int min[2] = {box.GetX(), box.GetY()}; - int max[2] = {box.GetRight(), box.GetBottom()}; + int min[2] = { box.GetX(), box.GetY() }; + int max[2] = { box.GetRight(), box.GetBottom() }; - return this->m_tree->Search(min, max, visitor); + return this->m_tree->Search( min, max, aVisitor ); } /** @@ -284,7 +291,6 @@ class SHAPE_INDEX { Iterator Begin(); private: - RTree* m_tree; }; @@ -293,58 +299,68 @@ class SHAPE_INDEX { */ template -SHAPE_INDEX::SHAPE_INDEX() { +SHAPE_INDEX::SHAPE_INDEX() +{ this->m_tree = new RTree(); } template -SHAPE_INDEX::~SHAPE_INDEX() { +SHAPE_INDEX::~SHAPE_INDEX() +{ delete this->m_tree; } template -void SHAPE_INDEX::Add(T shape) { - BOX2I box = boundingBox(shape); - int min[2]= {box.GetX(), box.GetY()}; - int max[2] = {box.GetRight(), box.GetBottom()}; - this->m_tree->Insert(min, max, shape); +void SHAPE_INDEX::Add( T aShape ) +{ + BOX2I box = boundingBox( aShape ); + int min[2] = { box.GetX(), box.GetY() }; + int max[2] = { box.GetRight(), box.GetBottom() }; + + this->m_tree->Insert( min, max, aShape ); } template -void SHAPE_INDEX::Remove(T shape) { - BOX2I box = boundingBox(shape); - int min[2]= {box.GetX(), box.GetY()}; - int max[2] = {box.GetRight(), box.GetBottom()}; - this->m_tree->Remove(min, max, shape); +void SHAPE_INDEX::Remove(T aShape) +{ + BOX2I box = boundingBox( aShape ); + int min[2] = { box.GetX(), box.GetY() }; + int max[2] = { box.GetRight(), box.GetBottom() }; + + this->m_tree->Remove( min, max, aShape ); } template -void SHAPE_INDEX::RemoveAll() { +void SHAPE_INDEX::RemoveAll() +{ this->m_tree->RemoveAll(); } template -void SHAPE_INDEX::Reindex() { +void SHAPE_INDEX::Reindex() +{ RTree* newTree; newTree = new RTree(); Iterator iter = this->Begin(); - while(!iter.IsNull()) { + while( !iter.IsNull() ) + { T shape = *iter; - BOX2I box = boundingBox(shape); - int min[2]= {box.GetX(), box.GetY()}; - int max[2] = {box.GetRight(), box.GetBottom()}; - newTree->Insert(min, max, shape); + BOX2I box = boundingBox( shape ); + int min[2] = { box.GetX(), box.GetY() }; + int max[2] = { box.GetRight(), box.GetBottom() }; + newTree->Insert( min, max, shape ); iter++; } + delete this->m_tree; this->m_tree = newTree; } template -typename SHAPE_INDEX::Iterator SHAPE_INDEX::Begin() { - return Iterator(this); +typename SHAPE_INDEX::Iterator SHAPE_INDEX::Begin() +{ + return Iterator( this ); } - #endif diff --git a/include/geometry/shape_line_chain.h b/include/geometry/shape_line_chain.h index 54e4662b23..ab865ae555 100644 --- a/include/geometry/shape_line_chain.h +++ b/include/geometry/shape_line_chain.h @@ -43,7 +43,6 @@ * SHAPE_LINE_CHAIN class shall not be used for polygons! */ class SHAPE_LINE_CHAIN : public SHAPE { - private: typedef std::vector::iterator point_iter; typedef std::vector::const_iterator point_citer; @@ -55,7 +54,8 @@ class SHAPE_LINE_CHAIN : public SHAPE { * * Represents an intersection between two line segments */ - struct Intersection { + struct Intersection + { /// segment belonging from the (this) argument of Intersect() SEG our; /// segment belonging from the aOther argument of Intersect() @@ -71,45 +71,45 @@ class SHAPE_LINE_CHAIN : public SHAPE { * Initializes an empty line chain. */ SHAPE_LINE_CHAIN(): - SHAPE (SH_LINE_CHAIN), m_closed(false) {}; + SHAPE( SH_LINE_CHAIN ), m_closed( false ) {}; /** * Copy Constructor */ - SHAPE_LINE_CHAIN(const SHAPE_LINE_CHAIN& aShape): - SHAPE (SH_LINE_CHAIN), m_points(aShape.m_points), m_closed(aShape.m_closed) {}; + SHAPE_LINE_CHAIN( const SHAPE_LINE_CHAIN& aShape ) : + SHAPE( SH_LINE_CHAIN ), m_points( aShape.m_points ), m_closed( aShape.m_closed ) {}; /** * Constructor * Initializes a 2-point line chain (a single segment) */ - SHAPE_LINE_CHAIN(const VECTOR2I& a, const VECTOR2I& b): - SHAPE (SH_LINE_CHAIN), - m_closed(false) + SHAPE_LINE_CHAIN( const VECTOR2I& aA, const VECTOR2I& aB ) : + SHAPE( SH_LINE_CHAIN ), + m_closed( false ) { - m_points.resize(2); - m_points[0] = a; - m_points[1] = b; + m_points.resize( 2 ); + m_points[0] = aA; + m_points[1] = aB; } - SHAPE_LINE_CHAIN(const VECTOR2I& a, const VECTOR2I& b, const VECTOR2I& c): - SHAPE (SH_LINE_CHAIN), - m_closed(false) + SHAPE_LINE_CHAIN( const VECTOR2I& aA, const VECTOR2I& aB, const VECTOR2I& aC ): + SHAPE( SH_LINE_CHAIN ), + m_closed( false ) { - m_points.resize(3); - m_points[0] = a; - m_points[1] = b; - m_points[2] = c; + m_points.resize( 3 ); + m_points[0] = aA; + m_points[1] = aB; + m_points[2] = aC; } - - SHAPE_LINE_CHAIN(const VECTOR2I *v, int count): - SHAPE (SH_LINE_CHAIN), - m_closed(false) + SHAPE_LINE_CHAIN(const VECTOR2I* aV, int aCount ) : + SHAPE( SH_LINE_CHAIN ), + m_closed( false ) { - m_points.resize(count); - for(int i = 0; i < count ; i++) - m_points[i] = *v++; + m_points.resize( aCount ); + + for( int i = 0; i < aCount; i++ ) + m_points[i] = *aV++; } ~SHAPE_LINE_CHAIN() {}; @@ -118,7 +118,8 @@ class SHAPE_LINE_CHAIN : public SHAPE { * Function Clear() * Removes all points from the line chain. */ - void Clear() { + void Clear() + { m_points.clear(); m_closed = false; } @@ -129,7 +130,7 @@ class SHAPE_LINE_CHAIN : public SHAPE { * Marks the line chain as closed (i.e. with a segment connecting the last point with the first point). * @param aClosed: whether the line chain is to be closed or not. */ - void SetClosed(bool aClosed) + void SetClosed( bool aClosed ) { m_closed = aClosed; } @@ -153,9 +154,10 @@ class SHAPE_LINE_CHAIN : public SHAPE { int SegmentCount() const { int c = m_points.size() - 1; - if(m_closed) + if( m_closed ) c++; - return std::max(0, c); + + return std::max( 0, c ); } /** @@ -167,86 +169,88 @@ class SHAPE_LINE_CHAIN : public SHAPE { int PointCount() const { return m_points.size(); - }; + } /** * Function Segment() * * Returns a segment referencing to the segment (index) in the line chain. * Modifying ends of the returned segment will modify corresponding points in the line chain. - * @param index: index of the segment in the line chain. Negative values are counted from the end (i.e. -1 means + * @param aIndex: index of the segment in the line chain. Negative values are counted from the end (i.e. -1 means * the last segment in the line chain) * @return SEG referenced to given segment in the line chain */ - SEG Segment ( int index ) + SEG Segment( int aIndex ) { - if(index < 0) - index += SegmentCount(); + if( aIndex < 0 ) + aIndex += SegmentCount(); - if(index == (m_points.size() - 1) && m_closed ) - return SEG ( m_points[index], m_points[0], index ); + if( aIndex == ( m_points.size() - 1 ) && m_closed ) + return SEG( m_points[aIndex], m_points[0], aIndex ); else - return SEG ( m_points[index], m_points[index + 1], index ); + return SEG( m_points[aIndex], m_points[aIndex + 1], aIndex ); } /** * Function CSegment() * * Returns a read-only segment referencing to the segment (index) in the line chain. - * @param index: index of the segment in the line chain. Negative values are counted from the end (i.e. -1 means + * @param aIndex: index of the segment in the line chain. Negative values are counted from the end (i.e. -1 means * the last segment in the line chain) * @return SEG referenced to given segment in the line chain */ - const SEG CSegment ( int index ) const + const SEG CSegment( int aIndex ) const { - if(index < 0) - index += SegmentCount(); + if( aIndex < 0 ) + aIndex += SegmentCount(); - if(index == (m_points.size() - 1) && m_closed ) - return SEG ( const_cast(m_points[index]), - const_cast(m_points[0]), index ); + if( aIndex == ( m_points.size() - 1 ) && m_closed ) + return SEG( const_cast( m_points[aIndex] ), + const_cast( m_points[0] ), aIndex ); else - return SEG ( const_cast(m_points[index]), - const_cast(m_points[index + 1]), index ); + return SEG( const_cast( m_points[aIndex] ), + const_cast( m_points[aIndex + 1] ), aIndex ); } /** * Function Point() * * Returns a reference to a given point in the line chain. - * @param index index of the point + * @param aIndex index of the point * @return reference to the point */ - VECTOR2I& Point ( int index ) + VECTOR2I& Point( int aIndex ) { - if(index < 0) - index += PointCount(); - return m_points[index]; + if( aIndex < 0 ) + aIndex += PointCount(); + + return m_points[aIndex]; } /** * Function CPoint() * * Returns a const reference to a given point in the line chain. - * @param index index of the point + * @param aIndex index of the point * @return const reference to the point */ - const VECTOR2I& CPoint ( int index ) const + const VECTOR2I& CPoint( int aIndex ) const { - if(index < 0) - index += PointCount(); - return m_points[index]; + if( aIndex < 0 ) + aIndex += PointCount(); + + return m_points[aIndex]; } /// @copydoc SHAPE::BBox() - const BOX2I BBox ( int aClearance = 0 ) const + const BOX2I BBox( int aClearance = 0 ) const { BOX2I bbox; - bbox.Compute(m_points); + bbox.Compute( m_points ); + return bbox; } - /** * Function Collide() * @@ -255,7 +259,7 @@ class SHAPE_LINE_CHAIN : public SHAPE { * @param aClearance minimum distance that does not qualify as a collision. * @return true, when a collision has been found */ - bool Collide ( const VECTOR2I& aP, int aClearance = 0 ) const; + bool Collide( const VECTOR2I& aP, int aClearance = 0 ) const; /** * Function Collide() @@ -265,7 +269,7 @@ class SHAPE_LINE_CHAIN : public SHAPE { * @param aClearance minimum distance that does not qualify as a collision. * @return true, when a collision has been found */ - bool Collide ( const BOX2I& aBox, int aClearance = 0 ) const; + bool Collide( const BOX2I& aBox, int aClearance = 0 ) const; /** * Function Collide() @@ -275,9 +279,8 @@ class SHAPE_LINE_CHAIN : public SHAPE { * @param aClearance minimum distance that does not qualify as a collision. * @return true, when a collision has been found */ - bool Collide ( const SEG& aSeg, int aClearance = 0 ) const; + bool Collide( const SEG& aSeg, int aClearance = 0 ) const; - /** * Function Distance() * @@ -285,7 +288,7 @@ class SHAPE_LINE_CHAIN : public SHAPE { * @param aP the point * @return minimum distance. */ - int Distance( const VECTOR2I & aP ) const; + int Distance( const VECTOR2I& aP ) const; /** * Function Reverse() @@ -307,13 +310,13 @@ class SHAPE_LINE_CHAIN : public SHAPE { * Function Append() * * Appends a new point at the end of the line chain. - * @param x X coordinate of the new point - * @param y Y coordinate of the new point + * @param aX is X coordinate of the new point + * @param aY is Y coordinate of the new point */ - void Append(int x, int y) + void Append( int aX, int aY ) { - VECTOR2I v(x, y); - Append(v); + VECTOR2I v( aX, aY ); + Append( v ); } /** @@ -322,15 +325,15 @@ class SHAPE_LINE_CHAIN : public SHAPE { * Appends a new point at the end of the line chain. * @param aP the new point */ - void Append(const VECTOR2I& aP) + void Append( const VECTOR2I& aP ) { - if(m_points.size() == 0) - m_bbox = BOX2I(aP, VECTOR2I(0, 0)); + if( m_points.size() == 0 ) + m_bbox = BOX2I( aP, VECTOR2I( 0, 0 ) ); - if (m_points.size() == 0 || CPoint(-1) != aP) + if( m_points.size() == 0 || CPoint( -1 ) != aP ) { - m_points.push_back(aP); - m_bbox.Merge(aP); + m_points.push_back( aP ); + m_bbox.Merge( aP ); } } @@ -340,22 +343,23 @@ class SHAPE_LINE_CHAIN : public SHAPE { * Appends another line chain at the end. * @param aOtherLine the line chain to be appended. */ - void Append(const SHAPE_LINE_CHAIN& aOtherLine) + void Append( const SHAPE_LINE_CHAIN& aOtherLine ) { - if(aOtherLine.PointCount() == 0) + if( aOtherLine.PointCount() == 0 ) return; - else if(PointCount() == 0 || aOtherLine.CPoint(0) != CPoint(-1)) + + else if( PointCount() == 0 || aOtherLine.CPoint( 0 ) != CPoint( -1 ) ) { - const VECTOR2I p = aOtherLine.CPoint(0); - m_points.push_back(p); - m_bbox.Merge(p); + const VECTOR2I p = aOtherLine.CPoint( 0 ); + m_points.push_back( p ); + m_bbox.Merge( p ); } - for(int i = 1; i m_points; + /// is the line chain closed? bool m_closed; + /// cached bounding box BOX2I m_bbox; }; diff --git a/include/tool/action_manager.h b/include/tool/action_manager.h index 78943a92fa..9f54c1f305 100644 --- a/include/tool/action_manager.h +++ b/include/tool/action_manager.h @@ -43,21 +43,21 @@ public: /** * Function RegisterAction() - * Adds a tool action to the manager set and sets it up. After that is is possible to invoke - * the action using hotkeys or its name. + * Adds a tool action to the manager and sets it up. After that is is possible to invoke + * the action using hotkeys or sending a command event with its name. * @param aAction: action to be added. Ownership is not transferred. */ void RegisterAction( TOOL_ACTION* aAction ); /** * Function UnregisterAction() - * Removes a tool action from the manager set and makes it unavailable for further usage. + * Removes a tool action from the manager and makes it unavailable for further usage. * @param aAction: action to be removed. */ void UnregisterAction( TOOL_ACTION* aAction ); /** - * Generates an unique ID from for a tool with given name. + * Generates an unique ID from for an action with given name. */ static int MakeActionId( const std::string& aActionName ); @@ -82,9 +82,16 @@ public: bool RunHotKey( int aHotKey ) const; private: + ///> Tool manager needed to run actions TOOL_MANAGER* m_toolMgr; + + ///> Map for indexing actions by their IDs std::map m_actionIdIndex; + + ///> Map for indexing actions by their names std::map m_actionNameIndex; + + ///> Map for indexing actions by their hotkeys std::map m_actionHotKeys; /** diff --git a/include/tool/context_menu.h b/include/tool/context_menu.h index cf4d752405..d4d5e2b532 100644 --- a/include/tool/context_menu.h +++ b/include/tool/context_menu.h @@ -29,7 +29,6 @@ #include #include -class wxMenu; class TOOL_INTERACTIVE; /** @@ -40,53 +39,102 @@ class TOOL_INTERACTIVE; */ class CONTEXT_MENU { - public: + ///> Default constructor CONTEXT_MENU(); + + ///> Copy constructor CONTEXT_MENU( const CONTEXT_MENU& aMenu ); + /** + * Function SetTitle() + * Sets title for the context menu. The title is shown as a text label shown on the top of + * the menu. + * @param aTitle is the new title. + */ void SetTitle( const wxString& aTitle ); + + /** + * Function Add() + * Adds an entry to the menu. After highlighting/selecting the entry, a TOOL_EVENT command is + * sent that contains ID of the entry. + * @param aLabel is the text label show in the menu. + * @param aId is the ID that is sent in the TOOL_EVENT. It should be unique for every entry. + */ void Add( const wxString& aLabel, int aId ); + + /** + * Function Add() + * Adds an entry to the menu, basing on the TOOL_ACTION object. After selecting the entry, + * a TOOL_EVENT command containing name of the action is sent. + * @param aAction is the action to be added to menu entry. + */ void Add( const TOOL_ACTION& aAction ); + + /** + * Function Clear() + * Removes all the entries from the menu (as well as its title). It leaves the menu in the + * initial state. + */ void Clear(); + /** + * Function GetMenu() + * Returns the instance of wxMenu object used to display the menu. + */ wxMenu* GetMenu() const { return const_cast( &m_menu ); } private: + ///> Class CMEventHandler takes care of handling menu events. After reception of particular + ///> events, it translates them to TOOL_EVENTs that may control tools. class CMEventHandler : public wxEvtHandler { public: + ///> Default constructor + ///> aMenu is the CONTEXT_MENU instance for which it handles events. CMEventHandler( CONTEXT_MENU* aMenu ) : m_menu( aMenu ) {}; + ///> Handler for menu events. void onEvent( wxEvent& aEvent ); private: + ///> CONTEXT_MENU instance for which it handles events. CONTEXT_MENU* m_menu; }; friend class TOOL_INTERACTIVE; + /** + * Function setTool() + * Sets a tool that is the creator of the menu. + * @param aTool is the tool that created the menu. + */ void setTool( TOOL_INTERACTIVE* aTool ) { m_tool = aTool; } /** + * Function getHotKeyDescription() * Returns a hot key in the string format accepted by wxMenu. - * - * @param aAction is the action with hot key to be converted. + * @param aAction is the action with hot key to be translated.. * @return Hot key in the string format compatible with wxMenu. */ std::string getHotKeyDescription( const TOOL_ACTION& aAction ) const; - /// Flag indicating that the menu title was set up + ///> Flag indicating that the menu title was set up. bool m_titleSet; + ///> Instance of wxMenu used for display of the context menu. wxMenu m_menu; + + ///> Instance of menu event handler. CMEventHandler m_handler; + + ///> Creator of the menu TOOL_INTERACTIVE* m_tool; /// Menu items with ID higher than that are considered TOOL_ACTIONs diff --git a/include/tool/tool_base.h b/include/tool/tool_base.h index 1b9da87305..ff26d95e59 100644 --- a/include/tool/tool_base.h +++ b/include/tool/tool_base.h @@ -42,17 +42,21 @@ class VIEW_CONTROLS; enum TOOL_Type { - TOOL_Interactive = 0x1, - TOOL_Batch = 0x2 + ///> Tool that interacts with the user + TOOL_Interactive = 0x01, + + ///> Tool that runs in the background without any user intervention + TOOL_Batch = 0x02 }; +/// Unique identifier for tools typedef int TOOL_ID; typedef DELEGATE TOOL_STATE_FUNC; /** * Class TOOL_BASE * - * Base abstract interface for all kinds of tools + * Base abstract interface for all kinds of tools. */ class TOOL_BASE @@ -61,25 +65,49 @@ public: TOOL_BASE( TOOL_Type aType, TOOL_ID aId, const std::string& aName = std::string( "" ) ) : m_type( aType ), m_toolId( aId ), - m_toolName( aName ) {}; + m_toolName( aName ), + m_toolMgr( NULL ){}; virtual ~TOOL_BASE() {}; + /** + * Function GetType() + * Returns the type of the tool. + * @return The type of the tool. + */ TOOL_Type GetType() const { return m_type; } + /** + * Function GetId() + * Returns the unique identifier of the tool. The identifier is set by an instance of + * TOOL_MANAGER. + * @return Identifier of the tool. + */ TOOL_ID GetId() const { return m_toolId; } + /** + * Function GetName() + * Returns the name of the tool. Tool names are expected to obey the format: + * application.ToolName (eg. pcbnew.InteractiveSelection). + * @return The name of the tool. + */ const std::string& GetName() const { return m_toolName; } + /** + * Function GetManager() + * Returns the instance of TOOL_MANAGER that takes care of the tool. + * @return Instance of the TOOL_MANAGER. If there is no TOOL_MANAGER associated, it returns + * NULL. + */ TOOL_MANAGER* GetManager() const { return m_toolMgr; @@ -96,14 +124,27 @@ protected: */ void attachManager( TOOL_MANAGER* aManager ); + /** + * Function getView() + * + * Returns the instance of VIEW object used in the application. It allows tools to draw. + * @return The instance of VIEW. + */ KiGfx::VIEW* getView() const; + + /** + * Function getViewControls() + * + * Returns the instance of VIEW_CONTROLS object used in the application. It allows tools to + * read & modify user input and its settings (eg. show cursor, enable snapping to grid, etc.) + * @return The instance of VIEW_CONTROLS. + */ KiGfx::VIEW_CONTROLS* getViewControls() const; /** * Function getEditFrame() * - * Returns the application window object, casted to requested user type, possibly with - * run-time type check + * Returns the application window object, casted to requested user type. */ template T* getEditFrame() const @@ -124,8 +165,14 @@ protected: return static_cast( m ); } + ///> Stores the type of the tool. TOOL_Type m_type; + + ///> Unique identifier for the tool, assigned by a TOOL_MANAGER instance. TOOL_ID m_toolId; + + ///> Name of the tool. Names are expected to obey the format application.ToolName + ///> (eg. pcbnew.InteractiveSelection). std::string m_toolName; TOOL_MANAGER* m_toolMgr; diff --git a/include/tool/tool_dispatcher.h b/include/tool/tool_dispatcher.h index a95464f38e..ac298226ae 100644 --- a/include/tool/tool_dispatcher.h +++ b/include/tool/tool_dispatcher.h @@ -29,7 +29,6 @@ #include -//#include #include class TOOL_MANAGER; @@ -61,26 +60,62 @@ public: TOOL_DISPATCHER( TOOL_MANAGER* aToolMgr, PCB_BASE_FRAME* aEditFrame ); virtual ~TOOL_DISPATCHER(); + /** + * Function ResetState() + * Brings the dispatcher to its initial state. + */ virtual void ResetState(); + + /** + * Function DispatchWxEvent() + * Processes wxEvents (mostly UI events), translates them to TOOL_EVENTs, and makes tools + * handle those. + * @param aEvent is the wxWidgets event to be processed. + */ virtual void DispatchWxEvent( wxEvent& aEvent ); - virtual void DispatchWxCommand( wxCommandEvent& aEvent ); + + /** + * Function DispatchWxCommand() + * Processes wxCommands (mostly menu related events) and runs appropriate actions (eg. run the + * specified tool). + * @param aEvent is the wxCommandEvent to be processed. + */ + virtual void DispatchWxCommand( const wxCommandEvent& aEvent ); private: + ///> Number of mouse buttons that is handled in events. static const int MouseButtonCount = 3; + + ///> The time threshold for a mouse button press that distinguishes between a single mouse + ///> click and a beginning of drag event (expressed in milliseconds). static const int DragTimeThreshold = 300; + + ///> The distance threshold for mouse cursor that disinguishes between a single mouse click + ///> and a beginning of drag event (expressed in screen pixels). static const int DragDistanceThreshold = 8; + ///> Handles mouse related events (click, motion, dragging) bool handleMouseButton( wxEvent& aEvent, int aIndex, bool aMotion ); - bool handlePopupMenu( wxEvent& aEvent ); + ///> Saves the state of key modifiers (Alt, Ctrl and so on). int decodeModifiers( const wxKeyboardState* aState ) const; + ///> Stores all the informations regarding a mouse button state. struct ButtonState; + + ///> The last mouse cursor position (in world coordinates). VECTOR2D m_lastMousePos; + + ///> State of mouse buttons. std::vector m_buttons; + ///> Returns the instance of VIEW, used by the application. KiGfx::VIEW* getView(); + + ///> Instance of tool manager that cooperates with the dispatcher. TOOL_MANAGER* m_toolMgr; + + ///> Instance of wxFrame that is the source of UI events. PCB_BASE_FRAME* m_editFrame; }; diff --git a/include/tool/tool_event.h b/include/tool/tool_event.h index 15438c8dd8..609b72326a 100644 --- a/include/tool/tool_event.h +++ b/include/tool/tool_event.h @@ -29,6 +29,7 @@ #include #include +#include #include @@ -71,17 +72,19 @@ enum TOOL_Actions TA_ViewDirty = 0x0800, TA_ChangeLayer = 0x1000, - // Tool cancel event. Issued automagically when the user hits escape or selects End Tool from the context menu. + // Tool cancel event. Issued automagically when the user hits escape or selects End Tool from + // the context menu. TA_CancelTool = 0x2000, - // Context menu update. Issued whenever context menu is open and the user hovers the mouse over one of choices. - // Used in dynamic highligting in disambiguation menu + // Context menu update. Issued whenever context menu is open and the user hovers the mouse + // over one of choices. Used in dynamic highligting in disambiguation menu TA_ContextMenuUpdate = 0x4000, - // Context menu choice. Sent if the user picked something from the context menu or closed it without selecting anything. + // Context menu choice. Sent if the user picked something from the context menu or + // closed it without selecting anything. TA_ContextMenuChoice = 0x8000, - // Tool action + // Tool action (allows to control tools) TA_Action = 0x10000, TA_Any = 0xffffffff @@ -129,6 +132,12 @@ enum CONTEXT_MENU_TRIGGER class TOOL_EVENT { public: + /** + * Function Format() + * Returns information about event in form of a human-readable string. + * + * @return Event information. + */ const std::string Format() const; TOOL_EVENT( TOOL_EventCategory aCategory = TC_None, TOOL_Actions aAction = TA_None, @@ -175,33 +184,44 @@ public: m_commandStr = aExtraParam; } + ///> Returns the category (eg. mouse/keyboard/action) of an event.. TOOL_EventCategory Category() const { return m_category; } + ///> Returns more specific information about the type of an event. TOOL_Actions Action() const { return m_actions; } + ///> Returns information about difference between current mouse cursor position and the place + ///> where dragging has started. const VECTOR2D Delta() const { + assert( m_category == TC_Mouse ); // this should be used only with mouse events return m_mouseDelta; } + ///> Returns mouse cursor position in world coordinates. const VECTOR2D& Position() const { + assert( m_category == TC_Mouse ); // this should be used only with mouse events return m_mousePos; } + ///> Returns the point where dragging has started. const VECTOR2D& DragOrigin() const { + assert( m_category == TC_Mouse ); // this should be used only with mouse events return m_mouseDragOrigin; } + ///> Returns information about mouse buttons state. int Buttons() const { + assert( m_category == TC_Mouse ); // this should be used only with mouse events return m_mouseButtons; } @@ -231,6 +251,7 @@ public: return m_actions == TA_CancelTool; } + ///> Returns information about key modifiers state (Ctrl, Alt, etc.) int Modifier( int aMask = MD_ModifierMask ) const { return ( m_modifiers & aMask ); @@ -251,8 +272,6 @@ public: return m_actions == TA_KeyDown; } - void Ignore(); - void SetMouseDragOrigin( const VECTOR2D &aP ) { m_mouseDragOrigin = aP; @@ -268,6 +287,13 @@ public: m_mouseDelta = aP; } + /** + * Function Matches() + * Tests whether two events match in terms of category & action or command. + * + * @param aEvent is the event to test against. + * @return True if two events match, false otherwise. + */ bool Matches( const TOOL_EVENT& aEvent ) const { if( !( m_category & aEvent.m_category ) ) @@ -299,13 +325,25 @@ private: TOOL_Actions m_actions; TOOL_ActionScope m_scope; + ///> Difference between mouse cursor position and + ///> the point where dragging event has started VECTOR2D m_mouseDelta; + + ///> Current mouse cursor position VECTOR2D m_mousePos; + + ///> Point where dragging has started VECTOR2D m_mouseDragOrigin; + ///> State of mouse buttons int m_mouseButtons; + + ///> Stores code of pressed/released key int m_keyCode; + + ///> State of key modifierts (Ctrl/Alt/etc.) int m_modifiers; + boost::optional m_commandId; boost::optional m_commandStr; }; @@ -324,7 +362,10 @@ public: typedef std::deque::iterator iterator; typedef std::deque::const_iterator const_iterator; + ///> Default constructor. Creates an empty list. TOOL_EVENT_LIST() {}; + + ///> Constructor for a list containing only one TOOL_EVENT. TOOL_EVENT_LIST( const TOOL_EVENT& aSingleEvent ) { m_events.push_back( aSingleEvent ); @@ -346,6 +387,11 @@ public: return boost::optional(); } + /** + * Function Add() + * Adds a tool event to the list. + * @param aEvent is the tool event to be addded. + */ void Add( const TOOL_EVENT& aEvent ) { m_events.push_back( aEvent ); diff --git a/include/tool/tool_interactive.h b/include/tool/tool_interactive.h index 14fd2dccbb..7915f225a8 100644 --- a/include/tool/tool_interactive.h +++ b/include/tool/tool_interactive.h @@ -35,6 +35,10 @@ class CONTEXT_MENU; class TOOL_INTERACTIVE : public TOOL_BASE { public: + /** + * Constructor + * + * Creates a tool with given id & name. The name must be unique. */ TOOL_INTERACTIVE( TOOL_ID aId, const std::string& aName ); /** @@ -46,8 +50,8 @@ public: /** * Function Reset() - * Brings the tool to a known, initial state. If the tool claimed anything from the model or the view, - * it must release it when its reset. + * Brings the tool to a known, initial state. If the tool claimed anything from + * the model or the view, it must release it when its reset. */ virtual void Reset() = 0; @@ -65,7 +69,9 @@ public: /** * Function SetContextMenu() * - * Assigns a context menu and tells when it should be activated + * Assigns a context menu and tells when it should be activated. + * @param aMenu is the menu to be assigned. + * @param aTrigger determines conditions upon which the context menu is activated. */ void SetContextMenu( CONTEXT_MENU* aMenu, CONTEXT_MENU_TRIGGER aTrigger = CMENU_BUTTON ); @@ -87,9 +93,8 @@ public: */ OPT_TOOL_EVENT Wait( const TOOL_EVENT_LIST& aEventList = TOOL_EVENT ( TC_Any, TA_Any ) ); - /** functions below are not yet implemented - their interface may change */ - template + /*template bool InvokeTool( const std::string& aToolName, const Parameters& parameters, ReturnValue& returnValue ); @@ -98,11 +103,10 @@ public: ReturnValue& returnValue ); template - void Yield( const T& returnValue ); + void Yield( const T& returnValue );*/ protected: - /* helper functions for constructing events for Wait() and Go() with - less typing */ + /* helper functions for constructing events for Wait() and Go() with less typing */ const TOOL_EVENT evActivate( std::string aToolName = "" ); const TOOL_EVENT evCommand( int aCommandId = -1 ); const TOOL_EVENT evCommand( std::string aCommandStr = "" ); diff --git a/pcbnew/tools/move_tool.cpp b/pcbnew/tools/move_tool.cpp index 96e348a941..69d2d00dba 100644 --- a/pcbnew/tools/move_tool.cpp +++ b/pcbnew/tools/move_tool.cpp @@ -36,6 +36,8 @@ using boost::optional; MOVE_TOOL::MOVE_TOOL() : TOOL_INTERACTIVE( "pcbnew.InteractiveMove" ), m_selectionTool( NULL ), + + // Available actions: m_activate( m_toolName, AS_GLOBAL, 'M', "Move", "Moves the selected item(s)" ), m_rotate( m_toolName + ".rotate", AS_CONTEXT, ' ', "Rotate", "Rotates selected item(s)" ), m_flip( m_toolName + ".flip", AS_CONTEXT, 'F', "Flip", "Flips selected item(s)" ) @@ -69,7 +71,7 @@ bool MOVE_TOOL::Init() m_toolMgr->RegisterAction( &m_rotate ); m_toolMgr->RegisterAction( &m_flip ); - // Add context menu entries for the selection tool + // Add context menu entries that are displayed when selection tool is active m_selectionTool->AddMenuItem( m_activate ); m_selectionTool->AddMenuItem( m_rotate ); m_selectionTool->AddMenuItem( m_flip ); @@ -92,7 +94,9 @@ int MOVE_TOOL::Main( TOOL_EVENT& aEvent ) VIEW* view = getView(); VIEW_CONTROLS* controls = getViewControls(); + // Add a VIEW_GROUP that will hold all modified items view->Add( &m_items ); + controls->ShowCursor( true ); controls->SetSnapping( true ); controls->SetAutoPan( true ); @@ -102,7 +106,7 @@ int MOVE_TOOL::Main( TOOL_EVENT& aEvent ) { if( evt->IsCancel() ) { - restore = true; + restore = true; // Cancelling the tool means that items have to be restored break; // Finish } @@ -111,12 +115,12 @@ int MOVE_TOOL::Main( TOOL_EVENT& aEvent ) { VECTOR2D cursorPos = getView()->ToWorld( getViewControls()->GetCursorPosition() ); - if( evt->Matches( m_rotate.GetEvent() ) ) + if( evt->Matches( m_rotate.GetEvent() ) ) // got rotation event? { m_state.Rotate( cursorPos, 900.0 ); m_items.ViewUpdate( VIEW_ITEM::GEOMETRY ); } - else if( evt->Matches( m_flip.GetEvent() ) ) + else if( evt->Matches( m_flip.GetEvent() ) ) // got flip event? { m_state.Flip( cursorPos ); m_items.ViewUpdate( VIEW_ITEM::GEOMETRY ); @@ -165,20 +169,22 @@ int MOVE_TOOL::Main( TOOL_EVENT& aEvent ) // Restore visibility of the original items vgSetVisibility( &m_items, true ); - // Movement has to be rollbacked, so restore the previous state of items if( restore ) { + // Modifications has to be rollbacked, so restore the previous state of items vgUpdate( &m_items, VIEW_ITEM::APPEARANCE ); m_state.RestoreAll(); } else { + // Changes are applied, so update the items vgUpdate( &m_items, m_state.GetUpdateFlag() ); m_state.Apply(); } m_items.Clear(); view->Remove( &m_items ); + controls->ShowCursor( false ); controls->SetSnapping( false ); controls->SetAutoPan( false ); diff --git a/pcbnew/tools/selection_area.h b/pcbnew/tools/selection_area.h index 10079dccd5..6c0f4dcf06 100644 --- a/pcbnew/tools/selection_area.h +++ b/pcbnew/tools/selection_area.h @@ -50,6 +50,7 @@ public: virtual const BOX2I ViewBBox() const; void ViewDraw( int aLayer, KiGfx::GAL* aGal ) const; + void ViewGetLayers( int aLayers[], int& aCount ) const; void SetOrigin ( VECTOR2I aOrigin ) diff --git a/pcbnew/tools/selection_tool.cpp b/pcbnew/tools/selection_tool.cpp index 72cc54a1be..c1133de729 100644 --- a/pcbnew/tools/selection_tool.cpp +++ b/pcbnew/tools/selection_tool.cpp @@ -83,7 +83,6 @@ bool SELECTION_TOOL::Init() int SELECTION_TOOL::Main( TOOL_EVENT& aEvent ) { BOARD* board = getModel( PCB_T ); - assert( board != NULL ); // Main loop: keep receiving events @@ -116,13 +115,16 @@ int SELECTION_TOOL::Main( TOOL_EVENT& aEvent ) } else { + // Check if dragging has started within any of selected items bounding box if( containsSelected( evt->Position() ) ) { + // Yes -> run the move tool and wait till it finishes m_toolMgr->InvokeTool( "pcbnew.InteractiveMove" ); Wait(); } else { + // No -> clear the selection list clearSelection(); } } @@ -135,7 +137,7 @@ int SELECTION_TOOL::Main( TOOL_EVENT& aEvent ) void SELECTION_TOOL::AddMenuItem( const TOOL_ACTION& aAction ) { - assert( aAction.GetId() > 0 ); // Check if the action was registered before + assert( aAction.GetId() > 0 ); // Check if the action was registered before in ACTION_MANAGER m_menu.Add( aAction ); } @@ -259,9 +261,9 @@ BOARD_ITEM* SELECTION_TOOL::pickSmallestComponent( GENERAL_COLLECTOR* aCollector bool SELECTION_TOOL::selectMultiple() { - VIEW* view = getView(); - bool cancelled = false; + bool cancelled = false; // Was the tool cancelled while it was running? m_multiple = true; // Multiple selection mode is active + VIEW* view = getView(); getViewControls()->SetAutoPan( true ); // Those 2 lines remove the blink-in-the-random-place effect @@ -291,7 +293,7 @@ bool SELECTION_TOOL::selectMultiple() if( evt->IsMouseUp( MB_Left ) ) { - // End drawing a selection box + // End drawing the selection box m_selArea->ViewSetVisible( false ); // Mark items within the selection box as selected @@ -315,6 +317,7 @@ bool SELECTION_TOOL::selectMultiple() // Now the context menu should be enabled if( !m_selectedItems.empty() ) SetContextMenu( &m_menu, CMENU_BUTTON ); + break; } } @@ -367,6 +370,7 @@ BOARD_ITEM* SELECTION_TOOL::disambiguationMenu( GENERAL_COLLECTOR* aCollector ) { optional id = evt->GetCommandId(); + // User has selected an item, so this one will be returned if( id && ( *id >= 0 ) ) current = ( *aCollector )[*id]; @@ -392,11 +396,12 @@ BOARD_ITEM* SELECTION_TOOL::disambiguationMenu( GENERAL_COLLECTOR* aCollector ) bool SELECTION_TOOL::selectable( const BOARD_ITEM* aItem ) const { + // Is high contrast mode enabled? bool highContrast = getView()->GetPainter()->GetSettings()->GetHighContrast(); if( highContrast ) { - bool onActive = false; + bool onActive = false; // Is the item on any of active layers? int layers[KiGfx::VIEW::VIEW_MAX_LAYERS], layers_count; // Filter out items that do not belong to active layers @@ -406,14 +411,14 @@ bool SELECTION_TOOL::selectable( const BOARD_ITEM* aItem ) const for( int i = 0; i < layers_count; ++i ) { - if( activeLayers.count( layers[i] ) > 0 ) // Item is on at least one active layer + if( activeLayers.count( layers[i] ) > 0 ) // Item is on at least one of active layers { onActive = true; break; } } - if( !onActive ) + if( !onActive ) // We do not want to select items that are in the background return false; } @@ -426,8 +431,7 @@ bool SELECTION_TOOL::selectable( const BOARD_ITEM* aItem ) const LAYER_NUM top, bottom; static_cast( aItem )->ReturnLayerPair( &top, &bottom ); - return ( board->IsLayerVisible( top ) || - board->IsLayerVisible( bottom ) ); + return ( board->IsLayerVisible( top ) || board->IsLayerVisible( bottom ) ); } break; @@ -473,8 +477,7 @@ bool SELECTION_TOOL::containsSelected( const VECTOR2I& aPoint ) const { // Check if the point is located within any of the currently selected items bounding boxes std::set::iterator it, it_end; - for( it = m_selectedItems.begin(), it_end = m_selectedItems.end(); - it != it_end; ++it ) + for( it = m_selectedItems.begin(), it_end = m_selectedItems.end(); it != it_end; ++it ) { BOX2I itemBox = (*it)->ViewBBox(); itemBox.Inflate( 500000 ); // Give some margin for gripping an item