int PCBNEW_CONTROL::ZoneDisplayMode( const TOOL_EVENT& aEvent ) { KIGFX::PCB_PAINTER* painter = static_cast<KIGFX::PCB_PAINTER*>( m_frame->GetGalCanvas()->GetView()->GetPainter() ); KIGFX::PCB_RENDER_SETTINGS* settings = static_cast<KIGFX::PCB_RENDER_SETTINGS*>( painter->GetSettings() ); DISPLAY_OPTIONS* displ_opts = (DISPLAY_OPTIONS*)m_frame->GetDisplayOptions(); // Apply new display options to the GAL canvas if( aEvent.IsAction( &COMMON_ACTIONS::zoneDisplayEnable ) ) displ_opts->m_DisplayZonesMode = 0; else if( aEvent.IsAction( &COMMON_ACTIONS::zoneDisplayDisable ) ) displ_opts->m_DisplayZonesMode = 1; else if( aEvent.IsAction( &COMMON_ACTIONS::zoneDisplayOutlines ) ) displ_opts->m_DisplayZonesMode = 2; else assert( false ); settings->LoadDisplayOptions( displ_opts ); BOARD* board = getModel<BOARD>(); for( int i = 0; i < board->GetAreaCount(); ++i ) board->GetArea( i )->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); m_frame->GetGalCanvas()->Refresh(); return 0; }
void LENGTH_TUNER_TOOL::handleCommonEvents( const TOOL_EVENT& aEvent ) { if( aEvent.IsAction( &ACT_RouterOptions ) ) { DIALOG_PNS_SETTINGS settingsDlg( m_frame, m_router->Settings() ); if( settingsDlg.ShowModal() ) { // FIXME: do we need an explicit update? } } PNS_MEANDER_PLACER_BASE* placer = static_cast<PNS_MEANDER_PLACER_BASE*>( m_router->Placer() ); if( !placer ) return; if( aEvent.IsAction( &ACT_Settings ) ) { PNS_MEANDER_SETTINGS settings = placer->MeanderSettings(); DIALOG_PNS_LENGTH_TUNING_SETTINGS settingsDlg( m_frame, settings, m_router->Mode() ); if( settingsDlg.ShowModal() ) { placer->UpdateSettings( settings ); } m_savedMeanderSettings = placer->MeanderSettings(); } }
bool TOOL_MANAGER::dispatchStandardEvents( const TOOL_EVENT& aEvent ) { if( aEvent.Action() == TA_KEY_PRESSED ) { // 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 } return true; }
void TOOL_BASE::updateEndItem( const TOOL_EVENT& aEvent ) { int layer; bool snapEnabled = !aEvent.Modifier( MD_SHIFT ); m_gridHelper->SetUseGrid( !aEvent.Modifier( MD_ALT ) ); m_gridHelper->SetSnap( snapEnabled ); controls()->ForceCursorPosition( false ); VECTOR2I mousePos = controls()->GetMousePosition(); if( m_router->Settings().Mode() != RM_MarkObstacles && ( m_router->GetCurrentNets().empty() || m_router->GetCurrentNets().front() < 0 ) ) { m_endSnapPoint = snapToItem( snapEnabled, nullptr, mousePos ); controls()->ForceCursorPosition( true, m_endSnapPoint ); m_endItem = nullptr; return; } if( m_router->IsPlacingVia() ) layer = -1; else layer = m_router->GetCurrentLayer(); ITEM* endItem = nullptr; std::vector<int> nets = m_router->GetCurrentNets(); for( int net : nets ) { endItem = pickSingleItem( mousePos, net, layer, false, { m_startItem } ); if( endItem ) break; } if( checkSnap( endItem ) ) { m_endItem = endItem; m_endSnapPoint = snapToItem( snapEnabled, endItem, mousePos ); } else { m_endItem = nullptr; m_endSnapPoint = m_gridHelper->Align( mousePos ); } controls()->ForceCursorPosition( true, m_endSnapPoint ); if( m_endItem ) { wxLogTrace( "PNS", "%s, layer : %d", m_endItem->KindStr().c_str(), m_endItem->Layers().Start() ); } }
void TOOL_MANAGER::RunAction( const TOOL_ACTION& aAction, bool aNow, void* aParam ) { TOOL_EVENT event = aAction.MakeEvent(); // Allow to override the action parameter if( aParam ) event.SetParameter( aParam ); if( aNow ) ProcessEvent( event ); else PostEvent( event ); }
int PCBNEW_CONTROL::ZoomInOut( const TOOL_EVENT& aEvent ) { KIGFX::VIEW* view = m_frame->GetGalCanvas()->GetView(); double zoomScale = 1.0; if( aEvent.IsAction( &COMMON_ACTIONS::zoomIn ) ) zoomScale = 1.3; else if( aEvent.IsAction( &COMMON_ACTIONS::zoomOut ) ) zoomScale = 0.7; view->SetScale( view->GetScale() * zoomScale, getViewControls()->GetCursorPosition() ); return 0; }
void PNS_TOOL_BASE::updateStartItem( TOOL_EVENT& aEvent ) { int tl = getView()->GetTopLayer(); VECTOR2I cp = m_ctls->GetCursorPosition(); VECTOR2I p; PNS_ITEM* startItem = NULL; bool snapEnabled = true; if( aEvent.IsMotion() || aEvent.IsClick() ) { snapEnabled = !aEvent.Modifier( MD_SHIFT ); p = aEvent.Position(); } else { p = cp; } startItem = pickSingleItem( p ); m_router->EnableSnapping( snapEnabled ); if( !snapEnabled && startItem && !startItem->Layers().Overlaps( tl ) ) startItem = NULL; if( startItem && startItem->Net() >= 0 ) { bool dummy; VECTOR2I psnap = snapToItem( startItem, p, dummy ); if( snapEnabled ) { m_startSnapPoint = psnap; m_ctls->ForceCursorPosition( true, psnap ); } else { m_startSnapPoint = cp; m_ctls->ForceCursorPosition( false ); } m_startItem = startItem; } else { m_startItem = NULL; m_startSnapPoint = cp; m_ctls->ForceCursorPosition( false ); } }
int PCBNEW_CONTROL::ZoomInOutCenter( const TOOL_EVENT& aEvent ) { KIGFX::VIEW* view = getView(); double zoomScale = 1.0; if( aEvent.IsAction( &COMMON_ACTIONS::zoomInCenter ) ) zoomScale = 1.3; else if( aEvent.IsAction( &COMMON_ACTIONS::zoomOutCenter ) ) zoomScale = 0.7; view->SetScale( view->GetScale() * zoomScale ); return 0; }
void ROUTER_TOOL::handleCommonEvents( const TOOL_EVENT& aEvent ) { #ifdef DEBUG if( aEvent.IsKeyPressed() ) { switch( aEvent.KeyCode() ) { case '0': wxLogTrace( "PNS", "saving drag/route log...\n" ); m_router->DumpLog(); break; } } #endif }
bool TOOL_MANAGER::dispatchActivation( const TOOL_EVENT& aEvent ) { if( aEvent.IsActivate() ) { std::map<std::string, TOOL_STATE*>::iterator tool = m_toolNameIndex.find( *aEvent.GetCommandStr() ); if( tool != m_toolNameIndex.end() ) { runTool( tool->second->theTool ); return true; } } return false; }
void POINT_EDITOR::updateEditedPoint( const TOOL_EVENT& aEvent ) { EDIT_POINT* point = m_editedPoint; if( aEvent.IsMotion() ) { point = m_editPoints->FindPoint( aEvent.Position() ); } else if( aEvent.IsDrag( BUT_LEFT ) ) { point = m_editPoints->FindPoint( aEvent.DragOrigin() ); } if( m_editedPoint != point ) setEditedPoint( point ); }
bool PCB_BASE_FRAME::InvokeDialogGrid() { wxPoint grid_origin = GetGridOrigin(); DIALOG_SET_GRID dlg( this, &m_UserGridUnit, g_UserUnit, &m_UserGridSize, &grid_origin, &m_FastGrid1, &m_FastGrid2, m_gridSelectBox->GetStrings() ); int ret = dlg.ShowModal(); if( ret == wxID_OK ) { if( GetGridOrigin() != grid_origin && IsType( FRAME_PCB ) ) OnModify(); // because grid origin is saved in board, show as modified SetGridOrigin( grid_origin ); BASE_SCREEN* screen = GetScreen(); screen->AddGrid( m_UserGridSize, m_UserGridUnit, ID_POPUP_GRID_USER ); // If the user grid is the current option, recall SetGrid() // to force new values put in list as current grid value if( screen->GetGridCmdId() == ID_POPUP_GRID_USER ) screen->SetGrid( ID_POPUP_GRID_USER ); // Notify GAL TOOL_MANAGER* mgr = GetToolManager(); if( mgr && IsGalCanvasActive() ) { mgr->RunAction( "common.Control.gridPreset", true, screen->GetGridCmdId() - ID_POPUP_GRID_LEVEL_1000 ); TOOL_EVENT gridOriginUpdate = COMMON_ACTIONS::gridSetOrigin.MakeEvent(); gridOriginUpdate.SetParameter( new VECTOR2D( grid_origin ) ); mgr->ProcessEvent( gridOriginUpdate ); } m_canvas->Refresh(); return true; } return false; }
void TOOL_BASE::updateStartItem( const TOOL_EVENT& aEvent, bool aIgnorePads ) { int tl = getView()->GetTopLayer(); VECTOR2I cp = controls()->GetCursorPosition( !aEvent.Modifier( MD_SHIFT ) ); VECTOR2I p; controls()->ForceCursorPosition( false ); m_gridHelper->SetUseGrid( !aEvent.Modifier( MD_ALT ) ); m_gridHelper->SetSnap( !aEvent.Modifier( MD_SHIFT ) ); bool snapEnabled = true; if( aEvent.IsMotion() || aEvent.IsClick() ) { snapEnabled = !aEvent.Modifier( MD_SHIFT ); p = aEvent.Position(); } else { p = cp; } m_startItem = pickSingleItem( p, -1, -1, aIgnorePads ); if( !snapEnabled && m_startItem && !m_startItem->Layers().Overlaps( tl ) ) m_startItem = nullptr; m_startSnapPoint = snapToItem( snapEnabled, m_startItem, p ); if( checkSnap( m_startItem ) ) { controls()->ForceCursorPosition( true, m_startSnapPoint ); } }
int PCBNEW_CONTROL::ZoomInOutCenter( TOOL_EVENT& aEvent ) { KIGFX::VIEW* view = m_frame->GetGalCanvas()->GetView(); KIGFX::GAL* gal = m_frame->GetGalCanvas()->GetGAL(); if( aEvent.IsAction( &COMMON_ACTIONS::zoomInCenter ) ) m_frame->SetPrevZoom(); else if( aEvent.IsAction( &COMMON_ACTIONS::zoomOutCenter ) ) m_frame->SetNextZoom(); double zoomFactor = gal->GetWorldScale() / gal->GetZoomFactor(); double zoom = 1.0 / ( zoomFactor * m_frame->GetZoom() ); view->SetScale( zoom ); setTransitions(); return 0; }
void TOOL_MANAGER::RunAction( const TOOL_ACTION& aAction, bool aNow, void* aParam ) { TOOL_EVENT event = aAction.MakeEvent(); // Allow to override the action parameter if( aParam ) event.SetParameter( aParam ); if( aNow ) { TOOL_STATE* current = m_activeState; processEvent( event ); setActiveState( current ); } else { PostEvent( event ); } }
void PNS_TOOL_BASE::updateEndItem( TOOL_EVENT& aEvent ) { VECTOR2I mp = m_ctls->GetMousePosition(); VECTOR2I p = getView()->ToWorld( mp ); VECTOR2I cp = m_ctls->GetCursorPosition(); int layer; bool snapEnabled = !aEvent.Modifier( MD_SHIFT ); m_router->EnableSnapping( snapEnabled ); if( m_router->GetCurrentNets().empty() || m_router->GetCurrentNets().front() < 0 ) { m_endItem = NULL; m_endSnapPoint = cp; return; } bool dummy; if( m_router->IsPlacingVia() ) layer = -1; else layer = m_router->GetCurrentLayer(); PNS_ITEM* endItem = NULL; std::vector<int> nets = m_router->GetCurrentNets(); for( int net : nets ) { endItem = pickSingleItem( p, net, layer ); if( endItem ) break; } if( endItem ) { VECTOR2I cursorPos = snapToItem( endItem, p, dummy ); m_ctls->ForceCursorPosition( true, cursorPos ); m_endItem = endItem; m_endSnapPoint = cursorPos; } else { m_endItem = NULL; m_endSnapPoint = cp; m_ctls->ForceCursorPosition( false ); } if( m_endItem ) { wxLogTrace( "PNS", "%s, layer : %d", m_endItem->KindStr().c_str(), m_endItem->Layers().Start() ); } }
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; } } }
bool TOOL_MANAGER::RunAction( const std::string& aActionName, bool aNow, void* aParam ) { TOOL_ACTION* action = m_actionMgr->FindAction( aActionName ); if( action ) { TOOL_EVENT event = action->MakeEvent(); // Allow to override the action parameter if( aParam ) event.SetParameter( aParam ); if( aNow ) ProcessEvent( event ); else PostEvent( event ); return true; } wxASSERT_MSG( action != NULL, wxString::Format( wxT( "Could not find action %s." ), aActionName ) ); return false; }
void ROUTER_TOOL::handleCommonEvents( const TOOL_EVENT& aEvent ) { #ifdef DEBUG if( aEvent.IsKeyPressed() ) { switch( aEvent.KeyCode() ) { case '0': TRACEn( 2, "saving drag/route log...\n" ); m_router->DumpLog(); break; } } else #endif if( aEvent.IsAction( &ACT_RouterOptions ) ) { DIALOG_PNS_SETTINGS settingsDlg( m_frame, m_router->Settings() ); if( settingsDlg.ShowModal() ) { // FIXME: do we need an explicit update? } } else if( aEvent.IsAction( &ACT_SetDpDimensions ) ) { PNS_SIZES_SETTINGS sizes = m_router->Sizes(); DIALOG_PNS_DIFF_PAIR_DIMENSIONS settingsDlg( m_frame, sizes ); if( settingsDlg.ShowModal() ) { m_router->UpdateSizes( sizes ); } } else if( aEvent.IsAction( &ACT_CustomTrackWidth ) ) { BOARD_DESIGN_SETTINGS& bds = m_board->GetDesignSettings(); DIALOG_TRACK_VIA_SIZE sizeDlg( m_frame, bds ); if( sizeDlg.ShowModal() ) { bds.UseCustomTrackViaSize( true ); m_toolMgr->RunAction( COMMON_ACTIONS::trackViaSizeChanged ); } } else if( aEvent.IsAction( &COMMON_ACTIONS::trackViaSizeChanged ) ) { PNS_SIZES_SETTINGS sizes( m_router->Sizes() ); sizes.ImportCurrent( m_board->GetDesignSettings() ); m_router->UpdateSizes( sizes ); } }
int PL_DRAWING_TOOLS::DrawShape( const TOOL_EVENT& aEvent ) { // We might be running as the same shape in another co-routine. Make sure that one // gets whacked. m_toolMgr->DeactivateTool(); bool isDrawLine; bool isImmediate = false; if( aEvent.IsAction( &PL_ACTIONS::drawLine ) ) { isDrawLine = true; m_frame->SetToolID( ID_PL_LINE_TOOL, wxCURSOR_PENCIL, _( "Draw line" ) ); } else if( aEvent.IsAction( &PL_ACTIONS::drawRectangle ) ) { isDrawLine = false; m_frame->SetToolID( ID_PL_RECTANGLE_TOOL, wxCURSOR_PENCIL, _( "Draw rectangle" ) ); } else if( aEvent.IsAction( &PL_ACTIONS::addLine ) ) { isDrawLine = true; isImmediate = true; } else if( aEvent.IsAction( &PL_ACTIONS::addRectangle ) ) { isDrawLine = false; isImmediate = true; } else wxCHECK_MSG( false, 0, "Unknown action in PL_DRAWING_TOOLS::DrawShape()" ); m_toolMgr->RunAction( PL_ACTIONS::clearSelection, true ); getViewControls()->ShowCursor( true ); Activate(); WS_DRAW_ITEM_BASE* item = nullptr; // Main loop: keep receiving events while( auto evt = Wait() ) { VECTOR2I cursorPos = getViewControls()->GetCursorPosition( !evt->Modifier( MD_ALT ) ); if( TOOL_EVT_UTILS::IsCancelInteractive( evt.get() ) ) { m_toolMgr->RunAction( PL_ACTIONS::clearSelection, true ); if( item ) { item = nullptr; m_frame->RollbackFromUndo(); if( !evt->IsActivate() && !isImmediate ) continue; } break; } else if( evt->IsClick( BUT_LEFT ) || ( isImmediate && !item ) ) { if( !item ) // start drawing { m_frame->SaveCopyInUndoList(); m_toolMgr->RunAction( PL_ACTIONS::clearSelection, true ); WS_DATA_ITEM::WS_ITEM_TYPE dataType; if( isDrawLine ) dataType = WS_DATA_ITEM::WS_SEGMENT; else dataType = WS_DATA_ITEM::WS_RECT; WS_DATA_ITEM* dataItem = m_frame->AddPageLayoutItem( dataType ); dataItem->MoveToUi( (wxPoint) cursorPos ); item = dataItem->GetDrawItems()[0]; item->SetFlags( IS_NEW ); m_selectionTool->AddItemToSel( item ); } else // finish drawing { item->ClearEditFlags(); item = nullptr; m_frame->OnModify(); if( isImmediate ) { m_toolMgr->RunAction( ACTIONS::activatePointEditor ); break; } } } else if( evt->IsAction( &PL_ACTIONS::refreshPreview ) || evt->IsMotion() ) { if( item ) { item->GetPeer()->MoveEndPointToUi( (wxPoint) cursorPos ); item->SetEnd( item->GetPeer()->GetEndPosUi( 0 ) ); getView()->Update( item ); } } else if( evt->IsClick( BUT_RIGHT ) ) { // Warp after context menu only if dragging... if( !item ) m_toolMgr->VetoContextMenuMouseWarp(); m_menu.ShowContextMenu( m_selectionTool->GetSelection() ); } // Enable autopanning and cursor capture only when there is a shape being drawn getViewControls()->SetAutoPan( !!item ); getViewControls()->CaptureCursor( !!item ); } m_frame->SetNoToolSelected(); return 0; }
int EDIT_TOOL::Duplicate( const TOOL_EVENT& aEvent ) { // Note: original items are no more modified. bool increment = aEvent.IsAction( &COMMON_ACTIONS::duplicateIncrement ); // first, check if we have a selection, or try to get one SELECTION_TOOL* selTool = m_toolMgr->GetTool<SELECTION_TOOL>(); const SELECTION& selection = selTool->GetSelection(); // Be sure that there is at least one item that we can modify if( !hoverSelection() ) return 0; // we have a selection to work on now, so start the tool process PCB_BASE_EDIT_FRAME* editFrame = getEditFrame<PCB_BASE_EDIT_FRAME>(); std::vector<BOARD_ITEM*> old_items; for( int i = 0; i < selection.Size(); ++i ) { BOARD_ITEM* item = selection.Item<BOARD_ITEM>( i ); if( item ) old_items.push_back( item ); } for( unsigned i = 0; i < old_items.size(); ++i ) { BOARD_ITEM* item = old_items[i]; // Unselect the item, so we won't pick it up again // Do this first, so a single-item duplicate will correctly call // SetCurItem and show the item properties m_toolMgr->RunAction( COMMON_ACTIONS::unselectItem, true, item ); BOARD_ITEM* new_item = NULL; if( m_editModules ) new_item = editFrame->GetBoard()->m_Modules->Duplicate( item, increment ); else { #if 0 // @TODO: see if we allow zone duplication here // Duplicate zones is especially tricky (overlaping zones must be merged) // so zones are not duplicated if( item->Type() != PCB_ZONE_AREA_T ) #endif new_item = editFrame->GetBoard()->Duplicate( item ); } if( new_item ) { m_commit->Add( new_item ); // Select the new item, so we can pick it up m_toolMgr->RunAction( COMMON_ACTIONS::selectItem, true, new_item ); } } // record the new items as added if( !selection.Empty() ) { editFrame->DisplayToolMsg( wxString::Format( _( "Duplicated %d item(s)" ), (int) old_items.size() ) ); // If items were duplicated, pick them up // this works well for "dropping" copies around and pushes the commit TOOL_EVENT evt = COMMON_ACTIONS::editActivate.MakeEvent(); Main( evt ); } return 0; };
void TOOL_MANAGER::dispatchInternal( const TOOL_EVENT& aEvent ) { // iterate over all registered tools for( auto it = m_activeTools.begin(); it != m_activeTools.end(); ++it ) { TOOL_STATE* st = m_toolIdIndex[*it]; // forward context menu events to the tool that created the menu if( aEvent.IsMenu() ) { if( *it != m_menuOwner ) continue; } // the tool state handler is waiting for events (i.e. called Wait() method) if( st->pendingWait ) { if( st->waitEvents.Matches( aEvent ) ) { // By default only messages are passed further m_passEvent = ( aEvent.Category() == TC_MESSAGE ); // got matching event? clear wait list and wake up the coroutine st->wakeupEvent = aEvent; st->pendingWait = false; st->waitEvents.clear(); if( st->cofunc ) { setActiveState( st ); bool end = !st->cofunc->Resume(); if( end ) it = finishTool( st ); } // If the tool did not request to propagate // the event to other tools, we should stop it now if( !m_passEvent ) break; } } } for( auto& state : m_toolState ) { TOOL_STATE* st = state.second; bool finished = false; // no state handler in progress - check if there are any transitions (defined by // Go() method that match the event. if( !st->transitions.empty() ) { for( TRANSITION& tr : st->transitions ) { if( tr.first.Matches( aEvent ) ) { auto func_copy = tr.second; // if there is already a context, then push it on the stack // and transfer the previous view control settings to the new context if( st->cofunc ) { auto vc = st->vcSettings; st->Push(); st->vcSettings = vc; } st->cofunc = new COROUTINE<int, const TOOL_EVENT&>( std::move( func_copy ) ); // as the state changes, the transition table has to be set up again st->transitions.clear(); // got match? Run the handler. setActiveState( st ); st->idle = false; st->cofunc->Call( aEvent ); if( !st->cofunc->Running() ) finishTool( st ); // The couroutine has finished immediately? // if it is a message, continue processing finished = !( aEvent.Category() == TC_MESSAGE ); // there is no point in further checking, as transitions got cleared break; } } } if( finished ) break; // only the first tool gets the event } }
void TOOL_MANAGER::dispatchInternal( const TOOL_EVENT& aEvent ) { // iterate over all registered tools for( auto it = m_activeTools.begin(); it != m_activeTools.end(); /* iteration is done inside */) { auto curIt = it; TOOL_STATE* st = m_toolIdIndex[*it]; ++it; // it might be overwritten, if the tool is removed the m_activeTools deque // the tool state handler is waiting for events (i.e. called Wait() method) if( st->pendingWait ) { if( st->waitEvents.Matches( aEvent ) ) { // By default, only messages are passed further m_passEvent = ( aEvent.Category() == TC_MESSAGE ); // got matching event? clear wait list and wake up the coroutine st->wakeupEvent = aEvent; st->pendingWait = false; st->waitEvents.clear(); if( st->cofunc && !st->cofunc->Resume() ) { if( finishTool( st, false ) ) // The couroutine has finished it = m_activeTools.erase( curIt ); } // If the tool did not request to propagate // the event to other tools, we should stop it now if( !m_passEvent ) break; } } } for( TOOL_STATE* st : ( m_toolState | boost::adaptors::map_values ) ) { // no state handler in progress - check if there are any transitions (defined by // Go() method that match the event. if( !st->pendingWait && !st->transitions.empty() ) { for( TRANSITION& tr : st->transitions ) { if( tr.first.Matches( aEvent ) ) { auto func_copy = tr.second; // if there is already a context, then store it if( st->cofunc ) st->Push(); st->cofunc = new COROUTINE<int, const TOOL_EVENT&>( std::move( func_copy ) ); // as the state changes, the transition table has to be set up again st->transitions.clear(); // got match? Run the handler. st->cofunc->Call( aEvent ); if( !st->cofunc->Running() ) finishTool( st ); // The couroutine has finished immediately? // there is no point in further checking, as transitions got cleared break; } } } } }
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; } }
int EDIT_TOOL::Duplicate( const TOOL_EVENT& aEvent ) { bool increment = aEvent.IsAction( &COMMON_ACTIONS::duplicateIncrement ); // first, check if we have a selection, or try to get one SELECTION_TOOL* selTool = m_toolMgr->GetTool<SELECTION_TOOL>(); const SELECTION& selection = selTool->GetSelection(); // Be sure that there is at least one item that we can modify if( !hoverSelection( selection ) ) return 0; // we have a selection to work on now, so start the tool process PCB_BASE_FRAME* editFrame = getEditFrame<PCB_BASE_FRAME>(); editFrame->OnModify(); // prevent other tools making undo points while the duplicate is going on // so that if you cancel, you don't get a duplicate object hiding over // the original incUndoInhibit(); if( m_editModules ) editFrame->SaveCopyInUndoList( editFrame->GetBoard()->m_Modules, UR_MODEDIT ); std::vector<BOARD_ITEM*> old_items; for( int i = 0; i < selection.Size(); ++i ) { BOARD_ITEM* item = selection.Item<BOARD_ITEM>( i ); if( item ) old_items.push_back( item ); } for( unsigned i = 0; i < old_items.size(); ++i ) { BOARD_ITEM* item = old_items[i]; // Unselect the item, so we won't pick it up again // Do this first, so a single-item duplicate will correctly call // SetCurItem and show the item properties m_toolMgr->RunAction( COMMON_ACTIONS::unselectItem, true, item ); BOARD_ITEM* new_item = NULL; if( m_editModules ) new_item = editFrame->GetBoard()->m_Modules->DuplicateAndAddItem( item, increment ); else { #if 0 // @TODO: see if we allow zone duplication here // Duplicate zones is especially tricky (overlaping zones must be merged) // so zones are not duplicated if( item->Type() != PCB_ZONE_AREA_T ) #endif new_item = editFrame->GetBoard()->DuplicateAndAddItem( item, increment ); } if( new_item ) { if( new_item->Type() == PCB_MODULE_T ) { static_cast<MODULE*>( new_item )->RunOnChildren( boost::bind( &KIGFX::VIEW::Add, getView(), _1 ) ); } editFrame->GetGalCanvas()->GetView()->Add( new_item ); // Select the new item, so we can pick it up m_toolMgr->RunAction( COMMON_ACTIONS::selectItem, true, new_item ); } } // record the new items as added if( !m_editModules ) editFrame->SaveCopyInUndoList( selection.items, UR_NEW ); editFrame->DisplayToolMsg( wxString::Format( _( "Duplicated %d item(s)" ), (int) old_items.size() ) ); // pick up the selected item(s) and start moving // this works well for "dropping" copies around TOOL_EVENT evt = COMMON_ACTIONS::editActivate.MakeEvent(); Main( evt ); // and re-enable undos decUndoInhibit(); return 0; }
int PL_DRAWING_TOOLS::PlaceItem( const TOOL_EVENT& aEvent ) { bool isText; bool isImmediate = false; if( aEvent.IsAction( &PL_ACTIONS::placeText ) ) { isText = true; m_frame->SetToolID( ID_PL_TEXT_TOOL, wxCURSOR_PENCIL, _( "Add text" ) ); } else if( aEvent.IsAction( &PL_ACTIONS::placeImage ) ) { isText = false; m_frame->SetToolID( ID_PL_IMAGE_TOOL, wxCURSOR_PENCIL, _( "Add image" ) ); } else if( aEvent.IsAction( & PL_ACTIONS::addText ) ) { isText = true; isImmediate = true; } else if( aEvent.IsAction( & PL_ACTIONS::addImage ) ) { isText = false; isImmediate = true; } else wxCHECK_MSG( false, 0, "Unknown action in PL_DRAWING_TOOLS::PlaceItem()" ); VECTOR2I cursorPos; WS_DRAW_ITEM_BASE* item = nullptr; m_toolMgr->RunAction( PL_ACTIONS::clearSelection, true ); getViewControls()->ShowCursor( true ); Activate(); // Main loop: keep receiving events while( OPT_TOOL_EVENT evt = Wait() ) { cursorPos = getViewControls()->GetCursorPosition( !evt->Modifier( MD_ALT ) ); if( TOOL_EVT_UTILS::IsCancelInteractive( evt.get() ) ) { if( item ) { m_toolMgr->RunAction( PL_ACTIONS::clearSelection, true ); delete item; item = nullptr; // There's nothing to roll-back, but we still need to pop the undo stack m_frame->RollbackFromUndo(); if( !evt->IsActivate() && !isImmediate ) continue; } break; } else if( evt->IsClick( BUT_LEFT ) || ( isImmediate && !item ) ) { // First click creates... if( !item ) { m_frame->SaveCopyInUndoList(); m_toolMgr->RunAction( PL_ACTIONS::clearSelection, true ); WS_DATA_ITEM* dataItem; dataItem = m_frame->AddPageLayoutItem( isText ? WS_DATA_ITEM::WS_TEXT : WS_DATA_ITEM::WS_BITMAP ); item = dataItem->GetDrawItems()[0]; item->SetFlags( IS_NEW | IS_MOVED ); m_selectionTool->AddItemToSel( item ); } // ... and second click places: else { item->GetPeer()->MoveStartPointToUi( (wxPoint) cursorPos ); item->SetPosition( item->GetPeer()->GetStartPosUi( 0 ) ); item->ClearEditFlags(); getView()->Update( item ); item = nullptr; m_frame->OnModify(); if( isImmediate ) break; } } else if( evt->IsClick( BUT_RIGHT ) ) { // Warp after context menu only if dragging... if( !item ) m_toolMgr->VetoContextMenuMouseWarp(); m_menu.ShowContextMenu( m_selectionTool->GetSelection() ); } else if( item && ( evt->IsAction( &PL_ACTIONS::refreshPreview ) || evt->IsMotion() ) ) { item->GetPeer()->MoveStartPointToUi( (wxPoint) cursorPos ); item->SetPosition( item->GetPeer()->GetStartPosUi( 0 ) ); getView()->Update( item ); } // Enable autopanning and cursor capture only when there is an item to be placed getViewControls()->SetAutoPan( !!item ); getViewControls()->CaptureCursor( !!item ); } m_frame->SetNoToolSelected(); return 0; }
bool TOOL_EVT_UTILS::IsRotateToolEvt( const TOOL_EVENT& aEvt ) { return aEvt.IsAction( &PCB_ACTIONS::rotateCw ) || aEvt.IsAction( &PCB_ACTIONS::rotateCcw ); }
bool TOOL_EVT_UTILS::IsCancelInteractive( const TOOL_EVENT& aEvt ) { return aEvt.IsAction( &ACTIONS::cancelInteractive ) || aEvt.IsActivate() || aEvt.IsCancel(); }