int ALIGN_DISTRIBUTE_TOOL::selectTarget( ALIGNMENT_RECTS& aItems, ALIGNMENT_RECTS& aLocked, T aGetValue ) { wxPoint curPos( getViewControls()->GetCursorPosition().x, getViewControls()->GetCursorPosition().y ); // after sorting, the fist item acts as the target for all others // unless we have a locked item, in which case we use that for the target int target = !aLocked.size() ? aGetValue( aItems.front() ): aGetValue( aLocked.front() ); // Iterate through both lists to find if we are mouse-over on one of the items. for( auto sel = aLocked.begin(); sel != aItems.end(); sel++ ) { // If there are locked items, prefer aligning to them over // aligning to the cursor as they do not move if( sel == aLocked.end() ) { if( aLocked.size() == 0 ) { sel = aItems.begin(); continue; } break; } // We take the first target that overlaps our cursor. // This is deterministic because we assume sorted arrays if( sel->second.Contains( curPos ) ) { target = aGetValue( *sel ); break; } } return target; }
int PCBNEW_CONTROL::ZoomCenter( const TOOL_EVENT& aEvent ) { KIGFX::VIEW_CONTROLS* ctls = getViewControls(); if( ctls->IsCursorWarpingEnabled() ) ctls->CenterOnCursor(); else getView()->SetCenter( getViewControls()->GetCursorPosition() ); return 0; }
int PCBNEW_CONTROL::GridSetOrigin( const TOOL_EVENT& aEvent ) { Activate(); m_frame->SetToolID( ID_PCB_PLACE_GRID_COORD_BUTT, wxCURSOR_PENCIL, _( "Adjust grid origin" ) ); KIGFX::VIEW_CONTROLS* controls = getViewControls(); controls->ShowCursor( true ); controls->SetSnapping( true ); controls->SetAutoPan( true ); while( OPT_TOOL_EVENT evt = Wait() ) { if( evt->IsClick( BUT_LEFT ) ) { getView()->GetGAL()->SetGridOrigin( controls->GetCursorPosition() ); getView()->MarkDirty(); } else if( evt->IsCancel() || evt->IsActivate() ) break; } controls->SetAutoPan( false ); controls->SetSnapping( false ); controls->ShowCursor( false ); m_frame->SetToolID( ID_NO_TOOL_SELECTED, wxCURSOR_DEFAULT, wxEmptyString ); return 0; }
int PCBNEW_CONTROL::ZoomCenter( const TOOL_EVENT& aEvent ) { KIGFX::VIEW* view = m_frame->GetGalCanvas()->GetView(); view->SetCenter( getViewControls()->GetCursorPosition() ); return 0; }
int SELECTION_TOOL::SingleSelection( TOOL_EVENT& aEvent ) { selectSingle( getView()->ToWorld( getViewControls()->GetMousePosition() ) ); setTransitions(); return 0; }
void DRAWING_TOOL::Reset( RESET_REASON aReason ) { // Init variables used by every drawing tool m_view = getView(); m_controls = getViewControls(); m_board = getModel<BOARD>(); m_frame = getEditFrame<PCB_EDIT_FRAME>(); }
// Miscellaneous int PCBNEW_CONTROL::ResetCoords( const TOOL_EVENT& aEvent ) { VECTOR2I cursorPos = getViewControls()->GetCursorPosition(); m_frame->GetScreen()->m_O_Curseur = wxPoint( cursorPos.x, cursorPos.y ); m_frame->UpdateStatusBar(); return 0; }
void PICKER_TOOL::setControls() { KIGFX::VIEW_CONTROLS* controls = getViewControls(); controls->ShowCursor( m_cursorVisible ); controls->SetSnapping( m_cursorSnapping ); controls->CaptureCursor( m_cursorCapture ); controls->SetAutoPan( m_autoPanning ); }
int PCBNEW_CONTROL::ZoomInOut( const TOOL_EVENT& aEvent ) { KIGFX::VIEW* view = m_frame->GetGalCanvas()->GetView(); KIGFX::VIEW_CONTROLS* ctls = getViewControls(); 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() ); if( ctls->IsCursorWarpingEnabled() ) ctls->CenterOnCursor(); return 0; }
SELECTION& PL_SELECTION_TOOL::RequestSelection() { // If nothing is selected do a hover selection if( m_selection.Empty() ) { VECTOR2D cursorPos = getViewControls()->GetCursorPosition( true ); ClearSelection(); SelectPoint( cursorPos ); m_selection.SetIsHover( true ); } return m_selection; }
int PICKER_TOOL::Main( const TOOL_EVENT& aEvent ) { KIGFX::VIEW_CONTROLS* controls = getViewControls(); assert( !m_picking ); m_picking = true; m_picked = boost::none; setControls(); while( OPT_TOOL_EVENT evt = Wait() ) { if( evt->IsClick( BUT_LEFT ) ) { bool getNext = false; m_picked = controls->GetCursorPosition(); if( m_clickHandler ) { try { getNext = (*m_clickHandler)( *m_picked ); } catch( std::exception& e ) { std::cerr << "PICKER_TOOL click handler error: " << e.what() << std::endl; break; } } if( !getNext ) break; else m_toolMgr->PassEvent(); } else if( evt->IsCancel() || evt->IsActivate() ) break; else m_toolMgr->PassEvent(); } reset(); getEditFrame<PCB_BASE_FRAME>()->SetToolID( ID_NO_TOOL_SELECTED, wxCURSOR_DEFAULT, wxEmptyString ); return 0; }
wxPoint EDIT_TOOL::getModificationPoint( const SELECTION& aSelection ) { if( aSelection.Size() == 1 ) { return aSelection.Item<BOARD_ITEM>( 0 )->GetPosition() - m_offset; } else { // If EDIT_TOOL is not currently active then it means that the cursor position is not // updated, so we have to fetch the latest value if( m_toolMgr->GetCurrentToolId() != m_toolId ) m_cursor = getViewControls()->GetCursorPosition(); return wxPoint( m_cursor.x, m_cursor.y ); } }
int PCBNEW_CONTROL::ZoomInOut( TOOL_EVENT& aEvent ) { KIGFX::VIEW* view = m_frame->GetGalCanvas()->GetView(); KIGFX::GAL* gal = m_frame->GetGalCanvas()->GetGAL(); if( aEvent.IsAction( &COMMON_ACTIONS::zoomIn ) ) m_frame->SetPrevZoom(); else if( aEvent.IsAction( &COMMON_ACTIONS::zoomOut ) ) m_frame->SetNextZoom(); double zoomFactor = gal->GetWorldScale() / gal->GetZoomFactor(); double zoom = 1.0 / ( zoomFactor * m_frame->GetZoom() ); view->SetScale( zoom, getViewControls()->GetCursorPosition() ); setTransitions(); return 0; }
void POINT_EDITOR::setEditedPoint( EDIT_POINT* aPoint ) { KIGFX::VIEW_CONTROLS* controls = getViewControls(); if( aPoint ) { controls->ForceCursorPosition( true, aPoint->GetPosition() ); controls->ShowCursor( true ); controls->SetSnapping( true ); } else { controls->ShowCursor( false ); controls->SetSnapping( false ); controls->ForceCursorPosition( false ); } m_editedPoint = aPoint; }
bool PL_SELECTION_TOOL::selectMultiple() { bool cancelled = false; // Was the tool cancelled while it was running? m_multiple = true; // Multiple selection mode is active KIGFX::VIEW* view = getView(); KIGFX::PREVIEW::SELECTION_AREA area; view->Add( &area ); while( OPT_TOOL_EVENT evt = Wait() ) { if( evt->IsAction( &ACTIONS::cancelInteractive ) || evt->IsActivate() || evt->IsCancel() ) { cancelled = true; break; } if( evt->IsDrag( BUT_LEFT ) ) { // Start drawing a selection box area.SetOrigin( evt->DragOrigin() ); area.SetEnd( evt->Position() ); area.SetAdditive( m_additive ); area.SetSubtractive( m_subtractive ); view->SetVisible( &area, true ); view->Update( &area ); getViewControls()->SetAutoPan( true ); } if( evt->IsMouseUp( BUT_LEFT ) ) { getViewControls()->SetAutoPan( false ); // End drawing the selection box view->SetVisible( &area, false ); int width = area.GetEnd().x - area.GetOrigin().x; int height = area.GetEnd().y - area.GetOrigin().y; /* Selection mode depends on direction of drag-selection: * Left > Right : Select objects that are fully enclosed by selection * Right > Left : Select objects that are crossed by selection */ bool windowSelection = width >= 0 ? true : false; // Construct an EDA_RECT to determine EDA_ITEM selection EDA_RECT selectionRect( (wxPoint)area.GetOrigin(), wxSize( width, height ) ); selectionRect.Normalize(); for( WS_DATA_ITEM* dataItem : WS_DATA_MODEL::GetTheInstance().GetItems() ) { for( WS_DRAW_ITEM_BASE* item : dataItem->GetDrawItems() ) { if( item->HitTest( selectionRect, windowSelection ) ) { if( m_subtractive ) unselect( item ); else select( item ); } } } // Inform other potentially interested tools if( !m_selection.Empty() ) m_toolMgr->ProcessEvent( EVENTS::SelectedEvent ); break; // Stop waiting for events } } getViewControls()->SetAutoPan( false ); // Stop drawing the selection box view->Remove( &area ); m_multiple = false; // Multiple selection mode is inactive if( !cancelled ) m_selection.ClearReferencePoint(); return cancelled; }
int PCBNEW_CONTROL::AppendBoard( const TOOL_EVENT& aEvent ) { int open_ctl; wxString fileName; PICKED_ITEMS_LIST undoListPicker; ITEM_PICKER picker( NULL, UR_NEW ); PCB_EDIT_FRAME* editFrame = dynamic_cast<PCB_EDIT_FRAME*>( m_frame ); BOARD* board = getModel<BOARD>(); KIGFX::VIEW* view = getView(); if( !editFrame ) return 0; // Pick a file to append if( !AskLoadBoardFileName( editFrame, &open_ctl, &fileName, true ) ) return 0; IO_MGR::PCB_FILE_T pluginType = plugin_type( fileName, open_ctl ); PLUGIN::RELEASER pi( IO_MGR::PluginFind( pluginType ) ); // keep track of existing items, in order to know what are the new items // (for undo command for instance) // Tracks are inserted, not appended, so mark the existing tracks to know what are the new tracks for( TRACK* track = board->m_Track; track; track = track->Next() ) track->SetFlags( FLAG0 ); // Other items are appended to the item list, so keep trace to the last existing item is enough MODULE* module = board->m_Modules.GetLast(); BOARD_ITEM* drawing = board->m_Drawings.GetLast(); int zonescount = board->GetAreaCount(); // Keep also the count of copper layers, to adjust if necessary int initialCopperLayerCount = board->GetCopperLayerCount(); LSET initialEnabledLayers = board->GetEnabledLayers(); // Load the data try { PROPERTIES props; char xbuf[30]; char ybuf[30]; // EAGLE_PLUGIN can use this info to center the BOARD, but it does not yet. sprintf( xbuf, "%d", editFrame->GetPageSizeIU().x ); sprintf( ybuf, "%d", editFrame->GetPageSizeIU().y ); props["page_width"] = xbuf; props["page_height"] = ybuf; editFrame->GetDesignSettings().m_NetClasses.Clear(); pi->Load( fileName, board, &props ); } catch( const IO_ERROR& ioe ) { wxString msg = wxString::Format( _( "Error loading board.\n%s" ), GetChars( ioe.errorText )); DisplayError( editFrame, msg ); return 0; } m_toolMgr->RunAction( COMMON_ACTIONS::selectionClear, true ); // Process the new items for( TRACK* track = board->m_Track; track; track = track->Next() ) { if( track->GetFlags() & FLAG0 ) { track->ClearFlags( FLAG0 ); continue; } picker.SetItem( track ); undoListPicker.PushItem( picker ); view->Add( track ); m_toolMgr->RunAction( COMMON_ACTIONS::selectItem, true, track ); } module = module ? module->Next() : board->m_Modules; for( ; module; module = module->Next() ) { picker.SetItem( module ); undoListPicker.PushItem( picker ); module->RunOnChildren( boost::bind( &KIGFX::VIEW::Add, view, _1 ) ); view->Add( module ); m_toolMgr->RunAction( COMMON_ACTIONS::selectItem, true, module ); } drawing = drawing ? drawing->Next() : board->m_Drawings; for( ; drawing; drawing = drawing->Next() ) { picker.SetItem( drawing ); undoListPicker.PushItem( picker ); view->Add( drawing ); m_toolMgr->RunAction( COMMON_ACTIONS::selectItem, true, drawing ); } for( ZONE_CONTAINER* zone = board->GetArea( zonescount ); zone; zone = board->GetArea( zonescount ) ) { picker.SetItem( zone ); undoListPicker.PushItem( picker ); zonescount++; view->Add( zone ); m_toolMgr->RunAction( COMMON_ACTIONS::selectItem, true, zone ); } if( undoListPicker.GetCount() == 0 ) return 0; editFrame->SaveCopyInUndoList( undoListPicker, UR_NEW ); // Synchronize layers // we should not ask PLUGINs to do these items: int copperLayerCount = board->GetCopperLayerCount(); if( copperLayerCount > initialCopperLayerCount ) board->SetCopperLayerCount( copperLayerCount ); // Enable all used layers, and make them visible: LSET enabledLayers = board->GetEnabledLayers(); enabledLayers |= initialEnabledLayers; board->SetEnabledLayers( enabledLayers ); board->SetVisibleLayers( enabledLayers ); editFrame->ReCreateLayerBox(); editFrame->ReFillLayerWidget(); static_cast<PCB_DRAW_PANEL_GAL*>( editFrame->GetGalCanvas() )->SyncLayersVisibility( board ); // Ratsnest board->BuildListOfNets(); board->SynchronizeNetsAndNetClasses(); board->GetRatsnest()->Recalculate(); // Start dragging the appended board VECTOR2D v( static_cast<BOARD_ITEM*>( undoListPicker.GetPickedItem( 0 ) )->GetPosition() ); getViewControls()->WarpCursor( v, true, true ); m_toolMgr->InvokeTool( "pcbnew.InteractiveEdit" ); return 0; }
int SELECTION_TOOL::Main( const TOOL_EVENT& aEvent ) { // Main loop: keep receiving events while( OPT_TOOL_EVENT evt = Wait() ) { // Should selected items be added to the current selection or // become the new selection (discarding previously selected items) m_additive = evt->Modifier( MD_SHIFT ); // single click? Select single object if( evt->IsClick( BUT_LEFT ) ) { if( evt->Modifier( MD_CTRL ) && !m_editModules ) { highlightNet( evt->Position() ); } else { if( !m_additive ) clearSelection(); selectCursor( evt->Position() ); } } // right click? if there is any object - show the context menu else if( evt->IsClick( BUT_RIGHT ) ) { bool emptySelection = m_selection.Empty(); if( emptySelection ) selectCursor( evt->Position() ); CONTEXT_MENU& contextMenu = m_menu.Generate( m_selection ); if( contextMenu.GetMenuItemCount() > 0 ) SetContextMenu( &contextMenu, CMENU_NOW ); m_preliminary = emptySelection; } // double click? Display the properties window else if( evt->IsDblClick( BUT_LEFT ) ) { if( m_selection.Empty() ) selectCursor( evt->Position() ); m_toolMgr->RunAction( COMMON_ACTIONS::properties ); } // drag with LMB? Select multiple objects (or at least draw a selection box) or drag them else if( evt->IsDrag( BUT_LEFT ) ) { if( m_additive ) { m_preliminary = false; selectMultiple(); } else if( m_selection.Empty() ) { m_preliminary = false; // There is nothing selected, so try to select something if( !selectCursor( getView()->ToWorld( getViewControls()->GetMousePosition() ), false ) ) { // If nothings has been selected or user wants to select more // draw the selection box selectMultiple(); } else { m_toolMgr->InvokeTool( "pcbnew.InteractiveEdit" ); } } else { // Check if dragging has started within any of selected items bounding box if( selectionContains( evt->Position() ) ) { // Yes -> run the move tool and wait till it finishes m_toolMgr->InvokeTool( "pcbnew.InteractiveEdit" ); } else { // No -> clear the selection list clearSelection(); } } } else if( evt->IsAction( &COMMON_ACTIONS::selectionCursor ) ) { // GetMousePosition() is used, as it is independent of snapping settings selectCursor( getView()->ToWorld( getViewControls()->GetMousePosition() ) ); } else if( evt->IsAction( &COMMON_ACTIONS::find ) ) { find( *evt ); } else if( evt->IsAction( &COMMON_ACTIONS::findMove ) ) { findMove( *evt ); } else if( evt->IsAction( &COMMON_ACTIONS::selectItem ) ) { SelectItem( *evt ); } else if( evt->IsAction( &COMMON_ACTIONS::unselectItem ) ) { UnselectItem( *evt ); } else if( evt->IsCancel() || evt->Action() == TA_UNDO_REDO || evt->IsAction( &COMMON_ACTIONS::selectionClear ) ) { clearSelection(); } else if( evt->IsAction( &COMMON_ACTIONS::selectConnection ) ) { selectConnection( *evt ); } else if( evt->IsAction( &COMMON_ACTIONS::selectCopper ) ) { selectCopper( *evt ); } else if( evt->IsAction( &COMMON_ACTIONS::selectNet ) ) { selectNet( *evt ); } else if( evt->Action() == TA_CONTEXT_MENU_CLOSED ) { if( m_preliminary ) clearSelection(); } } // This tool is supposed to be active forever assert( false ); return 0; }
// Cursor control int PCBNEW_CONTROL::CursorControl( const TOOL_EVENT& aEvent ) { long type = aEvent.Parameter<long>(); bool fastMove = type & COMMON_ACTIONS::CURSOR_FAST_MOVE; type &= ~COMMON_ACTIONS::CURSOR_FAST_MOVE; GRID_HELPER gridHelper( m_frame ); VECTOR2D cursor = getViewControls()->GetCursorPosition(); VECTOR2I gridSize = gridHelper.GetGrid(); VECTOR2D newCursor = gridHelper.Align( cursor ); if( fastMove ) gridSize = gridSize * 10; switch( type ) { case COMMON_ACTIONS::CURSOR_UP: newCursor -= VECTOR2D( 0, gridSize.y ); break; case COMMON_ACTIONS::CURSOR_DOWN: newCursor += VECTOR2D( 0, gridSize.y ); break; case COMMON_ACTIONS::CURSOR_LEFT: newCursor -= VECTOR2D( gridSize.x, 0 ); break; case COMMON_ACTIONS::CURSOR_RIGHT: newCursor += VECTOR2D( gridSize.x, 0 ); break; case COMMON_ACTIONS::CURSOR_CLICK: // fall through case COMMON_ACTIONS::CURSOR_DBL_CLICK: { TOOL_ACTIONS action = TA_NONE; int modifiers = 0; modifiers |= wxGetKeyState( WXK_SHIFT ) ? MD_SHIFT : 0; modifiers |= wxGetKeyState( WXK_CONTROL ) ? MD_CTRL : 0; modifiers |= wxGetKeyState( WXK_ALT ) ? MD_ALT : 0; if( type == COMMON_ACTIONS::CURSOR_CLICK ) action = TA_MOUSE_CLICK; else if( type == COMMON_ACTIONS::CURSOR_DBL_CLICK ) action = TA_MOUSE_DBLCLICK; else assert( false ); TOOL_EVENT evt( TC_MOUSE, action, BUT_LEFT | modifiers ); evt.SetMousePosition( getViewControls()->GetCursorPosition() ); m_toolMgr->ProcessEvent( evt ); return 0; } break; } // Handler cursor movement KIGFX::VIEW* view = getView(); newCursor = view->ToScreen( newCursor ); newCursor.x = KiROUND( newCursor.x ); newCursor.y = KiROUND( newCursor.y ); // Pan the screen if required const VECTOR2I& screenSize = view->GetGAL()->GetScreenPixelSize(); BOX2I screenBox( VECTOR2I( 0, 0 ), screenSize ); if( !screenBox.Contains( newCursor ) ) { VECTOR2D delta( 0, 0 ); if( newCursor.x < screenBox.GetLeft() ) { delta.x = newCursor.x - screenBox.GetLeft(); newCursor.x = screenBox.GetLeft(); } else if( newCursor.x > screenBox.GetRight() ) { delta.x = newCursor.x - screenBox.GetRight(); // -1 is to keep the cursor within the drawing area, // so the cursor coordinates are still updated newCursor.x = screenBox.GetRight() - 1; } if( newCursor.y < screenBox.GetTop() ) { delta.y = newCursor.y - screenBox.GetTop(); newCursor.y = screenBox.GetTop(); } else if( newCursor.y > screenBox.GetBottom() ) { delta.y = newCursor.y - screenBox.GetBottom(); // -1 is to keep the cursor within the drawing area, // so the cursor coordinates are still updated newCursor.y = screenBox.GetBottom() - 1; } view->SetCenter( view->GetCenter() + view->ToWorld( delta, false ) ); } m_frame->GetGalCanvas()->WarpPointer( newCursor.x, newCursor.y ); return 0; }
bool SELECTION_TOOL::selectMultiple() { bool cancelled = false; // Was the tool cancelled while it was running? m_multiple = true; // Multiple selection mode is active KIGFX::VIEW* view = getView(); getViewControls()->SetAutoPan( true ); SELECTION_AREA area; view->Add( &area ); while( OPT_TOOL_EVENT evt = Wait() ) { if( evt->IsCancel() ) { cancelled = true; break; } if( evt->IsDrag( BUT_LEFT ) ) { if( !m_additive ) clearSelection(); // Start drawing a selection box area.SetOrigin( evt->DragOrigin() ); area.SetEnd( evt->Position() ); area.ViewSetVisible( true ); area.ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); } if( evt->IsMouseUp( BUT_LEFT ) ) { // End drawing the selection box area.ViewSetVisible( false ); // Mark items within the selection box as selected std::vector<KIGFX::VIEW::LAYER_ITEM_PAIR> selectedItems; BOX2I selectionBox = area.ViewBBox(); view->Query( selectionBox, selectedItems ); // Get the list of selected items std::vector<KIGFX::VIEW::LAYER_ITEM_PAIR>::iterator it, it_end; for( it = selectedItems.begin(), it_end = selectedItems.end(); it != it_end; ++it ) { BOARD_ITEM* item = static_cast<BOARD_ITEM*>( it->first ); // Add only those items that are visible and fully within the selection box if( !item->IsSelected() && selectable( item ) && selectionBox.Contains( item->ViewBBox() ) ) { select( item ); } } // Do not display information about selected item,as there is more than one m_frame->SetCurItem( NULL ); if( !m_selection.Empty() ) { // Inform other potentially interested tools m_toolMgr->ProcessEvent( SelectedEvent ); } break; // Stop waiting for events } } // Stop drawing the selection box area.ViewSetVisible( false ); view->Remove( &area ); m_multiple = false; // Multiple selection mode is inactive getViewControls()->SetAutoPan( false ); return cancelled; }
int EDIT_TOOL::Main( TOOL_EVENT& aEvent ) { const SELECTION& selection = m_selectionTool->GetSelection(); // Shall the selection be cleared at the end? bool unselect = selection.Empty(); // Be sure that there is at least one item that we can modify if( !makeSelection( selection ) ) { setTransitions(); return 0; } Activate(); m_dragging = false; // Are selected items being dragged? bool restore = false; // Should items' state be restored when finishing the tool? // By default, modified items need to update their geometry m_updateFlag = KIGFX::VIEW_ITEM::GEOMETRY; KIGFX::VIEW_CONTROLS* controls = getViewControls(); PCB_BASE_EDIT_FRAME* editFrame = getEditFrame<PCB_BASE_EDIT_FRAME>(); controls->ShowCursor( true ); controls->SetSnapping( true ); controls->ForceCursorPosition( false ); // Main loop: keep receiving events while( OPT_TOOL_EVENT evt = Wait() ) { if( evt->IsCancel() ) { restore = true; // Cancelling the tool means that items have to be restored break; // Finish } else if( evt->Action() == TA_UNDO_REDO ) { unselect = true; break; } // Dispatch TOOL_ACTIONs else if( evt->Category() == TC_COMMAND ) { if( evt->IsAction( &COMMON_ACTIONS::rotate ) ) { Rotate( aEvent ); } else if( evt->IsAction( &COMMON_ACTIONS::flip ) ) { Flip( aEvent ); // Flip causes change of layers enableUpdateFlag( KIGFX::VIEW_ITEM::LAYERS ); } else if( evt->IsAction( &COMMON_ACTIONS::remove ) ) { Remove( aEvent ); break; // exit the loop, as there is no further processing for removed items } } else if( evt->IsMotion() || evt->IsDrag( BUT_LEFT ) ) { m_cursor = controls->GetCursorPosition(); if( m_dragging ) { wxPoint movement = wxPoint( m_cursor.x, m_cursor.y ) - selection.Item<BOARD_ITEM>( 0 )->GetPosition(); // Drag items to the current cursor position for( unsigned int i = 0; i < selection.items.GetCount(); ++i ) selection.Item<BOARD_ITEM>( i )->Move( movement + m_offset ); updateRatsnest( true ); } else // Prepare to start dragging { if( m_selectionTool->CheckLock() || selection.Empty() ) break; // Save items, so changes can be undone editFrame->OnModify(); editFrame->SaveCopyInUndoList( selection.items, UR_CHANGED ); if( selection.Size() == 1 ) { // Set the current cursor position to the first dragged item origin, so the // movement vector could be computed later m_cursor = VECTOR2I( selection.Item<BOARD_ITEM>( 0 )->GetPosition() ); m_offset.x = 0; m_offset.y = 0; } else { VECTOR2D origin; if( evt->IsDrag( BUT_LEFT ) ) origin = getView()->GetGAL()->GetGridPoint( evt->DragOrigin() ); else origin = getViewControls()->GetCursorPosition(); // Update dragging offset (distance between cursor and the first dragged item) m_offset = static_cast<BOARD_ITEM*>( selection.items.GetPickedItem( 0 ) )->GetPosition() - wxPoint( origin.x, origin.y ); } controls->SetAutoPan( true ); m_dragging = true; } selection.group->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); m_toolMgr->RunAction( COMMON_ACTIONS::pointEditorUpdate, true ); } else if( evt->IsMouseUp( BUT_LEFT ) || evt->IsClick( BUT_LEFT ) ) break; // Finish } m_dragging = false; m_offset.x = 0; m_offset.y = 0; if( restore ) { // Modifications have to be rollbacked, so restore the previous state of items wxCommandEvent dummy; editFrame->RestoreCopyFromUndoList( dummy ); } else { // Changes are applied, so update the items selection.group->ItemsViewUpdate( m_updateFlag ); } if( unselect ) m_toolMgr->RunAction( COMMON_ACTIONS::selectionClear, true ); RN_DATA* ratsnest = getModel<BOARD>()->GetRatsnest(); ratsnest->ClearSimple(); ratsnest->Recalculate(); controls->ShowCursor( false ); controls->SetSnapping( false ); controls->SetAutoPan( false ); setTransitions(); return 0; }
int EDIT_TOOL::Properties( TOOL_EVENT& aEvent ) { const SELECTION& selection = m_selectionTool->GetSelection(); PCB_BASE_EDIT_FRAME* editFrame = getEditFrame<PCB_BASE_EDIT_FRAME>(); if( !makeSelection( selection ) ) { setTransitions(); return 0; } // Properties are displayed when there is only one item selected if( selection.Size() == 1 ) { // Display properties dialog BOARD_ITEM* item = selection.Item<BOARD_ITEM>( 0 ); // Check if user wants to edit pad or module properties if( item->Type() == PCB_MODULE_T ) { VECTOR2D cursor = getViewControls()->GetCursorPosition(); for( D_PAD* pad = static_cast<MODULE*>( item )->Pads(); pad; pad = pad->Next() ) { if( pad->ViewBBox().Contains( cursor ) ) { // Turns out that user wants to edit a pad properties item = pad; break; } } } std::vector<PICKED_ITEMS_LIST*>& undoList = editFrame->GetScreen()->m_UndoList.m_CommandsList; // Some of properties dialogs alter pointers, so we should deselect them m_toolMgr->RunAction( COMMON_ACTIONS::selectionClear, true ); STATUS_FLAGS flags = item->GetFlags(); item->ClearFlags(); // It is necessary to determine if anything has changed PICKED_ITEMS_LIST* lastChange = undoList.empty() ? NULL : undoList.back(); // Display properties dialog editFrame->OnEditItemRequest( NULL, item ); PICKED_ITEMS_LIST* currentChange = undoList.empty() ? NULL : undoList.back(); if( lastChange != currentChange ) // Something has changed { processChanges( currentChange ); updateRatsnest( true ); getModel<BOARD>()->GetRatsnest()->Recalculate(); item->ViewUpdate(); m_toolMgr->RunAction( COMMON_ACTIONS::pointEditorUpdate, true ); } item->SetFlags( flags ); } setTransitions(); return 0; }
int SELECTION_TOOL::CursorSelection( const TOOL_EVENT& aEvent ) { selectCursor( getView()->ToWorld( getViewControls()->GetMousePosition() ) ); return 0; }
int POINT_EDITOR::OnSelectionChange( const TOOL_EVENT& aEvent ) { const SELECTION& selection = m_selectionTool->GetSelection(); if( selection.Size() == 1 ) { Activate(); KIGFX::VIEW_CONTROLS* controls = getViewControls(); KIGFX::VIEW* view = getView(); PCB_BASE_EDIT_FRAME* editFrame = getEditFrame<PCB_BASE_EDIT_FRAME>(); EDA_ITEM* item = selection.items.GetPickedItem( 0 ); m_editPoints = EDIT_POINTS_FACTORY::Make( item, getView()->GetGAL() ); if( !m_editPoints ) return 0; view->Add( m_editPoints.get() ); m_editedPoint = NULL; bool modified = false; // Main loop: keep receiving events while( OPT_TOOL_EVENT evt = Wait() ) { if( !m_editPoints || evt->Matches( m_selectionTool->ClearedEvent ) || evt->Matches( m_selectionTool->UnselectedEvent ) || evt->Matches( m_selectionTool->SelectedEvent ) ) { break; } if( evt->IsMotion() ) { EDIT_POINT* point = m_editPoints->FindPoint( evt->Position() ); if( m_editedPoint != point ) setEditedPoint( point ); } else if( evt->IsAction( &COMMON_ACTIONS::pointEditorAddCorner ) ) { addCorner( controls->GetCursorPosition() ); updatePoints(); } else if( evt->IsAction( &COMMON_ACTIONS::pointEditorRemoveCorner ) ) { if( m_editedPoint ) { removeCorner( m_editedPoint ); updatePoints(); } } else if( evt->IsDrag( BUT_LEFT ) && m_editedPoint ) { if( !modified ) { // Save items, so changes can be undone editFrame->OnModify(); editFrame->SaveCopyInUndoList( selection.items, UR_CHANGED ); controls->ForceCursorPosition( false ); m_original = *m_editedPoint; // Save the original position controls->SetAutoPan( true ); modified = true; } bool enableAltConstraint = !!evt->Modifier( MD_CTRL ); if( enableAltConstraint != (bool) m_altConstraint ) // alternative constraint setAltConstraint( enableAltConstraint ); m_editedPoint->SetPosition( controls->GetCursorPosition() ); if( m_altConstraint ) m_altConstraint->Apply(); else m_editedPoint->ApplyConstraint(); updateItem(); updatePoints(); m_editPoints->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); } else if( evt->IsAction( &COMMON_ACTIONS::pointEditorUpdate ) ) { updatePoints(); } else if( evt->IsMouseUp( BUT_LEFT ) ) { controls->SetAutoPan( false ); setAltConstraint( false ); modified = false; m_toolMgr->PassEvent(); } else if( evt->IsCancel() ) { if( modified ) // Restore the last change { wxCommandEvent dummy; editFrame->RestoreCopyFromUndoList( dummy ); updatePoints(); modified = false; } // Let the selection tool receive the event too m_toolMgr->PassEvent(); break; } else { m_toolMgr->PassEvent(); } } if( m_editPoints ) { finishItem(); item->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); view->Remove( m_editPoints.get() ); m_editPoints.reset(); } controls->ShowCursor( false ); controls->SetAutoPan( false ); controls->SetSnapping( false ); controls->ForceCursorPosition( false ); } return 0; }
int PCB_EDITOR_CONTROL::PlaceTarget( const TOOL_EVENT& aEvent ) { KIGFX::VIEW* view = getView(); KIGFX::VIEW_CONTROLS* controls = getViewControls(); BOARD* board = getModel<BOARD>(); PCB_TARGET* target = new PCB_TARGET( board ); // Init the new item attributes target->SetLayer( Edge_Cuts ); target->SetWidth( board->GetDesignSettings().m_EdgeSegmentWidth ); target->SetSize( Millimeter2iu( 5 ) ); VECTOR2I cursorPos = controls->GetCursorPosition(); target->SetPosition( wxPoint( cursorPos.x, cursorPos.y ) ); // Add a VIEW_GROUP that serves as a preview for the new item KIGFX::VIEW_GROUP preview( view ); preview.Add( target ); view->Add( &preview ); preview.ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); m_toolMgr->RunAction( COMMON_ACTIONS::selectionClear, true ); controls->SetSnapping( true ); Activate(); m_frame->SetToolID( ID_PCB_MIRE_BUTT, wxCURSOR_PENCIL, _( "Add layer alignment target" ) ); // Main loop: keep receiving events while( OPT_TOOL_EVENT evt = Wait() ) { cursorPos = controls->GetCursorPosition(); if( evt->IsCancel() || evt->IsActivate() ) break; else if( evt->IsAction( &COMMON_ACTIONS::incWidth ) ) { target->SetWidth( target->GetWidth() + WIDTH_STEP ); preview.ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); } else if( evt->IsAction( &COMMON_ACTIONS::decWidth ) ) { int width = target->GetWidth(); if( width > WIDTH_STEP ) { target->SetWidth( width - WIDTH_STEP ); preview.ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); } } else if( evt->IsClick( BUT_LEFT ) ) { assert( target->GetSize() > 0 ); assert( target->GetWidth() > 0 ); view->Add( target ); board->Add( target ); target->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); m_frame->OnModify(); m_frame->SaveCopyInUndoList( target, UR_NEW ); preview.Remove( target ); // Create next PCB_TARGET target = new PCB_TARGET( *target ); preview.Add( target ); } else if( evt->IsMotion() ) { target->SetPosition( wxPoint( cursorPos.x, cursorPos.y ) ); preview.ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); } } delete target; controls->SetSnapping( false ); view->Remove( &preview ); m_frame->SetToolID( ID_NO_TOOL_SELECTED, wxCURSOR_DEFAULT, wxEmptyString ); return 0; }
int EDIT_TOOL::Main( const TOOL_EVENT& aEvent ) { KIGFX::VIEW_CONTROLS* controls = getViewControls(); PCB_BASE_EDIT_FRAME* editFrame = getEditFrame<PCB_BASE_EDIT_FRAME>(); VECTOR2I originalCursorPos = controls->GetCursorPosition(); const SELECTION& selection = m_selectionTool->GetSelection(); // Shall the selection be cleared at the end? bool unselect = selection.Empty(); // Be sure that there is at least one item that we can modify. If nothing was selected before, // try looking for the stuff under mouse cursor (i.e. Kicad old-style hover selection) if( !hoverSelection( selection ) ) return 0; Activate(); m_dragging = false; // Are selected items being dragged? bool restore = false; // Should items' state be restored when finishing the tool? bool lockOverride = false; // By default, modified items need to update their geometry m_updateFlag = KIGFX::VIEW_ITEM::GEOMETRY; controls->ShowCursor( true ); // cumulative translation wxPoint totalMovement( 0, 0 ); GRID_HELPER grid( editFrame ); OPT_TOOL_EVENT evt = aEvent; // Main loop: keep receiving events do { if( evt->IsCancel() ) { restore = true; // Cancelling the tool means that items have to be restored break; // Finish } else if( evt->Action() == TA_UNDO_REDO ) { unselect = true; break; } else if( evt->IsAction( &COMMON_ACTIONS::editActivate ) || evt->IsMotion() || evt->IsDrag( BUT_LEFT ) ) { BOARD_ITEM* item = selection.Item<BOARD_ITEM>( 0 ); if( m_dragging && evt->Category() == TC_MOUSE ) { m_cursor = grid.BestSnapAnchor( evt->Position(), item ); controls->ForceCursorPosition( true, m_cursor ); wxPoint movement = wxPoint( m_cursor.x, m_cursor.y ) - item->GetPosition(); totalMovement += movement; // Drag items to the current cursor position for( unsigned int i = 0; i < selection.items.GetCount(); ++i ) selection.Item<BOARD_ITEM>( i )->Move( movement + m_offset ); updateRatsnest( true ); } else if( !m_dragging ) // Prepare to start dragging { if( !invokeInlineRouter() ) { m_selectionTool->SanitizeSelection(); if( selection.Empty() ) break; // deal with locked items (override lock or abort the operation) SELECTION_LOCK_FLAGS lockFlags = m_selectionTool->CheckLock(); if( lockFlags == SELECTION_LOCKED ) break; else if( lockFlags == SELECTION_LOCK_OVERRIDE ) lockOverride = true; // Save items, so changes can be undone if( !isUndoInhibited() ) { editFrame->OnModify(); editFrame->SaveCopyInUndoList( selection.items, UR_CHANGED ); } m_cursor = controls->GetCursorPosition(); if( selection.Size() == 1 ) { // Set the current cursor position to the first dragged item origin, so the // movement vector could be computed later m_cursor = grid.BestDragOrigin( originalCursorPos, item ); grid.SetAuxAxes( true, m_cursor ); } else { m_cursor = grid.Align( m_cursor ); } controls->ForceCursorPosition( true, m_cursor ); controls->WarpCursor( m_cursor, true ); VECTOR2I o = VECTOR2I( item->GetPosition() ); m_offset.x = o.x - m_cursor.x; m_offset.y = o.y - m_cursor.y; controls->SetAutoPan( true ); m_dragging = true; incUndoInhibit(); } } selection.group->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); m_toolMgr->RunAction( COMMON_ACTIONS::pointEditorUpdate, true ); } // Dispatch TOOL_ACTIONs else if( evt->Category() == TC_COMMAND ) { if( evt->IsAction( &COMMON_ACTIONS::rotate ) ) { Rotate( aEvent ); } else if( evt->IsAction( &COMMON_ACTIONS::flip ) ) { Flip( aEvent ); // Flip causes change of layers enableUpdateFlag( KIGFX::VIEW_ITEM::LAYERS ); } else if( evt->IsAction( &COMMON_ACTIONS::remove ) ) { Remove( aEvent ); break; // exit the loop, as there is no further processing for removed items } else if( evt->IsAction( &COMMON_ACTIONS::duplicate ) ) { // On duplicate, stop moving this item // The duplicate tool should then select the new item and start // a new move procedure break; } else if( evt->IsAction( &COMMON_ACTIONS::moveExact ) ) { // Can't do this, because the selection will then contain // stale pointers and it will all go horribly wrong... //editFrame->RestoreCopyFromUndoList( dummy ); // // So, instead, reset the position manually for( unsigned int i = 0; i < selection.items.GetCount(); ++i ) { BOARD_ITEM* item = selection.Item<BOARD_ITEM>( i ); item->SetPosition( item->GetPosition() - totalMovement ); // And what about flipping and rotation? // for now, they won't be undone, but maybe that is how // it should be, so you can flip and move exact in the // same action? } // This causes a double event, so we will get the dialogue // correctly, somehow - why does Rotate not? //MoveExact( aEvent ); break; // exit the loop - we move exactly, so we have finished moving } } else if( evt->IsMouseUp( BUT_LEFT ) || evt->IsClick( BUT_LEFT ) ) { if( !lockOverride ) break; // Finish lockOverride = false; } } while( evt = Wait() ); if( m_dragging ) decUndoInhibit(); m_dragging = false; m_offset.x = 0; m_offset.y = 0; if( restore ) { // Modifications have to be rollbacked, so restore the previous state of items wxCommandEvent dummy; editFrame->RestoreCopyFromUndoList( dummy ); } else { // Changes are applied, so update the items selection.group->ItemsViewUpdate( m_updateFlag ); } if( unselect ) m_toolMgr->RunAction( COMMON_ACTIONS::selectionClear, true ); RN_DATA* ratsnest = getModel<BOARD>()->GetRatsnest(); ratsnest->ClearSimple(); ratsnest->Recalculate(); controls->ShowCursor( false ); controls->SetAutoPan( false ); return 0; }
int PCB_EDITOR_CONTROL::PlaceModule( const TOOL_EVENT& aEvent ) { MODULE* module = NULL; KIGFX::VIEW* view = getView(); KIGFX::VIEW_CONTROLS* controls = getViewControls(); BOARD* board = getModel<BOARD>(); // Add a VIEW_GROUP that serves as a preview for the new item KIGFX::VIEW_GROUP preview( view ); view->Add( &preview ); m_toolMgr->RunAction( COMMON_ACTIONS::selectionClear, true ); controls->ShowCursor( true ); controls->SetSnapping( true ); Activate(); m_frame->SetToolID( ID_PCB_MODULE_BUTT, wxCURSOR_HAND, _( "Add footprint" ) ); // Main loop: keep receiving events while( OPT_TOOL_EVENT evt = Wait() ) { VECTOR2I cursorPos = controls->GetCursorPosition(); if( evt->IsCancel() || evt->IsActivate() ) { if( module ) { board->Delete( module ); // it was added by LoadModuleFromLibrary() module = NULL; preview.Clear(); preview.ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); controls->ShowCursor( true ); } else break; if( evt->IsActivate() ) // now finish unconditionally break; } else if( module && evt->Category() == TC_COMMAND ) { if( evt->IsAction( &COMMON_ACTIONS::rotate ) ) { module->Rotate( module->GetPosition(), m_frame->GetRotationAngle() ); preview.ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); } else if( evt->IsAction( &COMMON_ACTIONS::flip ) ) { module->Flip( module->GetPosition() ); preview.ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); } } else if( evt->IsClick( BUT_LEFT ) ) { if( !module ) { // Pick the module to be placed module = m_frame->LoadModuleFromLibrary( wxEmptyString, m_frame->Prj().PcbFootprintLibs(), true, NULL ); if( module == NULL ) continue; module->SetPosition( wxPoint( cursorPos.x, cursorPos.y ) ); // Add all the drawable parts to preview preview.Add( module ); module->RunOnChildren( boost::bind( &KIGFX::VIEW_GROUP::Add, &preview, _1 ) ); preview.ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); } else { // Place the selected module module->RunOnChildren( boost::bind( &KIGFX::VIEW::Add, view, _1 ) ); view->Add( module ); module->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); m_frame->OnModify(); m_frame->SaveCopyInUndoList( module, UR_NEW ); // Remove from preview preview.Remove( module ); module->RunOnChildren( boost::bind( &KIGFX::VIEW_GROUP::Remove, &preview, _1 ) ); module = NULL; // to indicate that there is no module that we currently modify } bool placing = ( module != NULL ); controls->SetAutoPan( placing ); controls->CaptureCursor( placing ); controls->ShowCursor( !placing ); } else if( module && evt->IsMotion() ) { module->SetPosition( wxPoint( cursorPos.x, cursorPos.y ) ); preview.ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); } } controls->ShowCursor( false ); controls->SetSnapping( false ); controls->SetAutoPan( false ); controls->CaptureCursor( false ); view->Remove( &preview ); m_frame->SetToolID( ID_NO_TOOL_SELECTED, wxCURSOR_DEFAULT, wxEmptyString ); 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; }
int PCB_EDITOR_CONTROL::HighlightNet( const TOOL_EVENT& aEvent ) { highlightNet( m_toolMgr, getView()->ToWorld( getViewControls()->GetMousePosition() ) ); return 0; }
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; }