Even more code comments and reformatting.

This commit is contained in:
Maciej Suminski 2013-09-27 18:51:21 +02:00
parent 3f320e4d68
commit 6b74b5771a
24 changed files with 412 additions and 338 deletions

View File

@ -31,36 +31,36 @@
typedef VECTOR2I::extended_type ecoord; typedef VECTOR2I::extended_type ecoord;
static inline bool Collide( const SHAPE_CIRCLE& a, const SHAPE_CIRCLE& b, int clearance, static inline bool Collide( const SHAPE_CIRCLE& aA, const SHAPE_CIRCLE& aB, int aClearance,
bool needMTV, VECTOR2I& aMTV ) bool aNeedMTV, VECTOR2I& aMTV )
{ {
ecoord min_dist = clearance + a.GetRadius() + b.GetRadius(); ecoord min_dist = aClearance + aA.GetRadius() + aB.GetRadius();
ecoord min_dist_sq = min_dist * min_dist; ecoord min_dist_sq = min_dist * min_dist;
const VECTOR2I delta = b.GetCenter() - a.GetCenter(); const VECTOR2I delta = aB.GetCenter() - aA.GetCenter();
ecoord dist_sq = delta.SquaredEuclideanNorm(); ecoord dist_sq = delta.SquaredEuclideanNorm();
if ( dist_sq >= min_dist_sq ) if ( dist_sq >= min_dist_sq )
return false; return false;
if ( needMTV ) if ( aNeedMTV )
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, static inline bool Collide( const SHAPE_RECT& aA, const SHAPE_CIRCLE& aB, int aClearance,
bool needMTV, VECTOR2I& aMTV ) bool aNeedMTV, VECTOR2I& aMTV )
{ {
const VECTOR2I c = b.GetCenter(); const VECTOR2I c = aB.GetCenter();
const VECTOR2I p0 = a.GetPosition(); const VECTOR2I p0 = aA.GetPosition();
const VECTOR2I size = a.GetSize(); const VECTOR2I size = aA.GetSize();
const ecoord r = b.GetRadius(); const ecoord r = aB.GetRadius();
const ecoord min_dist = clearance + r; const ecoord min_dist = aClearance + 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 ( aA.BBox( 0 ).Contains( c ) )
return true; return true;
const VECTOR2I vts[] = { const VECTOR2I vts[] = {
@ -86,7 +86,7 @@ static inline bool Collide( const SHAPE_RECT& a, const SHAPE_CIRCLE& b, int cle
if( dist_sq < min_dist_sq ) if( dist_sq < min_dist_sq )
{ {
if( !needMTV ) if( !aNeedMTV )
return true; return true;
else else
{ {
@ -102,7 +102,7 @@ static inline bool Collide( const SHAPE_RECT& a, const SHAPE_CIRCLE& b, int cle
VECTOR2I delta = c - nearest; VECTOR2I delta = c - nearest;
if( !needMTV ) if( !aNeedMTV )
return true; return true;
if( inside ) if( inside )
@ -114,12 +114,12 @@ static inline bool Collide( const SHAPE_RECT& a, const SHAPE_CIRCLE& b, int cle
} }
static inline bool Collide( const SHAPE_CIRCLE& a, const SHAPE_LINE_CHAIN& b, int clearance, static inline bool Collide( const SHAPE_CIRCLE& aA, const SHAPE_LINE_CHAIN& aB, int aClearance,
bool needMTV, VECTOR2I& aMTV ) bool aNeedMTV, VECTOR2I& aMTV )
{ {
for( int s = 0; s < b.SegmentCount(); s++ ) for( int s = 0; s < aB.SegmentCount(); s++ )
{ {
if ( a.Collide( b.CSegment( s ), clearance ) ) if ( aA.Collide( aB.CSegment( s ), aClearance ) )
return true; return true;
} }
@ -127,23 +127,23 @@ static inline bool Collide( const SHAPE_CIRCLE& a, const SHAPE_LINE_CHAIN& b, in
} }
static inline bool Collide( const SHAPE_LINE_CHAIN& a, const SHAPE_LINE_CHAIN& b, int clearance, static inline bool Collide( const SHAPE_LINE_CHAIN& aA, const SHAPE_LINE_CHAIN& aB, int aClearance,
bool needMTV, VECTOR2I& aMTV ) bool aNeedMTV, VECTOR2I& aMTV )
{ {
for( int i = 0; i < b.SegmentCount(); i++ ) for( int i = 0; i < aB.SegmentCount(); i++ )
if( a.Collide( b.CSegment(i), clearance ) ) if( aA.Collide( aB.CSegment(i), aClearance ) )
return true; return true;
return false; return false;
} }
static inline bool Collide( const SHAPE_RECT& a, const SHAPE_LINE_CHAIN& b, int clearance, static inline bool Collide( const SHAPE_RECT& aA, const SHAPE_LINE_CHAIN& aB, int aClearance,
bool needMTV, VECTOR2I& aMTV ) bool aNeedMTV, VECTOR2I& aMTV )
{ {
for( int s = 0; s < b.SegmentCount(); s++ ) for( int s = 0; s < aB.SegmentCount(); s++ )
{ {
SEG seg = b.CSegment( s ); SEG seg = aB.CSegment( s );
if( a.Collide( seg, clearance ) ) if( aA.Collide( seg, aClearance ) )
return true; return true;
} }
@ -151,58 +151,58 @@ 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* aA, const SHAPE* aB, int aClearance, bool aNeedMTV, VECTOR2I& aMTV )
{ {
switch( a->Type() ) switch( aA->Type() )
{ {
case SH_RECT: case SH_RECT:
switch( b->Type() ) switch( aB->Type() )
{ {
case SH_CIRCLE: case SH_CIRCLE:
return Collide( *static_cast<const SHAPE_RECT*>( a ), return Collide( *static_cast<const SHAPE_RECT*>( aA ),
*static_cast<const SHAPE_CIRCLE*>( b ), clearance, needMTV, aMTV ); *static_cast<const SHAPE_CIRCLE*>( aB ), aClearance, aNeedMTV, aMTV );
case SH_LINE_CHAIN: case SH_LINE_CHAIN:
return Collide( *static_cast<const SHAPE_RECT*>( a ), return Collide( *static_cast<const SHAPE_RECT*>( aA ),
*static_cast<const SHAPE_LINE_CHAIN*>( b ), clearance, needMTV, aMTV ); *static_cast<const SHAPE_LINE_CHAIN*>( aB ), aClearance, aNeedMTV, aMTV );
default: default:
break; break;
} }
case SH_CIRCLE: case SH_CIRCLE:
switch( b->Type() ) switch( aB->Type() )
{ {
case SH_RECT: case SH_RECT:
return Collide( *static_cast<const SHAPE_RECT*>( b ), return Collide( *static_cast<const SHAPE_RECT*>( aB ),
*static_cast<const SHAPE_CIRCLE*>( a ), clearance, needMTV, aMTV ); *static_cast<const SHAPE_CIRCLE*>( aA ), aClearance, aNeedMTV, aMTV );
case SH_CIRCLE: case SH_CIRCLE:
return Collide( *static_cast<const SHAPE_CIRCLE*>( a ), return Collide( *static_cast<const SHAPE_CIRCLE*>( aA ),
*static_cast<const SHAPE_CIRCLE*>( b ), clearance, needMTV, aMTV ); *static_cast<const SHAPE_CIRCLE*>( aB ), aClearance, aNeedMTV, aMTV );
case SH_LINE_CHAIN: case SH_LINE_CHAIN:
return Collide( *static_cast<const SHAPE_CIRCLE*>( a ), return Collide( *static_cast<const SHAPE_CIRCLE*>( aA ),
*static_cast<const SHAPE_LINE_CHAIN *>( b ), clearance, needMTV, aMTV ); *static_cast<const SHAPE_LINE_CHAIN *>( aB ), aClearance, aNeedMTV, aMTV );
default: default:
break; break;
} }
case SH_LINE_CHAIN: case SH_LINE_CHAIN:
switch( b->Type() ) switch( aB->Type() )
{ {
case SH_RECT: case SH_RECT:
return Collide( *static_cast<const SHAPE_RECT*>( b ), return Collide( *static_cast<const SHAPE_RECT*>( aB ),
*static_cast<const SHAPE_LINE_CHAIN*>( a ), clearance, needMTV, aMTV ); *static_cast<const SHAPE_LINE_CHAIN*>( aA ), aClearance, aNeedMTV, aMTV );
case SH_CIRCLE: case SH_CIRCLE:
return Collide( *static_cast<const SHAPE_CIRCLE*>( b ), return Collide( *static_cast<const SHAPE_CIRCLE*>( aB ),
*static_cast<const SHAPE_LINE_CHAIN*>( a ), clearance, needMTV, aMTV ); *static_cast<const SHAPE_LINE_CHAIN*>( aA ), aClearance, aNeedMTV, aMTV );
case SH_LINE_CHAIN: case SH_LINE_CHAIN:
return Collide( *static_cast<const SHAPE_LINE_CHAIN*>( a ), return Collide( *static_cast<const SHAPE_LINE_CHAIN*>( aA ),
*static_cast<const SHAPE_LINE_CHAIN*>( b ), clearance, needMTV, aMTV ); *static_cast<const SHAPE_LINE_CHAIN*>( aB ), aClearance, aNeedMTV, aMTV );
default: default:
break; break;

View File

@ -99,6 +99,7 @@ bool ACTION_MANAGER::RunHotKey( int aHotKey ) const
void ACTION_MANAGER::runAction( const TOOL_ACTION* aAction ) const void ACTION_MANAGER::runAction( const TOOL_ACTION* aAction ) const
{ {
TOOL_EVENT event = aAction->GetEvent(); TOOL_EVENT event = aAction->MakeEvent();
m_toolMgr->ProcessEvent( event ); m_toolMgr->ProcessEvent( event );
} }

View File

@ -151,24 +151,28 @@ void CONTEXT_MENU::CMEventHandler::onEvent( wxEvent& aEvent )
TOOL_EVENT evt; TOOL_EVENT evt;
wxEventType type = aEvent.GetEventType(); wxEventType type = aEvent.GetEventType();
// When the currently chosen item in the menu is changed, an update event is issued.
// For example, the selection tool can use this to dynamically highlight the current item
// from selection clarification popup.
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() );
// One of menu entries was selected..
else if( type == wxEVT_COMMAND_MENU_SELECTED ) else if( type == wxEVT_COMMAND_MENU_SELECTED )
{ {
if( aEvent.GetId() > m_actionId ) // Check if there is a TOOL_ACTION for the given ID
if( m_menu->m_toolActions.count( aEvent.GetId() ) == 1 )
{ {
// Handling TOOL_ACTIONs evt = m_menu->m_toolActions[aEvent.GetId()]->MakeEvent();
if( m_menu->m_toolActions.count( aEvent.GetId() ) == 1 )
evt = m_menu->m_toolActions[aEvent.GetId()]->GetEvent();
} }
else else
{ {
// Handling common menu entries // Handling non-action menu entries (e.g. items in clarification list)
evt = TOOL_EVENT( TC_Command, TA_ContextMenuChoice, aEvent.GetId() ); evt = TOOL_EVENT( TC_Command, TA_ContextMenuChoice, aEvent.GetId() );
} }
} }
// forward the action/update event to the TOOL_MANAGER
if( m_menu->m_tool ) if( m_menu->m_tool )
m_menu->m_tool->GetManager()->ProcessEvent( evt ); m_menu->m_tool->GetManager()->ProcessEvent( evt );
} }

View File

@ -39,6 +39,7 @@
using boost::optional; using boost::optional;
///> Stores information about a mouse button state
struct TOOL_DISPATCHER::ButtonState struct TOOL_DISPATCHER::ButtonState
{ {
ButtonState( TOOL_MouseButtons aButton, const wxEventType& aDownEvent, ButtonState( TOOL_MouseButtons aButton, const wxEventType& aDownEvent,
@ -217,6 +218,8 @@ void TOOL_DISPATCHER::DispatchWxEvent( wxEvent& aEvent )
type == wxEVT_LEFT_DOWN || type == wxEVT_LEFT_UP || type == wxEVT_LEFT_DOWN || type == wxEVT_LEFT_UP ||
type == wxEVT_MIDDLE_DOWN || type == wxEVT_MIDDLE_UP || type == wxEVT_MIDDLE_DOWN || type == wxEVT_MIDDLE_UP ||
type == wxEVT_RIGHT_DOWN || type == wxEVT_RIGHT_UP || type == wxEVT_RIGHT_DOWN || type == wxEVT_RIGHT_UP ||
// Event issued whem mouse retains position in screen coordinates,
// but changes in world coordinates (eg. autopanning)
type == KiGfx::WX_VIEW_CONTROLS::EVT_REFRESH_MOUSE ) type == KiGfx::WX_VIEW_CONTROLS::EVT_REFRESH_MOUSE )
{ {
VECTOR2D screenPos = m_toolMgr->GetViewControls()->GetCursorPosition(); VECTOR2D screenPos = m_toolMgr->GetViewControls()->GetCursorPosition();
@ -247,7 +250,7 @@ void TOOL_DISPATCHER::DispatchWxEvent( wxEvent& aEvent )
if( type == wxEVT_KEY_UP ) if( type == wxEVT_KEY_UP )
{ {
if( key == WXK_ESCAPE ) if( key == WXK_ESCAPE ) // ESC is the special key for cancelling tools
evt = TOOL_EVENT( TC_Command, TA_CancelTool ); evt = TOOL_EVENT( TC_Command, TA_CancelTool );
else else
evt = TOOL_EVENT( TC_Keyboard, TA_KeyUp, key | mods ); evt = TOOL_EVENT( TC_Keyboard, TA_KeyUp, key | mods );
@ -261,6 +264,7 @@ void TOOL_DISPATCHER::DispatchWxEvent( wxEvent& aEvent )
if( evt ) if( evt )
m_toolMgr->ProcessEvent( *evt ); m_toolMgr->ProcessEvent( *evt );
// pass the event to the GUI, it might still be interested in it
aEvent.Skip(); aEvent.Skip();
} }
@ -270,6 +274,7 @@ void TOOL_DISPATCHER::DispatchWxCommand( const wxCommandEvent& aEvent )
bool activateTool = false; bool activateTool = false;
std::string toolName; std::string toolName;
// fixme: use TOOL_ACTIONs here
switch( aEvent.GetId() ) switch( aEvent.GetId() )
{ {
case ID_PNS_ROUTER_TOOL: case ID_PNS_ROUTER_TOOL:
@ -282,6 +287,7 @@ void TOOL_DISPATCHER::DispatchWxCommand( const wxCommandEvent& aEvent )
break; break;
} }
// do nothing if the legacy view is active
if( activateTool && m_editFrame->IsGalCanvasActive() ) if( activateTool && m_editFrame->IsGalCanvasActive() )
m_toolMgr->InvokeTool( toolName ); m_toolMgr->InvokeTool( toolName );
} }

View File

@ -25,9 +25,8 @@
#include <cstring> #include <cstring>
#include <string> #include <string>
//#include <base_struct.h>
#include <tool/tool_event.h> #include <tool/tool_event.h>
#include <tool/tool_action.h>
#include <tool/tool_manager.h> #include <tool/tool_manager.h>
#include <boost/foreach.hpp> #include <boost/foreach.hpp>
@ -55,6 +54,12 @@ static const std::string flag2string( int flag, const FlagString* exps )
} }
bool TOOL_EVENT::IsAction( const TOOL_ACTION* aAction ) const
{
return Matches( aAction->MakeEvent() );
}
const std::string TOOL_EVENT::Format() const const std::string TOOL_EVENT::Format() const
{ {
std::string ev; std::string ev;

View File

@ -3,6 +3,7 @@
* *
* Copyright (C) 2013 CERN * Copyright (C) 2013 CERN
* @author Tomasz Wlostowski <tomasz.wlostowski@cern.ch> * @author Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
* @author Maciej Suminski <maciej.suminski@cern.ch>
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
@ -39,6 +40,7 @@
#include <tool/tool_manager.h> #include <tool/tool_manager.h>
#include <tool/context_menu.h> #include <tool/context_menu.h>
#include <tool/coroutine.h> #include <tool/coroutine.h>
#include <tool/action_manager.h>
#include <wxPcbStruct.h> #include <wxPcbStruct.h>
#include <class_drawpanel_gal.h> #include <class_drawpanel_gal.h>
@ -46,37 +48,38 @@
using boost::optional; using boost::optional;
using namespace std; using namespace std;
/// Struct describing the current state of a TOOL /// Struct describing the current execution state of a TOOL
struct TOOL_MANAGER::TOOL_STATE struct TOOL_MANAGER::TOOL_STATE
{ {
/// The tool itself /// The tool itself
TOOL_BASE* theTool; TOOL_BASE* theTool;
/// Is the tool active or idle at the moment /// Is the tool active (pending execution) or disabled at the moment
bool idle; bool idle;
/// Flag defining if the tool is waiting for any event /// Flag defining if the tool is waiting for any event (i.e. if it
/// issued a Wait() call).
bool pendingWait; bool pendingWait;
/// Is there a context menu to be displayed /// Is there a context menu being displayed
bool pendingContextMenu; bool pendingContextMenu;
/// Context menu used by the tool /// Context menu currently used by the tool
CONTEXT_MENU* contextMenu; CONTEXT_MENU* contextMenu;
/// Defines when a context menu is opened /// Defines when the context menu is opened
CONTEXT_MENU_TRIGGER contextMenuTrigger; CONTEXT_MENU_TRIGGER contextMenuTrigger;
/// Coroutine launched upon an event trigger /// Tool execution context
COROUTINE<int, TOOL_EVENT&>* cofunc; COROUTINE<int, TOOL_EVENT&>* cofunc;
/// The event that triggered the coroutine /// The event that triggered the execution/wakeup of the tool after Wait() call
TOOL_EVENT wakeupEvent; TOOL_EVENT wakeupEvent;
/// List of events that are triggering the coroutine /// List of events the tool is currently waiting for
TOOL_EVENT_LIST waitEvents; TOOL_EVENT_LIST waitEvents;
/// List of possible transitions (ie. association of events and functions that are executed /// List of possible transitions (ie. association of events and state handlers that are executed
/// upon the event reception /// upon the event reception
std::vector<TRANSITION> transitions; std::vector<TRANSITION> transitions;
@ -93,8 +96,9 @@ struct TOOL_MANAGER::TOOL_STATE
TOOL_MANAGER::TOOL_MANAGER() : TOOL_MANAGER::TOOL_MANAGER() :
m_actionMgr( this ), m_model( NULL ), m_view( NULL ) m_model( NULL ), m_view( NULL )
{ {
m_actionMgr = new ACTION_MANAGER( this );
} }
@ -108,6 +112,8 @@ TOOL_MANAGER::~TOOL_MANAGER()
delete it->second; // delete TOOL_STATE delete it->second; // delete TOOL_STATE
delete it->first; // delete the tool itself delete it->first; // delete the tool itself
} }
delete m_actionMgr;
} }
@ -154,7 +160,7 @@ bool TOOL_MANAGER::InvokeTool( TOOL_ID aToolId )
if( tool && tool->GetType() == TOOL_Interactive ) if( tool && tool->GetType() == TOOL_Interactive )
return invokeTool( tool ); return invokeTool( tool );
return false; return false; // there is no tool with the given id
} }
@ -165,7 +171,19 @@ bool TOOL_MANAGER::InvokeTool( const std::string& aToolName )
if( tool && tool->GetType() == TOOL_Interactive ) if( tool && tool->GetType() == TOOL_Interactive )
return invokeTool( tool ); return invokeTool( tool );
return false; return false; // there is no tool with the given name
}
void TOOL_MANAGER::RegisterAction( TOOL_ACTION* aAction )
{
m_actionMgr->RegisterAction( aAction );
}
void TOOL_MANAGER::UnregisterAction( TOOL_ACTION* aAction )
{
m_actionMgr->UnregisterAction( aAction );
} }
@ -187,7 +205,7 @@ bool TOOL_MANAGER::runTool( TOOL_ID aToolId )
if( tool && tool->GetType() == TOOL_Interactive ) if( tool && tool->GetType() == TOOL_Interactive )
return runTool( tool ); return runTool( tool );
return false; return false; // there is no tool with the given id
} }
@ -198,7 +216,7 @@ bool TOOL_MANAGER::runTool( const std::string& aToolName )
if( tool && tool->GetType() == TOOL_Interactive ) if( tool && tool->GetType() == TOOL_Interactive )
return runTool( tool ); return runTool( tool );
return false; return false; // there is no tool with the given name
} }
@ -260,8 +278,12 @@ optional<TOOL_EVENT> TOOL_MANAGER::ScheduleWait( TOOL_BASE* aTool,
{ {
TOOL_STATE* st = m_toolState[aTool]; TOOL_STATE* st = m_toolState[aTool];
// indicate to the manager that we are going to sleep and we shall be
// woken up when an event matching aConditions arrive
st->pendingWait = true; st->pendingWait = true;
st->waitEvents = aConditions; st->waitEvents = aConditions;
// switch context back to event dispatcher loop
st->cofunc->Yield(); st->cofunc->Yield();
return st->wakeupEvent; return st->wakeupEvent;
@ -300,7 +322,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) // the tool scheduled next state(s) by calling Go()
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
@ -313,6 +335,7 @@ void TOOL_MANAGER::dispatchInternal( TOOL_EVENT& aEvent )
{ {
st->transitions.clear(); st->transitions.clear();
// no tool context allocated yet? Create one.
if( !st->cofunc ) if( !st->cofunc )
st->cofunc = new COROUTINE<int, TOOL_EVENT&>( tr.second ); st->cofunc = new COROUTINE<int, TOOL_EVENT&>( tr.second );
else else
@ -322,7 +345,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 ); // The couroutine has finished immediately?
} }
} }
} }
@ -331,8 +354,27 @@ void TOOL_MANAGER::dispatchInternal( TOOL_EVENT& aEvent )
} }
bool TOOL_MANAGER::dispatchStandardEvents( TOOL_EVENT& aEvent )
{
if( aEvent.Action() == TA_KeyUp )
{
// Check if there is a hotkey associated
if( m_actionMgr->RunHotKey( aEvent.Modifier() | aEvent.KeyCode() ) )
return false; // hotkey event was handled so it does not go any further
}
else if( aEvent.Category() == TC_Command ) // it may be a tool activation event
{
dispatchActivation( aEvent );
// do not return false, as the event has to go on to the destined tool
}
return true;
}
bool TOOL_MANAGER::dispatchActivation( TOOL_EVENT& aEvent ) bool TOOL_MANAGER::dispatchActivation( TOOL_EVENT& aEvent )
{ {
// Look for the tool that has the same name as parameter in the processed command TOOL_EVENT
BOOST_FOREACH( TOOL_STATE* st, m_toolState | boost::adaptors::map_values ) BOOST_FOREACH( TOOL_STATE* st, m_toolState | boost::adaptors::map_values )
{ {
if( st->theTool->GetName() == aEvent.m_commandStr ) if( st->theTool->GetName() == aEvent.m_commandStr )
@ -359,7 +401,7 @@ void TOOL_MANAGER::finishTool( TOOL_STATE* aState )
if( it != m_activeTools.end() ) if( it != m_activeTools.end() )
m_activeTools.erase( it ); m_activeTools.erase( it );
else else
wxLogWarning( wxT( "Tried to finish not active tool" ) ); wxLogWarning( wxT( "Tried to finish inactive tool" ) );
aState->idle = true; aState->idle = true;
delete aState->cofunc; delete aState->cofunc;
@ -371,22 +413,19 @@ bool TOOL_MANAGER::ProcessEvent( TOOL_EVENT& aEvent )
{ {
// wxLogDebug( "event: %s", aEvent.Format().c_str() ); // wxLogDebug( "event: %s", aEvent.Format().c_str() );
if( aEvent.Action() == TA_KeyUp ) // Early dispatch of events destined for the TOOL_MANAGER
{ if( !dispatchStandardEvents( aEvent ) )
// Check if there is a hotkey associated return false;
if( m_actionMgr.RunHotKey( aEvent.Modifier() | aEvent.KeyCode() ) )
return false; // hotkey event was handled so it does not go any further
} else if( aEvent.Category() == TC_Command ) // it may be a tool activation event
{
dispatchActivation( aEvent );
}
dispatchInternal( aEvent ); dispatchInternal( aEvent );
// popup menu handling
BOOST_FOREACH( TOOL_ID toolId, m_activeTools ) BOOST_FOREACH( TOOL_ID toolId, m_activeTools )
{ {
TOOL_STATE* st = m_toolIdIndex[toolId]; TOOL_STATE* st = m_toolIdIndex[toolId];
// the tool requested a context menu. The menu is activated on RMB click (CMENU_BUTTON mode)
// or immediately (CMENU_NOW) mode. The latter is used for clarification lists.
if( st->contextMenuTrigger != CMENU_OFF ) if( st->contextMenuTrigger != CMENU_OFF )
{ {
if( st->contextMenuTrigger == CMENU_BUTTON && !aEvent.IsClick( MB_Right ) ) if( st->contextMenuTrigger == CMENU_BUTTON && !aEvent.IsClick( MB_Right ) )
@ -401,6 +440,7 @@ bool TOOL_MANAGER::ProcessEvent( TOOL_EVENT& aEvent )
boost::scoped_ptr<CONTEXT_MENU> menu( new CONTEXT_MENU( *st->contextMenu ) ); boost::scoped_ptr<CONTEXT_MENU> menu( new CONTEXT_MENU( *st->contextMenu ) );
GetEditFrame()->PopupMenu( menu->GetMenu() ); GetEditFrame()->PopupMenu( menu->GetMenu() );
//
TOOL_EVENT evt( TC_Command, TA_ContextMenuChoice ); TOOL_EVENT evt( TC_Command, TA_ContextMenuChoice );
dispatchInternal( evt ); dispatchInternal( evt );
@ -426,6 +466,7 @@ void TOOL_MANAGER::ScheduleContextMenu( TOOL_BASE* aTool, CONTEXT_MENU* aMenu,
st->contextMenu = aMenu; st->contextMenu = aMenu;
st->contextMenuTrigger = aTrigger; st->contextMenuTrigger = aTrigger;
// the tool wants the menu immediately? Preempt it and do so :)
if( aTrigger == CMENU_NOW ) if( aTrigger == CMENU_NOW )
st->cofunc->Yield(); st->cofunc->Yield();
} }

View File

@ -34,8 +34,8 @@
typedef boost::optional<VECTOR2I> OPT_VECTOR2I; typedef boost::optional<VECTOR2I> OPT_VECTOR2I;
class SEG { class SEG
{
private: private:
typedef VECTOR2I::extended_type ecoord; typedef VECTOR2I::extended_type ecoord;
@ -52,7 +52,7 @@ class SEG {
/** Default constructor /** Default constructor
* Creates an empty (0, 0) segment, locally-referenced * Creates an empty (0, 0) segment, locally-referenced
*/ */
SEG(): a(m_a), b(m_b) SEG() : a( m_a ), b( m_b )
{ {
a = m_a; a = m_a;
b = m_b; b = m_b;
@ -62,12 +62,12 @@ class SEG {
/** /**
* Constructor * Constructor
* Creates a segment between (x1, y1) and (x2, y2), locally referenced * Creates a segment between (aX1, aY1) and (aX2, aY2), locally referenced
*/ */
SEG ( int x1, int y1, int x2, int y2 ) : a(m_a), b(m_b) SEG( int aX1, int aY1, int aX2, int aY2 ) : a( m_a ), b( m_b )
{ {
m_a = VECTOR2I(x1, y1); m_a = VECTOR2I( aX1, aY1 );
m_b = VECTOR2I(x2, y2); m_b = VECTOR2I( aX2, aY2 );
a = m_a; a = m_a;
b = m_b; b = m_b;
m_is_local = true; m_is_local = true;
@ -78,7 +78,7 @@ class SEG {
* Constructor * Constructor
* Creates a segment between (aA) and (aB), locally referenced * Creates a segment between (aA) and (aB), locally referenced
*/ */
SEG ( const VECTOR2I& aA, const VECTOR2I& aB ): a(m_a), b(m_b), m_a(aA), m_b(aB) SEG( const VECTOR2I& aA, const VECTOR2I& aB ) : a( m_a ), b( m_b ), m_a( aA ), m_b( aB )
{ {
a = m_a; a = m_a;
b = m_b; b = m_b;
@ -93,7 +93,7 @@ class SEG {
* @param aB reference to the end point in the parent shape * @param aB reference to the end point in the parent shape
* @param aIndex index of the segment within the parent shape * @param aIndex index of the segment within the parent shape
*/ */
SEG ( VECTOR2I& aA, VECTOR2I& aB, int aIndex ): a(aA), b(aB) SEG ( VECTOR2I& aA, VECTOR2I& aB, int aIndex ) : a( aA ), b( aB )
{ {
m_is_local = false; m_is_local = false;
m_index = aIndex; m_index = aIndex;
@ -102,32 +102,32 @@ class SEG {
/** /**
* Copy constructor * Copy constructor
*/ */
SEG ( const SEG& seg ): a(m_a), b(m_b) SEG ( const SEG& aSeg ) : a( m_a ), b( m_b )
{ {
if (seg.m_is_local) if (aSeg.m_is_local)
{ {
m_a = seg.m_a; m_a = aSeg.m_a;
m_b = seg.m_b; m_b = aSeg.m_b;
a = m_a; a = m_a;
b = m_b; b = m_b;
m_is_local = true; m_is_local = true;
m_index = -1; m_index = -1;
} else { } else {
a = seg.a; a = aSeg.a;
b = seg.b; b = aSeg.b;
m_index = seg.m_index; m_index = aSeg.m_index;
m_is_local = false; m_is_local = false;
} }
} }
SEG& operator=(const SEG& seg) SEG& operator=( const SEG& aSeg )
{ {
a = seg.a; a = aSeg.a;
b = seg.b; b = aSeg.b;
m_a = seg.m_a; m_a = aSeg.m_a;
m_b = seg.m_b; m_b = aSeg.m_b;
m_index = seg.m_index; m_index = aSeg.m_index;
m_is_local = seg.m_is_local; m_is_local = aSeg.m_is_local;
return *this; return *this;
} }
@ -150,8 +150,9 @@ class SEG {
*/ */
int Side( const VECTOR2I& aP ) const int Side( const VECTOR2I& aP ) const
{ {
const ecoord det = (b - a).Cross(aP - a); const ecoord det = ( b - a ).Cross( aP - a );
return det < 0 ? -1 : (det > 0 ? 1 : 0);
return det < 0 ? -1 : ( det > 0 ? 1 : 0 );
} }
/** /**
@ -173,7 +174,6 @@ class SEG {
*/ */
const VECTOR2I NearestPoint( const VECTOR2I &aP ) const; const VECTOR2I NearestPoint( const VECTOR2I &aP ) const;
/** /**
* Function Intersect() * Function Intersect()
* *
@ -186,8 +186,6 @@ class SEG {
*/ */
OPT_VECTOR2I Intersect( const SEG& aSeg, bool aIgnoreEndpoints = false, bool aLines = false ) const; OPT_VECTOR2I Intersect( const SEG& aSeg, bool aIgnoreEndpoints = false, bool aLines = false ) const;
/** /**
* Function IntersectLines() * Function IntersectLines()
* *
@ -195,9 +193,9 @@ class SEG {
* @param aSeg segment defining the line to intersect with * @param aSeg segment defining the line to intersect with
* @return intersection point, if exists * @return intersection point, if exists
*/ */
OPT_VECTOR2I IntersectLines( const SEG& aSeg ) const OPT_VECTOR2I IntersectLines( const SEG& aSeg ) const
{ {
return Intersect ( aSeg, false, true ); return Intersect( aSeg, false, true );
} }
bool Collide( const SEG& aSeg, int aClearance ) const; bool Collide( const SEG& aSeg, int aClearance ) const;
@ -210,14 +208,13 @@ class SEG {
* @return minimum distance * @return minimum distance
*/ */
ecoord SquaredDistance( const SEG& aSeg ) const ; ecoord SquaredDistance( const SEG& aSeg ) const;
int Distance( const SEG& aSeg ) const int Distance( const SEG& aSeg ) const
{ {
return sqrt ( SquaredDistance(aSeg) ); return sqrt( SquaredDistance( aSeg ) );
} }
/** /**
* Function Distance() * Function Distance()
* *
@ -225,18 +222,16 @@ class SEG {
* @param aP the point * @param aP the point
* @return minimum distance * @return minimum distance
*/ */
ecoord SquaredDistance( const VECTOR2I& aP ) const ecoord SquaredDistance( const VECTOR2I& aP ) const
{ {
return (NearestPoint(aP) - aP).SquaredEuclideanNorm(); return ( NearestPoint( aP ) - aP ).SquaredEuclideanNorm();
} }
int Distance( const VECTOR2I& aP ) const int Distance( const VECTOR2I& aP ) const
{ {
return sqrt ( SquaredDistance( aP) ); return sqrt( SquaredDistance( aP ) );
} }
/** /**
* Function Collinear() * Function Collinear()
* *
@ -244,7 +239,6 @@ class SEG {
* @param aSeg the segment to chech colinearity with * @param aSeg the segment to chech colinearity with
* @return true, when segments are collinear. * @return true, when segments are collinear.
*/ */
bool Collinear( const SEG& aSeg ) const bool Collinear( const SEG& aSeg ) const
{ {
ecoord qa1 = a.y - b.y; ecoord qa1 = a.y - b.y;
@ -254,7 +248,7 @@ class SEG {
ecoord qb2 = aSeg.b.x - aSeg.a.x; ecoord qb2 = aSeg.b.x - aSeg.a.x;
ecoord qc2 = -qa2 * aSeg.a.x - qb2 * aSeg.a.y; ecoord qc2 = -qa2 * aSeg.a.x - qb2 * aSeg.a.y;
return (qa1 == qa2) && (qb1 == qb2) && (qc1 == qc2); return ( qa1 == qa2 ) && ( qb1 == qb2 ) && ( qc1 == qc2 );
} }
/** /**
@ -265,15 +259,14 @@ class SEG {
*/ */
int Length() const int Length() const
{ {
return (a - b).EuclideanNorm(); return ( a - b ).EuclideanNorm();
} }
ecoord SquaredLength() const ecoord SquaredLength() const
{ {
return (a - b).SquaredEuclideanNorm(); return ( a - b ).SquaredEuclideanNorm();
} }
/** /**
* Function Index() * Function Index()
* *
@ -285,20 +278,20 @@ class SEG {
return m_index; return m_index;
} }
bool Contains( const VECTOR2I& aP ) const;
bool Contains(const VECTOR2I& aP) const; bool PointCloserThan( const VECTOR2I& aP, int aDist ) const;
bool PointCloserThan ( const VECTOR2I& aP, int dist) const;
// friend std::ostream& operator<<( std::ostream& stream, const SEG& aSeg ); // friend std::ostream& operator<<( std::ostream& stream, const SEG& aSeg );
private: private:
bool ccw( const VECTOR2I& aA, const VECTOR2I& aB, const VECTOR2I &aC ) const;
bool ccw ( const VECTOR2I& a, const VECTOR2I& b, const VECTOR2I &c ) const;
///> locally stored start/end coordinates (used when m_is_local == true) ///> locally stored start/end coordinates (used when m_is_local == true)
VECTOR2I m_a, m_b; VECTOR2I m_a, m_b;
///> index withing the parent shape (used when m_is_local == false) ///> index withing the parent shape (used when m_is_local == false)
int m_index; int m_index;
///> locality flag ///> locality flag
bool m_is_local; bool m_is_local;
}; };
@ -306,49 +299,47 @@ class SEG {
inline VECTOR2I SEG::LineProject( const VECTOR2I& aP ) const inline VECTOR2I SEG::LineProject( const VECTOR2I& aP ) const
{ {
// fixme: numerical errors for large integers // fixme: numerical errors for large integers
assert(false); assert( false );
return VECTOR2I(0, 0); return VECTOR2I( 0, 0 );
} }
inline int SEG::LineDistance( const VECTOR2I& aP, bool aDetermineSide ) const inline int SEG::LineDistance( const VECTOR2I& aP, bool aDetermineSide ) const
{ {
ecoord p = a.y - b.y; ecoord p = a.y - b.y;
ecoord q = b.x - a.x; ecoord q = b.x - a.x;
ecoord r = -p * a.x - q * a.y; ecoord r = -p * a.x - q * a.y;
ecoord dist = ( p * aP.x + q * aP.y + r ) / sqrt( p * p + q * q ); ecoord dist = ( p * aP.x + q * aP.y + r ) / sqrt( p * p + q * q );
return aDetermineSide ? dist : abs(dist);
return aDetermineSide ? dist : abs( dist );
} }
inline const VECTOR2I SEG::NearestPoint( const VECTOR2I& aP ) const
inline const VECTOR2I SEG::NearestPoint(const VECTOR2I& aP) const
{ {
VECTOR2I d = b - a; VECTOR2I d = b - a;
ecoord l_squared = d.Dot(d); ecoord l_squared = d.Dot( d );
if( l_squared == 0 ) if( l_squared == 0 )
return a; return a;
ecoord t = d.Dot(aP - a); ecoord t = d.Dot( aP - a );
if( t < 0 ) if( t < 0 )
return a; return a;
else if( t > l_squared ) else if( t > l_squared )
return b; return b;
int xp = rescale(t, (ecoord)d.x, l_squared); int xp = rescale( t, (ecoord)d.x, l_squared );
int yp = rescale(t, (ecoord)d.y, l_squared); int yp = rescale( t, (ecoord)d.y, l_squared );
return a + VECTOR2I(xp, yp); return a + VECTOR2I( xp, yp );
} }
inline std::ostream& operator<<( std::ostream& aStream, const SEG& aSeg ) inline std::ostream& operator<<( std::ostream& aStream, const SEG& aSeg )
{ {
if(aSeg.m_is_local) if( aSeg.m_is_local )
aStream << "[ local " << aSeg.a << " - " << aSeg.b << " ]"; aStream << "[ local " << aSeg.a << " - " << aSeg.b << " ]";
return aStream; return aStream;
} }

View File

@ -45,7 +45,7 @@ enum ShapeType {
/** /**
* Class SHAPE * Class SHAPE
* *
* Represents an abstract shape on 2D plane. All SHAPEs implement SHAPE interface. * Represents an abstract shape on 2D plane.
*/ */
class SHAPE { class SHAPE {
protected: protected:
@ -58,7 +58,7 @@ class SHAPE {
* Creates an empty shape of type aType * Creates an empty shape of type aType
*/ */
SHAPE ( ShapeType aType ): m_type( aType ) { }; SHAPE ( ShapeType aType ) : m_type( aType ) { };
// Destructor // Destructor
virtual ~SHAPE() {}; virtual ~SHAPE() {};
@ -78,7 +78,7 @@ class SHAPE {
* @retval copy of the shape * @retval copy of the shape
*/ */
virtual SHAPE* Clone() const { virtual SHAPE* Clone() const {
assert(false); assert( false );
return NULL; return NULL;
}; };
@ -89,9 +89,9 @@ class SHAPE {
* a collision. * a collision.
* @return true, if there is a collision. * @return true, if there is a collision.
*/ */
virtual bool Collide ( const VECTOR2I& aP, int aClearance = 0 ) const virtual bool Collide( const VECTOR2I& aP, int aClearance = 0 ) const
{ {
return Collide(SEG(aP, aP), aClearance); return Collide( SEG( aP, aP ), aClearance );
} }
/** /**
@ -99,10 +99,13 @@ class SHAPE {
* *
* Checks if the boundary of shape (this) lies closer to the shape aShape than aClearance, indicating * Checks if the boundary of shape (this) lies closer to the shape aShape than aClearance, indicating
* a collision. * a collision.
* @param aShape shape to check collision against
* @param aClearance minimum clearance
* @param aMTV minimum translation vector
* @return true, if there is a collision. * @return true, if there is a collision.
*/ */
virtual bool Collide ( const SHAPE *aShape, int aClerance, VECTOR2I& aMTV ) const; virtual bool Collide( const SHAPE* aShape, int aClerance, VECTOR2I& aMTV ) const;
virtual bool Collide ( const SHAPE *aShape, int aClerance = 0 ) const; virtual bool Collide( const SHAPE* aShape, int aClerance = 0 ) const;
/** /**
* Function Collide() * Function Collide()
* *
@ -110,7 +113,7 @@ class SHAPE {
* a collision. * a collision.
* @return true, if there is a collision. * @return true, if there is a collision.
*/ */
virtual bool Collide ( const SEG& aSeg, int aClearance = 0) const = 0; virtual bool Collide( const SEG& aSeg, int aClearance = 0 ) const = 0;
/** /**
* Function Collide() * Function Collide()
@ -120,7 +123,7 @@ class SHAPE {
* @aClearance how much the bounding box is expanded wrs to the minimum enclosing rectangle for the shape. * @aClearance how much the bounding box is expanded wrs to the minimum enclosing rectangle for the shape.
* @return the bounding box. * @return the bounding box.
*/ */
virtual const BOX2I BBox ( int aClearance = 0 ) const = 0; virtual const BOX2I BBox( int aClearance = 0 ) const = 0;
/** /**
* Function Centre() * Function Centre()
@ -130,7 +133,7 @@ class SHAPE {
*/ */
virtual VECTOR2I Centre() const virtual VECTOR2I Centre() const
{ {
return BBox(0).Centre(); // if nothing better is available.... return BBox( 0 ).Centre(); // if nothing better is available....
} }
private: private:
@ -139,6 +142,6 @@ class SHAPE {
}; };
bool CollideShapes ( const SHAPE *a, const SHAPE *b, int clearance, bool needMTV, VECTOR2I& aMTV ); bool CollideShapes( const SHAPE *aA, const SHAPE *aB, int aClearance, bool aNeedMTV, VECTOR2I& aMTV );
#endif // __SHAPE_H #endif // __SHAPE_H

View File

@ -31,32 +31,31 @@ class SHAPE_CIRCLE : public SHAPE {
public: public:
SHAPE_CIRCLE(): SHAPE_CIRCLE():
SHAPE( SH_CIRCLE ), m_radius (0) {}; SHAPE( SH_CIRCLE ), m_radius( 0 ) {};
SHAPE_CIRCLE( const VECTOR2I& aCenter, int aRadius ): SHAPE_CIRCLE( const VECTOR2I& aCenter, int aRadius ):
SHAPE( SH_CIRCLE ), m_radius (aRadius), m_center(aCenter) {}; SHAPE( SH_CIRCLE ), m_radius( aRadius ), m_center( aCenter ) {};
~SHAPE_CIRCLE() {}; ~SHAPE_CIRCLE() {};
const BOX2I BBox(int aClearance = 0) const const BOX2I BBox( int aClearance = 0 ) const
{ {
const VECTOR2I rc (m_radius + aClearance, m_radius + aClearance); const VECTOR2I rc( m_radius + aClearance, m_radius + aClearance );
return BOX2I (m_center - rc, rc * 2); return BOX2I( m_center - rc, rc * 2 );
} }
bool Collide( const SEG& aSeg, int aClearance = 0 ) const
bool Collide(const SEG& aSeg, int aClearance = 0) const
{ {
int rc = aClearance + m_radius; int rc = aClearance + m_radius;
return aSeg.Distance(m_center) <= rc; return aSeg.Distance( m_center ) <= rc;
} }
void SetRadius(int aRadius) void SetRadius( int aRadius )
{ {
m_radius = aRadius; m_radius = aRadius;
} }
void SetCenter (const VECTOR2I& aCenter) void SetCenter( const VECTOR2I& aCenter )
{ {
m_center = aCenter; m_center = aCenter;
} }

View File

@ -62,9 +62,9 @@ const SHAPE* shapeFunctor( SHAPE* aItem );
* @return a BOX2I object containing the bounding box of the T object. * @return a BOX2I object containing the bounding box of the T object.
*/ */
template <class T> template <class T>
BOX2I boundingBox( T object ) BOX2I boundingBox( T aObject )
{ {
return shapeFunctor(object)->BBox(); return shapeFunctor( aObject )->BBox();
} }
/** /**
@ -77,9 +77,9 @@ BOX2I boundingBox( T object )
* @param visitor V visitor object * @param visitor V visitor object
*/ */
template <class T, class V> template <class T, class V>
void acceptVisitor( T object, V visitor ) void acceptVisitor( T aObject, V aVisitor )
{ {
visitor(object); aVisitor( aObject );
} }
/** /**
@ -94,22 +94,23 @@ void acceptVisitor( T object, V visitor )
* @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 aObject, U aAnotherObject, int aMinDistance )
{ {
return shapeFunctor( object )->Collide( anotherObject, minDistance ); return shapeFunctor( aObject )->Collide( aAnotherObject, aMinDistance );
} }
template<class T, class V> template<class T, class V>
bool queryCallback(T shape, void* context) bool queryCallback( T aShape, void* aContext )
{ {
V* visitor = (V*) context; V* visitor = (V*) aContext;
acceptVisitor<T,V>( shape, *visitor ); acceptVisitor<T,V>( aShape, *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
{ {
@ -123,9 +124,9 @@ 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>* aTree )
{ {
tree->GetFirst( iterator ); aTree->GetFirst( iterator );
} }
public: public:
@ -135,9 +136,9 @@ class SHAPE_INDEX {
* 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* aIndex )
{ {
Init( index->m_tree ); Init( aIndex->m_tree );
} }
/** /**
@ -321,7 +322,7 @@ void SHAPE_INDEX<T>::Add( T aShape )
} }
template<class T> template<class T>
void SHAPE_INDEX<T>::Remove(T aShape) void SHAPE_INDEX<T>::Remove( T aShape )
{ {
BOX2I box = boundingBox( aShape ); BOX2I box = boundingBox( aShape );
int min[2] = { box.GetX(), box.GetY() }; int min[2] = { box.GetX(), box.GetY() };

View File

@ -27,30 +27,29 @@
#include <boost/unordered_map.hpp> #include <boost/unordered_map.hpp>
template <class T> const SHAPE *defaultShapeFunctor( const T aItem ) template <class T> const SHAPE* defaultShapeFunctor( const T aItem )
{ {
return aItem->GetShape(); return aItem->GetShape();
} }
template <class T, const SHAPE *(ShapeFunctor)(const T) = defaultShapeFunctor<T> > template <class T, const SHAPE* (ShapeFunctor)(const T) = defaultShapeFunctor<T> >
class SHAPE_INDEX_LIST { class SHAPE_INDEX_LIST {
struct ShapeEntry { struct ShapeEntry {
ShapeEntry(T aParent) ShapeEntry( T aParent )
{ {
shape = ShapeFunctor(aParent); shape = ShapeFunctor( aParent );
bbox = shape->BBox(0); bbox = shape->BBox( 0 );
parent = aParent; parent = aParent;
} }
~ShapeEntry() ~ShapeEntry()
{ {
} }
T parent; T parent;
const SHAPE *shape; const SHAPE* shape;
BOX2I bbox; BOX2I bbox;
}; };
@ -58,18 +57,16 @@ class SHAPE_INDEX_LIST {
typedef typename std::vector<ShapeEntry>::iterator ShapeVecIter; typedef typename std::vector<ShapeEntry>::iterator ShapeVecIter;
public: public:
// "Normal" iterator interface, for STL algorithms.
// "Normal" iterator interface, for STL algorithms.
class iterator { class iterator {
public: public:
iterator() {}; iterator() {};
iterator( ShapeVecIter aCurrent) iterator( ShapeVecIter aCurrent )
: m_current(aCurrent) {}; : m_current( aCurrent ) {};
iterator(const iterator &b) : iterator( const iterator &aB ) :
m_current(b.m_current) {}; m_current( aB.m_current ) {};
T operator*() const T operator*() const
{ {
@ -81,25 +78,25 @@ public:
++m_current; ++m_current;
} }
iterator& operator++(int dummy) iterator& operator++( int aDummy )
{ {
++m_current; ++m_current;
return *this; return *this;
} }
bool operator ==( const iterator& rhs ) const bool operator==( const iterator& aRhs ) const
{ {
return m_current == rhs.m_current; return m_current == aRhs.m_current;
} }
bool operator !=( const iterator& rhs ) const bool operator!=( const iterator& aRhs ) const
{ {
return m_current != rhs.m_current; return m_current != aRhs.m_current;
} }
const iterator& operator=(const iterator& rhs) const iterator& operator=( const iterator& aRhs )
{ {
m_current = rhs.m_current; m_current = aRhs.m_current;
return *this; return *this;
} }
@ -107,40 +104,37 @@ public:
ShapeVecIter m_current; ShapeVecIter m_current;
}; };
// "Query" iterator, for iterating over a set of spatially matching shapes. // "Query" iterator, for iterating over a set of spatially matching shapes.
class query_iterator { class query_iterator {
public: public:
query_iterator() query_iterator()
{ {
} }
query_iterator( ShapeVecIter aCurrent, ShapeVecIter aEnd, SHAPE *aShape, int aMinDistance, bool aExact) query_iterator( ShapeVecIter aCurrent, ShapeVecIter aEnd, SHAPE* aShape,
: m_end(aEnd), int aMinDistance, bool aExact ) :
m_current(aCurrent), m_end( aEnd ),
m_shape(aShape), m_current( aCurrent ),
m_minDistance(aMinDistance), m_shape( aShape ),
m_exact(aExact) m_minDistance( aMinDistance ),
m_exact( aExact )
{ {
if(aShape) if( aShape )
{ {
m_refBBox = aShape->BBox(); m_refBBox = aShape->BBox();
next(); next();
} }
} }
query_iterator(const query_iterator &b) query_iterator( const query_iterator &aB ) :
: m_end(b.m_end), m_end( aB.m_end ),
m_current(b.m_current), m_current( aB.m_current ),
m_shape(b.m_shape), m_shape( aB.m_shape ),
m_minDistance(b.m_minDistance), m_minDistance( aB.m_minDistance ),
m_exact(b.m_exact), m_exact( aB.m_exact ),
m_refBBox(b.m_refBBox) m_refBBox( aB.m_refBBox )
{ {
} }
T operator*() const T operator*() const
{ {
@ -154,45 +148,45 @@ public:
return *this; return *this;
} }
query_iterator& operator++(int dummy) query_iterator& operator++( int aDummy )
{ {
++m_current; ++m_current;
next(); next();
return *this; return *this;
} }
bool operator ==( const query_iterator& rhs ) const bool operator==( const query_iterator& aRhs ) const
{ {
return m_current == rhs.m_current; return m_current == aRhs.m_current;
} }
bool operator !=( const query_iterator& rhs ) const bool operator!=( const query_iterator& aRhs ) const
{ {
return m_current != rhs.m_current; return m_current != aRhs.m_current;
} }
const query_iterator& operator=(const query_iterator& rhs) const query_iterator& operator=( const query_iterator& aRhs )
{ {
m_end = rhs.m_end; m_end = aRhs.m_end;
m_current = rhs.m_current; m_current = aRhs.m_current;
m_shape = rhs.m_shape; m_shape = aRhs.m_shape;
m_minDistance = rhs.m_minDistance; m_minDistance = aRhs.m_minDistance;
m_exact = rhs.m_exact; m_exact = aRhs.m_exact;
m_refBBox = rhs.m_refBBox; m_refBBox = aRhs.m_refBBox;
return *this; return *this;
} }
private: private:
void next() void next()
{ {
while(m_current != m_end) while( m_current != m_end )
{ {
if (m_refBBox.Distance(m_current->bbox) <= m_minDistance) if( m_refBBox.Distance( m_current->bbox ) <= m_minDistance )
{ {
if(!m_exact || m_current->shape->Collide(m_shape, m_minDistance)) if( !m_exact || m_current->shape->Collide( m_shape, m_minDistance ) )
return; return;
} }
++m_current; ++m_current;
} }
} }
@ -205,27 +199,27 @@ public:
int m_minDistance; int m_minDistance;
}; };
void Add(T aItem) void Add( T aItem )
{ {
ShapeEntry s (aItem); ShapeEntry s( aItem );
m_shapes.push_back(s); m_shapes.push_back(s);
} }
void Remove(const T aItem) void Remove( const T aItem )
{ {
ShapeVecIter i; ShapeVecIter i;
for(i=m_shapes.begin(); i!=m_shapes.end();++i) for( i = m_shapes.begin(); i != m_shapes.end(); ++i )
{ {
if(i->parent == aItem) if( i->parent == aItem )
break; break;
} }
if(i == m_shapes.end()) if( i == m_shapes.end() )
return; return;
m_shapes.erase(i); m_shapes.erase( i );
} }
int Size() const int Size() const
@ -234,37 +228,37 @@ public:
} }
template<class Visitor> template<class Visitor>
int Query( const SHAPE *aShape, int aMinDistance, Visitor &v, bool aExact = true) //const int Query( const SHAPE *aShape, int aMinDistance, Visitor &aV, bool aExact = true ) //const
{ {
ShapeVecIter i; ShapeVecIter i;
int n = 0; int n = 0;
VECTOR2I::extended_type minDistSq = (VECTOR2I::extended_type) aMinDistance * aMinDistance; VECTOR2I::extended_type minDistSq = (VECTOR2I::extended_type) aMinDistance * aMinDistance;
BOX2I refBBox = aShape->BBox(); BOX2I refBBox = aShape->BBox();
for(i = m_shapes.begin(); i!=m_shapes.end(); ++i) for( i = m_shapes.begin(); i != m_shapes.end(); ++i )
{ {
if (refBBox.SquaredDistance(i->bbox) <= minDistSq) if( refBBox.SquaredDistance( i->bbox ) <= minDistSq )
{ {
if(!aExact || i->shape->Collide(aShape, aMinDistance)) if( !aExact || i->shape->Collide( aShape, aMinDistance ) )
{ {
n++; n++;
if(!v( i->parent )) if( !aV( i->parent ) )
return n; return n;
} }
} }
} }
return n; return n;
} }
void Clear() void Clear()
{ {
m_shapes.clear(); m_shapes.clear();
} }
query_iterator qbegin( SHAPE *aShape, int aMinDistance, bool aExact ) query_iterator qbegin( SHAPE* aShape, int aMinDistance, bool aExact )
{ {
return query_iterator( m_shapes.begin(), m_shapes.end(), aShape, aMinDistance, aExact); return query_iterator( m_shapes.begin(), m_shapes.end(), aShape, aMinDistance, aExact );
} }
const query_iterator qend() const query_iterator qend()
@ -283,7 +277,6 @@ public:
} }
private: private:
ShapeVec m_shapes; ShapeVec m_shapes;
}; };

View File

@ -36,28 +36,28 @@ class SHAPE_RECT : public SHAPE {
* Constructor * Constructor
* Creates an empty (0-sized) rectangle * Creates an empty (0-sized) rectangle
*/ */
SHAPE_RECT(): SHAPE_RECT() :
SHAPE( SH_RECT ), m_w (0), m_h(0) {}; SHAPE( SH_RECT ), m_w( 0 ), m_h( 0 ) {};
/** /**
* Constructor * Constructor
* Creates a rectangle defined by top-left corner (x0, y0), width w and height h. * Creates a rectangle defined by top-left corner (aX0, aY0), width aW and height aH.
*/ */
SHAPE_RECT( int x0, int y0, int w, int h ): SHAPE_RECT( int aX0, int aY0, int aW, int aH ) :
SHAPE(SH_RECT), m_p0(x0, y0), m_w(w), m_h(h) {}; SHAPE( SH_RECT ), m_p0( aX0, aY0 ), m_w( aW ), m_h( aH ) {};
/** /**
* Constructor * Constructor
* Creates a rectangle defined by top-left corner p0, width w and height h. * Creates a rectangle defined by top-left corner aP0, width aW and height aH.
*/ */
SHAPE_RECT( const VECTOR2I &p0, int w, int h ): SHAPE_RECT( const VECTOR2I &aP0, int aW, int aH ) :
SHAPE(SH_RECT), m_p0(p0), m_w(w), m_h(h) {}; SHAPE( SH_RECT ), m_p0( aP0 ), m_w( aW ), m_h( aH ) {};
/// @copydoc SHAPE::BBox() /// @copydoc SHAPE::BBox()
const BOX2I BBox(int aClearance = 0) const const BOX2I BBox(int aClearance = 0) const
{ {
BOX2I bbox( VECTOR2I (m_p0.x - aClearance, m_p0.y - aClearance ), BOX2I bbox( VECTOR2I( m_p0.x - aClearance, m_p0.y - aClearance ),
VECTOR2I (m_w + 2 * aClearance, m_h + 2 * aClearance )); VECTOR2I( m_w + 2 * aClearance, m_h + 2 * aClearance ) );
//printf("bb : %s\n",bbox.Format().c_str()); //printf("bb : %s\n",bbox.Format().c_str());
return bbox; return bbox;
} }
@ -70,11 +70,11 @@ class SHAPE_RECT : public SHAPE {
*/ */
int Diagonal() const int Diagonal() const
{ {
return VECTOR2I(m_w, m_h).EuclideanNorm(); return VECTOR2I( m_w, m_h ).EuclideanNorm();
} }
/// @copydoc SHAPE::Collide() /// @copydoc SHAPE::Collide()
bool Collide(const SEG& aSeg, int aClearance = 0) const bool Collide( const SEG& aSeg, int aClearance = 0 ) const
{ {
//VECTOR2I pmin = VECTOR2I(std::min(aSeg.a.x, aSeg.b.x), std::min(aSeg.a.y, aSeg.b.y)); //VECTOR2I pmin = VECTOR2I(std::min(aSeg.a.x, aSeg.b.x), std::min(aSeg.a.y, aSeg.b.y));
//VECTOR2I pmax = VECTOR2I(std::max(aSeg.a.x, aSeg.b.x), std::max(aSeg.a.y, aSeg.b.y)); //VECTOR2I pmax = VECTOR2I(std::max(aSeg.a.x, aSeg.b.x), std::max(aSeg.a.y, aSeg.b.y));
@ -83,19 +83,19 @@ class SHAPE_RECT : public SHAPE {
//if (BBox(0).SquaredDistance(r) > aClearance * aClearance) //if (BBox(0).SquaredDistance(r) > aClearance * aClearance)
// return false; // return false;
if(BBox(0).Contains(aSeg.a) || BBox(0).Contains(aSeg.b)) if( BBox( 0 ).Contains( aSeg.a ) || BBox( 0 ).Contains( aSeg.b ) )
return true; return true;
VECTOR2I vts[] = { VECTOR2I(m_p0.x, m_p0.y), VECTOR2I vts[] = { VECTOR2I( m_p0.x, m_p0.y ),
VECTOR2I(m_p0.x, m_p0.y + m_h), VECTOR2I( m_p0.x, m_p0.y + m_h ),
VECTOR2I(m_p0.x + m_w, m_p0.y + m_h), VECTOR2I( m_p0.x + m_w, m_p0.y + m_h ),
VECTOR2I(m_p0.x + m_w, m_p0.y), VECTOR2I( m_p0.x + m_w, m_p0.y ),
VECTOR2I(m_p0.x, m_p0.y) }; VECTOR2I( m_p0.x, m_p0.y ) };
for (int i = 0; i < 4; i++) for( int i = 0; i < 4; i++ )
{ {
SEG s(vts[i], vts[i+1], i); SEG s( vts[i], vts[i + 1], i );
if(s.Distance(aSeg) <= aClearance) if( s.Distance( aSeg ) <= aClearance )
return true; return true;
} }
@ -114,7 +114,7 @@ class SHAPE_RECT : public SHAPE {
* *
* @return size of the rectangle * @return size of the rectangle
*/ */
const VECTOR2I GetSize() const { return VECTOR2I(m_w, m_h); } const VECTOR2I GetSize() const { return VECTOR2I( m_w, m_h ); }
/** /**
* Function GetWidth() * Function GetWidth()
@ -133,8 +133,10 @@ class SHAPE_RECT : public SHAPE {
private: private:
///> Top-left corner ///> Top-left corner
VECTOR2I m_p0; VECTOR2I m_p0;
///> Width ///> Width
int m_w; int m_w;
///> Height ///> Height
int m_h; int m_h;
}; };

View File

@ -32,6 +32,12 @@ class TOOL_BASE;
class TOOL_MANAGER; class TOOL_MANAGER;
class TOOL_ACTION; class TOOL_ACTION;
/**
* Class ACTION_MANAGER
*
* Takes care of TOOL_ACTION objects. Registers them and allows to run them using associated
* hot keys, names or ids.
*/
class ACTION_MANAGER class ACTION_MANAGER
{ {
public: public:

View File

@ -140,7 +140,7 @@ private:
/// Menu items with ID higher than that are considered TOOL_ACTIONs /// Menu items with ID higher than that are considered TOOL_ACTIONs
static const int m_actionId = 10000; static const int m_actionId = 10000;
/// Stores tool actions that are choosable from the menu. Does not take the ownership. /// Associates tool actions with menu item IDs. Non-owning.
std::map<int, const TOOL_ACTION*> m_toolActions; std::map<int, const TOOL_ACTION*> m_toolActions;
}; };

View File

@ -181,7 +181,7 @@ public:
} }
private: private:
static const int c_defaultStackSize = 2000000; static const int c_defaultStackSize = 2000000; // fixme: make configurable
/* real entry point of the coroutine */ /* real entry point of the coroutine */
static void callerStub( intptr_t data ) static void callerStub( intptr_t data )

View File

@ -3,6 +3,7 @@
* *
* Copyright (C) 2013 CERN * Copyright (C) 2013 CERN
* @author Tomasz Wlostowski <tomasz.wlostowski@cern.ch> * @author Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
* @author Maciej Suminski <maciej.suminski@cern.ch>
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
@ -31,10 +32,16 @@
#include <tool/tool_base.h> #include <tool/tool_base.h>
#include <tool/action_manager.h> #include <tool/action_manager.h>
// TOOL_ACTION - represents a single action. For instance: /**
// - changing layer to top by pressing PgUp * Class TOOL_ACTION
// - running the DRC from the menu *
// and so on, and so forth.... * Represents a single user action. For instance:
* - changing layer to top by pressing PgUp
* - running the DRC from the menu
* and so on, and so forth....
* Action class groups all necessary properties of an action, including explanation,
* icons, hotkeys,.menu items, etc.
*/
class TOOL_ACTION class TOOL_ACTION
{ {
public: public:
@ -133,13 +140,13 @@ public:
} }
/** /**
* Function GetEvent() * Function MakeEvent()
* Returns the event associated with the action (ie. the event that will be sent after * Returns the event associated with the action (ie. the event that will be sent after
* activating the action). * activating the action).
* *
* @return The event associated with the action. * @return The event associated with the action.
*/ */
TOOL_EVENT GetEvent() const TOOL_EVENT MakeEvent() const
{ {
return TOOL_EVENT( TC_Command, TA_Action, m_name, m_scope ); return TOOL_EVENT( TC_Command, TA_Action, m_name, m_scope );
} }

View File

@ -42,10 +42,10 @@ namespace KiGfx {
* Class TOOL_DISPATCHER * Class TOOL_DISPATCHER
* *
* - takes wx events, * - takes wx events,
* - fixes all wx quirks (mouse warping, etc) * - fixes all wx quirks (mouse warping, panning, ordering problems, etc)
* - translates coordinates to world space * - translates coordinates to world space
* - low-level input conditioning (drag/click threshold), updating mouse position during view auto-scroll/pan. * - low-level input conditioning (drag/click threshold), updating mouse position during view auto-scroll/pan.
* - issues TOOL_EVENTS to the manager * - issues TOOL_EVENTS to the tool manager
*/ */
class TOOL_DISPATCHER class TOOL_DISPATCHER
@ -100,6 +100,7 @@ private:
///> Saves the state of key modifiers (Alt, Ctrl and so on). ///> 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. ///> Stores all the informations regarding a mouse button state.
struct ButtonState; struct ButtonState;

View File

@ -33,6 +33,7 @@
#include <boost/optional.hpp> #include <boost/optional.hpp>
class TOOL_ACTION;
class TOOL_MANAGER; class TOOL_MANAGER;
/** /**
@ -313,6 +314,14 @@ public:
return true; return true;
} }
/**
* Function IsAction()
* Tests if the event contains an action issued upon activation of the given TOOL_ACTION.
* @param aAction is the TOOL_ACTION to be checked against.
* @return True if it matches the given TOOL_ACTION.
*/
bool IsAction( const TOOL_ACTION* aAction ) const;
boost::optional<int> GetCommandId() boost::optional<int> GetCommandId()
{ {
return m_commandId; return m_commandId;

View File

@ -3,6 +3,7 @@
* *
* Copyright (C) 2013 CERN * Copyright (C) 2013 CERN
* @author Tomasz Wlostowski <tomasz.wlostowski@cern.ch> * @author Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
* @author Maciej Suminski <maciej.suminski@cern.ch>
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
@ -30,11 +31,10 @@
#include <math/vector2d.h> #include <math/vector2d.h>
#include <tool/tool_event.h>
#include <tool/tool_base.h> #include <tool/tool_base.h>
#include <tool/action_manager.h>
class TOOL_BASE; class TOOL_BASE;
class ACTION_MANAGER;
class CONTEXT_MENU; class CONTEXT_MENU;
class wxWindow; class wxWindow;
@ -89,10 +89,7 @@ public:
* *
* @param aAction is the action to be registered. * @param aAction is the action to be registered.
*/ */
void RegisterAction( TOOL_ACTION* aAction ) void RegisterAction( TOOL_ACTION* aAction );
{
m_actionMgr.RegisterAction( aAction );
}
/** /**
* Function UnregisterAction() * Function UnregisterAction()
@ -100,10 +97,7 @@ public:
* *
* @param aAction is the action to be unregistered. * @param aAction is the action to be unregistered.
*/ */
void UnregisterAction( TOOL_ACTION* aAction ) void UnregisterAction( TOOL_ACTION* aAction );
{
m_actionMgr.UnregisterAction( aAction );
}
/** /**
* Function FindTool() * Function FindTool()
@ -205,6 +199,14 @@ private:
void dispatchInternal( TOOL_EVENT& aEvent ); void dispatchInternal( TOOL_EVENT& aEvent );
/**
* Function dispatchStandardEvents()
* Handles specific events, that are intended for TOOL_MANAGER rather than tools.
* @aEvent is the event to be processed.
* @return False if the event was processed and should not go any further.
*/
bool dispatchStandardEvents( TOOL_EVENT& aEvent );
/** /**
* Function dispatchActivation() * Function dispatchActivation()
* Checks if it is a valid activation event and invokes a proper tool. * Checks if it is a valid activation event and invokes a proper tool.
@ -215,7 +217,8 @@ private:
/** /**
* Function invokeTool() * Function invokeTool()
* Invokes a tool by sending a proper event. * Invokes a tool by sending a proper event (in contrary to runTool, which makes the tool run
* for real).
* @param aTool is the tool to be invoked. * @param aTool is the tool to be invoked.
*/ */
bool invokeTool( TOOL_BASE* aTool ); bool invokeTool( TOOL_BASE* aTool );
@ -291,7 +294,9 @@ private:
/// Stack of the active tools /// Stack of the active tools
std::deque<TOOL_ID> m_activeTools; std::deque<TOOL_ID> m_activeTools;
ACTION_MANAGER m_actionMgr; /// Instance of ACTION_MANAGER that handles TOOL_ACTIONs
ACTION_MANAGER* m_actionMgr;
EDA_ITEM* m_model; EDA_ITEM* m_model;
KiGfx::VIEW* m_view; KiGfx::VIEW* m_view;
KiGfx::VIEW_CONTROLS* m_viewControls; KiGfx::VIEW_CONTROLS* m_viewControls;

View File

@ -84,15 +84,16 @@ public:
/// @copydoc VIEW_CONTROLS::GetCursorPosition() /// @copydoc VIEW_CONTROLS::GetCursorPosition()
virtual const VECTOR2D GetCursorPosition() const; virtual const VECTOR2D GetCursorPosition() const;
/// Event that forces mouse move event in the dispatcher /// Event that forces mouse move event in the dispatcher (eg. used in autopanning, when mouse
/// cursor does not move in screen coordinates, but does in world coordinates)
static const wxEventType EVT_REFRESH_MOUSE; static const wxEventType EVT_REFRESH_MOUSE;
private: private:
/// Possible states for WX_VIEW_CONTROLS /// Possible states for WX_VIEW_CONTROLS
enum State { enum State {
IDLE = 1, IDLE = 1, /// Nothing is happening
DRAG_PANNING, DRAG_PANNING, /// Panning with mouse button pressed
AUTO_PANNING, AUTO_PANNING, /// Panning on approaching borders of the frame
}; };
/** /**

View File

@ -22,6 +22,12 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/ */
#ifndef ITEM_STATE_H_
#define ITEM_STATE_H_
#include <deque>
#include <class_board_item.h>
/** /**
* Class ITEM_STATE * Class ITEM_STATE
* *
@ -29,13 +35,6 @@
* the introduced changes. Does not take ownership of modified items, neither takes care of * the introduced changes. Does not take ownership of modified items, neither takes care of
* refreshing. * refreshing.
*/ */
#ifndef ITEM_STATE_H_
#define ITEM_STATE_H_
#include <deque>
#include <class_board_item.h>
class ITEM_STATE class ITEM_STATE
{ {
public: public:
@ -278,4 +277,3 @@ private:
}; };
#endif /* ITEM_STATE_H_ */ #endif /* ITEM_STATE_H_ */

View File

@ -53,7 +53,7 @@ MOVE_TOOL::~MOVE_TOOL()
void MOVE_TOOL::Reset() void MOVE_TOOL::Reset()
{ {
// The tool launches upon reception of action event ("pcbnew.InteractiveMove") // The tool launches upon reception of action event ("pcbnew.InteractiveMove")
Go( &MOVE_TOOL::Main, m_activate.GetEvent() ); Go( &MOVE_TOOL::Main, m_activate.MakeEvent() );
} }
@ -115,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() ) ) // got rotation event? if( evt->IsAction( &m_rotate ) ) // 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() ) ) // got flip event? else if( evt->IsAction( &m_flip ) ) // got flip event?
{ {
m_state.Flip( cursorPos ); m_state.Flip( cursorPos );
m_items.ViewUpdate( VIEW_ITEM::GEOMETRY ); m_items.ViewUpdate( VIEW_ITEM::GEOMETRY );

View File

@ -27,8 +27,8 @@
#include <math/vector2d.h> #include <math/vector2d.h>
#include <tool/tool_interactive.h> #include <tool/tool_interactive.h>
#include <tool/item_state.h>
#include <view/view_group.h> #include <view/view_group.h>
#include "item_state.h"
class BOARD_ITEM; class BOARD_ITEM;
class SELECTION_TOOL; class SELECTION_TOOL;

View File

@ -68,7 +68,7 @@ void SELECTION_TOOL::Reset()
m_selectedItems.clear(); m_selectedItems.clear();
// The tool launches upon reception of action event ("pcbnew.InteractiveSelection") // The tool launches upon reception of action event ("pcbnew.InteractiveSelection")
Go( &SELECTION_TOOL::Main, m_activate.GetEvent() ); Go( &SELECTION_TOOL::Main, m_activate.MakeEvent() );
} }
@ -266,7 +266,7 @@ bool SELECTION_TOOL::selectMultiple()
VIEW* view = getView(); VIEW* view = getView();
getViewControls()->SetAutoPan( true ); getViewControls()->SetAutoPan( true );
// Those 2 lines remove the blink-in-the-random-place effect // These 2 lines remove the blink-in-the-random-place effect
m_selArea->SetOrigin( VECTOR2I( 0, 0 ) ); m_selArea->SetOrigin( VECTOR2I( 0, 0 ) );
m_selArea->SetEnd( VECTOR2I( 0, 0 ) ); m_selArea->SetEnd( VECTOR2I( 0, 0 ) );
view->Add( m_selArea ); view->Add( m_selArea );
@ -467,7 +467,6 @@ bool SELECTION_TOOL::selectable( const BOARD_ITEM* aItem ) const
break; break;
} }
// All other items are selected only if the layer on which they exist is visible // All other items are selected only if the layer on which they exist is visible
return board->IsLayerVisible( aItem->GetLayer() ); return board->IsLayerVisible( aItem->GetLayer() );
} }
@ -475,12 +474,14 @@ bool SELECTION_TOOL::selectable( const BOARD_ITEM* aItem ) const
bool SELECTION_TOOL::containsSelected( const VECTOR2I& aPoint ) const bool SELECTION_TOOL::containsSelected( const VECTOR2I& aPoint ) const
{ {
const unsigned GRIP_MARGIN = 500000;
// 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(); it != it_end; ++it ) for( it = m_selectedItems.begin(), it_end = m_selectedItems.end(); it != it_end; ++it )
{ {
BOX2I itemBox = (*it)->ViewBBox(); BOX2I itemBox = (*it)->ViewBBox();
itemBox.Inflate( 500000 ); // Give some margin for gripping an item itemBox.Inflate( GRIP_MARGIN ); // Give some margin for gripping an item
if( itemBox.Contains( aPoint ) ) if( itemBox.Contains( aPoint ) )
return true; return true;