void TOOL_MANAGER::dispatchContextMenu( const TOOL_EVENT& aEvent ) { 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_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() ); // Run update handlers m->UpdateAll(); boost::scoped_ptr<CONTEXT_MENU> menu( new CONTEXT_MENU( *m ) ); 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 ); } TOOL_EVENT evt( TC_COMMAND, TA_CONTEXT_MENU_CLOSED ); evt.SetParameter( m ); dispatchInternal( evt ); m_viewControls->ForceCursorPosition( forcedCursor, cursorPos ); break; } } }
void CONTEXT_MENU::copyFrom( const CONTEXT_MENU& aMenu ) { m_icon = aMenu.m_icon; m_titleSet = aMenu.m_titleSet; m_selected = -1; // aMenu.m_selected; m_tool = aMenu.m_tool; m_toolActions = aMenu.m_toolActions; m_parent = NULL; // aMenu.m_parent; m_menu_handler = aMenu.m_menu_handler; m_update_handler = aMenu.m_update_handler; // Copy all the menu entries for( int i = 0; i < (int) aMenu.GetMenuItemCount(); ++i ) { wxMenuItem* item = aMenu.FindItemByPosition( i ); appendCopy( item ); } }
BOARD_ITEM* SELECTION_TOOL::disambiguationMenu( GENERAL_COLLECTOR* aCollector ) { BOARD_ITEM* current = NULL; boost::shared_ptr<BRIGHT_BOX> brightBox; CONTEXT_MENU menu; int limit = std::min( 10, aCollector->GetCount() ); for( int i = 0; i < limit; ++i ) { wxString text; BOARD_ITEM* item = ( *aCollector )[i]; text = item->GetSelectMenuText(); menu.Add( text, i + 1 ); } menu.SetTitle( _( "Clarify selection" ) ); SetContextMenu( &menu, CMENU_NOW ); while( OPT_TOOL_EVENT evt = Wait() ) { if( evt->Action() == TA_CONTEXT_MENU_UPDATE ) { if( current ) current->ClearBrightened(); int id = *evt->GetCommandId(); // User has pointed an item, so show it in a different way if( id > 0 && id <= limit ) { current = ( *aCollector )[id - 1]; current->SetBrightened(); } else { current = NULL; } } else if( evt->Action() == TA_CONTEXT_MENU_CHOICE ) { boost::optional<int> id = evt->GetCommandId(); // User has selected an item, so this one will be returned if( id && ( *id > 0 ) ) current = ( *aCollector )[*id - 1]; break; } // Draw a mark to show which item is available to be selected if( current && current->IsBrightened() ) { brightBox.reset( new BRIGHT_BOX( current ) ); getView()->Add( brightBox.get() ); // BRIGHT_BOX is removed from view on destruction } } return current; }
EDA_ITEM* GERBVIEW_SELECTION_TOOL::disambiguationMenu( GERBER_COLLECTOR* aCollector ) { EDA_ITEM* current = NULL; KIGFX::VIEW_GROUP highlightGroup; CONTEXT_MENU menu; highlightGroup.SetLayer( LAYER_GP_OVERLAY ); getView()->Add( &highlightGroup ); int limit = std::min( 10, aCollector->GetCount() ); for( int i = 0; i < limit; ++i ) { wxString text; EDA_ITEM* item = ( *aCollector )[i]; text = item->GetSelectMenuText(); menu.Add( text, i + 1 ); } menu.SetTitle( _( "Clarify selection" ) ); menu.DisplayTitle( true ); SetContextMenu( &menu, CMENU_NOW ); while( OPT_TOOL_EVENT evt = Wait() ) { if( evt->Action() == TA_CONTEXT_MENU_UPDATE ) { if( current ) { current->ClearBrightened(); getView()->Hide( current, false ); highlightGroup.Remove( current ); getView()->MarkTargetDirty( KIGFX::TARGET_OVERLAY ); } int id = *evt->GetCommandId(); // User has pointed an item, so show it in a different way if( id > 0 && id <= limit ) { current = ( *aCollector )[id - 1]; current->SetBrightened(); getView()->Hide( current, true ); highlightGroup.Add( current ); getView()->MarkTargetDirty( KIGFX::TARGET_OVERLAY ); } else { current = NULL; } } else if( evt->Action() == TA_CONTEXT_MENU_CHOICE ) { OPT<int> id = evt->GetCommandId(); // User has selected an item, so this one will be returned if( id && ( *id > 0 ) ) current = ( *aCollector )[*id - 1]; else current = NULL; break; } } if( current && current->IsBrightened() ) { current->ClearBrightened(); getView()->Hide( current, false ); getView()->MarkTargetDirty( KIGFX::TARGET_OVERLAY ); } getView()->Remove( &highlightGroup ); return current; }
void TOOL_MANAGER::dispatchContextMenu( const TOOL_EVENT& aEvent ) { 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 ) 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; // Store the cursor position, so the tools could execute actions // using the point where the user has invoked a context menu m_menuCursor = m_viewControls->GetCursorPosition(); // Save all tools cursor settings, as they will be overridden for( auto idState : m_toolIdIndex ) { TOOL_STATE* s = idState.second; const auto& vc = s->vcSettings; if( vc.m_forceCursorPosition ) m_cursorSettings[idState.first] = vc.m_forcedPosition; else m_cursorSettings[idState.first] = NULLOPT; } m_viewControls->ForceCursorPosition( true, m_menuCursor ); // Display a copy of menu std::unique_ptr<CONTEXT_MENU> menu( m->Clone() ); // Run update handlers on the created copy menu->UpdateAll(); m_menuOwner = toolId; m_menuActive = true; auto frame = dynamic_cast<wxFrame*>( m_editFrame ); if( frame ) frame->PopupMenu( menu.get() ); // Warp the cursor as long as the menu wasn't clicked out of if( menu->GetSelected() >= 0 ) m_viewControls->WarpCursor( m_menuCursor, true, false ); // Otherwise notify the tool of a cancelled menu else { 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 ); evt.SetParameter( m ); dispatchInternal( evt ); m_menuActive = false; m_menuOwner = -1; // Restore cursor settings for( auto cursorSetting : m_cursorSettings ) { auto it = m_toolIdIndex.find( cursorSetting.first ); wxASSERT( it != m_toolIdIndex.end() ); if( it == m_toolIdIndex.end() ) continue; KIGFX::VC_SETTINGS& vc = it->second->vcSettings; vc.m_forceCursorPosition = (bool) cursorSetting.second; vc.m_forcedPosition = cursorSetting.second ? *cursorSetting.second : VECTOR2D( 0, 0 ); } m_cursorSettings.clear(); break; } }
BOARD_ITEM* SELECTION_TOOL::disambiguationMenu( GENERAL_COLLECTOR* aCollector ) { BOARD_ITEM* current = NULL; BRIGHT_BOX brightBox; CONTEXT_MENU menu; getView()->Add( &brightBox ); int limit = std::min( 10, aCollector->GetCount() ); for( int i = 0; i < limit; ++i ) { wxString text; BOARD_ITEM* item = ( *aCollector )[i]; text = item->GetSelectMenuText(); menu.Add( text, i + 1 ); } menu.SetTitle( _( "Clarify selection" ) ); SetContextMenu( &menu, CMENU_NOW ); while( OPT_TOOL_EVENT evt = Wait() ) { if( evt->Action() == TA_CONTEXT_MENU_UPDATE ) { if( current ) current->ClearBrightened(); int id = *evt->GetCommandId(); // User has pointed an item, so show it in a different way if( id > 0 && id <= limit ) { current = ( *aCollector )[id - 1]; current->SetBrightened(); } else { current = NULL; } } else if( evt->Action() == TA_CONTEXT_MENU_CHOICE ) { boost::optional<int> id = evt->GetCommandId(); // User has selected an item, so this one will be returned if( id && ( *id > 0 ) ) current = ( *aCollector )[*id - 1]; else current = NULL; break; } // Draw a mark to show which item is available to be selected if( current && current->IsBrightened() ) { brightBox.SetItem( current ); getView()->SetVisible( &brightBox, true ); // getView()->Hide( &brightBox, false ); getView()->Update( &brightBox, KIGFX::GEOMETRY ); getView()->MarkTargetDirty( KIGFX::TARGET_OVERLAY ); } } getView()->Remove( &brightBox ); return current; }