Do not freeze cursor when a tool was cancelled using the context menu

dispatchContextMenu() stores the cursor position before displaying a
menu, so the tools use the original cursor position when processing
events (instead of the mouse position pointing to a menu entry). Later,
the previous position has to be restored, but if in the meantime the
tool was cancelled - previous settings were restored to a wrong tool.
This commit is contained in:
Maciej Suminski 2017-02-24 16:39:52 +01:00
parent b25ded4d90
commit e34b73e187
4 changed files with 75 additions and 40 deletions

View File

@ -625,55 +625,68 @@ bool TOOL_MANAGER::dispatchActivation( const TOOL_EVENT& aEvent )
void TOOL_MANAGER::dispatchContextMenu( const TOOL_EVENT& aEvent )
{
// Store the current tool ID to decide whether to restore the cursor position
TOOL_ID activeTool = GetCurrentToolId();
for( TOOL_ID toolId : m_activeTools )
{
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 )
continue;
if( st->contextMenuTrigger == CMENU_BUTTON && !aEvent.IsClick( BUT_RIGHT ) )
break;
st->pendingWait = true;
st->waitEvents = TOOL_EVENT( TC_ANY, TA_ANY );
// Store the menu pointer in case it is changed by the TOOL when handling menu events
CONTEXT_MENU* m = st->contextMenu;
if( st->contextMenuTrigger == CMENU_NOW )
st->contextMenuTrigger = CMENU_OFF;
VECTOR2D cursor = m_viewControls->GetCursorPosition();
// Temporarily store the cursor position, so the tools could execute actions
// using the point where the user has invoked a context menu
if( m_viewControls->ForcedCursorPosition() )
m_origCursor = cursor;
m_viewControls->ForceCursorPosition( true, cursor );
// Display a copy of menu
std::unique_ptr<CONTEXT_MENU> menu( m->Clone() );
// Run update handlers on the created copy
menu->UpdateAll();
GetEditFrame()->PopupMenu( menu.get() );
// If nothing was chosen from the context menu, we must notify the tool as well
if( menu->GetSelected() < 0 )
{
if( st->contextMenuTrigger == CMENU_BUTTON && !aEvent.IsClick( BUT_RIGHT ) )
break;
st->pendingWait = true;
st->waitEvents = TOOL_EVENT( TC_ANY, TA_ANY );
// Store the menu pointer in case it is changed by the TOOL when handling menu events
CONTEXT_MENU* m = st->contextMenu;
if( st->contextMenuTrigger == CMENU_NOW )
st->contextMenuTrigger = CMENU_OFF;
// Temporarily store the cursor position, so the tools could execute actions
// using the point where the user has invoked a context menu
bool forcedCursor = m_viewControls->IsCursorPositionForced();
VECTOR2D cursorPos = m_viewControls->GetCursorPosition();
m_viewControls->ForceCursorPosition( true, m_viewControls->GetCursorPosition() );
// Display a copy of menu
std::unique_ptr<CONTEXT_MENU> menu( m->Clone() );
// Run update handlers on the created copy
menu->UpdateAll();
GetEditFrame()->PopupMenu( menu.get() );
// If nothing was chosen from the context menu, we must notify the tool as well
if( menu->GetSelected() < 0 )
{
TOOL_EVENT evt( TC_COMMAND, TA_CONTEXT_MENU_CHOICE, -1 );
evt.SetParameter( m );
dispatchInternal( evt );
}
// Notify the tools that menu has been closed
TOOL_EVENT evt( TC_COMMAND, TA_CONTEXT_MENU_CLOSED );
TOOL_EVENT evt( TC_COMMAND, TA_CONTEXT_MENU_CHOICE, -1 );
evt.SetParameter( m );
dispatchInternal( evt );
m_viewControls->ForceCursorPosition( forcedCursor, cursorPos );
break;
}
// Notify the tools that menu has been closed
TOOL_EVENT evt( TC_COMMAND, TA_CONTEXT_MENU_CLOSED );
evt.SetParameter( m );
dispatchInternal( evt );
// Restore the cursor settings if the tool is still active
if( activeTool == GetCurrentToolId() )
{
m_viewControls->ForceCursorPosition( (bool) m_origCursor,
m_origCursor.value_or( VECTOR2D( 0, 0 ) ) );
}
m_origCursor = boost::none;
break;
}
}
@ -684,8 +697,18 @@ TOOL_MANAGER::ID_LIST::iterator TOOL_MANAGER::finishTool( TOOL_STATE* aState )
// Store the current VIEW_CONTROLS settings
if( TOOL_STATE* state = GetCurrentToolState() )
{
state->vcSettings = m_viewControls->GetSettings();
// If context menu has overridden the cursor position, restore the original one
// (see dispatchContextMenu())
if( m_origCursor )
{
state->vcSettings.m_forceCursorPosition = true;
state->vcSettings.m_forcedPosition = *m_origCursor;
}
}
if( !aState->Pop() )
{
// Deactivate the tool if there are no other contexts saved on the stack

View File

@ -64,7 +64,6 @@ public:
*/
void SetContextMenu( CONTEXT_MENU* aMenu, CONTEXT_MENU_TRIGGER aTrigger = CMENU_BUTTON );
/**
* Function RunMainStack()
*

View File

@ -468,6 +468,9 @@ private:
/// Instance of ACTION_MANAGER that handles TOOL_ACTIONs
ACTION_MANAGER* m_actionMgr;
/// Original cursor position, if overridden by the context menu handler
boost::optional<VECTOR2D> m_origCursor;
EDA_ITEM* m_model;
KIGFX::VIEW* m_view;
KIGFX::VIEW_CONTROLS* m_viewControls;

View File

@ -139,6 +139,16 @@ public:
m_settings.m_forcedPosition = aPosition;
}
/**
* Function ForcedCursorPosition()
* Returns true if the current cursor position is forced to a specific location, ignoring
* the mouse cursor position.
*/
bool ForcedCursorPosition() const
{
return m_settings.m_forceCursorPosition;
}
/**
* Function ShowCursor()
* Enables or disables display of cursor.