diff --git a/eeschema/schematic_undo_redo.cpp b/eeschema/schematic_undo_redo.cpp index 8e649a0dd9..a215a4da0b 100644 --- a/eeschema/schematic_undo_redo.cpp +++ b/eeschema/schematic_undo_redo.cpp @@ -181,7 +181,7 @@ void SwapData( EDA_BaseStruct* aItem, EDA_BaseStruct* aImage ) /***********************************************************************/ -void WinEDA_SchematicFrame::SaveCopyInUndoList( SCH_ITEM* aItemToCopy, +void WinEDA_SchematicFrame::SaveCopyInUndoList( SCH_ITEM* aItem, UndoRedoOpType aCommandType, const wxPoint& aTransformPoint ) /***********************************************************************/ @@ -194,6 +194,7 @@ void WinEDA_SchematicFrame::SaveCopyInUndoList( SCH_ITEM* aItemToCopy, * UR_NEW * UR_DELETED * UR_WIRE_IMAGE + * UR_MOVED * * If it is a delete command, items are put on list with the .Flags member set to UR_DELETED. * When it will be really deleted, the EEDrawList and the subhierarchy will be deleted. @@ -211,15 +212,14 @@ void WinEDA_SchematicFrame::SaveCopyInUndoList( SCH_ITEM* aItemToCopy, PICKED_ITEMS_LIST* commandToUndo = new PICKED_ITEMS_LIST(); commandToUndo->m_TransformPoint = aTransformPoint; - ITEM_PICKER itemWrapper( aItemToCopy, aCommandType ); - itemWrapper.m_PickedItemType = aItemToCopy->Type(); + ITEM_PICKER itemWrapper( aItem, aCommandType ); + itemWrapper.m_PickedItemType = aItem->Type(); switch( aCommandType ) { - case UR_CHANGED: /* Create a copy of schematic */ - CopyOfItem = DuplicateStruct( aItemToCopy ); - itemWrapper.m_PickedItem = CopyOfItem; - itemWrapper.m_Link = aItemToCopy; + case UR_CHANGED: /* Create a copy of item */ + CopyOfItem = DuplicateStruct( aItem ); + itemWrapper.m_Link = CopyOfItem; if ( CopyOfItem ) commandToUndo->PushItem( itemWrapper ); break; @@ -269,21 +269,20 @@ void WinEDA_SchematicFrame::SaveCopyInUndoList( PICKED_ITEMS_LIST& aItemsList, for( unsigned ii = 0; ii < aItemsList.GetCount(); ii++ ) { - SCH_ITEM* ItemToCopy = (SCH_ITEM*) aItemsList.GetPickedItem( ii ); + SCH_ITEM* item = (SCH_ITEM*) aItemsList.GetPickedItem( ii ); UndoRedoOpType command = aItemsList.GetPickedItemStatus( ii ); if( command == UR_UNSPECIFIED ) { command = aTypeCommand; } - itemWrapper.m_PickedItem = ItemToCopy; - itemWrapper.m_PickedItemType = ItemToCopy->Type(); + itemWrapper.m_PickedItem = item; + itemWrapper.m_PickedItemType = item->Type(); itemWrapper.m_UndoRedoStatus = command; switch( command ) { - case UR_CHANGED: /* Create a copy of schematic */ - CopyOfItem = DuplicateStruct( ItemToCopy ); - itemWrapper.m_PickedItem = CopyOfItem; - itemWrapper.m_Link = ItemToCopy; + case UR_CHANGED: /* Create a copy of item */ + CopyOfItem = DuplicateStruct( item ); + itemWrapper.m_Link = CopyOfItem; if ( CopyOfItem ) commandToUndo->PushItem( itemWrapper ); break; @@ -291,11 +290,7 @@ void WinEDA_SchematicFrame::SaveCopyInUndoList( PICKED_ITEMS_LIST& aItemsList, case UR_MOVED: case UR_MIRRORED_Y: case UR_NEW: - commandToUndo->PushItem( itemWrapper ); - break; - case UR_DELETED: - ItemToCopy->m_Flags = UR_DELETED; commandToUndo->PushItem( itemWrapper ); break; @@ -338,6 +333,7 @@ void WinEDA_SchematicFrame::PutDataInPreviousState( PICKED_ITEMS_LIST* aList, bo ITEM_PICKER itemWrapper = aList->GetItemWrapper( ii ); item = (SCH_ITEM*) itemWrapper.m_PickedItem; wxASSERT( item ); + item->m_Flags = 0; SCH_ITEM* image = (SCH_ITEM*) itemWrapper.m_Link; switch( itemWrapper.m_UndoRedoStatus ) { @@ -348,14 +344,12 @@ void WinEDA_SchematicFrame::PutDataInPreviousState( PICKED_ITEMS_LIST* aList, bo case UR_NEW: /* new items are deleted */ aList->SetPickedItemStatus( UR_DELETED, ii ); GetScreen()->RemoveFromDrawList( item ); - item->m_Flags = UR_DELETED; break; case UR_DELETED: /* deleted items are put in EEdrawList, as new items */ aList->SetPickedItemStatus( UR_NEW, ii ); item->SetNext( GetScreen()->EEDrawList ); GetScreen()->EEDrawList = item; - item->m_Flags = 0; break; case UR_MOVED: @@ -500,7 +494,7 @@ void SCH_SCREEN::ClearUndoORRedoList( UNDO_REDO_CONTAINER& aList, int aItemCount { case UR_WIRE_IMAGE: while( item ) - { + { // Delete old copy of wires EDA_BaseStruct* nextitem = item->Next(); delete item; item = nextitem; @@ -515,9 +509,23 @@ void SCH_SCREEN::ClearUndoORRedoList( UNDO_REDO_CONTAINER& aList, int aItemCount case UR_NEW: // Do nothing, items are in use break; - default: - delete item; + case UR_DELETED: + delete item; // Delete the picked item, because it was deleted from schematic break; + + case UR_CHANGED: + delete wrapper.m_Link; // Delete the copy of item (the item is itself in use) + break; + + default: + { + wxString msg; + msg.Printf( + wxT("ClearUndoORRedoList() error: unexpected undo/redo type %d"), + wrapper.m_UndoRedoStatus ); + wxMessageBox( msg ); + break; + } } } diff --git a/include/board_item_struct.h b/include/board_item_struct.h index f18f8cdcb6..5e496846d7 100644 --- a/include/board_item_struct.h +++ b/include/board_item_struct.h @@ -87,8 +87,10 @@ public: * Function SetLayer * sets the layer this item is on. * @param aLayer The layer number. + * is virtual because some items (in fact: class COTATION) + * have a slightly different initialisation */ - void SetLayer( int aLayer ) { m_Layer = aLayer; } + virtual void SetLayer( int aLayer ) { m_Layer = aLayer; } /** diff --git a/pcbnew/board_undo_redo.cpp b/pcbnew/board_undo_redo.cpp index a46d934619..2095585a44 100644 --- a/pcbnew/board_undo_redo.cpp +++ b/pcbnew/board_undo_redo.cpp @@ -104,12 +104,16 @@ static bool TestForExistingItem( BOARD* aPcb, BOARD_ITEM* aItem ) /**************************************************************/ -void SwapData( EDA_BaseStruct* aItem, EDA_BaseStruct* aImage ) +void SwapData( BOARD_ITEM* aItem, BOARD_ITEM* aImage ) /***************************************************************/ -/* Used if undo / redo command: - * swap data between Item and its copy, pointed by its .m_Image member - * swapped data is data modified by edition, so not all values are swapped +/** Function SwapData + * Used in undo / redo command: + * swap data between Item and a copy + * swapped data is data modified by edition, mainly sizes and texts + * so ONLY FEW values are swapped + * @param aItem = the item + * @param aImage = a copy of the item */ { if( aItem == NULL || aImage == NULL ) @@ -118,8 +122,64 @@ void SwapData( EDA_BaseStruct* aItem, EDA_BaseStruct* aImage ) return; } + int layer, layerimg; + layer = aItem->GetLayer(); + layerimg = aImage->GetLayer(); + aItem->SetLayer(layerimg); + aImage->SetLayer(layer); + switch( aItem->Type() ) { + case TYPE_MODULE: + wxMessageBox( wxT( "SwapData(): TYPE_MODULE not handled" ) ); + break; + + case TYPE_ZONE_CONTAINER: + wxMessageBox( wxT( "SwapData(): TYPE_ZONE_CONTAINER not handled" ) ); + break; + + case TYPE_DRAWSEGMENT: + EXCHG( ((TRACK*)aItem)->m_Start, ((TRACK*)aImage)->m_Start); + EXCHG( ((TRACK*)aItem)->m_End, ((TRACK*)aImage)->m_End); + EXCHG( ((TRACK*)aItem)->m_Width, ((TRACK*)aImage)->m_Width); + EXCHG( ((TRACK*)aItem)->m_Shape, ((TRACK*)aImage)->m_Shape); + break; + + case TYPE_TRACK: + case TYPE_VIA: + case TYPE_ZONE: + EXCHG( ((TRACK*)aItem)->m_Start, ((TRACK*)aImage)->m_Start); + EXCHG( ((TRACK*)aItem)->m_End, ((TRACK*)aImage)->m_End); + EXCHG( ((TRACK*)aItem)->m_Width, ((TRACK*)aImage)->m_Width); + EXCHG( ((TRACK*)aItem)->m_Shape, ((TRACK*)aImage)->m_Shape); + break; + + case TYPE_TEXTE: + EXCHG( ((TEXTE_PCB*)aItem)->m_Mirror, ((TEXTE_PCB*)aImage)->m_Mirror); + EXCHG( ((TEXTE_PCB*)aItem)->m_Size, ((TEXTE_PCB*)aImage)->m_Size); + EXCHG( ((TEXTE_PCB*)aItem)->m_Pos, ((TEXTE_PCB*)aImage)->m_Pos); + EXCHG( ((TEXTE_PCB*)aItem)->m_Width, ((TEXTE_PCB*)aImage)->m_Width); + EXCHG( ((TEXTE_PCB*)aItem)->m_Orient, ((TEXTE_PCB*)aImage)->m_Orient); + EXCHG( ((TEXTE_PCB*)aItem)->m_Text, ((TEXTE_PCB*)aImage)->m_Text); + EXCHG( ((TEXTE_PCB*)aItem)->m_Italic, ((TEXTE_PCB*)aImage)->m_Italic); + EXCHG( ((TEXTE_PCB*)aItem)->m_Bold, ((TEXTE_PCB*)aImage)->m_Bold); + EXCHG( ((TEXTE_PCB*)aItem)->m_HJustify, ((TEXTE_PCB*)aImage)->m_HJustify); + EXCHG( ((TEXTE_PCB*)aItem)->m_VJustify, ((TEXTE_PCB*)aImage)->m_VJustify); + break; + + case TYPE_MIRE: + EXCHG(((MIREPCB*)aItem)->m_Pos,((MIREPCB*)aImage)->m_Pos); + EXCHG(((MIREPCB*)aItem)->m_Width, ((MIREPCB*)aImage)->m_Width); + EXCHG(((MIREPCB*)aItem)->m_Size, ((MIREPCB*)aImage)->m_Size); + EXCHG(((MIREPCB*)aItem)->m_Shape, ((MIREPCB*)aImage)->m_Shape); + break; + + case TYPE_COTATION: + EXCHG(((COTATION*)aItem)->m_Text->m_Size, ((COTATION*)aImage)->m_Text->m_Size); + EXCHG(((COTATION*)aItem)->m_Text->m_Width, ((COTATION*)aImage)->m_Text->m_Width); + EXCHG(((COTATION*)aItem)->m_Text->m_Mirror, ((COTATION*)aImage)->m_Text->m_Mirror); + break; + default: wxMessageBox( wxT( "SwapData() error: unexpected type" ) ); break; @@ -223,7 +283,7 @@ BOARD_ITEM* DuplicateStruct( BOARD_ITEM* aItem ) /***********************************************************************/ -void WinEDA_PcbFrame::SaveCopyInUndoList( BOARD_ITEM* aItemToCopy, +void WinEDA_PcbFrame::SaveCopyInUndoList( BOARD_ITEM* aItem, UndoRedoOpType aCommandType, const wxPoint& aTransformPoint ) /***********************************************************************/ @@ -250,15 +310,14 @@ void WinEDA_PcbFrame::SaveCopyInUndoList( BOARD_ITEM* aItemToCopy, commandToUndo->m_TransformPoint = aTransformPoint; - ITEM_PICKER itemWrapper( aItemToCopy, aCommandType ); - itemWrapper.m_PickedItemType = aItemToCopy->Type(); + ITEM_PICKER itemWrapper( aItem, aCommandType ); + itemWrapper.m_PickedItemType = aItem->Type(); switch( aCommandType ) { case UR_CHANGED: /* Create a copy of schematic */ - CopyOfItem = NULL;//DuplicateStruct( aItemToCopy ); - itemWrapper.m_PickedItem = CopyOfItem; - itemWrapper.m_Link = aItemToCopy; + CopyOfItem = DuplicateStruct( aItem ); + itemWrapper.m_Link = CopyOfItem; if( CopyOfItem ) commandToUndo->PushItem( itemWrapper ); break; @@ -324,8 +383,8 @@ void WinEDA_PcbFrame::SaveCopyInUndoList( PICKED_ITEMS_LIST& aItemsList, { case UR_CHANGED: /* Create a copy of schematic */ CopyOfItem = DuplicateStruct( item ); - itemWrapper.m_PickedItem = CopyOfItem; - itemWrapper.m_Link = item; + itemWrapper.m_PickedItem = item; + itemWrapper.m_Link = CopyOfItem; if( CopyOfItem ) commandToUndo->PushItem( itemWrapper ); break; @@ -371,6 +430,7 @@ void WinEDA_PcbFrame::PutDataInPreviousState( PICKED_ITEMS_LIST* aList, bool aRe { BOARD_ITEM* item; bool not_found = false; + bool reBuild_ratsnest = false; for( unsigned ii = 0; ii < aList->GetCount(); ii++ ) { @@ -388,25 +448,58 @@ void WinEDA_PcbFrame::PutDataInPreviousState( PICKED_ITEMS_LIST* aList, bool aRe continue; } } + item->m_Flags = 0; + // see if one must rebuild ratsnets and pointers lists + switch( item->Type() ) + { + case TYPE_MODULE: + case TYPE_ZONE_CONTAINER: + case TYPE_TRACK: + case TYPE_VIA: + 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); - SwapData( item, image ); + // Note modules and zones containers have a lot of data + // so items and thier copy are swapped, not just edited data + // The main drawback is pointers on these items must be rebuilt + // but often, this is needed by connectivity change, + // so this is not really an important drawback in this function + // Could change later + switch( item->Type() ) + { + case TYPE_MODULE: + case TYPE_ZONE_CONTAINER: + // Swap the item and its copy + GetBoard()->Remove(item); + GetBoard()->Add(image); + aList->SetPickedItem(image, ii); + aList->SetPickedItemLink(item, ii); + break; + + default: + // For other items: swap editable data only + SwapData( item, image ); + break; + } } break; case UR_NEW: /* new items are deleted */ aList->SetPickedItemStatus( UR_DELETED, ii ); GetBoard()->Remove( item ); - item->m_Flags = UR_DELETED; break; case UR_DELETED: /* deleted items are put in List, as new items */ aList->SetPickedItemStatus( UR_NEW, ii ); GetBoard()->Add( item ); - item->m_Flags = 0; break; case UR_MOVED: @@ -436,7 +529,9 @@ void WinEDA_PcbFrame::PutDataInPreviousState( PICKED_ITEMS_LIST* aList, bool aRe if( not_found ) wxMessageBox( wxT( "Incomplete undo/redo command: item not found" ) ); - Compile_Ratsnest( NULL, true ); + // Rebuild pointers and rastnest + if( reBuild_ratsnest ) + Compile_Ratsnest( NULL, true ); } @@ -527,8 +622,7 @@ void PCB_SCREEN::ClearUndoORRedoList( UNDO_REDO_CONTAINER& aList, int aItemCount while( 1 ) { ITEM_PICKER wrapper = curr_cmd->PopItem(); - EDA_BaseStruct* item = wrapper.m_PickedItem; - if( item == NULL ) // No more item in list. + if( wrapper.m_PickedItem == NULL ) // No more item in list. break; switch( wrapper.m_UndoRedoStatus ) { @@ -545,8 +639,12 @@ void PCB_SCREEN::ClearUndoORRedoList( UNDO_REDO_CONTAINER& aList, int aItemCount case UR_NEW: // Do nothing, items are in use, the picker is not owner of items break; - default: - delete item; // the picker is owner of this item + case UR_CHANGED: + delete wrapper.m_Link; // the picker is owner of this item + break; + + default: + delete wrapper.m_PickedItem; // the picker is owner of this item break; } } diff --git a/pcbnew/class_cotation.cpp b/pcbnew/class_cotation.cpp index b9f70e186f..eacf8317aa 100644 --- a/pcbnew/class_cotation.cpp +++ b/pcbnew/class_cotation.cpp @@ -39,7 +39,7 @@ void COTATION:: SetText( const wxString& NewText ) /**********************************/ -wxString COTATION:: GetText( void ) +wxString COTATION::GetText( void ) /**********************************/ /* Reutun the dimension text */ @@ -47,6 +47,16 @@ wxString COTATION:: GetText( void ) return m_Text->m_Text; } +/** + * Function SetLayer + * sets the layer this item is on. + * @param aLayer The layer number. + */ +void COTATION::SetLayer( int aLayer ) +{ + m_Layer = aLayer; + m_Text->SetLayer( aLayer); +} /*************************************/ void COTATION::Copy( COTATION* source ) diff --git a/pcbnew/class_cotation.h b/pcbnew/class_cotation.h index 010a5543ed..74a6673d87 100644 --- a/pcbnew/class_cotation.h +++ b/pcbnew/class_cotation.h @@ -37,6 +37,13 @@ public: } + /** + * Function SetLayer + * sets the layer this item is on. + * @param aLayer The layer number. + */ + void SetLayer( int aLayer ); + bool ReadCotationDescr( FILE* File, int* LineNum ); /** diff --git a/pcbnew/clean.cpp b/pcbnew/clean.cpp index ca7dfdcc73..4d2e7843ae 100644 --- a/pcbnew/clean.cpp +++ b/pcbnew/clean.cpp @@ -76,6 +76,9 @@ void Clean_Pcb_Items( WinEDA_PcbFrame* frame, wxDC* DC ) frame->MsgPanel->EraseMsgBox(); frame->GetBoard()->GetNumSegmTrack(); // update the count + // Clear undo and redo lists to avoid inconsistencies between lists + frame->GetScreen()->ClearUndoRedoList(); + /* Rebuild the pad infos (pad list and netcodes) to ensure an up to date info */ frame->GetBoard()->m_Status_Pcb = 0; frame->GetBoard()->m_NetInfo->BuildListOfNets(); diff --git a/pcbnew/cotation.cpp b/pcbnew/cotation.cpp index 177012dab4..1d78a0ea6a 100644 --- a/pcbnew/cotation.cpp +++ b/pcbnew/cotation.cpp @@ -161,6 +161,7 @@ void WinEDA_CotationPropertiesFrame::OnOkClick( wxCommandEvent& event ) CurrentCotation->Draw( m_Parent->DrawPanel, m_DC, GR_XOR ); } + m_Parent->SaveCopyInUndoList(CurrentCotation, UR_CHANGED); if( m_Name->GetValue() != wxEmptyString ) { CurrentCotation->SetText( m_Name->GetValue() ); @@ -172,7 +173,6 @@ void WinEDA_CotationPropertiesFrame::OnOkClick( wxCommandEvent& event ) CurrentCotation->m_Text->m_Mirror = (m_Mirror->GetSelection() == 1) ? true : false; CurrentCotation->SetLayer( m_SelLayerBox->GetChoice() + FIRST_NO_COPPER_LAYER ); - CurrentCotation->m_Text->SetLayer( m_SelLayerBox->GetChoice() + FIRST_NO_COPPER_LAYER ); if( m_DC ) // Affichage nouveau texte { diff --git a/pcbnew/dialog_pcb_text_properties.cpp b/pcbnew/dialog_pcb_text_properties.cpp index bb7aa1def0..ce5146d73d 100644 --- a/pcbnew/dialog_pcb_text_properties.cpp +++ b/pcbnew/dialog_pcb_text_properties.cpp @@ -197,6 +197,18 @@ void WinEDA_TextPCBPropertiesFrame::OnCancelClick( wxCommandEvent& WXUNUSED( eve void WinEDA_TextPCBPropertiesFrame::OnOkClick( wxCommandEvent& event ) { + // If no other command in progress, prepare undo command + // (for a command in progress, will be made later, at the completion of command) + if( CurrentTextPCB->m_Flags == 0 ) + m_Parent->SaveCopyInUndoList( CurrentTextPCB, UR_CHANGED ); + + /* set flag in edit to force undo/redo/abort proper operation, + * and avoid new calls to SaveCopyInUndoList for the same text + * this can occurs when a text is moved, and then rotated, edited .. + */ + if( CurrentTextPCB->m_Flags != 0 ) + CurrentTextPCB->m_Flags |= IN_EDIT; + // test for acceptable values for parameters: wxSize newsize = m_TxtSizeCtrl->GetValue(); diff --git a/pcbnew/edit_pcb_text.cpp b/pcbnew/edit_pcb_text.cpp index 12dc133520..17cdff2ff0 100644 --- a/pcbnew/edit_pcb_text.cpp +++ b/pcbnew/edit_pcb_text.cpp @@ -10,13 +10,16 @@ #include "pcbnew.h" #include "wxPcbStruct.h" +#include "protos.h" + /* Local functions */ static void Move_Texte_Pcb( WinEDA_DrawPanel* panel, wxDC* DC, bool erase ); static void Abort_Edit_Pcb_Text( WinEDA_DrawPanel* Panel, wxDC* DC ); -/* Local variables : */ -static wxPoint old_pos; // initial position of the text when moving it - +/* variables : */ +static TEXTE_PCB s_TextCopy( (BOARD_ITEM*) NULL ); /* copy of the edited text + * (used to undo/redo/abort a complex edition command + */ /*************************************************************/ void Abort_Edit_Pcb_Text( WinEDA_DrawPanel* Panel, wxDC* DC ) @@ -27,21 +30,27 @@ void Abort_Edit_Pcb_Text( WinEDA_DrawPanel* Panel, wxDC* DC ) * Si un texte est selectionne, ses coord initiales sont regenerees */ { - TEXTE_PCB* TextePcb; - - TextePcb = (TEXTE_PCB*) Panel->GetScreen()->GetCurItem(); - - if( TextePcb ) - { - TextePcb->Draw( Panel, DC, GR_XOR ); - TextePcb->m_Pos = old_pos; - TextePcb->Draw( Panel, DC, GR_OR ); - TextePcb->m_Flags = 0; - } - Panel->ManageCurseur = NULL; Panel->ForceCloseManageCurseur = NULL; - ((WinEDA_PcbFrame*)Panel->m_Parent)->SetCurItem( NULL ); + ( (WinEDA_PcbFrame*) Panel->m_Parent )->SetCurItem( NULL ); + + TEXTE_PCB* TextePcb = (TEXTE_PCB*) Panel->GetScreen()->GetCurItem(); + + if( TextePcb == NULL ) // Should not occur + return; + + TextePcb->Draw( Panel, DC, GR_XOR ); + + if( (TextePcb->m_Flags & IS_NEW) ) // If new: remove it + { + TextePcb->DeleteStructure(); + return; + } + + + SwapData(TextePcb, &s_TextCopy); + TextePcb->Draw( Panel, DC, GR_OR ); + TextePcb->m_Flags = 0; } @@ -53,14 +62,35 @@ void WinEDA_PcbFrame::Place_Texte_Pcb( TEXTE_PCB* TextePcb, wxDC* DC ) * Place the current text being moving */ { + DrawPanel->ManageCurseur = NULL; + DrawPanel->ForceCloseManageCurseur = NULL; + SetCurItem( NULL ); + if( TextePcb == NULL ) return; TextePcb->Draw( DrawPanel, DC, GR_OR ); - DrawPanel->ManageCurseur = NULL; - DrawPanel->ForceCloseManageCurseur = NULL; - SetCurItem( NULL ); GetScreen()->SetModify(); + + if( (TextePcb->m_Flags & IS_NEW) ) // If new: prepare undo command + { + SaveCopyInUndoList( TextePcb, UR_NEW ); + TextePcb->m_Flags = 0; + return; + } + + if( TextePcb->m_Flags == IS_MOVED ) // If moved only + SaveCopyInUndoList( TextePcb, UR_MOVED, TextePcb->m_Pos - s_TextCopy.m_Pos ); + else + { + // Restore initial params + SwapData( TextePcb, &s_TextCopy); + // Prepare undo command + SaveCopyInUndoList( TextePcb, UR_CHANGED ); + SwapData( TextePcb, &s_TextCopy); + // Restore current params + } + TextePcb->m_Flags = 0; } @@ -74,7 +104,11 @@ void WinEDA_PcbFrame::StartMoveTextePcb( TEXTE_PCB* TextePcb, wxDC* DC ) { if( TextePcb == NULL ) return; - old_pos = TextePcb->m_Pos; + + // if it is an existing item: prepare a copy to undo/abort command + if( (TextePcb->m_Flags & IS_NEW) == 0 ) + s_TextCopy.Copy( TextePcb ); + TextePcb->Draw( DrawPanel, DC, GR_XOR ); TextePcb->m_Flags |= IS_MOVED; TextePcb->DisplayInfo( this ); @@ -116,8 +150,8 @@ void WinEDA_PcbFrame::Delete_Texte_Pcb( TEXTE_PCB* TextePcb, wxDC* DC ) TextePcb->Draw( DrawPanel, DC, GR_XOR ); - SaveCopyInUndoList(TextePcb, UR_DELETED); - TextePcb ->UnLink(); + SaveCopyInUndoList( TextePcb, UR_DELETED ); + TextePcb->UnLink(); DrawPanel->ManageCurseur = NULL; DrawPanel->ForceCloseManageCurseur = NULL; SetCurItem( NULL ); @@ -136,8 +170,8 @@ TEXTE_PCB* WinEDA_PcbFrame::Create_Texte_Pcb( wxDC* DC ) GetBoard()->Add( TextePcb ); /* Mise a jour des caracteristiques */ - TextePcb->m_Flags = IS_NEW; - TextePcb->SetLayer( ((PCB_SCREEN*)GetScreen())->m_Active_Layer ); + TextePcb->m_Flags = IS_NEW; + TextePcb->SetLayer( ( (PCB_SCREEN*) GetScreen() )->m_Active_Layer ); TextePcb->m_Mirror = false; if( TextePcb->GetLayer() == COPPER_LAYER_N ) TextePcb->m_Mirror = true; @@ -149,7 +183,7 @@ TEXTE_PCB* WinEDA_PcbFrame::Create_Texte_Pcb( wxDC* DC ) InstallTextPCBOptionsFrame( TextePcb, DC ); if( TextePcb->m_Text.IsEmpty() ) { - TextePcb ->DeleteStructure(); + TextePcb->DeleteStructure(); TextePcb = NULL; } else @@ -172,16 +206,16 @@ void WinEDA_PcbFrame::Rotate_Texte_Pcb( TEXTE_PCB* TextePcb, wxDC* DC ) /* effacement du texte : */ TextePcb->Draw( DrawPanel, DC, GR_XOR ); - TextePcb->m_Orient += angle; - if( TextePcb->m_Orient >= 3600 ) - TextePcb->m_Orient -= 3600; - if( TextePcb->m_Orient < 0 ) - TextePcb->m_Orient += 3600; + NORMALIZE_ANGLE( TextePcb->m_Orient ); /* Redessin du Texte */ TextePcb->Draw( DrawPanel, DC, drawmode ); TextePcb->DisplayInfo( this ); + if( TextePcb->m_Flags == 0 ) // i.e. not edited, or moved + SaveCopyInUndoList( TextePcb, UR_ROTATED, TextePcb->m_Pos ); + else // set flag edit, to show it was a complex command + TextePcb->m_Flags |= IN_EDIT; GetScreen()->SetModify(); } diff --git a/pcbnew/mirepcb.cpp b/pcbnew/mirepcb.cpp index e7ead52506..7fa377e16b 100644 --- a/pcbnew/mirepcb.cpp +++ b/pcbnew/mirepcb.cpp @@ -1,5 +1,5 @@ /*********************************************/ -/* Routines de gestion des mires de centrage */ +/* Functions to edite targets (class MIRE) */ /*********************************************/ #include "fctsys.h" @@ -9,14 +9,18 @@ #include "pcbnew.h" #include "wxPcbStruct.h" +#include "protos.h" + /* Routines Locales */ -static void Exit_EditMire( WinEDA_DrawPanel* Panel, wxDC* DC ); -static void Montre_Position_Mire( WinEDA_DrawPanel* panel, wxDC* DC, bool erase ); +static void AbortMoveAndEditTarget( WinEDA_DrawPanel* Panel, wxDC* DC ); +static void ShowTargetShapeWhileMovingMouse( WinEDA_DrawPanel* panel, wxDC* DC, bool erase ); -/* Variables locales : */ -static wxPoint OldPos; +/* Local variables : */ static int MireDefaultSize = 5000; +static MIREPCB s_TargetCopy( NULL ); /* Used to store "old" values of the current item + * parameters before edition (used in undo/redo or cancel operations) + */ enum id_mire_properties { ID_SIZE_MIRE = 1900, // (Not currently used anywhere else) @@ -46,8 +50,8 @@ public: ~WinEDA_MirePropertiesFrame() { } private: - void OnOkClick( wxCommandEvent& event ); - void OnCancelClick( wxCommandEvent& event ); + void OnOkClick( wxCommandEvent& event ); + void OnCancelClick( wxCommandEvent& event ); DECLARE_EVENT_TABLE() }; @@ -81,7 +85,7 @@ WinEDA_MirePropertiesFrame::WinEDA_MirePropertiesFrame( WinEDA_PcbFrame* parent, wxButton* Button; m_Parent = parent; - m_DC = DC; + m_DC = DC; Centre(); m_MirePcb = Mire; @@ -141,11 +145,18 @@ void WinEDA_MirePropertiesFrame::OnOkClick( wxCommandEvent& event ) { m_MirePcb->Draw( m_Parent->DrawPanel, m_DC, GR_XOR ); + // Save old item in undo list, if is is not curently edited (will be later if so) + if( m_MirePcb->m_Flags == 0 ) + m_Parent->SaveCopyInUndoList( m_MirePcb, UR_CHANGED ); + + if( m_MirePcb->m_Flags != 0) // other edition in progress (MOVE, NEW ..) + m_MirePcb->m_Flags |= IN_EDIT; // set flag in edit to force undo/redo/abort proper operation + m_MirePcb->m_Width = m_MireWidthCtrl->GetValue(); MireDefaultSize = m_MirePcb->m_Size = m_MireSizeCtrl->GetValue(); m_MirePcb->m_Shape = m_MireShape->GetSelection() ? 1 : 0; - m_MirePcb->Draw( m_Parent->DrawPanel, m_DC, GR_OR ); + m_MirePcb->Draw( m_Parent->DrawPanel, m_DC, (m_MirePcb->m_Flags & IS_MOVED) ? GR_XOR : GR_OR ); m_Parent->GetScreen()->SetModify(); EndModal( 1 ); @@ -160,13 +171,13 @@ void WinEDA_PcbFrame::Delete_Mire( MIREPCB* MirePcb, wxDC* DC ) return; MirePcb->Draw( DrawPanel, DC, GR_XOR ); - SaveCopyInUndoList(MirePcb, UR_DELETED); + SaveCopyInUndoList( MirePcb, UR_DELETED ); MirePcb->UnLink(); } /**********************************************************/ -static void Exit_EditMire( WinEDA_DrawPanel* Panel, wxDC* DC ) +static void AbortMoveAndEditTarget( WinEDA_DrawPanel* Panel, wxDC* DC ) /**********************************************************/ { BASE_SCREEN* screen = Panel->GetScreen(); @@ -174,24 +185,30 @@ static void Exit_EditMire( WinEDA_DrawPanel* Panel, wxDC* DC ) Panel->ManageCurseur = NULL; Panel->ForceCloseManageCurseur = NULL; + ((WinEDA_PcbFrame*)Panel->m_Parent)->SetCurItem( NULL ); - if( MirePcb ) + if( MirePcb == NULL ) + return; + + MirePcb->Draw( Panel, DC, GR_XOR ); + + if( MirePcb->m_Flags & IS_NEW ) // If it is new, delete it { - /* Effacement de la mire */ MirePcb->Draw( Panel, DC, GR_XOR ); - - if( MirePcb->m_Flags & IS_NEW ) + MirePcb->DeleteStructure(); + MirePcb = NULL; + } + else /* it is an existing item: retrieve initial values of parameters */ + { + if( (MirePcb->m_Flags & IN_EDIT) ) { - MirePcb->Draw( Panel, DC, GR_XOR ); - MirePcb ->DeleteStructure(); - MirePcb = NULL; - } - else /* Ancienne mire en deplacement: Remise en ancienne position */ - { - MirePcb->m_Pos = OldPos; - MirePcb->m_Flags = 0; - MirePcb->Draw( Panel, DC, GR_OR ); + MirePcb->m_Pos = s_TargetCopy.m_Pos; + MirePcb->m_Width = s_TargetCopy.m_Width; + MirePcb->m_Size = s_TargetCopy.m_Size; + MirePcb->m_Shape = s_TargetCopy.m_Shape; } + MirePcb->m_Flags = 0; + MirePcb->Draw( Panel, DC, GR_OR ); } } @@ -205,12 +222,13 @@ MIREPCB* WinEDA_PcbFrame::Create_Mire( wxDC* DC ) { MIREPCB* MirePcb = new MIREPCB( GetBoard() ); + MirePcb->m_Flags = IS_NEW; + GetBoard()->Add( MirePcb ); MirePcb->SetLayer( EDGE_N ); MirePcb->m_Width = g_DesignSettings.m_EdgeSegmentWidth; MirePcb->m_Size = MireDefaultSize; - MirePcb->m_Pos = GetScreen()->m_Curseur; Place_Mire( MirePcb, DC ); @@ -228,10 +246,10 @@ void WinEDA_PcbFrame::StartMove_Mire( MIREPCB* MirePcb, wxDC* DC ) if( MirePcb == NULL ) return; - OldPos = MirePcb->m_Pos; + s_TargetCopy = *MirePcb; MirePcb->m_Flags |= IS_MOVED; - DrawPanel->ManageCurseur = Montre_Position_Mire; - DrawPanel->ForceCloseManageCurseur = Exit_EditMire; + DrawPanel->ManageCurseur = ShowTargetShapeWhileMovingMouse; + DrawPanel->ForceCloseManageCurseur = AbortMoveAndEditTarget; SetCurItem( MirePcb ); } @@ -244,17 +262,38 @@ void WinEDA_PcbFrame::Place_Mire( MIREPCB* MirePcb, wxDC* DC ) return; MirePcb->Draw( DrawPanel, DC, GR_OR ); - - MirePcb->m_Flags = 0; DrawPanel->ManageCurseur = NULL; DrawPanel->ForceCloseManageCurseur = NULL; SetCurItem( NULL ); GetScreen()->SetModify(); + + if( (MirePcb->m_Flags & IS_NEW) ) + { + SaveCopyInUndoList( MirePcb, UR_NEW ); + MirePcb->m_Flags = 0; + return; + } + + + if( MirePcb->m_Flags == IS_MOVED ) + { + SaveCopyInUndoList( MirePcb, UR_MOVED, MirePcb->m_Pos - s_TargetCopy.m_Pos ); + MirePcb->m_Flags = 0; + return; + } + + if( (MirePcb->m_Flags & IN_EDIT) ) + { + SwapData( MirePcb, &s_TargetCopy ); + SaveCopyInUndoList( MirePcb, UR_CHANGED ); + SwapData( MirePcb, &s_TargetCopy ); + } + MirePcb->m_Flags = 0; } /******************************************************************************/ -static void Montre_Position_Mire( WinEDA_DrawPanel* panel, wxDC* DC, bool erase ) +static void ShowTargetShapeWhileMovingMouse( WinEDA_DrawPanel* panel, wxDC* DC, bool erase ) /*********************************************************************************/ /* redessin du contour de la piste lors des deplacements de la souris */ { diff --git a/pcbnew/netlist.cpp b/pcbnew/netlist.cpp index 6df607fdc3..ad37ec701d 100644 --- a/pcbnew/netlist.cpp +++ b/pcbnew/netlist.cpp @@ -173,8 +173,12 @@ void ReadPcbNetlist( WinEDA_PcbFrame* aFrame, aMessageWindow->AppendText( msg + wxT( "\n" ) ); } + // Clear undo and redo lists to avoid inconsistencies between lists + aFrame->GetScreen()->ClearUndoRedoList(); + aFrame->GetScreen()->SetModify(); - aFrame->GetBoard()->m_Status_Pcb = 0; State = 0; LineNum = 0; Comment = 0; + aFrame->GetBoard()->m_Status_Pcb = 0; + State = 0; LineNum = 0; Comment = 0; s_NbNewModules = 0; wxBusyCursor dummy; // Shows an hourglass while calculating diff --git a/pcbnew/protos.h b/pcbnew/protos.h index e2ca2771e7..242a7dee9e 100644 --- a/pcbnew/protos.h +++ b/pcbnew/protos.h @@ -11,6 +11,15 @@ class COMMAND; +/** Function SwapData + * Used in undo / redo command: + * swap data between Item and a copy + * swapped data is data modified by edition, so NOT ALL values are swapped + * @param aItem = the item + * @param aImage = a copy of the item + */ +void SwapData( BOARD_ITEM* aItem, BOARD_ITEM* aImage ); + /* install function for DialogNonCopperZonesEditor dialog frame :*/ bool InstallDialogNonCopperZonesEditor(WinEDA_PcbFrame* aParent, ZONE_CONTAINER* aZone);