Action plugins: handle undo/redo feature when running an action plugin.

This commit is contained in:
Jean-Samuel Reynaud 2017-02-06 08:39:32 +01:00 committed by jean-pierre charras
parent 431abcff0c
commit 13395d34dd
2 changed files with 344 additions and 9 deletions

View File

@ -0,0 +1,157 @@
from pcbnew import *
import random
import pprint
class testundoredo0(ActionPlugin):
def defaults(self):
self.name = "Test Undo/Redo: Remove footprints"
self.category = "Test Undo/Redo"
self.description = ""
def Run(self):
pcb = GetBoard()
for module in pcb.GetModules():
pcb.RemoveNative(module)
class testundoredo1(ActionPlugin):
def defaults(self):
self.name = "Test Undo/Redo: Remove all board items"
self.category = "Test Undo/Redo"
self.description = ""
def Run(self):
pcb = GetBoard()
while pcb.GetAreaCount() > 0:
area = pcb.GetArea(0)
pcb.RemoveNative(area)
for module in pcb.GetModules():
pcb.RemoveNative(module)
for track in pcb.GetTracks():
pcb.RemoveNative(track)
for draw in pcb.m_Drawings:
pcb.RemoveNative(draw)
class testundoredo2(ActionPlugin):
def defaults(self):
self.name = "Test Undo/Redo: Generate random content"
self.category = "Test Undo/Redo"
self.description = ""
def createFPCXModule(self,pads):
size_025_160mm = wxSizeMM(0.25,1.6)
size_150_200mm = wxSizeMM(1.50,2.0)
# create a new module, it's parent is our previously created pcb
module = MODULE(self.pcb)
module.SetReference("FPC"+str(pads)) # give it a reference name
module.Reference().SetPosition(wxPointMM(-1,-1))
self.pcb.Add(module) # add it to our pcb
m_pos = wxPointMM(0,0)#random.randint(10,200),random.randint(10,200))
module.SetPosition(m_pos)
# create a pad array and add it to the module
def smdRectPad(module,size,pos,name):
pad = D_PAD(module)
pad.SetSize(size)
pad.SetShape(PAD_SHAPE_RECT)
pad.SetAttribute(PAD_ATTRIB_SMD)
pad.SetLayerSet(pad.SMDMask())
pad.SetPosition(pos)
pad.SetPadName(name)
return pad
for n in range (0,pads):
pad = smdRectPad(module,size_025_160mm,wxPointMM(0.5*n,0),str(n+1))
module.Add(pad)
pad_s0 = smdRectPad(module,size_150_200mm,wxPointMM(-1.6,1.3),"0")
pad_s1 = smdRectPad(module,size_150_200mm,wxPointMM((pads-1)*0.5+1.6,1.3),"0")
module.Add(pad_s0)
module.Add(pad_s1)
e = EDGE_MODULE(module)
e.SetStart0(wxPointMM(-1,0))
e.SetEnd0(wxPointMM(0,0))
e.SetWidth(FromMM(0.2))
e.SetLayer(F_SilkS)
e.SetShape(S_SEGMENT)
module.Add(e)
module.SetPosition(wxPointMM(random.randint(20,200),random.randint(20,150)))
return module
def Run(self):
self.pcb = GetBoard()
random.seed()
for i in range(10):
seg = DRAWSEGMENT()
seg.SetLayer( random.choice([Edge_Cuts,Cmts_User,Eco1_User,Eco2_User]) )
seg.SetStart( wxPointMM( random.randint(10,100),
random.randint(10,100) ) )
seg.SetEnd( wxPointMM( random.randint(10,100),
random.randint(10,100) ) )
self.pcb.Add( seg )
if i%2 == 0:
t = TRACK(None)
else:
t = VIA(None)
#t.SetLayerPair(segments['layerPair'][0],segments['layerPair'][1])
t.SetViaType(VIA_THROUGH)
t.SetDrill(FromMM(random.randint(1,20)/10.0))
t.SetStart(wxPointMM(random.randint(100,150),random.randint(100,150)))
t.SetEnd(wxPointMM(random.randint(100,150),random.randint(100,150)))
t.SetWidth(FromMM(random.randint(1,15)/10.0))
t.SetLayer(random.choice([F_Cu,B_Cu]))
self.pcb.Add(t)
self.createFPCXModule(random.randint(2,40))
class testundoredo3(ActionPlugin):
def defaults(self):
self.name = "Test Undo/Redo: Move elements randomly"
self.category = "Test Undo/Redo"
self.description = ""
def Run(self):
pcb = GetBoard()
for i in range(0,pcb.GetAreaCount()):
area = pcb.GetArea(i)
area.Move(wxPointMM(random.randint(-20,20),random.randint(-20,20)))
for module in pcb.GetModules():
module.Move(wxPointMM(random.randint(-20,20),random.randint(-20,20)))
if random.randint(0,10) > 5:
module.Flip(module.GetPosition())
for track in pcb.GetTracks():
track.Move(wxPointMM(random.randint(-20,20),random.randint(-20,20)))
for draw in pcb.m_Drawings:
draw.Move(wxPointMM(random.randint(-20,20),random.randint(-20,20)))
testundoredo0().register()
testundoredo1().register()
testundoredo2().register()
testundoredo3().register()

