Commit 3f320e4d authored by Maciej Suminski's avatar Maciej Suminski

Some more comments and code formatting.

parent 6e0c7a93
...@@ -121,11 +121,6 @@ void EDA_DRAW_PANEL_GAL::onPaint( wxPaintEvent& WXUNUSED( aEvent ) ) ...@@ -121,11 +121,6 @@ void EDA_DRAW_PANEL_GAL::onPaint( wxPaintEvent& WXUNUSED( aEvent ) )
m_pendingRefresh = false; m_pendingRefresh = false;
m_lastRefresh = wxGetLocalTimeMillis(); m_lastRefresh = wxGetLocalTimeMillis();
#ifdef __WXDEBUG__
prof_counter time;
prof_start( &time, false );
#endif /* __WXDEBUG__ */
m_gal->BeginDrawing(); m_gal->BeginDrawing();
m_gal->SetBackgroundColor( KiGfx::COLOR4D( 0.0, 0.0, 0.0, 1.0 ) ); m_gal->SetBackgroundColor( KiGfx::COLOR4D( 0.0, 0.0, 0.0, 1.0 ) );
m_gal->ClearScreen(); m_gal->ClearScreen();
...@@ -138,12 +133,6 @@ void EDA_DRAW_PANEL_GAL::onPaint( wxPaintEvent& WXUNUSED( aEvent ) ) ...@@ -138,12 +133,6 @@ void EDA_DRAW_PANEL_GAL::onPaint( wxPaintEvent& WXUNUSED( aEvent ) )
m_gal->DrawCursor( m_viewControls->GetCursorPosition() ); m_gal->DrawCursor( m_viewControls->GetCursorPosition() );
m_gal->EndDrawing(); m_gal->EndDrawing();
#ifdef __WXDEBUG__
prof_end( &time );
wxLogDebug( wxT( "EDA_DRAW_PANEL_GAL::Refresh: %.0f ms (%.0f fps)" ),
static_cast<double>( time.value ) / 1000.0, 1000000.0 / static_cast<double>( time.value ) );
#endif /* __WXDEBUG__ */
} }
......
...@@ -25,126 +25,128 @@ ...@@ -25,126 +25,128 @@
#include <geometry/seg.h> #include <geometry/seg.h>
template <typename T> int sgn(T val) { template<typename T> int sgn( T val ) {
return (T(0) < val) - (val < T(0)); 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; VECTOR2I d = b - a;
ecoord dist_sq = (ecoord) dist * dist; ecoord dist_sq = (ecoord) dist * dist;
SEG::ecoord l_squared = d.Dot(d); SEG::ecoord l_squared = d.Dot( d );
SEG::ecoord t = d.Dot(aP - a); SEG::ecoord t = d.Dot( aP - a );
if( t <= 0 || !l_squared ) if( t <= 0 || !l_squared )
return (aP - a).SquaredEuclideanNorm() < dist_sq; return ( aP - a ).SquaredEuclideanNorm() < dist_sq;
else if( t >= l_squared ) 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 ca = -sgn( d.y );
int cb = sgn(d.x); int cb = sgn( d.x );
int cc = -ca * a.x - cb * a.y; int cc = -ca * a.x - cb * a.y;
ecoord num = ca * aP.x + cb * aP.y + cc; ecoord num = ca * aP.x + cb * aP.y + cc;
num *= num; num *= num;
if(ca && cb) if( ca && cb )
num >>= 1; num >>= 1;
if(num > (dist_sq + 100)) if( num > ( dist_sq + 100 ) )
return false; return false;
else if(num < (dist_sq - 100)) else if( num < ( dist_sq - 100 ) )
return true; return true;
} }
VECTOR2I nearest; VECTOR2I nearest;
nearest.x = a.x + rescale(t, (ecoord)d.x, l_squared); nearest.x = a.x + rescale( t, (ecoord)d.x, l_squared );
nearest.y = a.y + rescale(t, (ecoord)d.y, 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 SEG::ecoord SEG::SquaredDistance( const SEG& aSeg ) const
{ {
// fixme: rather inefficient.... // fixme: rather inefficient....
if(Intersect(aSeg)) if( Intersect( aSeg ) )
return 0; return 0;
const VECTOR2I pts[4] = const VECTOR2I pts[4] =
{ {
aSeg.NearestPoint(a) - a, aSeg.NearestPoint( a ) - a,
aSeg.NearestPoint(b) - b, aSeg.NearestPoint( b ) - b,
NearestPoint(aSeg.a) - aSeg.a, NearestPoint( aSeg.a ) - aSeg.a,
NearestPoint(aSeg.b) - aSeg.b NearestPoint( aSeg.b ) - aSeg.b
}; };
ecoord m = VECTOR2I::ECOORD_MAX; ecoord m = VECTOR2I::ECOORD_MAX;
for (int i = 0; i<4 ; i++) for( int i = 0; i < 4; i++ )
m = std::min(m, pts[i].SquaredEuclideanNorm()); m = std::min( m, pts[i].SquaredEuclideanNorm() );
return m;
return m;
} }
OPT_VECTOR2I SEG::Intersect( const SEG& aSeg, bool aIgnoreEndpoints, bool aLines ) const OPT_VECTOR2I SEG::Intersect( const SEG& aSeg, bool aIgnoreEndpoints, bool aLines ) const
{ {
const VECTOR2I e (b - a); const VECTOR2I e ( b - a );
const VECTOR2I f (aSeg.b - aSeg.a); const VECTOR2I f ( aSeg.b - aSeg.a );
const VECTOR2I ac (aSeg.a - a); const VECTOR2I ac ( aSeg.a - a );
ecoord d = f.Cross(e); ecoord d = f.Cross( e );
ecoord p = f.Cross(ac); ecoord p = f.Cross( ac );
ecoord q = e.Cross(ac); ecoord q = e.Cross( ac );
if(d == 0) if( d == 0 )
return OPT_VECTOR2I(); 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(); 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(); 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(); return OPT_VECTOR2I();
VECTOR2I ip ( aSeg.a.x + rescale(q, (ecoord)f.x, d), VECTOR2I ip( aSeg.a.x + rescale( q, (ecoord)f.x, d ),
aSeg.a.y + rescale(q, (ecoord)f.y, d) ); aSeg.a.y + rescale( q, (ecoord)f.y, d ) );
return ip; 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 bool SEG::Collide( const SEG& aSeg, int aClearance ) const
{ {
// check for intersection // check for intersection
// fixme: move to a method // 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; return true;
#define CHK(_seg, _pt) \ #define CHK(_seg, _pt) \
if( (_seg).PointCloserThan (_pt, aClearance ) ) return true; if( (_seg).PointCloserThan (_pt, aClearance ) ) return true;
CHK(*this, aSeg.a); CHK( *this, aSeg.a );
CHK(*this, aSeg.b); CHK( *this, aSeg.b );
CHK(aSeg, a); CHK( aSeg, a );
CHK(aSeg, b); CHK( aSeg, b );
#undef CHK #undef CHK
return false; return false;
} }
bool SEG::Contains(const VECTOR2I& aP) const
{
return PointCloserThan(aP, 1);
}
bool SEG::Contains( const VECTOR2I& aP ) const
{
return PointCloserThan( aP, 1 );
}
...@@ -31,7 +31,8 @@ ...@@ -31,7 +31,8 @@
typedef VECTOR2I::extended_type ecoord; 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 = clearance + a.GetRadius() + b.GetRadius();
ecoord min_dist_sq = min_dist * min_dist; 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 ...@@ -44,12 +45,13 @@ static inline bool Collide( const SHAPE_CIRCLE& a, const SHAPE_CIRCLE& b, int cl
return false; return false;
if ( needMTV ) 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; 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 c = b.GetCenter();
const VECTOR2I p0 = a.GetPosition(); const VECTOR2I p0 = a.GetPosition();
...@@ -58,7 +60,7 @@ static inline bool Collide( const SHAPE_RECT& a, const SHAPE_CIRCLE& b, int cle ...@@ -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 = clearance + r;
const ecoord min_dist_sq = min_dist * min_dist; const ecoord min_dist_sq = min_dist * min_dist;
if (a.BBox(0).Contains(c)) if ( a.BBox( 0 ).Contains( c ) )
return true; return true;
const VECTOR2I vts[] = { const VECTOR2I vts[] = {
...@@ -71,73 +73,77 @@ static inline bool Collide( const SHAPE_RECT& a, const SHAPE_CIRCLE& b, int cle ...@@ -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; ecoord nearest_seg_dist_sq = VECTOR2I::ECOORD_MAX;
VECTOR2I nearest; VECTOR2I nearest;
bool inside = c.x >= p0.x && c.x <= (p0.x + size.x) bool inside = c.x >= p0.x && c.x <= ( p0.x + size.x )
&& c.y >= p0.y && c.y <= (p0.y + size.y); && 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]); const SEG seg( vts[i], vts[i+1] );
ecoord dist_sq = seg.SquaredDistance ( c ); ecoord dist_sq = seg.SquaredDistance( c );
if( dist_sq < min_dist_sq )
if(dist_sq < min_dist_sq)
{ {
if(!needMTV) if( !needMTV )
return true; return true;
else else
{ {
nearest = seg.NearestPoint ( c ); nearest = seg.NearestPoint( c );
nearest_seg_dist_sq = dist_sq; 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; return false;
VECTOR2I delta = c - nearest; VECTOR2I delta = c - nearest;
if(!needMTV) if( !needMTV )
return true; return true;
if(inside) if( inside )
aMTV = -delta.Resize(sqrt(abs(r * r + nearest_seg_dist_sq) + 1)); aMTV = -delta.Resize( sqrt( abs( r * r + nearest_seg_dist_sq ) + 1 ) );
else 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; 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 true;
} }
return false; 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++) for( int i = 0; i < b.SegmentCount(); i++ )
if(a.Collide(b.CSegment(i), clearance)) if( a.Collide( b.CSegment(i), clearance ) )
return true; return true;
return false; 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); SEG seg = b.CSegment( s );
if ( a.Collide (seg, clearance)) if( a.Collide( seg, clearance ) )
return true; return true;
} }
...@@ -145,66 +151,83 @@ static inline bool Collide( const SHAPE_RECT& a, const SHAPE_LINE_CHAIN& b, int ...@@ -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: case SH_RECT:
switch(b->Type()) switch( b->Type() )
{ {
case SH_CIRCLE: case SH_CIRCLE:
return Collide( *static_cast<const SHAPE_RECT *> (a), *static_cast<const SHAPE_CIRCLE *> (b), clearance, needMTV, aMTV ); return Collide( *static_cast<const SHAPE_RECT*>( a ),
*static_cast<const SHAPE_CIRCLE*>( b ), clearance, needMTV, aMTV );
case SH_LINE_CHAIN: case SH_LINE_CHAIN:
return Collide( *static_cast<const SHAPE_RECT *> (a), *static_cast<const SHAPE_LINE_CHAIN *> (b), clearance, needMTV, aMTV ); return Collide( *static_cast<const SHAPE_RECT*>( a ),
*static_cast<const SHAPE_LINE_CHAIN*>( b ), clearance, needMTV, aMTV );
default: default:
break; break;
} }
case SH_CIRCLE: case SH_CIRCLE:
switch(b->Type()) switch( b->Type() )
{ {
case SH_RECT: case SH_RECT:
return Collide( *static_cast<const SHAPE_RECT *> (b), *static_cast<const SHAPE_CIRCLE *> (a), clearance, needMTV, aMTV ); return Collide( *static_cast<const SHAPE_RECT*>( b ),
*static_cast<const SHAPE_CIRCLE*>( a ), clearance, needMTV, aMTV );
case SH_CIRCLE: case SH_CIRCLE:
return Collide( *static_cast<const SHAPE_CIRCLE *> (a), *static_cast<const SHAPE_CIRCLE *> (b), clearance, needMTV, aMTV ); return Collide( *static_cast<const SHAPE_CIRCLE*>( a ),
*static_cast<const SHAPE_CIRCLE*>( b ), clearance, needMTV, aMTV );
case SH_LINE_CHAIN: case SH_LINE_CHAIN:
return Collide( *static_cast<const SHAPE_CIRCLE *> (a), *static_cast<const SHAPE_LINE_CHAIN *> (b), clearance, needMTV, aMTV ); return Collide( *static_cast<const SHAPE_CIRCLE*>( a ),
*static_cast<const SHAPE_LINE_CHAIN *>( b ), clearance, needMTV, aMTV );
default: default:
break; break;
} }
case SH_LINE_CHAIN: case SH_LINE_CHAIN:
switch(b->Type()) switch( b->Type() )
{ {
case SH_RECT: case SH_RECT:
return Collide( *static_cast<const SHAPE_RECT *> (b), *static_cast<const SHAPE_LINE_CHAIN *> (a), clearance, needMTV, aMTV ); return Collide( *static_cast<const SHAPE_RECT*>( b ),
*static_cast<const SHAPE_LINE_CHAIN*>( a ), clearance, needMTV, aMTV );
case SH_CIRCLE: case SH_CIRCLE:
return Collide( *static_cast<const SHAPE_CIRCLE *> (b), *static_cast<const SHAPE_LINE_CHAIN *> (a), clearance, needMTV, aMTV ); return Collide( *static_cast<const SHAPE_CIRCLE*>( b ),
*static_cast<const SHAPE_LINE_CHAIN*>( a ), clearance, needMTV, aMTV );
case SH_LINE_CHAIN: case SH_LINE_CHAIN:
return Collide( *static_cast<const SHAPE_LINE_CHAIN *> (a), *static_cast<const SHAPE_LINE_CHAIN *> (b), clearance, needMTV, aMTV ); return Collide( *static_cast<const SHAPE_LINE_CHAIN*>( a ),
*static_cast<const SHAPE_LINE_CHAIN*>( b ), clearance, needMTV, aMTV );
default: default:
break; break;
} }
default: default:
break; break;
} }
bool unsupported_collision = true; bool unsupported_collision = true;
assert(unsupported_collision == false); assert( unsupported_collision == false );
return 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); 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; VECTOR2I dummy;
return CollideShapes( this, aShape, aClerance, false, dummy); return CollideShapes( this, aShape, aClerance, false, dummy );
} }
...@@ -30,4 +30,3 @@ const SHAPE* shapeFunctor( SHAPE* aItem ) ...@@ -30,4 +30,3 @@ const SHAPE* shapeFunctor( SHAPE* aItem )
{ {
return aItem; return aItem;
} }
This diff is collapsed.
...@@ -52,8 +52,9 @@ void ACTION_MANAGER::RegisterAction( TOOL_ACTION* aAction ) ...@@ -52,8 +52,9 @@ void ACTION_MANAGER::RegisterAction( TOOL_ACTION* aAction )
void ACTION_MANAGER::UnregisterAction( TOOL_ACTION* aAction ) void ACTION_MANAGER::UnregisterAction( TOOL_ACTION* aAction )
{ {
// Indicate that we no longer care about the object // Indicate that the ACTION_MANAGER no longer care about the object
aAction->setActionMgr( NULL ); aAction->setActionMgr( NULL );
aAction->setId( -1 );
m_actionNameIndex.erase( aAction->m_name ); m_actionNameIndex.erase( aAction->m_name );
m_actionIdIndex.erase( aAction->m_id ); m_actionIdIndex.erase( aAction->m_id );
...@@ -75,7 +76,7 @@ bool ACTION_MANAGER::RunAction( const std::string& aActionName ) const ...@@ -75,7 +76,7 @@ bool ACTION_MANAGER::RunAction( const std::string& aActionName ) const
std::map<std::string, TOOL_ACTION*>::const_iterator it = m_actionNameIndex.find( aActionName ); std::map<std::string, TOOL_ACTION*>::const_iterator it = m_actionNameIndex.find( aActionName );
if( it == m_actionNameIndex.end() ) if( it == m_actionNameIndex.end() )
return false; return false; // no action with given name found
runAction( it->second ); runAction( it->second );
...@@ -88,7 +89,7 @@ bool ACTION_MANAGER::RunHotKey( int aHotKey ) const ...@@ -88,7 +89,7 @@ bool ACTION_MANAGER::RunHotKey( int aHotKey ) const
std::map<int, TOOL_ACTION*>::const_iterator it = m_actionHotKeys.find( aHotKey ); std::map<int, TOOL_ACTION*>::const_iterator it = m_actionHotKeys.find( aHotKey );
if( it == m_actionHotKeys.end() ) if( it == m_actionHotKeys.end() )
return false; return false; // no appropriate action found for the hotkey
runAction( it->second ); runAction( it->second );
......
...@@ -62,13 +62,15 @@ CONTEXT_MENU::CONTEXT_MENU( const CONTEXT_MENU& aMenu ) : ...@@ -62,13 +62,15 @@ CONTEXT_MENU::CONTEXT_MENU( const CONTEXT_MENU& aMenu ) :
wxEmptyString, wxITEM_NORMAL ) ); 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; m_toolActions = aMenu.m_toolActions;
} }
void CONTEXT_MENU::SetTitle( const wxString& aTitle ) void CONTEXT_MENU::SetTitle( const wxString& aTitle )
{ {
// TODO handle an empty string (remove title and separator)
// Unfortunately wxMenu::SetTitle() does nothing.. // Unfortunately wxMenu::SetTitle() does nothing..
if( m_titleSet ) if( m_titleSet )
{ {
...@@ -85,12 +87,18 @@ void CONTEXT_MENU::SetTitle( const wxString& aTitle ) ...@@ -85,12 +87,18 @@ void CONTEXT_MENU::SetTitle( const wxString& aTitle )
void CONTEXT_MENU::Add( const wxString& aLabel, int aId ) 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 ) ); m_menu.Append( new wxMenuItem( &m_menu, aId, aLabel, wxEmptyString, wxITEM_NORMAL ) );
} }
void CONTEXT_MENU::Add( const TOOL_ACTION& aAction ) 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(); int id = m_actionId + aAction.GetId();
wxString menuEntry; wxString menuEntry;
...@@ -110,6 +118,7 @@ void CONTEXT_MENU::Clear() ...@@ -110,6 +118,7 @@ void CONTEXT_MENU::Clear()
{ {
m_titleSet = false; m_titleSet = false;
// Remove all the entries from context menu
for( unsigned i = 0; i < m_menu.GetMenuItemCount(); ++i ) for( unsigned i = 0; i < m_menu.GetMenuItemCount(); ++i )
m_menu.Destroy( m_menu.FindItemByPosition( 0 ) ); m_menu.Destroy( m_menu.FindItemByPosition( 0 ) );
...@@ -144,15 +153,18 @@ void CONTEXT_MENU::CMEventHandler::onEvent( wxEvent& aEvent ) ...@@ -144,15 +153,18 @@ void CONTEXT_MENU::CMEventHandler::onEvent( wxEvent& aEvent )
if( type == wxEVT_MENU_HIGHLIGHT ) if( type == wxEVT_MENU_HIGHLIGHT )
evt = TOOL_EVENT( TC_Command, TA_ContextMenuUpdate, aEvent.GetId() ); evt = TOOL_EVENT( TC_Command, TA_ContextMenuUpdate, aEvent.GetId() );
else if( type == wxEVT_COMMAND_MENU_SELECTED ) else if( type == wxEVT_COMMAND_MENU_SELECTED )
{ {
if( aEvent.GetId() > m_actionId ) if( aEvent.GetId() > m_actionId )
{ {
// Handling TOOL_ACTIONs
if( m_menu->m_toolActions.count( aEvent.GetId() ) == 1 ) if( m_menu->m_toolActions.count( aEvent.GetId() ) == 1 )
evt = m_menu->m_toolActions[aEvent.GetId()]->GetEvent(); evt = m_menu->m_toolActions[aEvent.GetId()]->GetEvent();
} }
else else
{ {
// Handling common menu entries
evt = TOOL_EVENT( TC_Command, TA_ContextMenuChoice, aEvent.GetId() ); evt = TOOL_EVENT( TC_Command, TA_ContextMenuChoice, aEvent.GetId() );
} }
} }
......
...@@ -42,28 +42,41 @@ using boost::optional; ...@@ -42,28 +42,41 @@ using boost::optional;
struct TOOL_DISPATCHER::ButtonState struct TOOL_DISPATCHER::ButtonState
{ {
ButtonState( TOOL_MouseButtons aButton, const wxEventType& aDownEvent, ButtonState( TOOL_MouseButtons aButton, const wxEventType& aDownEvent,
const wxEventType& aUpEvent, bool aTriggerMenu = false ) : const wxEventType& aUpEvent ) :
button( aButton ), button( aButton ),
downEvent( aDownEvent ), downEvent( aDownEvent ),
upEvent( aUpEvent ), upEvent( aUpEvent )
triggerContextMenu( aTriggerMenu )
{}; {};
///> Flag indicating that dragging is active for the given button.
bool dragging; bool dragging;
///> Flag indicating that the given button is pressed.
bool pressed; bool pressed;
///> Point where dragging has started (in world coordinates).
VECTOR2D dragOrigin; VECTOR2D dragOrigin;
///> Point where click event has occurred.
VECTOR2D downPosition; VECTOR2D downPosition;
///> Difference between drag origin point and current mouse position (expressed as distance in
///> pixels).
double dragMaxDelta; double dragMaxDelta;
///> Determines the mouse button for which information are stored.
TOOL_MouseButtons button; TOOL_MouseButtons button;
///> The type of wxEvent that determines mouse button press.
wxEventType downEvent; wxEventType downEvent;
///> The type of wxEvent that determines mouse button release.
wxEventType upEvent; wxEventType upEvent;
bool triggerContextMenu;
///> Time stamp for the last mouse button press event.
wxLongLong downTimestamp; wxLongLong downTimestamp;
///> Restores initial state.
void Reset() void Reset()
{ {
dragging = false; dragging = false;
...@@ -76,7 +89,7 @@ TOOL_DISPATCHER::TOOL_DISPATCHER( TOOL_MANAGER* aToolMgr, PCB_BASE_FRAME* aEditF ...@@ -76,7 +89,7 @@ TOOL_DISPATCHER::TOOL_DISPATCHER( TOOL_MANAGER* aToolMgr, PCB_BASE_FRAME* aEditF
m_toolMgr( aToolMgr ), m_editFrame( aEditFrame ) 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_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 ) ); m_buttons.push_back( new ButtonState( MB_Middle, wxEVT_MIDDLE_DOWN, wxEVT_MIDDLE_UP ) );
ResetState(); ResetState();
...@@ -124,14 +137,14 @@ bool TOOL_DISPATCHER::handleMouseButton( wxEvent& aEvent, int aIndex, bool aMoti ...@@ -124,14 +137,14 @@ bool TOOL_DISPATCHER::handleMouseButton( wxEvent& aEvent, int aIndex, bool aMoti
wxEventType type = aEvent.GetEventType(); wxEventType type = aEvent.GetEventType();
optional<TOOL_EVENT> evt; optional<TOOL_EVENT> evt;
bool isClick = false; bool isClick = false;
bool up = type == st->upEvent; bool up = type == st->upEvent;
bool down = type == st->downEvent; bool down = type == st->downEvent;
int mods = decodeModifiers( static_cast<wxMouseEvent*>( &aEvent ) ); int mods = decodeModifiers( static_cast<wxMouseEvent*>( &aEvent ) );
int args = st->button | mods; int args = st->button | mods;
if( down ) if( down ) // Handle mouse button press
{ {
st->downTimestamp = wxGetLocalTimeMillis(); st->downTimestamp = wxGetLocalTimeMillis();
st->dragOrigin = m_lastMousePos; st->dragOrigin = m_lastMousePos;
...@@ -140,7 +153,7 @@ bool TOOL_DISPATCHER::handleMouseButton( wxEvent& aEvent, int aIndex, bool aMoti ...@@ -140,7 +153,7 @@ bool TOOL_DISPATCHER::handleMouseButton( wxEvent& aEvent, int aIndex, bool aMoti
st->pressed = true; st->pressed = true;
evt = TOOL_EVENT( TC_Mouse, TA_MouseDown, args ); evt = TOOL_EVENT( TC_Mouse, TA_MouseDown, args );
} }
else if( up ) else if( up ) // Handle mouse button release
{ {
st->pressed = false; st->pressed = false;
...@@ -148,6 +161,7 @@ bool TOOL_DISPATCHER::handleMouseButton( wxEvent& aEvent, int aIndex, bool aMoti ...@@ -148,6 +161,7 @@ bool TOOL_DISPATCHER::handleMouseButton( wxEvent& aEvent, int aIndex, bool aMoti
{ {
wxLongLong t = wxGetLocalTimeMillis(); wxLongLong t = wxGetLocalTimeMillis();
// Determine if it was just a single click or beginning of dragging
if( t - st->downTimestamp < DragTimeThreshold && if( t - st->downTimestamp < DragTimeThreshold &&
st->dragMaxDelta < DragDistanceThreshold ) st->dragMaxDelta < DragDistanceThreshold )
isClick = true; isClick = true;
...@@ -156,7 +170,6 @@ bool TOOL_DISPATCHER::handleMouseButton( wxEvent& aEvent, int aIndex, bool aMoti ...@@ -156,7 +170,6 @@ bool TOOL_DISPATCHER::handleMouseButton( wxEvent& aEvent, int aIndex, bool aMoti
} }
else else
isClick = true; isClick = true;
if( isClick ) if( isClick )
evt = TOOL_EVENT( TC_Mouse, TA_MouseClick, args ); evt = TOOL_EVENT( TC_Mouse, TA_MouseClick, args );
...@@ -208,6 +221,7 @@ void TOOL_DISPATCHER::DispatchWxEvent( wxEvent& aEvent ) ...@@ -208,6 +221,7 @@ void TOOL_DISPATCHER::DispatchWxEvent( wxEvent& aEvent )
{ {
VECTOR2D screenPos = m_toolMgr->GetViewControls()->GetCursorPosition(); VECTOR2D screenPos = m_toolMgr->GetViewControls()->GetCursorPosition();
VECTOR2D pos = getView()->ToWorld( screenPos ); VECTOR2D pos = getView()->ToWorld( screenPos );
if( pos != m_lastMousePos || type == KiGfx::WX_VIEW_CONTROLS::EVT_REFRESH_MOUSE ) if( pos != m_lastMousePos || type == KiGfx::WX_VIEW_CONTROLS::EVT_REFRESH_MOUSE )
{ {
motion = true; motion = true;
...@@ -251,7 +265,7 @@ void TOOL_DISPATCHER::DispatchWxEvent( wxEvent& aEvent ) ...@@ -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; bool activateTool = false;
std::string toolName; std::string toolName;
......
...@@ -25,7 +25,7 @@ ...@@ -25,7 +25,7 @@
#include <cstring> #include <cstring>
#include <string> #include <string>
#include <base_struct.h> //#include <base_struct.h>
#include <tool/tool_event.h> #include <tool/tool_event.h>
#include <tool/tool_manager.h> #include <tool/tool_manager.h>
......
...@@ -288,10 +288,7 @@ void TOOL_MANAGER::dispatchInternal( TOOL_EVENT& aEvent ) ...@@ -288,10 +288,7 @@ void TOOL_MANAGER::dispatchInternal( TOOL_EVENT& aEvent )
st->pendingWait = false; st->pendingWait = false;
st->waitEvents.clear(); st->waitEvents.clear();
if( st->cofunc && !st->cofunc->Resume() ) if( st->cofunc && !st->cofunc->Resume() )
{ finishTool( st ); // The couroutine has finished
// The couroutine has finished
finishTool( st );
}
// If the tool did not request to propagate // If the tool did not request to propagate
// the event to other tools, we should stop it now // the event to other tools, we should stop it now
...@@ -303,6 +300,7 @@ void TOOL_MANAGER::dispatchInternal( TOOL_EVENT& aEvent ) ...@@ -303,6 +300,7 @@ void TOOL_MANAGER::dispatchInternal( TOOL_EVENT& aEvent )
BOOST_FOREACH( TOOL_STATE* st, m_toolState | boost::adaptors::map_values ) 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 ) if( !st->pendingWait )
{ {
// no state handler in progress - check if there are any transitions (defined by // no state handler in progress - check if there are any transitions (defined by
...@@ -324,9 +322,7 @@ void TOOL_MANAGER::dispatchInternal( TOOL_EVENT& aEvent ) ...@@ -324,9 +322,7 @@ void TOOL_MANAGER::dispatchInternal( TOOL_EVENT& aEvent )
st->cofunc->Call( aEvent ); st->cofunc->Call( aEvent );
if( !st->cofunc->Running() ) if( !st->cofunc->Running() )
{ finishTool( st ); // The couroutine has finished
finishTool( st );
}
} }
} }
} }
......
...@@ -93,28 +93,27 @@ void acceptVisitor( T object, V visitor ) ...@@ -93,28 +93,27 @@ void acceptVisitor( T object, V visitor )
* @param minDistance minimum collision distance * @param minDistance minimum collision distance
* @return if object and anotherObject collide * @return if object and anotherObject collide
*/ */
template <class T, class U> template<class T, class U>
bool collide( T object, U anotherObject, int minDistance ) bool collide( T object, U anotherObject, int minDistance )
{ {
return shapeFunctor(object)->Collide( anotherObject, minDistance ); return shapeFunctor( object )->Collide( anotherObject, minDistance );
} }
template<class T, class V> template<class T, class V>
bool queryCallback(T shape, void* context) { bool queryCallback(T shape, void* context)
{
V* visitor = (V*) context; V* visitor = (V*) context;
acceptVisitor<T,V>(shape, *visitor); acceptVisitor<T,V>( shape, *visitor );
return true; return true;
} }
template <class T = SHAPE*> template<class T = SHAPE*>
class SHAPE_INDEX { class SHAPE_INDEX {
public: public:
class Iterator class Iterator
{ {
private: private:
typedef typename RTree<T, int, 2, float>::Iterator RTreeIterator; typedef typename RTree<T, int, 2, float>::Iterator RTreeIterator;
RTreeIterator iterator; RTreeIterator iterator;
...@@ -124,20 +123,21 @@ class SHAPE_INDEX { ...@@ -124,20 +123,21 @@ class SHAPE_INDEX {
* Setup the internal tree iterator. * Setup the internal tree iterator.
* @param tree pointer to a RTREE object * @param tree pointer to a RTREE object
*/ */
void Init(RTree<T, int, 2, float>* tree) { void Init( RTree<T, int, 2, float>* tree )
tree->GetFirst(iterator); {
tree->GetFirst( iterator );
} }
public: public:
/** /**
* Iterator constructor * Iterator constructor
* *
* Creates an iterator for the index object * Creates an iterator for the index object
* @param index SHAPE_INDEX object to iterate * @param index SHAPE_INDEX object to iterate
*/ */
Iterator(SHAPE_INDEX* index) { Iterator( SHAPE_INDEX* index )
Init(index->m_tree); {
Init( index->m_tree );
} }
/** /**
...@@ -145,7 +145,8 @@ class SHAPE_INDEX { ...@@ -145,7 +145,8 @@ class SHAPE_INDEX {
* *
* Returns the next data element. * Returns the next data element.
*/ */
T operator*() { T operator*()
{
return *iterator; return *iterator;
} }
...@@ -154,7 +155,8 @@ class SHAPE_INDEX { ...@@ -154,7 +155,8 @@ class SHAPE_INDEX {
* *
* Shifts the iterator to the next element. * Shifts the iterator to the next element.
*/ */
bool operator++() { bool operator++()
{
return ++iterator; return ++iterator;
} }
...@@ -163,7 +165,8 @@ class SHAPE_INDEX { ...@@ -163,7 +165,8 @@ class SHAPE_INDEX {
* *
* Shifts the iterator to the next element. * Shifts the iterator to the next element.
*/ */
bool operator++(int) { bool operator++( int )
{
return ++iterator; return ++iterator;
} }
...@@ -173,7 +176,8 @@ class SHAPE_INDEX { ...@@ -173,7 +176,8 @@ class SHAPE_INDEX {
* Checks if the iterator has reached the end. * Checks if the iterator has reached the end.
* @return true if it is in an invalid position (data finished) * @return true if it is in an invalid position (data finished)
*/ */
bool IsNull() { bool IsNull()
{
return iterator.IsNull(); return iterator.IsNull();
} }
...@@ -183,7 +187,8 @@ class SHAPE_INDEX { ...@@ -183,7 +187,8 @@ class SHAPE_INDEX {
* Checks if the iterator has not reached the end. * Checks if the iterator has not reached the end.
* @return true if it is in an valid position (data not finished) * @return true if it is in an valid position (data not finished)
*/ */
bool IsNotNull() { bool IsNotNull()
{
return iterator.IsNotNull(); return iterator.IsNotNull();
} }
...@@ -192,12 +197,13 @@ class SHAPE_INDEX { ...@@ -192,12 +197,13 @@ class SHAPE_INDEX {
* *
* Returns the current element of the iterator and moves to the next * Returns the current element of the iterator and moves to the next
* position. * position.
* @return SHAPE object pointed by the iterator before moving to the * @return SHAPE object pointed by the iterator before moving to the next position.
* next position.
*/ */
T Next() { T Next()
{
T object = *iterator; T object = *iterator;
++iterator; ++iterator;
return object; return object;
} }
}; };
...@@ -210,17 +216,17 @@ class SHAPE_INDEX { ...@@ -210,17 +216,17 @@ class SHAPE_INDEX {
* Function Add() * Function Add()
* *
* Adds a SHAPE to the index. * 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() * Function Remove()
* *
* Removes a SHAPE to the index. * 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() * Function RemoveAll()
...@@ -236,12 +242,14 @@ class SHAPE_INDEX { ...@@ -236,12 +242,14 @@ class SHAPE_INDEX {
* @param visitor Visitor object to be run * @param visitor Visitor object to be run
*/ */
template<class V> template<class V>
void Accept( V visitor ) void Accept( V aVisitor )
{ {
Iterator iter = this->Begin(); Iterator iter = this->Begin();
while(!iter.IsNull()) {
while( !iter.IsNull() )
{
T shape = *iter; T shape = *iter;
acceptVisitor(shape, visitor); acceptVisitor( shape, aVisitor );
iter++; iter++;
} }
} }
...@@ -262,17 +270,16 @@ class SHAPE_INDEX { ...@@ -262,17 +270,16 @@ class SHAPE_INDEX {
* @param minDistance distance threshold * @param minDistance distance threshold
* @param visitor object to be invoked on every object contained in the search area. * @param visitor object to be invoked on every object contained in the search area.
*/ */
template<class V>
template<class V> int Query( const SHAPE *aShape, int aMinDistance, V& aVisitor, bool aExact )
int Query( const SHAPE *shape, int minDistance, V& visitor, bool aExact )
{ {
BOX2I box = shape->BBox(); BOX2I box = aShape->BBox();
box.Inflate(minDistance); box.Inflate( aMinDistance );
int min[2] = {box.GetX(), box.GetY()}; int min[2] = { box.GetX(), box.GetY() };
int max[2] = {box.GetRight(), box.GetBottom()}; 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 { ...@@ -284,7 +291,6 @@ class SHAPE_INDEX {
Iterator Begin(); Iterator Begin();
private: private:
RTree<T, int, 2, float>* m_tree; RTree<T, int, 2, float>* m_tree;
}; };
...@@ -293,58 +299,68 @@ class SHAPE_INDEX { ...@@ -293,58 +299,68 @@ class SHAPE_INDEX {
*/ */
template<class T> template<class T>
SHAPE_INDEX<T>::SHAPE_INDEX() { SHAPE_INDEX<T>::SHAPE_INDEX()
{
this->m_tree = new RTree<T, int, 2, float>(); this->m_tree = new RTree<T, int, 2, float>();
} }
template<class T> template<class T>
SHAPE_INDEX<T>::~SHAPE_INDEX() { SHAPE_INDEX<T>::~SHAPE_INDEX()
{
delete this->m_tree; delete this->m_tree;
} }
template<class T> template<class T>
void SHAPE_INDEX<T>::Add(T shape) { void SHAPE_INDEX<T>::Add( T aShape )
BOX2I box = boundingBox(shape); {
int min[2]= {box.GetX(), box.GetY()}; BOX2I box = boundingBox( aShape );
int max[2] = {box.GetRight(), box.GetBottom()}; int min[2] = { box.GetX(), box.GetY() };
this->m_tree->Insert(min, max, shape); int max[2] = { box.GetRight(), box.GetBottom() };
this->m_tree->Insert( min, max, aShape );
} }
template<class T> template<class T>
void SHAPE_INDEX<T>::Remove(T shape) { void SHAPE_INDEX<T>::Remove(T aShape)
BOX2I box = boundingBox(shape); {
int min[2]= {box.GetX(), box.GetY()}; BOX2I box = boundingBox( aShape );
int max[2] = {box.GetRight(), box.GetBottom()}; int min[2] = { box.GetX(), box.GetY() };
this->m_tree->Remove(min, max, shape); int max[2] = { box.GetRight(), box.GetBottom() };
this->m_tree->Remove( min, max, aShape );
} }
template<class T> template<class T>
void SHAPE_INDEX<T>::RemoveAll() { void SHAPE_INDEX<T>::RemoveAll()
{
this->m_tree->RemoveAll(); this->m_tree->RemoveAll();
} }
template<class T> template<class T>
void SHAPE_INDEX<T>::Reindex() { void SHAPE_INDEX<T>::Reindex()
{
RTree<T, int, 2, float>* newTree; RTree<T, int, 2, float>* newTree;
newTree = new RTree<T, int, 2, float>(); newTree = new RTree<T, int, 2, float>();
Iterator iter = this->Begin(); Iterator iter = this->Begin();
while(!iter.IsNull()) { while( !iter.IsNull() )
{
T shape = *iter; T shape = *iter;
BOX2I box = boundingBox(shape); BOX2I box = boundingBox( shape );
int min[2]= {box.GetX(), box.GetY()}; int min[2] = { box.GetX(), box.GetY() };
int max[2] = {box.GetRight(), box.GetBottom()}; int max[2] = { box.GetRight(), box.GetBottom() };
newTree->Insert(min, max, shape); newTree->Insert( min, max, shape );
iter++; iter++;
} }
delete this->m_tree; delete this->m_tree;
this->m_tree = newTree; this->m_tree = newTree;
} }
template<class T> template<class T>
typename SHAPE_INDEX<T>::Iterator SHAPE_INDEX<T>::Begin() { typename SHAPE_INDEX<T>::Iterator SHAPE_INDEX<T>::Begin()
return Iterator(this); {
return Iterator( this );
} }
#endif #endif
This diff is collapsed.
...@@ -43,21 +43,21 @@ public: ...@@ -43,21 +43,21 @@ public:
/** /**
* Function RegisterAction() * Function RegisterAction()
* Adds a tool action to the manager set and sets it up. After that is is possible to invoke * Adds a tool action to the manager and sets it up. After that is is possible to invoke
* the action using hotkeys or its name. * the action using hotkeys or sending a command event with its name.
* @param aAction: action to be added. Ownership is not transferred. * @param aAction: action to be added. Ownership is not transferred.
*/ */
void RegisterAction( TOOL_ACTION* aAction ); void RegisterAction( TOOL_ACTION* aAction );
/** /**
* Function UnregisterAction() * 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. * @param aAction: action to be removed.
*/ */
void UnregisterAction( TOOL_ACTION* aAction ); 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 ); static int MakeActionId( const std::string& aActionName );
...@@ -82,9 +82,16 @@ public: ...@@ -82,9 +82,16 @@ public:
bool RunHotKey( int aHotKey ) const; bool RunHotKey( int aHotKey ) const;
private: private:
///> Tool manager needed to run actions
TOOL_MANAGER* m_toolMgr; TOOL_MANAGER* m_toolMgr;
///> Map for indexing actions by their IDs
std::map<int, TOOL_ACTION*> m_actionIdIndex; std::map<int, TOOL_ACTION*> m_actionIdIndex;
///> Map for indexing actions by their names
std::map<std::string, TOOL_ACTION*> m_actionNameIndex; std::map<std::string, TOOL_ACTION*> m_actionNameIndex;
///> Map for indexing actions by their hotkeys
std::map<int, TOOL_ACTION*> m_actionHotKeys; std::map<int, TOOL_ACTION*> m_actionHotKeys;
/** /**
......
...@@ -29,7 +29,6 @@ ...@@ -29,7 +29,6 @@
#include <tool/tool_action.h> #include <tool/tool_action.h>
#include <map> #include <map>
class wxMenu;
class TOOL_INTERACTIVE; class TOOL_INTERACTIVE;
/** /**
...@@ -40,53 +39,102 @@ class TOOL_INTERACTIVE; ...@@ -40,53 +39,102 @@ class TOOL_INTERACTIVE;
*/ */
class CONTEXT_MENU class CONTEXT_MENU
{ {
public: public:
///> Default constructor
CONTEXT_MENU(); CONTEXT_MENU();
///> Copy constructor
CONTEXT_MENU( const CONTEXT_MENU& aMenu ); 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 ); 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 ); 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 ); 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(); void Clear();
/**
* Function GetMenu()
* Returns the instance of wxMenu object used to display the menu.
*/
wxMenu* GetMenu() const wxMenu* GetMenu() const
{ {
return const_cast<wxMenu*>( &m_menu ); return const_cast<wxMenu*>( &m_menu );
} }
private: 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 class CMEventHandler : public wxEvtHandler
{ {
public: public:
///> Default constructor
///> aMenu is the CONTEXT_MENU instance for which it handles events.
CMEventHandler( CONTEXT_MENU* aMenu ) : m_menu( aMenu ) {}; CMEventHandler( CONTEXT_MENU* aMenu ) : m_menu( aMenu ) {};
///> Handler for menu events.
void onEvent( wxEvent& aEvent ); void onEvent( wxEvent& aEvent );
private: private:
///> CONTEXT_MENU instance for which it handles events.
CONTEXT_MENU* m_menu; CONTEXT_MENU* m_menu;
}; };
friend class TOOL_INTERACTIVE; 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 ) void setTool( TOOL_INTERACTIVE* aTool )
{ {
m_tool = aTool; m_tool = aTool;
} }
/** /**
* Function getHotKeyDescription()
* Returns a hot key in the string format accepted by wxMenu. * Returns a hot key in the string format accepted by wxMenu.
* * @param aAction is the action with hot key to be translated..
* @param aAction is the action with hot key to be converted.
* @return Hot key in the string format compatible with wxMenu. * @return Hot key in the string format compatible with wxMenu.
*/ */
std::string getHotKeyDescription( const TOOL_ACTION& aAction ) const; 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; bool m_titleSet;
///> Instance of wxMenu used for display of the context menu.
wxMenu m_menu; wxMenu m_menu;
///> Instance of menu event handler.
CMEventHandler m_handler; CMEventHandler m_handler;
///> Creator of the menu
TOOL_INTERACTIVE* m_tool; TOOL_INTERACTIVE* m_tool;
/// Menu items with ID higher than that are considered TOOL_ACTIONs /// Menu items with ID higher than that are considered TOOL_ACTIONs
......
...@@ -42,17 +42,21 @@ class VIEW_CONTROLS; ...@@ -42,17 +42,21 @@ class VIEW_CONTROLS;
enum TOOL_Type enum TOOL_Type
{ {
TOOL_Interactive = 0x1, ///> Tool that interacts with the user
TOOL_Batch = 0x2 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 int TOOL_ID;
typedef DELEGATE<int, TOOL_EVENT&> TOOL_STATE_FUNC; typedef DELEGATE<int, TOOL_EVENT&> TOOL_STATE_FUNC;
/** /**
* Class TOOL_BASE * Class TOOL_BASE
* *
* Base abstract interface for all kinds of tools * Base abstract interface for all kinds of tools.
*/ */
class TOOL_BASE class TOOL_BASE
...@@ -61,25 +65,49 @@ public: ...@@ -61,25 +65,49 @@ public:
TOOL_BASE( TOOL_Type aType, TOOL_ID aId, const std::string& aName = std::string( "" ) ) : TOOL_BASE( TOOL_Type aType, TOOL_ID aId, const std::string& aName = std::string( "" ) ) :
m_type( aType ), m_type( aType ),
m_toolId( aId ), m_toolId( aId ),
m_toolName( aName ) {}; m_toolName( aName ),
m_toolMgr( NULL ){};
virtual ~TOOL_BASE() {}; virtual ~TOOL_BASE() {};
/**
* Function GetType()
* Returns the type of the tool.
* @return The type of the tool.
*/
TOOL_Type GetType() const TOOL_Type GetType() const
{ {
return m_type; 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 TOOL_ID GetId() const
{ {
return m_toolId; 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 const std::string& GetName() const
{ {
return m_toolName; 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 TOOL_MANAGER* GetManager() const
{ {
return m_toolMgr; return m_toolMgr;
...@@ -96,14 +124,27 @@ protected: ...@@ -96,14 +124,27 @@ protected:
*/ */
void attachManager( TOOL_MANAGER* aManager ); 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; 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; KiGfx::VIEW_CONTROLS* getViewControls() const;
/** /**
* Function getEditFrame() * Function getEditFrame()
* *
* Returns the application window object, casted to requested user type, possibly with * Returns the application window object, casted to requested user type.
* run-time type check
*/ */
template<typename T> template<typename T>
T* getEditFrame() const T* getEditFrame() const
...@@ -124,8 +165,14 @@ protected: ...@@ -124,8 +165,14 @@ protected:
return static_cast<T*>( m ); return static_cast<T*>( m );
} }
///> Stores the type of the tool.
TOOL_Type m_type; TOOL_Type m_type;
///> Unique identifier for the tool, assigned by a TOOL_MANAGER instance.
TOOL_ID m_toolId; TOOL_ID m_toolId;
///> Name of the tool. Names are expected to obey the format application.ToolName
///> (eg. pcbnew.InteractiveSelection).
std::string m_toolName; std::string m_toolName;
TOOL_MANAGER* m_toolMgr; TOOL_MANAGER* m_toolMgr;
......
...@@ -29,7 +29,6 @@ ...@@ -29,7 +29,6 @@
#include <tool/tool_event.h> #include <tool/tool_event.h>
//#include <wx/event.h>
#include <wx/kbdstate.h> #include <wx/kbdstate.h>
class TOOL_MANAGER; class TOOL_MANAGER;
...@@ -61,26 +60,62 @@ public: ...@@ -61,26 +60,62 @@ public:
TOOL_DISPATCHER( TOOL_MANAGER* aToolMgr, PCB_BASE_FRAME* aEditFrame ); TOOL_DISPATCHER( TOOL_MANAGER* aToolMgr, PCB_BASE_FRAME* aEditFrame );
virtual ~TOOL_DISPATCHER(); virtual ~TOOL_DISPATCHER();
/**
* Function ResetState()
* Brings the dispatcher to its initial state.
*/
virtual void ResetState(); 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 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: private:
///> Number of mouse buttons that is handled in events.
static const int MouseButtonCount = 3; 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; 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; static const int DragDistanceThreshold = 8;
///> Handles mouse related events (click, motion, dragging)
bool handleMouseButton( wxEvent& aEvent, int aIndex, bool aMotion ); 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; int decodeModifiers( const wxKeyboardState* aState ) const;
///> Stores all the informations regarding a mouse button state.
struct ButtonState; struct ButtonState;
///> The last mouse cursor position (in world coordinates).
VECTOR2D m_lastMousePos; VECTOR2D m_lastMousePos;
///> State of mouse buttons.
std::vector<ButtonState*> m_buttons; std::vector<ButtonState*> m_buttons;
///> Returns the instance of VIEW, used by the application.
KiGfx::VIEW* getView(); KiGfx::VIEW* getView();
///> Instance of tool manager that cooperates with the dispatcher.
TOOL_MANAGER* m_toolMgr; TOOL_MANAGER* m_toolMgr;
///> Instance of wxFrame that is the source of UI events.
PCB_BASE_FRAME* m_editFrame; PCB_BASE_FRAME* m_editFrame;
}; };
......
...@@ -29,6 +29,7 @@ ...@@ -29,6 +29,7 @@
#include <deque> #include <deque>
#include <math/vector2d.h> #include <math/vector2d.h>
#include <cassert>
#include <boost/optional.hpp> #include <boost/optional.hpp>
...@@ -71,17 +72,19 @@ enum TOOL_Actions ...@@ -71,17 +72,19 @@ enum TOOL_Actions
TA_ViewDirty = 0x0800, TA_ViewDirty = 0x0800,
TA_ChangeLayer = 0x1000, 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, TA_CancelTool = 0x2000,
// Context menu update. Issued whenever context menu is open and the user hovers the mouse over one of choices. // Context menu update. Issued whenever context menu is open and the user hovers the mouse
// Used in dynamic highligting in disambiguation menu // over one of choices. Used in dynamic highligting in disambiguation menu
TA_ContextMenuUpdate = 0x4000, 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, TA_ContextMenuChoice = 0x8000,
// Tool action // Tool action (allows to control tools)
TA_Action = 0x10000, TA_Action = 0x10000,
TA_Any = 0xffffffff TA_Any = 0xffffffff
...@@ -129,6 +132,12 @@ enum CONTEXT_MENU_TRIGGER ...@@ -129,6 +132,12 @@ enum CONTEXT_MENU_TRIGGER
class TOOL_EVENT class TOOL_EVENT
{ {
public: public:
/**
* Function Format()
* Returns information about event in form of a human-readable string.
*
* @return Event information.
*/
const std::string Format() const; const std::string Format() const;
TOOL_EVENT( TOOL_EventCategory aCategory = TC_None, TOOL_Actions aAction = TA_None, TOOL_EVENT( TOOL_EventCategory aCategory = TC_None, TOOL_Actions aAction = TA_None,
...@@ -175,33 +184,44 @@ public: ...@@ -175,33 +184,44 @@ public:
m_commandStr = aExtraParam; m_commandStr = aExtraParam;
} }
///> Returns the category (eg. mouse/keyboard/action) of an event..
TOOL_EventCategory Category() const TOOL_EventCategory Category() const
{ {
return m_category; return m_category;
} }
///> Returns more specific information about the type of an event.
TOOL_Actions Action() const TOOL_Actions Action() const
{ {
return m_actions; return m_actions;
} }
///> Returns information about difference between current mouse cursor position and the place
///> where dragging has started.
const VECTOR2D Delta() const const VECTOR2D Delta() const
{ {
assert( m_category == TC_Mouse ); // this should be used only with mouse events
return m_mouseDelta; return m_mouseDelta;
} }
///> Returns mouse cursor position in world coordinates.
const VECTOR2D& Position() const const VECTOR2D& Position() const
{ {
assert( m_category == TC_Mouse ); // this should be used only with mouse events
return m_mousePos; return m_mousePos;
} }
///> Returns the point where dragging has started.
const VECTOR2D& DragOrigin() const const VECTOR2D& DragOrigin() const
{ {
assert( m_category == TC_Mouse ); // this should be used only with mouse events
return m_mouseDragOrigin; return m_mouseDragOrigin;
} }
///> Returns information about mouse buttons state.
int Buttons() const int Buttons() const
{ {
assert( m_category == TC_Mouse ); // this should be used only with mouse events
return m_mouseButtons; return m_mouseButtons;
} }
...@@ -231,6 +251,7 @@ public: ...@@ -231,6 +251,7 @@ public:
return m_actions == TA_CancelTool; return m_actions == TA_CancelTool;
} }
///> Returns information about key modifiers state (Ctrl, Alt, etc.)
int Modifier( int aMask = MD_ModifierMask ) const int Modifier( int aMask = MD_ModifierMask ) const
{ {
return ( m_modifiers & aMask ); return ( m_modifiers & aMask );
...@@ -251,8 +272,6 @@ public: ...@@ -251,8 +272,6 @@ public:
return m_actions == TA_KeyDown; return m_actions == TA_KeyDown;
} }
void Ignore();
void SetMouseDragOrigin( const VECTOR2D &aP ) void SetMouseDragOrigin( const VECTOR2D &aP )
{ {
m_mouseDragOrigin = aP; m_mouseDragOrigin = aP;
...@@ -268,6 +287,13 @@ public: ...@@ -268,6 +287,13 @@ public:
m_mouseDelta = aP; 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 bool Matches( const TOOL_EVENT& aEvent ) const
{ {
if( !( m_category & aEvent.m_category ) ) if( !( m_category & aEvent.m_category ) )
...@@ -299,13 +325,25 @@ private: ...@@ -299,13 +325,25 @@ private:
TOOL_Actions m_actions; TOOL_Actions m_actions;
TOOL_ActionScope m_scope; TOOL_ActionScope m_scope;
///> Difference between mouse cursor position and
///> the point where dragging event has started
VECTOR2D m_mouseDelta; VECTOR2D m_mouseDelta;
///> Current mouse cursor position
VECTOR2D m_mousePos; VECTOR2D m_mousePos;
///> Point where dragging has started
VECTOR2D m_mouseDragOrigin; VECTOR2D m_mouseDragOrigin;
///> State of mouse buttons
int m_mouseButtons; int m_mouseButtons;
///> Stores code of pressed/released key
int m_keyCode; int m_keyCode;
///> State of key modifierts (Ctrl/Alt/etc.)
int m_modifiers; int m_modifiers;
boost::optional<int> m_commandId; boost::optional<int> m_commandId;
boost::optional<std::string> m_commandStr; boost::optional<std::string> m_commandStr;
}; };
...@@ -324,7 +362,10 @@ public: ...@@ -324,7 +362,10 @@ public:
typedef std::deque<TOOL_EVENT>::iterator iterator; typedef std::deque<TOOL_EVENT>::iterator iterator;
typedef std::deque<TOOL_EVENT>::const_iterator const_iterator; typedef std::deque<TOOL_EVENT>::const_iterator const_iterator;
///> Default constructor. Creates an empty list.
TOOL_EVENT_LIST() {}; TOOL_EVENT_LIST() {};
///> Constructor for a list containing only one TOOL_EVENT.
TOOL_EVENT_LIST( const TOOL_EVENT& aSingleEvent ) TOOL_EVENT_LIST( const TOOL_EVENT& aSingleEvent )
{ {
m_events.push_back( aSingleEvent ); m_events.push_back( aSingleEvent );
...@@ -346,6 +387,11 @@ public: ...@@ -346,6 +387,11 @@ public:
return boost::optional<const TOOL_EVENT&>(); return boost::optional<const TOOL_EVENT&>();
} }
/**
* Function Add()
* Adds a tool event to the list.
* @param aEvent is the tool event to be addded.
*/
void Add( const TOOL_EVENT& aEvent ) void Add( const TOOL_EVENT& aEvent )
{ {
m_events.push_back( aEvent ); m_events.push_back( aEvent );
......
...@@ -35,6 +35,10 @@ class CONTEXT_MENU; ...@@ -35,6 +35,10 @@ class CONTEXT_MENU;
class TOOL_INTERACTIVE : public TOOL_BASE class TOOL_INTERACTIVE : public TOOL_BASE
{ {
public: public:
/**
* Constructor
*
* Creates a tool with given id & name. The name must be unique. */
TOOL_INTERACTIVE( TOOL_ID aId, const std::string& aName ); TOOL_INTERACTIVE( TOOL_ID aId, const std::string& aName );
/** /**
...@@ -46,8 +50,8 @@ public: ...@@ -46,8 +50,8 @@ public:
/** /**
* Function Reset() * Function Reset()
* Brings the tool to a known, initial state. If the tool claimed anything from the model or the view, * Brings the tool to a known, initial state. If the tool claimed anything from
* it must release it when its reset. * the model or the view, it must release it when its reset.
*/ */
virtual void Reset() = 0; virtual void Reset() = 0;
...@@ -65,7 +69,9 @@ public: ...@@ -65,7 +69,9 @@ public:
/** /**
* Function SetContextMenu() * 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 ); void SetContextMenu( CONTEXT_MENU* aMenu, CONTEXT_MENU_TRIGGER aTrigger = CMENU_BUTTON );
...@@ -87,9 +93,8 @@ public: ...@@ -87,9 +93,8 @@ public:
*/ */
OPT_TOOL_EVENT Wait( const TOOL_EVENT_LIST& aEventList = TOOL_EVENT ( TC_Any, TA_Any ) ); 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 */ /** functions below are not yet implemented - their interface may change */
template<class Parameters, class ReturnValue> /*template<class Parameters, class ReturnValue>
bool InvokeTool( const std::string& aToolName, const Parameters& parameters, bool InvokeTool( const std::string& aToolName, const Parameters& parameters,
ReturnValue& returnValue ); ReturnValue& returnValue );
...@@ -98,11 +103,10 @@ public: ...@@ -98,11 +103,10 @@ public:
ReturnValue& returnValue ); ReturnValue& returnValue );
template<class T> template<class T>
void Yield( const T& returnValue ); void Yield( const T& returnValue );*/
protected: protected:
/* helper functions for constructing events for Wait() and Go() with /* helper functions for constructing events for Wait() and Go() with less typing */
less typing */
const TOOL_EVENT evActivate( std::string aToolName = "" ); const TOOL_EVENT evActivate( std::string aToolName = "" );
const TOOL_EVENT evCommand( int aCommandId = -1 ); const TOOL_EVENT evCommand( int aCommandId = -1 );
const TOOL_EVENT evCommand( std::string aCommandStr = "" ); const TOOL_EVENT evCommand( std::string aCommandStr = "" );
......
...@@ -36,6 +36,8 @@ using boost::optional; ...@@ -36,6 +36,8 @@ using boost::optional;
MOVE_TOOL::MOVE_TOOL() : MOVE_TOOL::MOVE_TOOL() :
TOOL_INTERACTIVE( "pcbnew.InteractiveMove" ), m_selectionTool( NULL ), TOOL_INTERACTIVE( "pcbnew.InteractiveMove" ), m_selectionTool( NULL ),
// Available actions:
m_activate( m_toolName, AS_GLOBAL, 'M', "Move", "Moves the selected item(s)" ), 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_rotate( m_toolName + ".rotate", AS_CONTEXT, ' ', "Rotate", "Rotates selected item(s)" ),
m_flip( m_toolName + ".flip", AS_CONTEXT, 'F', "Flip", "Flips selected item(s)" ) m_flip( m_toolName + ".flip", AS_CONTEXT, 'F', "Flip", "Flips selected item(s)" )
...@@ -69,7 +71,7 @@ bool MOVE_TOOL::Init() ...@@ -69,7 +71,7 @@ bool MOVE_TOOL::Init()
m_toolMgr->RegisterAction( &m_rotate ); m_toolMgr->RegisterAction( &m_rotate );
m_toolMgr->RegisterAction( &m_flip ); 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_activate );
m_selectionTool->AddMenuItem( m_rotate ); m_selectionTool->AddMenuItem( m_rotate );
m_selectionTool->AddMenuItem( m_flip ); m_selectionTool->AddMenuItem( m_flip );
...@@ -92,7 +94,9 @@ int MOVE_TOOL::Main( TOOL_EVENT& aEvent ) ...@@ -92,7 +94,9 @@ int MOVE_TOOL::Main( TOOL_EVENT& aEvent )
VIEW* view = getView(); VIEW* view = getView();
VIEW_CONTROLS* controls = getViewControls(); VIEW_CONTROLS* controls = getViewControls();
// Add a VIEW_GROUP that will hold all modified items
view->Add( &m_items ); view->Add( &m_items );
controls->ShowCursor( true ); controls->ShowCursor( true );
controls->SetSnapping( true ); controls->SetSnapping( true );
controls->SetAutoPan( true ); controls->SetAutoPan( true );
...@@ -102,7 +106,7 @@ int MOVE_TOOL::Main( TOOL_EVENT& aEvent ) ...@@ -102,7 +106,7 @@ int MOVE_TOOL::Main( TOOL_EVENT& aEvent )
{ {
if( evt->IsCancel() ) if( evt->IsCancel() )
{ {
restore = true; restore = true; // Cancelling the tool means that items have to be restored
break; // Finish break; // Finish
} }
...@@ -111,12 +115,12 @@ int MOVE_TOOL::Main( TOOL_EVENT& aEvent ) ...@@ -111,12 +115,12 @@ int MOVE_TOOL::Main( TOOL_EVENT& aEvent )
{ {
VECTOR2D cursorPos = getView()->ToWorld( getViewControls()->GetCursorPosition() ); 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_state.Rotate( cursorPos, 900.0 );
m_items.ViewUpdate( VIEW_ITEM::GEOMETRY ); 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_state.Flip( cursorPos );
m_items.ViewUpdate( VIEW_ITEM::GEOMETRY ); m_items.ViewUpdate( VIEW_ITEM::GEOMETRY );
...@@ -165,20 +169,22 @@ int MOVE_TOOL::Main( TOOL_EVENT& aEvent ) ...@@ -165,20 +169,22 @@ int MOVE_TOOL::Main( TOOL_EVENT& aEvent )
// Restore visibility of the original items // Restore visibility of the original items
vgSetVisibility( &m_items, true ); vgSetVisibility( &m_items, true );
// Movement has to be rollbacked, so restore the previous state of items
if( restore ) if( restore )
{ {
// Modifications has to be rollbacked, so restore the previous state of items
vgUpdate( &m_items, VIEW_ITEM::APPEARANCE ); vgUpdate( &m_items, VIEW_ITEM::APPEARANCE );
m_state.RestoreAll(); m_state.RestoreAll();
} }
else else
{ {
// Changes are applied, so update the items
vgUpdate( &m_items, m_state.GetUpdateFlag() ); vgUpdate( &m_items, m_state.GetUpdateFlag() );
m_state.Apply(); m_state.Apply();
} }
m_items.Clear(); m_items.Clear();
view->Remove( &m_items ); view->Remove( &m_items );
controls->ShowCursor( false ); controls->ShowCursor( false );
controls->SetSnapping( false ); controls->SetSnapping( false );
controls->SetAutoPan( false ); controls->SetAutoPan( false );
......
...@@ -50,6 +50,7 @@ public: ...@@ -50,6 +50,7 @@ public:
virtual const BOX2I ViewBBox() const; virtual const BOX2I ViewBBox() const;
void ViewDraw( int aLayer, KiGfx::GAL* aGal ) const; void ViewDraw( int aLayer, KiGfx::GAL* aGal ) const;
void ViewGetLayers( int aLayers[], int& aCount ) const; void ViewGetLayers( int aLayers[], int& aCount ) const;
void SetOrigin ( VECTOR2I aOrigin ) void SetOrigin ( VECTOR2I aOrigin )
......
...@@ -83,7 +83,6 @@ bool SELECTION_TOOL::Init() ...@@ -83,7 +83,6 @@ bool SELECTION_TOOL::Init()
int SELECTION_TOOL::Main( TOOL_EVENT& aEvent ) int SELECTION_TOOL::Main( TOOL_EVENT& aEvent )
{ {
BOARD* board = getModel<BOARD>( PCB_T ); BOARD* board = getModel<BOARD>( PCB_T );
assert( board != NULL ); assert( board != NULL );
// Main loop: keep receiving events // Main loop: keep receiving events
...@@ -116,13 +115,16 @@ int SELECTION_TOOL::Main( TOOL_EVENT& aEvent ) ...@@ -116,13 +115,16 @@ int SELECTION_TOOL::Main( TOOL_EVENT& aEvent )
} }
else else
{ {
// Check if dragging has started within any of selected items bounding box
if( containsSelected( evt->Position() ) ) if( containsSelected( evt->Position() ) )
{ {
// Yes -> run the move tool and wait till it finishes
m_toolMgr->InvokeTool( "pcbnew.InteractiveMove" ); m_toolMgr->InvokeTool( "pcbnew.InteractiveMove" );
Wait(); Wait();
} }
else else
{ {
// No -> clear the selection list
clearSelection(); clearSelection();
} }
} }
...@@ -135,7 +137,7 @@ int SELECTION_TOOL::Main( TOOL_EVENT& aEvent ) ...@@ -135,7 +137,7 @@ int SELECTION_TOOL::Main( TOOL_EVENT& aEvent )
void SELECTION_TOOL::AddMenuItem( const TOOL_ACTION& aAction ) 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 ); m_menu.Add( aAction );
} }
...@@ -259,9 +261,9 @@ BOARD_ITEM* SELECTION_TOOL::pickSmallestComponent( GENERAL_COLLECTOR* aCollector ...@@ -259,9 +261,9 @@ BOARD_ITEM* SELECTION_TOOL::pickSmallestComponent( GENERAL_COLLECTOR* aCollector
bool SELECTION_TOOL::selectMultiple() bool SELECTION_TOOL::selectMultiple()
{ {
VIEW* view = getView(); bool cancelled = false; // Was the tool cancelled while it was running?
bool cancelled = false;
m_multiple = true; // Multiple selection mode is active m_multiple = true; // Multiple selection mode is active
VIEW* view = getView();
getViewControls()->SetAutoPan( true ); getViewControls()->SetAutoPan( true );
// Those 2 lines remove the blink-in-the-random-place effect // Those 2 lines remove the blink-in-the-random-place effect
...@@ -291,7 +293,7 @@ bool SELECTION_TOOL::selectMultiple() ...@@ -291,7 +293,7 @@ bool SELECTION_TOOL::selectMultiple()
if( evt->IsMouseUp( MB_Left ) ) if( evt->IsMouseUp( MB_Left ) )
{ {
// End drawing a selection box // End drawing the selection box
m_selArea->ViewSetVisible( false ); m_selArea->ViewSetVisible( false );
// Mark items within the selection box as selected // Mark items within the selection box as selected
...@@ -315,6 +317,7 @@ bool SELECTION_TOOL::selectMultiple() ...@@ -315,6 +317,7 @@ bool SELECTION_TOOL::selectMultiple()
// Now the context menu should be enabled // Now the context menu should be enabled
if( !m_selectedItems.empty() ) if( !m_selectedItems.empty() )
SetContextMenu( &m_menu, CMENU_BUTTON ); SetContextMenu( &m_menu, CMENU_BUTTON );
break; break;
} }
} }
...@@ -367,6 +370,7 @@ BOARD_ITEM* SELECTION_TOOL::disambiguationMenu( GENERAL_COLLECTOR* aCollector ) ...@@ -367,6 +370,7 @@ BOARD_ITEM* SELECTION_TOOL::disambiguationMenu( GENERAL_COLLECTOR* aCollector )
{ {
optional<int> id = evt->GetCommandId(); optional<int> id = evt->GetCommandId();
// User has selected an item, so this one will be returned
if( id && ( *id >= 0 ) ) if( id && ( *id >= 0 ) )
current = ( *aCollector )[*id]; current = ( *aCollector )[*id];
...@@ -392,11 +396,12 @@ BOARD_ITEM* SELECTION_TOOL::disambiguationMenu( GENERAL_COLLECTOR* aCollector ) ...@@ -392,11 +396,12 @@ BOARD_ITEM* SELECTION_TOOL::disambiguationMenu( GENERAL_COLLECTOR* aCollector )
bool SELECTION_TOOL::selectable( const BOARD_ITEM* aItem ) const bool SELECTION_TOOL::selectable( const BOARD_ITEM* aItem ) const
{ {
// Is high contrast mode enabled?
bool highContrast = getView()->GetPainter()->GetSettings()->GetHighContrast(); bool highContrast = getView()->GetPainter()->GetSettings()->GetHighContrast();
if( highContrast ) 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; int layers[KiGfx::VIEW::VIEW_MAX_LAYERS], layers_count;
// Filter out items that do not belong to active layers // Filter out items that do not belong to active layers
...@@ -406,14 +411,14 @@ bool SELECTION_TOOL::selectable( const BOARD_ITEM* aItem ) const ...@@ -406,14 +411,14 @@ bool SELECTION_TOOL::selectable( const BOARD_ITEM* aItem ) const
for( int i = 0; i < layers_count; ++i ) 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; onActive = true;
break; break;
} }
} }
if( !onActive ) if( !onActive ) // We do not want to select items that are in the background
return false; return false;
} }
...@@ -426,8 +431,7 @@ bool SELECTION_TOOL::selectable( const BOARD_ITEM* aItem ) const ...@@ -426,8 +431,7 @@ bool SELECTION_TOOL::selectable( const BOARD_ITEM* aItem ) const
LAYER_NUM top, bottom; LAYER_NUM top, bottom;
static_cast<const SEGVIA*>( aItem )->ReturnLayerPair( &top, &bottom ); static_cast<const SEGVIA*>( aItem )->ReturnLayerPair( &top, &bottom );
return ( board->IsLayerVisible( top ) || return ( board->IsLayerVisible( top ) || board->IsLayerVisible( bottom ) );
board->IsLayerVisible( bottom ) );
} }
break; break;
...@@ -473,8 +477,7 @@ bool SELECTION_TOOL::containsSelected( const VECTOR2I& aPoint ) const ...@@ -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 // Check if the point is located within any of the currently selected items bounding boxes
std::set<BOARD_ITEM*>::iterator it, it_end; std::set<BOARD_ITEM*>::iterator it, it_end;
for( it = m_selectedItems.begin(), it_end = m_selectedItems.end(); for( it = m_selectedItems.begin(), it_end = m_selectedItems.end(); it != it_end; ++it )
it != it_end; ++it )
{ {
BOX2I itemBox = (*it)->ViewBBox(); BOX2I itemBox = (*it)->ViewBBox();
itemBox.Inflate( 500000 ); // Give some margin for gripping an item itemBox.Inflate( 500000 ); // Give some margin for gripping an item
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment