void FOOTPRINT_EDIT_FRAME::RestoreCopyFromUndoList( wxCommandEvent& aEvent ) { if( UndoRedoBlocked() ) return; if( GetScreen()->GetUndoCommandCount() <= 0 ) return; // Inform tools that undo command was issued TOOL_EVENT event( TC_MESSAGE, TA_UNDO_REDO, AS_GLOBAL ); m_toolManager->ProcessEvent( event ); if( UndoRedoBlocked() ) return; // Save current module state in redo list PICKED_ITEMS_LIST* lastcmd = new PICKED_ITEMS_LIST(); MODULE* module = GetBoard()->m_Modules.PopFront(); ITEM_PICKER wrapper( module, UR_MODEDIT ); KIGFX::VIEW* view = GetGalCanvas()->GetView(); lastcmd->PushItem( wrapper ); GetScreen()->PushCommandToRedoList( lastcmd ); view->Remove( module ); module->RunOnChildren( std::bind( &KIGFX::VIEW::Remove, view, _1 ) ); // Retrieve last module state from undo list lastcmd = GetScreen()->PopCommandFromUndoList(); wrapper = lastcmd->PopItem(); module = (MODULE*) wrapper.GetItem(); delete lastcmd; if( module ) { GetBoard()->Add( module, ADD_APPEND ); view->Add( module ); module->RunOnChildren( std::bind( &KIGFX::VIEW::Add, view, _1 ) ); module->ViewUpdate(); } SetCurItem( NULL ); OnModify(); m_canvas->Refresh(); }
void EDIT_TOOL::processChanges( const PICKED_ITEMS_LIST* aList ) { KIGFX::VIEW* view = getView(); RN_DATA* ratsnest = getModel<BOARD>()->GetRatsnest(); for( unsigned int i = 0; i < aList->GetCount(); ++i ) { UNDO_REDO_T operation = aList->GetPickedItemStatus( i ); BOARD_ITEM* updItem = static_cast<BOARD_ITEM*>( aList->GetPickedItem( i ) ); switch( operation ) { case UR_CHANGED: ratsnest->Update( updItem ); // fall through case UR_MODEDIT: updItem->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); break; case UR_DELETED: if( updItem->Type() == PCB_MODULE_T ) static_cast<MODULE*>( updItem )->RunOnChildren( boost::bind( &KIGFX::VIEW::Remove, view, _1 ) ); view->Remove( updItem ); //ratsnest->Remove( updItem ); // this is done in BOARD::Remove break; case UR_NEW: if( updItem->Type() == PCB_MODULE_T ) static_cast<MODULE*>( updItem )->RunOnChildren( boost::bind( &KIGFX::VIEW::Add, view, _1 ) ); view->Add( updItem ); //ratsnest->Add( updItem ); // this is done in BOARD::Add break; default: assert( false ); // Not handled break; } } }
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; }
void PCB_EDIT_FRAME::ReadPcbNetlist( const wxString& aNetlistFileName, const wxString& aCmpFileName, REPORTER* aReporter, bool aChangeFootprints, bool aDeleteUnconnectedTracks, bool aDeleteExtraFootprints, bool aSelectByTimeStamp, bool aDeleteSinglePadNets, bool aIsDryRun ) { wxString msg; NETLIST netlist; KIGFX::VIEW* view = GetGalCanvas()->GetView(); BOARD* board = GetBoard(); std::vector<MODULE*> newFootprints; // keep trace of the initial baord area, if we want to place new footprints // outside the existinag board EDA_RECT bbox = board->GetBoundingBox(); netlist.SetIsDryRun( aIsDryRun ); netlist.SetFindByTimeStamp( aSelectByTimeStamp ); netlist.SetDeleteExtraFootprints( aDeleteExtraFootprints ); netlist.SetReplaceFootprints( aChangeFootprints ); try { std::unique_ptr<NETLIST_READER> netlistReader( NETLIST_READER::GetNetlistReader( &netlist, aNetlistFileName, aCmpFileName ) ); if( !netlistReader.get() ) { msg.Printf( _( "Cannot open netlist file \"%s\"." ), GetChars( aNetlistFileName ) ); wxMessageBox( msg, _( "Netlist Load Error." ), wxOK | wxICON_ERROR, this ); return; } SetLastNetListRead( aNetlistFileName ); netlistReader->LoadNetlist(); LoadFootprints( netlist, aReporter ); } catch( const IO_ERROR& ioe ) { msg.Printf( _( "Error loading netlist.\n%s" ), ioe.What().GetData() ); wxMessageBox( msg, _( "Netlist Load Error" ), wxOK | wxICON_ERROR ); return; } // Clear undo and redo lists to avoid inconsistencies between lists if( !netlist.IsDryRun() ) GetScreen()->ClearUndoRedoList(); if( !netlist.IsDryRun() ) { // Remove old modules for( MODULE* module = board->m_Modules; module; module = module->Next() ) { view->Remove( module ); } } // Clear selection, just in case a selected item has to be removed m_toolManager->RunAction( PCB_ACTIONS::selectionClear, true ); netlist.SortByReference(); board->ReplaceNetlist( netlist, aDeleteSinglePadNets, &newFootprints, aReporter ); // If it was a dry run, nothing has changed so we're done. if( netlist.IsDryRun() ) return; if( IsGalCanvasActive() ) { SpreadFootprints( &newFootprints, false, false, GetCrossHairPosition() ); if( !newFootprints.empty() ) { for( MODULE* footprint : newFootprints ) { m_toolManager->RunAction( PCB_ACTIONS::selectItem, true, footprint ); } m_toolManager->InvokeTool( "pcbnew.InteractiveEdit" ); } } else { wxPoint placementAreaPosition; // Place area to the left side of the board. // if the board is empty, the bbox position is (0,0) placementAreaPosition.x = bbox.GetEnd().x + Millimeter2iu( 10 ); placementAreaPosition.y = bbox.GetOrigin().y; SpreadFootprints( &newFootprints, false, false, placementAreaPosition ); } OnModify(); SetCurItem( NULL ); // Reload modules for( MODULE* module = board->m_Modules; module; module = module->Next() ) { view->Add( module ); } if( aDeleteUnconnectedTracks && board->m_Track ) { // Remove erroneous tracks. This should probably pushed down to the #BOARD object. RemoveMisConnectedTracks(); } // Rebuild the board connectivity: board->GetConnectivity()->Build( board ); SetMsgPanel( board ); m_canvas->Refresh(); }
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; }
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; }
void PCB_EDIT_FRAME::ReadPcbNetlist( const wxString& aNetlistFileName, const wxString& aCmpFileName, REPORTER* aReporter, bool aChangeFootprints, bool aDeleteUnconnectedTracks, bool aDeleteExtraFootprints, bool aSelectByTimeStamp, bool aDeleteSinglePadNets, bool aIsDryRun ) { wxString msg; NETLIST netlist; KIGFX::VIEW* view = GetGalCanvas()->GetView(); BOARD* board = GetBoard(); netlist.SetIsDryRun( aIsDryRun ); netlist.SetFindByTimeStamp( aSelectByTimeStamp ); netlist.SetDeleteExtraFootprints( aDeleteExtraFootprints ); netlist.SetReplaceFootprints( aChangeFootprints ); try { std::auto_ptr<NETLIST_READER> netlistReader( NETLIST_READER::GetNetlistReader( &netlist, aNetlistFileName, aCmpFileName ) ); if( !netlistReader.get() ) { msg.Printf( _( "Cannot open netlist file \"%s\"." ), GetChars( aNetlistFileName ) ); wxMessageBox( msg, _( "Netlist Load Error." ), wxOK | wxICON_ERROR, this ); return; } SetLastNetListRead( aNetlistFileName ); netlistReader->LoadNetlist(); loadFootprints( netlist, aReporter ); } catch( const IO_ERROR& ioe ) { msg.Printf( _( "Error loading netlist.\n%s" ), ioe.errorText.GetData() ); wxMessageBox( msg, _( "Netlist Load Error" ), wxOK | wxICON_ERROR ); return; } // Clear undo and redo lists to avoid inconsistencies between lists if( !netlist.IsDryRun() ) GetScreen()->ClearUndoRedoList(); if( !netlist.IsDryRun() ) { // Remove old modules for( MODULE* module = board->m_Modules; module; module = module->Next() ) { module->RunOnChildren( boost::bind( &KIGFX::VIEW::Remove, view, _1 ) ); view->Remove( module ); } } // Clear selection, just in case a selected item has to be removed m_toolManager->RunAction( COMMON_ACTIONS::selectionClear, true ); netlist.SortByReference(); board->ReplaceNetlist( netlist, aDeleteSinglePadNets, aReporter ); // If it was a dry run, nothing has changed so we're done. if( netlist.IsDryRun() ) return; OnModify(); SetCurItem( NULL ); // Reload modules for( MODULE* module = board->m_Modules; module; module = module->Next() ) { module->RunOnChildren( boost::bind( &KIGFX::VIEW::Add, view, _1 ) ); view->Add( module ); module->ViewUpdate(); } if( aDeleteUnconnectedTracks && board->m_Track ) { // Remove erroneous tracks. This should probably pushed down to the #BOARD object. RemoveMisConnectedTracks(); } // Rebuild the board connectivity: if( IsGalCanvasActive() ) board->GetRatsnest()->ProcessBoard(); Compile_Ratsnest( NULL, true ); SetMsgPanel( board ); m_canvas->Refresh(); }
void PCB_EDIT_FRAME::PutDataInPreviousState( PICKED_ITEMS_LIST* aList, bool aRedoCommand, bool aRebuildRatsnet ) { BOARD_ITEM* item; bool not_found = false; bool reBuild_ratsnest = false; KIGFX::VIEW* view = GetGalCanvas()->GetView(); RN_DATA* ratsnest = GetBoard()->GetRatsnest(); // Undo in the reverse order of list creation: (this can allow stacked changes // like the same item can be changes and deleted in the same complex command bool build_item_list = true; // if true the list of existing items must be rebuilt for( int ii = aList->GetCount() - 1; ii >= 0 ; ii-- ) { item = (BOARD_ITEM*) aList->GetPickedItem( ii ); wxASSERT( item ); /* Test for existence of item on board. * It could be deleted, and no more on board: * - if a call to SaveCopyInUndoList was forgotten in Pcbnew * - in zones outlines, when a change in one zone merges this zone with an other * This test avoids a Pcbnew crash * Obviously, this test is not made for deleted items */ UNDO_REDO_T status = aList->GetPickedItemStatus( ii ); if( status != UR_DELETED ) { if( build_item_list ) // Build list of existing items, for integrity test TestForExistingItem( GetBoard(), NULL ); build_item_list = false; if( !TestForExistingItem( GetBoard(), item ) ) { // Remove this non existent item aList->RemovePicker( ii ); ii++; // the current item was removed, ii points now the next item // decrement it because it will be incremented later not_found = true; continue; } } item->ClearFlags(); // see if we must rebuild ratsnets and pointers lists switch( item->Type() ) { case PCB_MODULE_T: case PCB_ZONE_AREA_T: case PCB_TRACE_T: case PCB_VIA_T: reBuild_ratsnest = true; break; default: break; } switch( aList->GetPickedItemStatus( ii ) ) { case UR_CHANGED: /* Exchange old and new data for each item */ { BOARD_ITEM* image = (BOARD_ITEM*) aList->GetPickedItemLink( ii ); // Remove all pads/drawings/texts, as they become invalid // for the VIEW after SwapData() called for modules if( item->Type() == PCB_MODULE_T ) { MODULE* oldModule = static_cast<MODULE*>( item ); oldModule->RunOnChildren( boost::bind( &KIGFX::VIEW::Remove, view, _1 ) ); } ratsnest->Remove( item ); item->SwapData( image ); // Update all pads/drawings/texts, as they become invalid // for the VIEW after SwapData() called for modules if( item->Type() == PCB_MODULE_T ) { MODULE* newModule = static_cast<MODULE*>( item ); newModule->RunOnChildren( boost::bind( &KIGFX::VIEW::Add, view, _1 ) ); } ratsnest->Add( item ); item->ClearFlags( SELECTED ); item->ViewUpdate( KIGFX::VIEW_ITEM::LAYERS ); } break; case UR_NEW: /* new items are deleted */ aList->SetPickedItemStatus( UR_DELETED, ii ); GetBoard()->Remove( item ); if( item->Type() == PCB_MODULE_T ) { MODULE* module = static_cast<MODULE*>( item ); module->RunOnChildren( boost::bind( &KIGFX::VIEW::Remove, view, _1 ) ); } view->Remove( item ); item->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); break; case UR_DELETED: /* deleted items are put in List, as new items */ aList->SetPickedItemStatus( UR_NEW, ii ); GetBoard()->Add( item ); if( item->Type() == PCB_MODULE_T ) { MODULE* module = static_cast<MODULE*>( item ); module->RunOnChildren( boost::bind( &KIGFX::VIEW::Add, view, _1) ); } view->Add( item ); item->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); build_item_list = true; break; case UR_MOVED: item->Move( aRedoCommand ? aList->m_TransformPoint : -aList->m_TransformPoint ); item->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); ratsnest->Update( item ); break; case UR_ROTATED: item->Rotate( aList->m_TransformPoint, aRedoCommand ? m_rotationAngle : -m_rotationAngle ); item->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); ratsnest->Update( item ); break; case UR_ROTATED_CLOCKWISE: item->Rotate( aList->m_TransformPoint, aRedoCommand ? -m_rotationAngle : m_rotationAngle ); item->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); ratsnest->Update( item ); break; case UR_FLIPPED: item->Flip( aList->m_TransformPoint ); item->ViewUpdate( KIGFX::VIEW_ITEM::LAYERS ); ratsnest->Update( item ); break; default: { wxString msg; msg.Printf( wxT( "PutDataInPreviousState() error (unknown code %X)" ), aList->GetPickedItemStatus( ii ) ); wxMessageBox( msg ); } break; } } if( not_found ) wxMessageBox( wxT( "Incomplete undo/redo operation: some items not found" ) ); // Rebuild pointers and ratsnest that can be changed. if( reBuild_ratsnest && aRebuildRatsnet ) { if( IsGalCanvasActive() ) ratsnest->Recalculate(); else Compile_Ratsnest( NULL, true ); } }
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( PCB_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 ) { delete module; module = NULL; preview.Clear(); controls->ShowCursor( true ); } else break; if( evt->IsActivate() ) // now finish unconditionally break; } else if( module && evt->Category() == TC_COMMAND ) { if( TOOL_EVT_UTILS::IsRotateToolEvt( *evt ) ) { const auto rotationAngle = TOOL_EVT_UTILS::GetEventRotationAngle( *m_frame, *evt ); module->Rotate( module->GetPosition(), rotationAngle ); view->Update( &preview ); } else if( evt->IsAction( &PCB_ACTIONS::flip ) ) { module->Flip( module->GetPosition() ); view->Update( &preview ); } } 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 has been added in LoadModuleFromLibrary(), // so we have to remove it before committing the change @todo LEGACY board->Remove( module ); module->SetPosition( wxPoint( cursorPos.x, cursorPos.y ) ); // Add all the drawable parts to preview preview.Add( module ); module->RunOnChildren( std::bind( &KIGFX::VIEW_GROUP::Add, &preview, _1 ) ); } else { BOARD_COMMIT commit( m_frame ); commit.Add( module ); commit.Push( _( "Place a module" ) ); // Remove from preview preview.Remove( module ); module->RunOnChildren( std::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 ) ); view->Update( &preview ); } } view->Remove( &preview ); m_frame->SetToolID( ID_NO_TOOL_SELECTED, wxCURSOR_DEFAULT, wxEmptyString ); return 0; }
void BOARD_COMMIT::Push( const wxString& aMessage, bool aCreateUndoEntry, bool aSetDirtyBit ) { // Objects potentially interested in changes: PICKED_ITEMS_LIST undoList; KIGFX::VIEW* view = m_toolMgr->GetView(); BOARD* board = (BOARD*) m_toolMgr->GetModel(); PCB_BASE_FRAME* frame = (PCB_BASE_FRAME*) m_toolMgr->GetEditFrame(); auto connectivity = board->GetConnectivity(); std::set<EDA_ITEM*> savedModules; std::vector<BOARD_ITEM*> itemsToDeselect; if( Empty() ) return; for( COMMIT_LINE& ent : m_changes ) { int changeType = ent.m_type & CHT_TYPE; int changeFlags = ent.m_type & CHT_FLAGS; BOARD_ITEM* boardItem = static_cast<BOARD_ITEM*>( ent.m_item ); // Module items need to be saved in the undo buffer before modification if( m_editModules ) { // Be sure that we are storing a module if( ent.m_item->Type() != PCB_MODULE_T ) ent.m_item = ent.m_item->GetParent(); // We have not saved the module yet, so let's create an entry if( savedModules.count( ent.m_item ) == 0 ) { if( !ent.m_copy ) { wxASSERT( changeType != CHT_MODIFY ); // too late to make a copy.. ent.m_copy = ent.m_item->Clone(); } wxASSERT( ent.m_item->Type() == PCB_MODULE_T ); wxASSERT( ent.m_copy->Type() == PCB_MODULE_T ); if( aCreateUndoEntry ) { ITEM_PICKER itemWrapper( ent.m_item, UR_CHANGED ); itemWrapper.SetLink( ent.m_copy ); undoList.PushItem( itemWrapper ); frame->SaveCopyInUndoList( undoList, UR_CHANGED ); } savedModules.insert( ent.m_item ); static_cast<MODULE*>( ent.m_item )->SetLastEditTime(); } } switch( changeType ) { case CHT_ADD: { if( !m_editModules ) { if( aCreateUndoEntry ) { undoList.PushItem( ITEM_PICKER( boardItem, UR_NEW ) ); } if( !( changeFlags & CHT_DONE ) ) board->Add( boardItem ); // handles connectivity } else { // modules inside modules are not supported yet wxASSERT( boardItem->Type() != PCB_MODULE_T ); boardItem->SetParent( board->m_Modules.GetFirst() ); if( !( changeFlags & CHT_DONE ) ) board->m_Modules->Add( boardItem ); } view->Add( boardItem ); break; } case CHT_REMOVE: { if( !m_editModules && aCreateUndoEntry ) undoList.PushItem( ITEM_PICKER( boardItem, UR_DELETED ) ); switch( boardItem->Type() ) { // Module items case PCB_PAD_T: case PCB_MODULE_EDGE_T: case PCB_MODULE_TEXT_T: // This level can only handle module items when editing modules if( !m_editModules ) break; if( boardItem->Type() == PCB_MODULE_TEXT_T ) { TEXTE_MODULE* text = static_cast<TEXTE_MODULE*>( boardItem ); // don't allow deletion of Reference or Value if( text->GetType() != TEXTE_MODULE::TEXT_is_DIVERS ) break; } view->Remove( boardItem ); if( !( changeFlags & CHT_DONE ) ) { MODULE* module = static_cast<MODULE*>( boardItem->GetParent() ); wxASSERT( module && module->Type() == PCB_MODULE_T ); module->Delete( boardItem ); } board->m_Status_Pcb = 0; // it is done in the legacy view (ratsnest perhaps?) break; // Board items case PCB_LINE_T: // a segment not on copper layers case PCB_TEXT_T: // a text on a layer case PCB_TRACE_T: // a track segment (segment on a copper layer) case PCB_VIA_T: // a via (like track segment on a copper layer) case PCB_DIMENSION_T: // a dimension (graphic item) case PCB_TARGET_T: // a target (graphic item) case PCB_MARKER_T: // a marker used to show something case PCB_ZONE_AREA_T: itemsToDeselect.push_back( boardItem ); view->Remove( boardItem ); if( !( changeFlags & CHT_DONE ) ) board->Remove( boardItem ); break; case PCB_MODULE_T: { itemsToDeselect.push_back( boardItem ); // There are no modules inside a module yet wxASSERT( !m_editModules ); MODULE* module = static_cast<MODULE*>( boardItem ); view->Remove( module ); module->ClearFlags(); if( !( changeFlags & CHT_DONE ) ) board->Remove( module ); // handles connectivity // Clear flags to indicate, that the ratsnest, list of nets & pads are not valid anymore board->m_Status_Pcb = 0; } break; default: // other types do not need to (or should not) be handled wxASSERT( false ); break; } break; } case CHT_MODIFY: { if( !m_editModules && aCreateUndoEntry ) { ITEM_PICKER itemWrapper( boardItem, UR_CHANGED ); wxASSERT( ent.m_copy ); itemWrapper.SetLink( ent.m_copy ); undoList.PushItem( itemWrapper ); } if( ent.m_copy ) connectivity->MarkItemNetAsDirty( static_cast<BOARD_ITEM*>( ent.m_copy ) ); connectivity->Update( boardItem ); view->Update( boardItem ); // if no undo entry is needed, the copy would create a memory leak if( !aCreateUndoEntry ) delete ent.m_copy; break; } default: wxASSERT( false ); break; } } // Removing an item should trigger the unselect action // but only after all items are removed otherwise we can get // flickering depending on the system if( itemsToDeselect.size() > 0 ) m_toolMgr->RunAction( PCB_ACTIONS::unselectItems, true, &itemsToDeselect ); if( !m_editModules && aCreateUndoEntry ) frame->SaveCopyInUndoList( undoList, UR_UNSPECIFIED ); if( TOOL_MANAGER* toolMgr = frame->GetToolManager() ) toolMgr->PostEvent( { TC_MESSAGE, TA_MODEL_CHANGE, AS_GLOBAL } ); if ( !m_editModules ) { auto panel = static_cast<PCB_DRAW_PANEL_GAL*>( frame->GetGalCanvas() ); connectivity->RecalculateRatsnest(); connectivity->ClearDynamicRatsnest(); panel->RedrawRatsnest(); } if( aSetDirtyBit ) frame->OnModify(); frame->UpdateMsgPanel(); clear(); }
void BOARD_COMMIT::Revert() { PICKED_ITEMS_LIST undoList; KIGFX::VIEW* view = m_toolMgr->GetView(); BOARD* board = (BOARD*) m_toolMgr->GetModel(); auto connectivity = board->GetConnectivity(); for( auto it = m_changes.rbegin(); it != m_changes.rend(); ++it ) { COMMIT_LINE& ent = *it; BOARD_ITEM* item = static_cast<BOARD_ITEM*>( ent.m_item ); BOARD_ITEM* copy = static_cast<BOARD_ITEM*>( ent.m_copy ); int changeType = ent.m_type & CHT_TYPE; int changeFlags = ent.m_type & CHT_FLAGS; switch( changeType ) { case CHT_ADD: if( !( changeFlags & CHT_DONE ) ) break; view->Remove( item ); connectivity->Remove( item ); board->Remove( item ); break; case CHT_REMOVE: if( !( changeFlags & CHT_DONE ) ) break; if( item->Type() == PCB_MODULE_T ) { MODULE* newModule = static_cast<MODULE*>( item ); newModule->RunOnChildren( std::bind( &EDA_ITEM::ClearFlags, _1, SELECTED ) ); } view->Add( item ); connectivity->Add( item ); board->Add( item ); break; case CHT_MODIFY: { view->Remove( item ); connectivity->Remove( item ); item->SwapData( copy ); item->ClearFlags( SELECTED ); // Update all pads/drawings/texts, as they become invalid // for the VIEW after SwapData() called for modules if( item->Type() == PCB_MODULE_T ) { MODULE* newModule = static_cast<MODULE*>( item ); newModule->RunOnChildren( std::bind( &EDA_ITEM::ClearFlags, _1, SELECTED ) ); } view->Add( item ); connectivity->Add( item ); delete copy; break; } default: wxASSERT( false ); break; } } if ( !m_editModules ) connectivity->RecalculateRatsnest(); clear(); }
void BOARD_COMMIT::Push( const wxString& aMessage ) { // Objects potentially interested in changes: PICKED_ITEMS_LIST undoList; KIGFX::VIEW* view = m_toolMgr->GetView(); BOARD* board = (BOARD*) m_toolMgr->GetModel(); PCB_BASE_FRAME* frame = (PCB_BASE_FRAME*) m_toolMgr->GetEditFrame(); RN_DATA* ratsnest = board->GetRatsnest(); std::set<EDA_ITEM*> savedModules; if( Empty() ) return; for( COMMIT_LINE& ent : m_changes ) { int changeType = ent.m_type & CHT_TYPE; int changeFlags = ent.m_type & CHT_FLAGS; BOARD_ITEM* boardItem = static_cast<BOARD_ITEM*>( ent.m_item ); // Module items need to be saved in the undo buffer before modification if( m_editModules ) { // Be sure that we are storing a module if( ent.m_item->Type() != PCB_MODULE_T ) ent.m_item = ent.m_item->GetParent(); // We have not saved the module yet, so let's create an entry if( savedModules.count( ent.m_item ) == 0 ) { if( !ent.m_copy ) { assert( changeType != CHT_MODIFY ); // too late to make a copy.. ent.m_copy = ent.m_item->Clone(); } assert( ent.m_item->Type() == PCB_MODULE_T ); assert( ent.m_copy->Type() == PCB_MODULE_T ); ITEM_PICKER itemWrapper( ent.m_item, UR_CHANGED ); itemWrapper.SetLink( ent.m_copy ); undoList.PushItem( itemWrapper ); frame->SaveCopyInUndoList( undoList, UR_CHANGED ); savedModules.insert( ent.m_item ); static_cast<MODULE*>( ent.m_item )->SetLastEditTime(); } } switch( changeType ) { case CHT_ADD: { if( !m_editModules ) { undoList.PushItem( ITEM_PICKER( boardItem, UR_NEW ) ); if( !( changeFlags & CHT_DONE ) ) board->Add( boardItem ); //ratsnest->Add( boardItem ); // TODO currently done by BOARD::Add() if( boardItem->Type() == PCB_MODULE_T ) { MODULE* mod = static_cast<MODULE*>( boardItem ); mod->RunOnChildren( boost::bind( &KIGFX::VIEW::Add, view, _1 ) ); } } else { // modules inside modules are not supported yet assert( boardItem->Type() != PCB_MODULE_T ); if( !( changeFlags & CHT_DONE ) ) board->m_Modules->Add( boardItem ); } view->Add( boardItem ); break; } case CHT_REMOVE: { if( !m_editModules ) { undoList.PushItem( ITEM_PICKER( boardItem, UR_DELETED ) ); } switch( boardItem->Type() ) { // Module items case PCB_PAD_T: case PCB_MODULE_EDGE_T: case PCB_MODULE_TEXT_T: { // Do not allow footprint text removal when not editing a module if( !m_editModules ) break; bool remove = true; if( boardItem->Type() == PCB_MODULE_TEXT_T ) { TEXTE_MODULE* text = static_cast<TEXTE_MODULE*>( boardItem ); switch( text->GetType() ) { case TEXTE_MODULE::TEXT_is_REFERENCE: //DisplayError( frame, _( "Cannot delete component reference." ) ); remove = false; break; case TEXTE_MODULE::TEXT_is_VALUE: //DisplayError( frame, _( "Cannot delete component value." ) ); remove = false; break; case TEXTE_MODULE::TEXT_is_DIVERS: // suppress warnings break; default: assert( false ); break; } } if( remove ) { view->Remove( boardItem ); if( !( changeFlags & CHT_DONE ) ) { MODULE* module = static_cast<MODULE*>( boardItem->GetParent() ); assert( module && module->Type() == PCB_MODULE_T ); module->Delete( boardItem ); } board->m_Status_Pcb = 0; // it is done in the legacy view (ratsnest perhaps?) } break; } // Board items case PCB_LINE_T: // a segment not on copper layers case PCB_TEXT_T: // a text on a layer case PCB_TRACE_T: // a track segment (segment on a copper layer) case PCB_VIA_T: // a via (like track segment on a copper layer) case PCB_DIMENSION_T: // a dimension (graphic item) case PCB_TARGET_T: // a target (graphic item) case PCB_MARKER_T: // a marker used to show something case PCB_ZONE_T: // SEG_ZONE items are now deprecated case PCB_ZONE_AREA_T: view->Remove( boardItem ); if( !( changeFlags & CHT_DONE ) ) board->Remove( boardItem ); //ratsnest->Remove( boardItem ); // currently done by BOARD::Remove() break; case PCB_MODULE_T: { // There are no modules inside a module yet assert( !m_editModules ); MODULE* module = static_cast<MODULE*>( boardItem ); module->ClearFlags(); module->RunOnChildren( boost::bind( &KIGFX::VIEW::Remove, view, _1 ) ); view->Remove( module ); if( !( changeFlags & CHT_DONE ) ) board->Remove( module ); // Clear flags to indicate, that the ratsnest, list of nets & pads are not valid anymore board->m_Status_Pcb = 0; } break; default: // other types do not need to (or should not) be handled assert( false ); break; } break; } case CHT_MODIFY: { if( !m_editModules ) { ITEM_PICKER itemWrapper( boardItem, UR_CHANGED ); assert( ent.m_copy ); itemWrapper.SetLink( ent.m_copy ); undoList.PushItem( itemWrapper ); } boardItem->ViewUpdate( KIGFX::VIEW_ITEM::ALL ); ratsnest->Update( boardItem ); break; } default: assert( false ); break; } } if( !m_editModules ) frame->SaveCopyInUndoList( undoList, UR_UNSPECIFIED ); frame->OnModify(); ratsnest->Recalculate(); clear(); }
void BOARD_COMMIT::Revert() { PICKED_ITEMS_LIST undoList; KIGFX::VIEW* view = m_toolMgr->GetView(); BOARD* board = (BOARD*) m_toolMgr->GetModel(); RN_DATA* ratsnest = board->GetRatsnest(); for( auto it = m_changes.rbegin(); it != m_changes.rend(); ++it ) { COMMIT_LINE& ent = *it; BOARD_ITEM* item = static_cast<BOARD_ITEM*>( ent.m_item ); BOARD_ITEM* copy = static_cast<BOARD_ITEM*>( ent.m_copy ); switch( ent.m_type ) { case CHT_ADD: if( item->Type() == PCB_MODULE_T ) { MODULE* oldModule = static_cast<MODULE*>( item ); oldModule->RunOnChildren( boost::bind( &KIGFX::VIEW::Remove, view, _1 ) ); } view->Remove( item ); ratsnest->Remove( item ); break; case CHT_REMOVE: if( item->Type() == PCB_MODULE_T ) { MODULE* newModule = static_cast<MODULE*>( item ); newModule->RunOnChildren( boost::bind( &EDA_ITEM::ClearFlags, _1, SELECTED ) ); newModule->RunOnChildren( boost::bind( &KIGFX::VIEW::Add, view, _1 ) ); } view->Add( item ); ratsnest->Add( item ); break; case CHT_MODIFY: { if( item->Type() == PCB_MODULE_T ) { MODULE* oldModule = static_cast<MODULE*>( item ); oldModule->RunOnChildren( boost::bind( &KIGFX::VIEW::Remove, view, _1 ) ); } view->Remove( item ); ratsnest->Remove( item ); item->SwapData( copy ); item->ClearFlags( SELECTED ); // Update all pads/drawings/texts, as they become invalid // for the VIEW after SwapData() called for modules if( item->Type() == PCB_MODULE_T ) { MODULE* newModule = static_cast<MODULE*>( item ); newModule->RunOnChildren( boost::bind( &EDA_ITEM::ClearFlags, _1, SELECTED ) ); newModule->RunOnChildren( boost::bind( &KIGFX::VIEW::Add, view, _1 ) ); } view->Add( item ); ratsnest->Add( item ); delete copy; break; } default: assert( false ); break; } } ratsnest->Recalculate(); clear(); }
void FOOTPRINT_EDIT_FRAME::Process_Special_Functions( wxCommandEvent& event ) { int id = event.GetId(); wxPoint pos; INSTALL_UNBUFFERED_DC( dc, m_canvas ); wxGetMousePosition( &pos.x, &pos.y ); pos.y += 20; switch( id ) { case wxID_CUT: case wxID_COPY: case ID_TOOLBARH_PCB_SELECT_LAYER: case ID_MODEDIT_PAD_SETTINGS: case ID_PCB_USER_GRID_SETUP: case ID_POPUP_PCB_ROTATE_TEXTEPCB: case ID_POPUP_PCB_EDIT_TEXTEPCB: case ID_POPUP_PCB_ROTATE_TEXTMODULE: case ID_POPUP_PCB_ROTATE_MODULE_CLOCKWISE: case ID_POPUP_PCB_ROTATE_MODULE_COUNTERCLOCKWISE: case ID_POPUP_PCB_EDIT_TEXTMODULE: case ID_POPUP_PCB_IMPORT_PAD_SETTINGS: case ID_POPUP_PCB_EXPORT_PAD_SETTINGS: case ID_POPUP_PCB_GLOBAL_IMPORT_PAD_SETTINGS: case ID_POPUP_PCB_STOP_CURRENT_DRAWING: case ID_POPUP_MODEDIT_EDIT_BODY_ITEM: case ID_POPUP_MODEDIT_EDIT_WIDTH_ALL_EDGE: case ID_POPUP_MODEDIT_EDIT_LAYER_ALL_EDGE: case ID_POPUP_MODEDIT_ENTER_EDGE_WIDTH: case ID_POPUP_PCB_DELETE_EDGE: case ID_POPUP_PCB_DELETE_TEXTMODULE: case ID_POPUP_PCB_DELETE_PAD: case ID_POPUP_DELETE_BLOCK: case ID_POPUP_PLACE_BLOCK: case ID_POPUP_ZOOM_BLOCK: case ID_POPUP_MIRROR_X_BLOCK: case ID_POPUP_ROTATE_BLOCK: case ID_POPUP_COPY_BLOCK: break; case ID_POPUP_CANCEL_CURRENT_COMMAND: default: if( m_canvas->IsMouseCaptured() ) { // for all other commands: stop the move in progress m_canvas->CallEndMouseCapture( &dc ); } if( id != ID_POPUP_CANCEL_CURRENT_COMMAND ) SetToolID( ID_NO_TOOL_SELECTED, m_canvas->GetDefaultCursor(), wxEmptyString ); break; } switch( id ) { case ID_EXIT: Close( true ); break; case ID_MODEDIT_SELECT_CURRENT_LIB: { wxString library = SelectLibrary( GetCurrentLib() ); if( library.size() ) { Prj().SetRString( PROJECT::PCB_LIB_NICKNAME, library ); updateTitle(); } } break; case ID_OPEN_MODULE_VIEWER: { FOOTPRINT_VIEWER_FRAME* viewer = (FOOTPRINT_VIEWER_FRAME*) Kiway().Player( FRAME_PCB_MODULE_VIEWER, false ); if( !viewer ) { viewer = (FOOTPRINT_VIEWER_FRAME*) Kiway().Player( FRAME_PCB_MODULE_VIEWER, true ); viewer->Show( true ); viewer->Zoom_Automatique( false ); } else { // On Windows, Raise() does not bring the window on screen, when iconized if( viewer->IsIconized() ) viewer->Iconize( false ); viewer->Raise(); // Raising the window does not set the focus on Linux. This should work on // any platform. if( wxWindow::FindFocus() != viewer ) viewer->SetFocus(); } } break; case ID_MODEDIT_DELETE_PART: DeleteModuleFromCurrentLibrary(); break; case ID_MODEDIT_NEW_MODULE: { if( !Clear_Pcb( true ) ) break; SetCrossHairPosition( wxPoint( 0, 0 ) ); MODULE* module = CreateNewModule( wxEmptyString ); if( module ) // i.e. if create module command not aborted { // Initialize data relative to nets and netclasses (for a new // module the defaults are used) // This is mandatory to handle and draw pads GetBoard()->BuildListOfNets(); module->SetPosition( wxPoint( 0, 0 ) ); if( GetBoard()->m_Modules ) GetBoard()->m_Modules->ClearFlags(); Zoom_Automatique( false ); } updateView(); m_canvas->Refresh(); GetScreen()->ClrModify(); } break; case ID_MODEDIT_NEW_MODULE_FROM_WIZARD: { if( GetScreen()->IsModify() && !GetBoard()->IsEmpty() ) { if( !IsOK( this, _( "Current Footprint will be lost and this operation cannot be undone. Continue ?" ) ) ) break; } FOOTPRINT_WIZARD_FRAME* wizard = (FOOTPRINT_WIZARD_FRAME*) Kiway().Player( FRAME_PCB_FOOTPRINT_WIZARD_MODAL, true ); if( wizard->ShowModal( NULL, this ) ) { // Creates the new footprint from python script wizard MODULE* module = wizard->GetBuiltFootprint(); if( module == NULL ) // i.e. if create module command aborted break; Clear_Pcb( false ); SetCrossHairPosition( wxPoint( 0, 0 ) ); // Add the new object to board GetBoard()->Add( module, ADD_APPEND ); // Initialize data relative to nets and netclasses (for a new // module the defaults are used) // This is mandatory to handle and draw pads GetBoard()->BuildListOfNets(); module->SetPosition( wxPoint( 0, 0 ) ); module->ClearFlags(); Zoom_Automatique( false ); updateView(); m_canvas->Refresh(); if( m_Draw3DFrame ) m_Draw3DFrame->NewDisplay(); GetScreen()->ClrModify(); } wizard->Destroy(); } break; case ID_MODEDIT_SAVE_LIBMODULE: if( GetBoard()->m_Modules && GetCurrentLib().size() ) { SaveFootprintInLibrary( GetCurrentLib(), GetBoard()->m_Modules, true, true ); GetScreen()->ClrModify(); } break; case ID_MODEDIT_INSERT_MODULE_IN_BOARD: case ID_MODEDIT_UPDATE_MODULE_IN_BOARD: { // update module in the current board, // not just add it to the board with total disregard for the netlist... PCB_EDIT_FRAME* pcbframe = (PCB_EDIT_FRAME*) Kiway().Player( FRAME_PCB, false ); if( pcbframe == NULL ) // happens when the board editor is not active (or closed) { wxMessageBox( _("No board currently edited" ) ); break; } BOARD* mainpcb = pcbframe->GetBoard(); MODULE* source_module = NULL; MODULE* module_in_edit = GetBoard()->m_Modules; // Search the old module (source) if exists // Because this source could be deleted when editing the main board... if( module_in_edit->GetLink() ) // this is not a new module ... { source_module = mainpcb->m_Modules; for( ; source_module != NULL; source_module = (MODULE*) source_module->Next() ) { if( module_in_edit->GetLink() == source_module->GetTimeStamp() ) break; } } if( ( source_module == NULL ) && ( id == ID_MODEDIT_UPDATE_MODULE_IN_BOARD ) ) // source not found { wxString msg; msg.Printf( _( "Unable to find the footprint source on the main board" ) ); msg << _( "\nCannot update the footprint" ); DisplayError( this, msg ); break; } if( ( source_module != NULL ) && ( id == ID_MODEDIT_INSERT_MODULE_IN_BOARD ) ) // source not found { wxString msg; msg.Printf( _( "A footprint source was found on the main board" ) ); msg << _( "\nCannot insert this footprint" ); DisplayError( this, msg ); break; } m_toolManager->RunAction( COMMON_ACTIONS::selectionClear, true ); // Create the "new" module MODULE* newmodule = new MODULE( *module_in_edit ); newmodule->SetParent( mainpcb ); newmodule->SetLink( 0 ); // Put the footprint in the main pcb linked list. mainpcb->Add( newmodule ); if( source_module ) // this is an update command { // In the main board, // the new module replace the old module (pos, orient, ref, value // and connexions are kept) // and the source_module (old module) is deleted PICKED_ITEMS_LIST pickList; if( pcbframe->IsGalCanvasActive() ) { KIGFX::VIEW* view = pcbframe->GetGalCanvas()->GetView(); source_module->RunOnChildren( boost::bind( &KIGFX::VIEW::Remove, view, _1 ) ); view->Remove( source_module ); } pcbframe->Exchange_Module( source_module, newmodule, &pickList ); newmodule->SetTimeStamp( module_in_edit->GetLink() ); if( pickList.GetCount() ) pcbframe->SaveCopyInUndoList( pickList, UR_UNSPECIFIED ); } else // This is an insert command { wxPoint cursor_pos = pcbframe->GetCrossHairPosition(); pcbframe->SetCrossHairPosition( wxPoint( 0, 0 ) ); pcbframe->PlaceModule( newmodule, NULL ); newmodule->SetPosition( wxPoint( 0, 0 ) ); pcbframe->SetCrossHairPosition( cursor_pos ); newmodule->SetTimeStamp( GetNewTimeStamp() ); pcbframe->SaveCopyInUndoList( newmodule, UR_NEW ); } newmodule->ClearFlags(); GetScreen()->ClrModify(); pcbframe->SetCurItem( NULL ); mainpcb->m_Status_Pcb = 0; if( pcbframe->IsGalCanvasActive() ) { RN_DATA* ratsnest = pcbframe->GetBoard()->GetRatsnest(); ratsnest->Update( newmodule ); ratsnest->Recalculate(); KIGFX::VIEW* view = pcbframe->GetGalCanvas()->GetView(); newmodule->RunOnChildren( boost::bind( &KIGFX::VIEW::Add, view, _1 ) ); view->Add( newmodule ); pcbframe->GetGalCanvas()->ForceRefresh(); } } break; case ID_MODEDIT_IMPORT_PART: if( ! Clear_Pcb( true ) ) break; // //this command is aborted SetCrossHairPosition( wxPoint( 0, 0 ) ); Import_Module(); if( GetBoard()->m_Modules ) GetBoard()->m_Modules->ClearFlags(); GetScreen()->ClrModify(); Zoom_Automatique( false ); m_canvas->Refresh(); if( m_Draw3DFrame ) m_Draw3DFrame->NewDisplay(); break; case ID_MODEDIT_EXPORT_PART: if( GetBoard()->m_Modules ) Export_Module( GetBoard()->m_Modules ); break; case ID_MODEDIT_CREATE_NEW_LIB_AND_SAVE_CURRENT_PART: if( GetBoard()->m_Modules ) { // CreateModuleLibrary() only creates a new library, does not save footprint wxString libPath = CreateNewLibrary(); if( libPath.size() ) SaveCurrentModule( &libPath ); } break; case ID_MODEDIT_SHEET_SET: break; case ID_MODEDIT_LOAD_MODULE: wxLogDebug( wxT( "Loading module from library " ) + getLibPath() ); if( ! Clear_Pcb( true ) ) break; SetCrossHairPosition( wxPoint( 0, 0 ) ); LoadModuleFromLibrary( GetCurrentLib(), Prj().PcbFootprintLibs(), true ); if( GetBoard() && GetBoard()->m_Modules ) { GetBoard()->m_Modules->ClearFlags(); // if either m_Reference or m_Value are gone, reinstall them - // otherwise you cannot see what you are doing on board TEXTE_MODULE* ref = &GetBoard()->m_Modules->Reference(); TEXTE_MODULE* val = &GetBoard()->m_Modules->Value(); if( val && ref ) { ref->SetType( TEXTE_MODULE::TEXT_is_REFERENCE ); // just in case ... if( ref->GetLength() == 0 ) ref->SetText( wxT( "Ref**" ) ); val->SetType( TEXTE_MODULE::TEXT_is_VALUE ); // just in case ... if( val->GetLength() == 0 ) val->SetText( wxT( "Val**" ) ); } } Zoom_Automatique( false ); if( m_Draw3DFrame ) m_Draw3DFrame->NewDisplay(); GetScreen()->ClrModify(); updateView(); m_canvas->Refresh(); break; case ID_MODEDIT_PAD_SETTINGS: InstallPadOptionsFrame( NULL ); break; case ID_MODEDIT_CHECK: // Currently: not implemented break; case ID_MODEDIT_EDIT_MODULE_PROPERTIES: if( GetBoard()->m_Modules ) { SetCurItem( GetBoard()->m_Modules ); DIALOG_MODULE_MODULE_EDITOR dialog( this, (MODULE*) GetScreen()->GetCurItem() ); int ret = dialog.ShowModal(); GetScreen()->GetCurItem()->ClearFlags(); GetBoard()->m_Modules.GetFirst()->ViewUpdate(); if( ret > 0 ) m_canvas->Refresh(); } break; case ID_POPUP_CLOSE_CURRENT_TOOL: break; case ID_POPUP_CANCEL_CURRENT_COMMAND: break; case ID_POPUP_PCB_ROTATE_MODULE_COUNTERCLOCKWISE: m_canvas->MoveCursorToCrossHair(); Rotate_Module( NULL, (MODULE*) GetScreen()->GetCurItem(), 900, true ); m_canvas->Refresh(); break; case ID_POPUP_PCB_ROTATE_MODULE_CLOCKWISE: m_canvas->MoveCursorToCrossHair(); Rotate_Module( NULL, (MODULE*) GetScreen()->GetCurItem(), -900, true ); m_canvas->Refresh(); break; case ID_POPUP_PCB_EDIT_MODULE_PRMS: { DIALOG_MODULE_MODULE_EDITOR dialog( this, (MODULE*) GetScreen()->GetCurItem() ); dialog.ShowModal(); GetScreen()->GetCurItem()->ClearFlags(); m_canvas->MoveCursorToCrossHair(); m_canvas->Refresh(); } break; case ID_POPUP_PCB_MOVE_PAD_REQUEST: m_canvas->MoveCursorToCrossHair(); StartMovePad( (D_PAD*) GetScreen()->GetCurItem(), &dc, false ); break; case ID_POPUP_PCB_EDIT_PAD: InstallPadOptionsFrame( (D_PAD*) GetScreen()->GetCurItem() ); m_canvas->MoveCursorToCrossHair(); break; case ID_POPUP_PCB_DELETE_PAD: SaveCopyInUndoList( GetBoard()->m_Modules, UR_MODEDIT ); DeletePad( (D_PAD*) GetScreen()->GetCurItem(), false ); SetCurItem( NULL ); m_canvas->MoveCursorToCrossHair(); break; case ID_POPUP_PCB_DUPLICATE_ITEM: duplicateItems( false ); break; case ID_POPUP_PCB_DUPLICATE_ITEM_AND_INCREMENT: duplicateItems( true ); break; case ID_POPUP_PCB_MOVE_EXACT: moveExact(); break; case ID_POPUP_PCB_CREATE_ARRAY: createArray(); break; case ID_POPUP_PCB_IMPORT_PAD_SETTINGS: SaveCopyInUndoList( GetBoard()->m_Modules, UR_MODEDIT ); m_canvas->MoveCursorToCrossHair(); Import_Pad_Settings( (D_PAD*) GetScreen()->GetCurItem(), true ); break; case ID_POPUP_PCB_GLOBAL_IMPORT_PAD_SETTINGS: SaveCopyInUndoList( GetBoard()->m_Modules, UR_MODEDIT ); // Calls the global change dialog: DlgGlobalChange_PadSettings( (D_PAD*) GetScreen()->GetCurItem() ); m_canvas->MoveCursorToCrossHair(); break; case ID_POPUP_PCB_EXPORT_PAD_SETTINGS: m_canvas->MoveCursorToCrossHair(); Export_Pad_Settings( (D_PAD*) GetScreen()->GetCurItem() ); break; case ID_POPUP_PCB_EDIT_TEXTMODULE: InstallTextModOptionsFrame( static_cast<TEXTE_MODULE*>( GetScreen()->GetCurItem() ), &dc ); m_canvas->MoveCursorToCrossHair(); break; case ID_POPUP_PCB_MOVE_TEXTMODULE_REQUEST: m_canvas->MoveCursorToCrossHair(); StartMoveTexteModule( static_cast<TEXTE_MODULE*>( GetScreen()->GetCurItem() ), &dc ); break; case ID_POPUP_PCB_ROTATE_TEXTMODULE: RotateTextModule( static_cast<TEXTE_MODULE*>( GetScreen()->GetCurItem() ), &dc ); m_canvas->MoveCursorToCrossHair(); break; case ID_POPUP_PCB_DELETE_TEXTMODULE: SaveCopyInUndoList( GetBoard()->m_Modules, UR_MODEDIT ); DeleteTextModule( static_cast<TEXTE_MODULE*>( GetScreen()->GetCurItem() ) ); SetCurItem( NULL ); m_canvas->MoveCursorToCrossHair(); break; case ID_POPUP_PCB_MOVE_EDGE: Start_Move_EdgeMod( static_cast<EDGE_MODULE*>( GetScreen()->GetCurItem() ), &dc ); m_canvas->MoveCursorToCrossHair(); break; case ID_POPUP_PCB_STOP_CURRENT_DRAWING: m_canvas->MoveCursorToCrossHair(); if( GetScreen()->GetCurItem()->IsNew() ) { End_Edge_Module( (EDGE_MODULE*) GetScreen()->GetCurItem() ); SetCurItem( NULL ); } break; case ID_POPUP_MODEDIT_ENTER_EDGE_WIDTH: { EDGE_MODULE* edge = NULL; if( GetScreen()->GetCurItem() && ( GetScreen()->GetCurItem()->Type() == PCB_MODULE_EDGE_T ) ) { edge = (EDGE_MODULE*) GetScreen()->GetCurItem(); } Enter_Edge_Width( edge ); m_canvas->MoveCursorToCrossHair(); if( edge ) m_canvas->Refresh(); } break; case ID_POPUP_MODEDIT_EDIT_BODY_ITEM : m_canvas->MoveCursorToCrossHair(); InstallFootprintBodyItemPropertiesDlg( (EDGE_MODULE*) GetScreen()->GetCurItem() ); m_canvas->Refresh(); break; case ID_POPUP_MODEDIT_EDIT_WIDTH_ALL_EDGE: m_canvas->MoveCursorToCrossHair(); Edit_Edge_Width( NULL ); m_canvas->Refresh(); break; case ID_POPUP_MODEDIT_EDIT_LAYER_ALL_EDGE: m_canvas->MoveCursorToCrossHair(); Edit_Edge_Layer( NULL ); m_canvas->Refresh(); break; case ID_POPUP_PCB_DELETE_EDGE: SaveCopyInUndoList( GetBoard()->m_Modules, UR_MODEDIT ); m_canvas->MoveCursorToCrossHair(); RemoveStruct( GetScreen()->GetCurItem() ); SetCurItem( NULL ); break; case ID_MODEDIT_MODULE_ROTATE: case ID_MODEDIT_MODULE_MIRROR: case ID_MODEDIT_MODULE_MOVE_EXACT: SaveCopyInUndoList( GetBoard()->m_Modules, UR_MODEDIT ); Transform( (MODULE*) GetScreen()->GetCurItem(), id ); m_canvas->Refresh(); break; case ID_PCB_DRAWINGS_WIDTHS_SETUP: InstallOptionsFrame( pos ); break; case ID_PCB_PAD_SETUP: { BOARD_ITEM* item = GetCurItem(); if( item ) { if( item->Type() != PCB_PAD_T ) item = NULL; } InstallPadOptionsFrame( (D_PAD*) item ); } break; case ID_PCB_USER_GRID_SETUP: InvokeDialogGrid(); break; case ID_POPUP_PLACE_BLOCK: GetScreen()->m_BlockLocate.SetCommand( BLOCK_MOVE ); m_canvas->SetAutoPanRequest( false ); HandleBlockPlace( &dc ); break; case ID_POPUP_COPY_BLOCK: GetScreen()->m_BlockLocate.SetCommand( BLOCK_COPY ); GetScreen()->m_BlockLocate.SetMessageBlock( this ); m_canvas->SetAutoPanRequest( false ); HandleBlockPlace( &dc ); break; case ID_POPUP_ZOOM_BLOCK: GetScreen()->m_BlockLocate.SetCommand( BLOCK_ZOOM ); GetScreen()->m_BlockLocate.SetMessageBlock( this ); HandleBlockEnd( &dc ); break; case ID_POPUP_DELETE_BLOCK: GetScreen()->m_BlockLocate.SetCommand( BLOCK_DELETE ); GetScreen()->m_BlockLocate.SetMessageBlock( this ); HandleBlockEnd( &dc ); break; case ID_POPUP_ROTATE_BLOCK: GetScreen()->m_BlockLocate.SetCommand( BLOCK_ROTATE ); GetScreen()->m_BlockLocate.SetMessageBlock( this ); HandleBlockEnd( &dc ); break; case ID_POPUP_MIRROR_X_BLOCK: GetScreen()->m_BlockLocate.SetCommand( BLOCK_MIRROR_X ); GetScreen()->m_BlockLocate.SetMessageBlock( this ); HandleBlockEnd( &dc ); break; case ID_POPUP_MOVE_BLOCK_EXACT: GetScreen()->m_BlockLocate.SetCommand( BLOCK_MOVE_EXACT ); GetScreen()->m_BlockLocate.SetMessageBlock( this ); HandleBlockEnd( &dc ); break; case ID_GEN_IMPORT_DXF_FILE: if( GetBoard()->m_Modules ) { InvokeDXFDialogModuleImport( this, GetBoard()->m_Modules ); m_canvas->Refresh(); } break; default: DisplayError( this, wxT( "FOOTPRINT_EDIT_FRAME::Process_Special_Functions error" ) ); break; } }
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 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 PCB_EDITOR_CONTROL::ZoneMerge( const TOOL_EVENT& aEvent ) { SELECTION selection = m_toolMgr->GetTool<SELECTION_TOOL>()->GetSelection(); BOARD* board = getModel<BOARD>(); RN_DATA* ratsnest = board->GetRatsnest(); KIGFX::VIEW* view = getView(); if( selection.Size() < 2 ) return 0; PICKED_ITEMS_LIST changes; int netcode = -1; // Loop through all combinations for( int ia1 = 0; ia1 < selection.Size() - 1; ++ia1 ) { ZONE_CONTAINER* curr_area = dynamic_cast<ZONE_CONTAINER*>( selection.Item<EDA_ITEM>( ia1 ) ); if( !curr_area ) continue; netcode = curr_area->GetNetCode(); EDA_RECT b1 = curr_area->Outline()->GetBoundingBox(); bool mod_ia1 = false; for( int ia2 = selection.Size() - 1; ia2 > ia1; --ia2 ) { ZONE_CONTAINER* area2 = dynamic_cast<ZONE_CONTAINER*>( selection.Item<EDA_ITEM>( ia2 ) ); if( !area2 ) continue; if( area2->GetNetCode() != netcode ) continue; if( curr_area->GetPriority() != area2->GetPriority() ) continue; if( curr_area->GetIsKeepout() != area2->GetIsKeepout() ) continue; if( curr_area->GetLayer() != area2->GetLayer() ) continue; EDA_RECT b2 = area2->Outline()->GetBoundingBox(); if( b1.Intersects( b2 ) ) { EDA_ITEM* backup = curr_area->Clone(); bool ret = board->TestAreaIntersection( curr_area, area2 ); if( ret && board->CombineAreas( &changes, curr_area, area2 ) ) { mod_ia1 = true; selection.items.RemovePicker( ia2 ); ITEM_PICKER picker( curr_area, UR_CHANGED ); picker.SetLink( backup ); changes.PushItem( picker ); } else { delete backup; } } } if( mod_ia1 ) --ia1; // if modified, we need to check it again } m_toolMgr->RunAction( COMMON_ACTIONS::selectionClear, true ); m_frame->SaveCopyInUndoList( changes, UR_UNSPECIFIED ); for( unsigned i = 0; i < changes.GetCount(); ++i ) { ITEM_PICKER picker = changes.GetItemWrapper( i ); BOARD_ITEM* item = static_cast<BOARD_ITEM*>( picker.GetItem() ); if( picker.GetStatus() == UR_DELETED ) { view->Remove( item ); ratsnest->Remove( item ); } else if( picker.GetStatus() == UR_CHANGED ) { item->ViewUpdate( KIGFX::VIEW_ITEM::ALL ); m_toolMgr->RunAction( COMMON_ACTIONS::selectItem, true, item ); } } return 0; }
bool GERBVIEW_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 ); KIGFX::PREVIEW::SELECTION_AREA area; view->Add( &area ); while( OPT_TOOL_EVENT evt = Wait() ) { if( 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 ); } if( evt->IsMouseUp( BUT_LEFT ) ) { // End drawing the selection box view->SetVisible( &area, false ); // Mark items within the selection box as selected std::vector<KIGFX::VIEW::LAYER_ITEM_PAIR> selectedItems; // Filter the view items based on the selection box 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; int width = area.GetEnd().x - area.GetOrigin().x; int height = area.GetEnd().y - area.GetOrigin().y; // Construct an EDA_RECT to determine EDA_ITEM selection EDA_RECT selectionRect( wxPoint( area.GetOrigin().x, area.GetOrigin().y ), wxSize( width, height ) ); selectionRect.Normalize(); for( it = selectedItems.begin(), it_end = selectedItems.end(); it != it_end; ++it ) { auto item = static_cast<GERBER_DRAW_ITEM*>( it->first ); if( !item || !selectable( item ) ) continue; /* 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 */ if( width >= 0 ) { if( selectionBox.Contains( item->ViewBBox() ) ) { if( m_subtractive ) unselect( item ); else select( item ); } } else { if( item->HitTest( selectionRect ) ) { if( m_subtractive ) unselect( item ); else select( item ); } } } if( m_selection.Size() == 1 ) m_frame->SetCurItem( static_cast<GERBER_DRAW_ITEM*>( m_selection.Front() ) ); else m_frame->SetCurItem( NULL ); // Inform other potentially interested tools if( !m_selection.Empty() ) m_toolMgr->ProcessEvent( SelectedEvent ); break; // Stop waiting for events } } // Stop drawing the selection box view->Remove( &area ); m_multiple = false; // Multiple selection mode is inactive getViewControls()->SetAutoPan( false ); return cancelled; }