View File

@ -36,6 +36,8 @@
#include <class_board.h>
#include <class_module.h>
#include <class_track.h>
#include <class_drawsegment.h>
#include <class_zone.h>
#include <board_commit.h>
#include <kicad_device_context.h>
@ -176,14 +178,190 @@ void PCB_EDIT_FRAME::OnActionPlugin( wxCommandEvent& aEvent )
if( actionPlugin )
{
// TODO: Adding recovery point for jobs
// BOARD_COMMIT commit( this );
// commit.Push( _( "External plugin" ) );
PICKED_ITEMS_LIST itemsList;
BOARD* currentPcb = GetBoard();
bool fromEmpty = false;
actionPlugin->Run();
itemsList.m_Status = UR_CHANGED;
OnModify();
// Append tracks:
for( BOARD_ITEM* item = currentPcb->m_Track; item != NULL; item = item->Next() )
{
ITEM_PICKER picker( item, UR_CHANGED );
itemsList.PushItem( picker );
}
// Append modules:
for( BOARD_ITEM* item = currentPcb->m_Modules; item != NULL; item = item->Next() )
{
ITEM_PICKER picker( item, UR_CHANGED );
itemsList.PushItem( picker );
}
// Append drawings
for( BOARD_ITEM* item = currentPcb->m_Drawings; item != NULL; item = item->Next() )
{
ITEM_PICKER picker( item, UR_CHANGED );
itemsList.PushItem( picker );
}
// Append zones outlines
for( int ii = 0; ii < currentPcb->GetAreaCount(); ii++ )
{
ITEM_PICKER picker( (EDA_ITEM*) currentPcb->GetArea(
ii ), UR_CHANGED );
itemsList.PushItem( picker );
}
// Append zones segm:
for( BOARD_ITEM* item = currentPcb->m_Zone; item != NULL; item = item->Next() )
{
ITEM_PICKER picker( item, UR_CHANGED );
itemsList.PushItem( picker );
}
if( itemsList.GetCount() > 0 )
SaveCopyInUndoList( itemsList, UR_CHANGED, wxPoint( 0.0, 0.0 ) );
else
fromEmpty = true;
itemsList.ClearItemsList();
// Execute plugin himself...
actionPlugin->Run();
currentPcb->m_Status_Pcb = 0;
// Get back the undo buffer to fix some modifications
PICKED_ITEMS_LIST* oldBuffer = NULL;
if( fromEmpty )
{
oldBuffer = new PICKED_ITEMS_LIST();
oldBuffer->m_Status = UR_NEW;
}
else
{
oldBuffer = GetScreen()->PopCommandFromUndoList();
wxASSERT( oldBuffer );
}
// Try do discover what was modified
PICKED_ITEMS_LIST deletedItemsList;
// Found deleted modules
for( unsigned int i = 0; i < oldBuffer->GetCount(); i++ )
{
BOARD_ITEM* item = (BOARD_ITEM*) oldBuffer->GetPickedItem( i );
ITEM_PICKER picker( item, UR_DELETED );
wxASSERT( item );
switch( item->Type() )
{
case PCB_NETINFO_T:
case PCB_MARKER_T:
case PCB_MODULE_T:
case PCB_TRACE_T:
case PCB_VIA_T:
case PCB_LINE_T:
case PCB_TEXT_T:
case PCB_DIMENSION_T:
case PCB_TARGET_T:
case PCB_ZONE_T:
// If item has a list it's mean that the element is on the board
if( item->GetList() == NULL )
{
deletedItemsList.PushItem( picker );
}
break;
case PCB_ZONE_AREA_T:
{
bool zoneFound = false;
for( int ii = 0; ii < currentPcb->GetAreaCount(); ii++ )
zoneFound |= currentPcb->GetArea( ii ) == item;
if( !zoneFound )
{
deletedItemsList.PushItem( picker );
}
break;
}
default:
wxString msg;
msg.Printf( wxT( "(PCB_EDIT_FRAME::OnActionPlugin) needs work: "
"BOARD_ITEM type (%d) not handled" ),
item->Type() );
wxFAIL_MSG( msg );
break;
}
}
// Mark deleted elements in undolist
for( unsigned int i = 0; i < deletedItemsList.GetCount(); i++ )
{
oldBuffer->PushItem( deletedItemsList.GetItemWrapper( i ) );
}
// Find new modules
for( BOARD_ITEM* item = currentPcb->m_Modules; item != NULL; item = item->Next() )
{
if( !oldBuffer->ContainsItem( item ) )
{
ITEM_PICKER picker( item, UR_NEW );
oldBuffer->PushItem( picker );
}
}
for( BOARD_ITEM* item = currentPcb->m_Track; item != NULL; item = item->Next() )
{
if( !oldBuffer->ContainsItem( item ) )
{
ITEM_PICKER picker( item, UR_NEW );
oldBuffer->PushItem( picker );
}
}
for( BOARD_ITEM* item = currentPcb->m_Drawings; item != NULL; item = item->Next() )
{
if( !oldBuffer->ContainsItem( item ) )
{
ITEM_PICKER picker( item, UR_NEW );
oldBuffer->PushItem( picker );
}
}
for( BOARD_ITEM* item = currentPcb->m_Zone; item != NULL; item = item->Next() )
{
if( !oldBuffer->ContainsItem( item ) )
{
ITEM_PICKER picker( item, UR_NEW );
oldBuffer->PushItem( picker );
}
}
for( int ii = 0; ii < currentPcb->GetAreaCount(); ii++ )
{
if( !oldBuffer->ContainsItem( (EDA_ITEM*) currentPcb->GetArea( ii ) ) )
{
ITEM_PICKER picker( (EDA_ITEM*) currentPcb->GetArea(
ii ), UR_NEW );
oldBuffer->PushItem( picker );
}
}
GetScreen()->PushCommandToUndoList( oldBuffer );
if( IsGalCanvasActive() )
{
UseGalCanvas( GetGalCanvas() );
@ -201,7 +379,7 @@ void PCB_EDIT_FRAME::RebuildActionPluginMenus()
{
wxMenu* actionMenu = GetMenuBar()->FindItem( ID_TOOLBARH_PCB_ACTION_PLUGIN )->GetSubMenu();
if( !actionMenu ) // Should not occur.
if( !actionMenu ) // Should not occur.
return;
// First, remove existing submenus, if they are too many
@ -235,7 +413,7 @@ void PCB_EDIT_FRAME::RebuildActionPluginMenus()
{
wxMenuItem* item;
if( ii < (int)available_menus.size() )
if( ii < (int) available_menus.size() )
{
item = available_menus[ii];
item->SetItemLabel( ACTION_PLUGINS::GetAction( ii )->GetName() );
@ -248,9 +426,9 @@ void PCB_EDIT_FRAME::RebuildActionPluginMenus()
ACTION_PLUGINS::GetAction( ii )->GetDescription(),
KiBitmap( hammer_xpm ) );
Connect( item->GetId(), wxEVT_COMMAND_MENU_SELECTED,
(wxObjectEventFunction) (wxEventFunction) (wxCommandEventFunction) &
PCB_EDIT_FRAME::OnActionPlugin );
Connect( item->GetId(), wxEVT_COMMAND_MENU_SELECTED,
(wxObjectEventFunction) (wxEventFunction) (wxCommandEventFunction) &
PCB_EDIT_FRAME::OnActionPlugin );
}
ACTION_PLUGINS::SetActionMenu( ii, item->GetId() );