Implement repeatDrawItem in modern toolkit and fix bugs.

Fixes moving of SCH_FIELDS.
Fixes undo operations around SCH_FIELDS and SCH_PINS.
This commit is contained in:
Jeff Young 2019-04-26 23:23:12 +01:00
parent 4e0208dfba
commit eacc3e67a5
12 changed files with 248 additions and 294 deletions

View File

@ -309,8 +309,7 @@ bool SCH_EDIT_FRAME::BreakSegment( SCH_LINE* aSegment, const wxPoint& aPoint,
} }
bool SCH_EDIT_FRAME::BreakSegments( const wxPoint& aPoint, bool aAppend, bool SCH_EDIT_FRAME::BreakSegments( const wxPoint& aPoint, bool aAppend, SCH_SCREEN* aScreen )
SCH_SCREEN* aScreen )
{ {
if( aScreen == nullptr ) if( aScreen == nullptr )
aScreen = GetScreen(); aScreen = GetScreen();
@ -429,8 +428,7 @@ void SCH_EDIT_FRAME::DeleteJunction( SCH_ITEM* aJunction, bool aAppend )
} }
SCH_JUNCTION* SCH_EDIT_FRAME::AddJunction( const wxPoint& aPosition, SCH_JUNCTION* SCH_EDIT_FRAME::AddJunction( const wxPoint& aPosition, bool aAppend, bool aFinal )
bool aAppend, bool aFinal )
{ {
SCH_JUNCTION* junction = new SCH_JUNCTION( aPosition ); SCH_JUNCTION* junction = new SCH_JUNCTION( aPosition );
bool broken_segments = false; bool broken_segments = false;
@ -474,46 +472,3 @@ SCH_NO_CONNECT* SCH_EDIT_FRAME::AddNoConnect( const wxPoint& aPosition )
} }
void SCH_EDIT_FRAME::RepeatDrawItem()
{
SCH_ITEM* repeater = GetRepeatItem();
if( !repeater )
return;
// clone the repeater, move it, insert into display list, then save a copy
// via SetRepeatItem();
SCH_ITEM* my_clone = (SCH_ITEM*) repeater->Clone();
// If cloning a component then put into 'move' mode.
if( my_clone->Type() == SCH_COMPONENT_T )
{
wxPoint pos = GetCrossHairPosition() - ( (SCH_COMPONENT*) my_clone )->GetPosition();
my_clone->SetFlags( IS_NEW );
( (SCH_COMPONENT*) my_clone )->SetTimeStamp( GetNewTimeStamp() );
my_clone->Move( pos );
PrepareMoveItem( my_clone );
}
else
{
my_clone->Move( GetRepeatStep() );
if( my_clone->CanIncrementLabel() )
( (SCH_TEXT*) my_clone )->IncrementLabel( GetRepeatDeltaLabel() );
AddToScreen( my_clone );
if( my_clone->IsConnectable() )
TestDanglingEnds();
SaveCopyInUndoList( my_clone, UR_NEW );
my_clone->ClearFlags();
}
// clone my_clone, now that it has been moved, thus saving new position.
SetRepeatItem( my_clone );
}

View File

@ -2,7 +2,7 @@
* This program source code file is part of KiCad, a free EDA CAD application. * This program source code file is part of KiCad, a free EDA CAD application.
* *
* Copyright (C) 2012 jean-pierre.charras * Copyright (C) 2012 jean-pierre.charras
* Copyright (C) 2012-2016 KiCad Developers, see change_log.txt for contributors. * Copyright (C) 2012-2019 KiCad Developers, see change_log.txt for contributors.
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
@ -22,10 +22,6 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/ */
/**
* @file edit_bitmap.cpp
*/
#include <fctsys.h> #include <fctsys.h>
#include <sch_draw_panel.h> #include <sch_draw_panel.h>
#include <sch_view.h> #include <sch_view.h>
@ -36,42 +32,6 @@
#include <view/view_group.h> #include <view/view_group.h>
SCH_BITMAP* SCH_EDIT_FRAME::CreateNewImage()
{
wxFileDialog fileDlg( this, _( "Choose Image" ), wxEmptyString, wxEmptyString,
_( "Image Files " ) + wxImage::GetImageExtWildcard(),
wxFD_OPEN );
if( fileDlg.ShowModal() != wxID_OK )
return nullptr;
wxString fullFilename = fileDlg.GetPath();
if( !wxFileExists( fullFilename ) )
{
wxMessageBox( _( "Couldn't load image from \"%s\"" ), fullFilename );
return nullptr;
}
wxPoint pos = GetCrossHairPosition();
SCH_BITMAP* image = new SCH_BITMAP( pos );
if( !image->ReadImageFile( fullFilename ) )
{
wxMessageBox( _( "Couldn't load image from \"%s\"" ), fullFilename );
delete image;
return nullptr;
}
image->SetFlags( IS_NEW );
PrepareMoveItem( image );
// OnModify();
return image;
}
bool SCH_EDIT_FRAME::EditImage( SCH_BITMAP* aItem ) bool SCH_EDIT_FRAME::EditImage( SCH_BITMAP* aItem )
{ {
// TODO: change image scale or more // TODO: change image scale or more

View File

@ -492,11 +492,6 @@ bool SCH_EDIT_FRAME::OnHotKey( wxDC* aDC, int aHotKey, const wxPoint& aPosition,
GetEventHandler()->ProcessEvent( cmd ); GetEventHandler()->ProcessEvent( cmd );
break; break;
case HK_REPEAT_LAST:
if( notBusy )
RepeatDrawItem();
break;
case HK_END_CURR_LINEWIREBUS: case HK_END_CURR_LINEWIREBUS:
// this key terminates a new line/bus/wire in progress // this key terminates a new line/bus/wire in progress
if( aItem && aItem->IsNew() && if( aItem && aItem->IsNew() &&

View File

@ -751,7 +751,6 @@ public:
SCH_BUS_BUS_ENTRY* CreateBusBusEntry(); SCH_BUS_BUS_ENTRY* CreateBusBusEntry();
SCH_TEXT* CreateNewText( int aType ); SCH_TEXT* CreateNewText( int aType );
SCH_BITMAP* CreateNewImage();
/** /**
* Performs routine schematic cleaning including breaking wire and buses and * Performs routine schematic cleaning including breaking wire and buses and
@ -912,14 +911,6 @@ private:
*/ */
void NormalizeSchematicOnFirstLoad(); void NormalizeSchematicOnFirstLoad();
/**
* Start moving \a aItem using the mouse.
*
* @param aItem A pointer to an SCH_ITEM to move.
* @param aDC The device context to draw \a aItem.
*/
void PrepareMoveItem( SCH_ITEM* aItem );
// Text, label, glabel // Text, label, glabel
void EditSchematicText( SCH_TEXT* TextStruct ); void EditSchematicText( SCH_TEXT* TextStruct );
@ -1231,14 +1222,6 @@ public:
*/ */
virtual bool HandleBlockEnd( wxDC* aDC ) override; virtual bool HandleBlockEnd( wxDC* aDC ) override;
/**
* Repeat the last item placement if the last item was a bus, bus entry,
* label, or component.
*
* Labels that end with a number will be incremented.
*/
void RepeatDrawItem();
/** /**
* Clone \a aItem and owns that clone in this container. * Clone \a aItem and owns that clone in this container.
*/ */

View File

@ -1123,10 +1123,7 @@ void SCH_PAINTER::draw( SCH_COMPONENT *aComp, int aLayer )
aComp->GetFields( fields, false ); aComp->GetFields( fields, false );
for( SCH_FIELD* field : fields ) for( SCH_FIELD* field : fields )
{ draw( field, aLayer );
if( !field->IsMoving() )
draw( field, aLayer );
}
} }

View File

@ -375,149 +375,6 @@ void SCH_EDIT_FRAME::DeleteConnection( bool aFullConnection )
} }
// This function is a callback function, called by the mouse cursor moving event
static void moveItemWithMouseCursor( EDA_DRAW_PANEL* aPanel, wxDC* aDC,
const wxPoint& aPosition, bool aErase )
{
SCH_SCREEN* screen = (SCH_SCREEN*) aPanel->GetScreen();
SCH_ITEM* item = screen->GetCurItem();
auto panel = static_cast<SCH_DRAW_PANEL*>( aPanel );
auto view = panel->GetView();
wxCHECK_RET( (item != NULL), wxT( "Cannot move invalid schematic item." ) );
wxPoint cpos = aPanel->GetParent()->GetCrossHairPosition();
cpos -= item->GetStoredPos();
item->SetPosition( cpos );
view->Hide( item );
view->ClearPreview();
view->AddToPreview( item->Clone() );
// Needed when moving a bitmap image to avoid ugly rendering and artifacts,
// because a bitmap is drawn only as non cached
if( item->Type() == SCH_BITMAP_T )
view->MarkTargetDirty( KIGFX::TARGET_NONCACHED );
}
/**
* Callback function called when aborting a move item with mouse cursor command.
*/
static void abortMoveItem( EDA_DRAW_PANEL* aPanel, wxDC* aDC )
{
SCH_SCREEN* screen = (SCH_SCREEN*) aPanel->GetScreen();
SCH_ITEM* item = screen->GetCurItem();
SCH_EDIT_FRAME* parent = (SCH_EDIT_FRAME*) aPanel->GetParent();
auto panel = static_cast<SCH_DRAW_PANEL*>( aPanel );
auto view = panel->GetView();
parent->SetRepeatItem( NULL );
screen->SetCurItem( NULL );
view->ClearPreview();
view->ClearHiddenFlags();
if( item == NULL ) /* no current item */
return;
if( item->IsNew() )
{
delete item;
}
else
{
SCH_ITEM* oldItem = parent->GetUndoItem();
SCH_ITEM* currentItem;
// Items that are children of other objects are undone by swapping the contents
// of the parent items.
if( (item->Type() == SCH_SHEET_PIN_T) || (item->Type() == SCH_FIELD_T) )
currentItem = (SCH_ITEM*) item->GetParent();
else
currentItem = item;
wxCHECK_RET( oldItem != NULL && currentItem->Type() == oldItem->Type(),
wxT( "Cannot restore undefined or bad last schematic item." ) );
// Never delete existing item, because it can be referenced by an undo/redo command
// Just restore its data
view->Remove( currentItem );
currentItem->SwapData( oldItem );
item->ClearFlags();
view->Add( currentItem );
view->Hide( item, false );
}
screen->TestDanglingEnds();
aPanel->Refresh();
}
void SCH_EDIT_FRAME::PrepareMoveItem( SCH_ITEM* aItem )
{
wxCHECK_RET( aItem != NULL, wxT( "Cannot move invalid schematic item" ) );
GetToolManager()->DeactivateTool();
SetRepeatItem( NULL );
if( !aItem->IsNew() )
{
if( (aItem->Type() == SCH_SHEET_PIN_T) || (aItem->Type() == SCH_FIELD_T) )
SetUndoItem( (SCH_ITEM*) aItem->GetParent() );
else
SetUndoItem( aItem );
}
std::vector<DANGLING_END_ITEM> emptySet;
aItem->UpdateDanglingState( emptySet );
aItem->SetFlags( IS_MOVED );
if( aItem->Type() == SCH_FIELD_T && aItem->GetParent()->Type() == SCH_COMPONENT_T )
{
// Now that we're moving a field, they're no longer autoplaced.
SCH_COMPONENT *parent = static_cast<SCH_COMPONENT*>( aItem->GetParent() );
parent->ClearFieldsAutoplaced();
}
// These are owned by their parent, and so their parent must erase them
if( aItem->Type() == SCH_SHEET_PIN_T || aItem->Type() == SCH_FIELD_T )
RefreshItem( aItem );
// For some items, moving the cursor to anchor is not good (for instance large
// hierarchical sheets or components can have the anchor outside the view)
if( aItem->IsMovableFromAnchorPoint() )
{
SetCrossHairPosition( aItem->GetPosition() );
m_canvas->MoveCursorToCrossHair();
aItem->SetStoredPos( wxPoint( 0,0 ) );
}
else
{
// Round the point under the cursor to a multiple of the grid
wxPoint cursorpos = GetCrossHairPosition() - aItem->GetPosition();
wxPoint gridsize = GetScreen()->GetGridSize();
cursorpos.x = ( cursorpos.x / gridsize.x ) * gridsize.x;
cursorpos.y = ( cursorpos.y / gridsize.y ) * gridsize.y;
aItem->SetStoredPos( cursorpos );
}
if( !aItem->IsNew() )
OnModify();
GetScreen()->SetCurItem( aItem );
m_canvas->SetMouseCapture( moveItemWithMouseCursor, abortMoveItem );
m_canvas->CallMouseCapture( nullptr, wxDefaultPosition, false );
m_canvas->Refresh();
}
void SCH_EDIT_FRAME::SelectAllFromSheet( wxCommandEvent& aEvent ) void SCH_EDIT_FRAME::SelectAllFromSheet( wxCommandEvent& aEvent )
{ {
SCH_SELECTION_TOOL* selTool = GetToolManager()->GetTool<SCH_SELECTION_TOOL>(); SCH_SELECTION_TOOL* selTool = GetToolManager()->GetTool<SCH_SELECTION_TOOL>();

View File

@ -96,9 +96,7 @@ SCH_SHEET_PIN* SCH_EDIT_FRAME::CreateSheetPin( SCH_SHEET* aSheet )
m_lastSheetPinTextSize = sheetPin->GetTextSize(); m_lastSheetPinTextSize = sheetPin->GetTextSize();
sheetPin->SetPosition( GetCrossHairPosition() ); sheetPin->SetPosition( GetCrossHairPosition() );
PrepareMoveItem( sheetPin );
OnModify();
return sheetPin; return sheetPin;
} }
@ -141,7 +139,5 @@ SCH_SHEET_PIN* SCH_EDIT_FRAME::ImportSheetPin( SCH_SHEET* aSheet )
sheetPin->SetShape( label->GetShape() ); sheetPin->SetShape( label->GetShape() );
sheetPin->SetPosition( GetCrossHairPosition() ); sheetPin->SetPosition( GetCrossHairPosition() );
PrepareMoveItem( sheetPin );
return sheetPin; return sheetPin;
} }

View File

@ -206,6 +206,9 @@ OPT<TOOL_EVENT> SCH_ACTIONS::TranslateLegacyId( int aId )
case ID_POPUP_SCH_DUPLICATE: case ID_POPUP_SCH_DUPLICATE:
return SCH_ACTIONS::duplicate.MakeEvent(); return SCH_ACTIONS::duplicate.MakeEvent();
case ID_REPEAT_BUTT:
return SCH_ACTIONS::repeatDrawItem.MakeEvent();
} }
return OPT<TOOL_EVENT>(); return OPT<TOOL_EVENT>();

View File

@ -114,6 +114,7 @@ public:
// Editing // Editing
static TOOL_ACTION move; static TOOL_ACTION move;
static TOOL_ACTION duplicate; static TOOL_ACTION duplicate;
static TOOL_ACTION repeatDrawItem;
static TOOL_ACTION rotateCW; static TOOL_ACTION rotateCW;
static TOOL_ACTION rotateCCW; static TOOL_ACTION rotateCCW;
static TOOL_ACTION mirrorX; static TOOL_ACTION mirrorX;

View File

@ -258,7 +258,7 @@ int SCH_DRAWING_TOOL::PlacePower( const TOOL_EVENT& aEvent )
int SCH_DRAWING_TOOL::doPlaceComponent( SCH_COMPONENT* aComponent, SCHLIB_FILTER* aFilter, int SCH_DRAWING_TOOL::doPlaceComponent( SCH_COMPONENT* aComponent, SCHLIB_FILTER* aFilter,
SCH_BASE_FRAME::HISTORY_LIST aHistoryList ) SCH_BASE_FRAME::HISTORY_LIST aHistoryList )
{ {
VECTOR2I cursorPos = m_controls->GetCursorPosition(); VECTOR2I cursorPos = m_controls->GetCursorPosition();
@ -383,6 +383,128 @@ int SCH_DRAWING_TOOL::doPlaceComponent( SCH_COMPONENT* aComponent, SCHLIB_FILTER
} }
int SCH_DRAWING_TOOL::PlaceImage( const TOOL_EVENT& aEvent )
{
SCH_BITMAP* image = aEvent.Parameter<SCH_BITMAP*>();
m_frame->SetToolID( ID_ADD_IMAGE_BUTT, wxCURSOR_PENCIL, _( "Add image" ) );
VECTOR2I cursorPos = m_controls->GetCursorPosition();
m_toolMgr->RunAction( SCH_ACTIONS::selectionClear, true );
m_controls->ShowCursor( true );
m_controls->SetSnapping( true );
Activate();
// Add all the drawable parts to preview
if( image )
{
image->SetPosition( (wxPoint)cursorPos );
m_view->ClearPreview();
m_view->AddToPreview( image->Clone() );
}
// Main loop: keep receiving events
while( OPT_TOOL_EVENT evt = Wait() )
{
cursorPos = m_controls->GetCursorPosition( !evt->Modifier( MD_ALT ) );
if( evt->IsAction( &ACTIONS::cancelInteractive ) || evt->IsActivate() || evt->IsCancel() )
{
if( image )
{
m_toolMgr->RunAction( SCH_ACTIONS::selectionClear, true );
getModel<SCH_SCREEN>()->SetCurItem( nullptr );
m_view->ClearPreview();
m_view->ClearHiddenFlags();
delete image;
image = nullptr;
}
else
break;
if( evt->IsActivate() ) // now finish unconditionally
break;
}
else if( evt->IsClick( BUT_LEFT ) )
{
if( !image )
{
m_frame->GetCanvas()->SetIgnoreMouseEvents( true );
wxFileDialog dlg( m_frame, _( "Choose Image" ), wxEmptyString, wxEmptyString,
_( "Image Files " ) + wxImage::GetImageExtWildcard(), wxFD_OPEN );
if( dlg.ShowModal() != wxID_OK )
continue;
// Restore cursor after dialog
m_frame->GetCanvas()->MoveCursorToCrossHair();
m_frame->GetCanvas()->SetIgnoreMouseEvents( false );
wxString fullFilename = dlg.GetPath();
if( !wxFileExists( fullFilename ) )
{
wxMessageBox( _( "Couldn't load image from \"%s\"" ), fullFilename );
continue;
}
image = new SCH_BITMAP( (wxPoint)cursorPos );
if( !image->ReadImageFile( fullFilename ) )
{
wxMessageBox( _( "Couldn't load image from \"%s\"" ), fullFilename );
image = nullptr;
delete image;
continue;
}
MSG_PANEL_ITEMS items;
image->GetMsgPanelInfo( m_frame->GetUserUnits(), items );
m_frame->SetMsgPanel( items );
image->SetFlags( IS_MOVED );
m_frame->SetRepeatItem( image );
m_frame->GetScreen()->SetCurItem( image );
m_view->ClearPreview();
m_view->AddToPreview( image->Clone() );
m_controls->SetCursorPosition( cursorPos, false );
}
else
{
m_view->ClearPreview();
m_frame->AddItemToScreen( image );
image = nullptr;
}
}
else if( evt->IsClick( BUT_RIGHT ) )
{
// JEY TODO
// m_menu.ShowContextMenu( selTool->GetSelection() );
}
else if( image && ( evt->IsAction( &SCH_ACTIONS::refreshPreview ) || evt->IsMotion() ) )
{
image->SetPosition( (wxPoint)cursorPos );
m_view->ClearPreview();
m_view->AddToPreview( image->Clone() );
}
// Enable autopanning and cursor capture only when there is a module to be placed
m_controls->SetAutoPan( !!image );
m_controls->CaptureCursor( !!image );
}
m_frame->SetNoToolSelected();
return 0;
}
int SCH_DRAWING_TOOL::PlaceNoConnect( const TOOL_EVENT& aEvent ) int SCH_DRAWING_TOOL::PlaceNoConnect( const TOOL_EVENT& aEvent )
{ {
m_frame->SetToolID( ID_NOCONN_BUTT, wxCURSOR_PENCIL, _( "Add no connect" ) ); m_frame->SetToolID( ID_NOCONN_BUTT, wxCURSOR_PENCIL, _( "Add no connect" ) );
@ -505,13 +627,6 @@ int SCH_DRAWING_TOOL::PlaceSchematicText( const TOOL_EVENT& aEvent )
} }
int SCH_DRAWING_TOOL::PlaceImage( const TOOL_EVENT& aEvent )
{
m_frame->SetToolID( ID_ADD_IMAGE_BUTT, wxCURSOR_PENCIL, _( "Add image" ) );
return doTwoClickPlace( SCH_BITMAP_T );
}
int SCH_DRAWING_TOOL::doTwoClickPlace( KICAD_T aType ) int SCH_DRAWING_TOOL::doTwoClickPlace( KICAD_T aType )
{ {
SCH_SELECTION_TOOL* selTool = m_toolMgr->GetTool<SCH_SELECTION_TOOL>(); SCH_SELECTION_TOOL* selTool = m_toolMgr->GetTool<SCH_SELECTION_TOOL>();
@ -567,9 +682,6 @@ int SCH_DRAWING_TOOL::doTwoClickPlace( KICAD_T aType )
case SCH_TEXT_T: case SCH_TEXT_T:
item = m_frame->CreateNewText( LAYER_NOTES ); item = m_frame->CreateNewText( LAYER_NOTES );
break; break;
case SCH_BITMAP_T:
item = m_frame->CreateNewImage();
break;
case SCH_SHEET_PIN_T: case SCH_SHEET_PIN_T:
item = selTool->SelectPoint( cursorPos, SCH_COLLECTOR::SheetsAndSheetLabels ); item = selTool->SelectPoint( cursorPos, SCH_COLLECTOR::SheetsAndSheetLabels );
if( item ) if( item )

View File

@ -46,6 +46,10 @@ TOOL_ACTION SCH_ACTIONS::duplicate( "eeschema.InteractiveEdit.duplicate",
AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_DUPLICATE ), AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_DUPLICATE ),
_( "Duplicate" ), _( "Duplicates the selected item(s)" ), duplicate_xpm ); _( "Duplicate" ), _( "Duplicates the selected item(s)" ), duplicate_xpm );
TOOL_ACTION SCH_ACTIONS::repeatDrawItem( "eeschema.InteractiveEdit.repeatDrawItem",
AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_REPEAT_LAST ),
_( "Repeat Last Item" ), _( "Duplicates the last drawn item" ) );
TOOL_ACTION SCH_ACTIONS::rotateCW( "eeschema.InteractiveEdit.rotateCW", TOOL_ACTION SCH_ACTIONS::rotateCW( "eeschema.InteractiveEdit.rotateCW",
AS_GLOBAL, 0, AS_GLOBAL, 0,
_( "Rotate Clockwise" ), _( "Rotates selected item(s) clockwise" ), rotate_cw_xpm ); _( "Rotate Clockwise" ), _( "Rotates selected item(s) clockwise" ), rotate_cw_xpm );
@ -133,7 +137,7 @@ int SCH_EDIT_TOOL::Main( const TOOL_EVENT& aEvent )
// Be sure that there is at least one item that we can modify. If nothing was selected before, // Be sure that there is at least one item that we can modify. If nothing was selected before,
// try looking for the stuff under mouse cursor (i.e. Kicad old-style hover selection) // try looking for the stuff under mouse cursor (i.e. Kicad old-style hover selection)
SELECTION& selection = m_selectionTool->RequestSelection( SCH_COLLECTOR::DraggableItems ); SELECTION& selection = m_selectionTool->RequestSelection( SCH_COLLECTOR::MovableItems );
bool unselect = selection.IsHover(); bool unselect = selection.IsHover();
if( m_dragging || selection.Empty() ) if( m_dragging || selection.Empty() )
@ -169,12 +173,11 @@ int SCH_EDIT_TOOL::Main( const TOOL_EVENT& aEvent )
{ {
SCH_ITEM* item = static_cast<SCH_ITEM*>( selection.GetItem( i ) ); SCH_ITEM* item = static_cast<SCH_ITEM*>( selection.GetItem( i ) );
// Don't double move footprint pads, fields, etc. // Don't double move pins, fields, etc.
if( item->GetParent() && item->GetParent()->IsSelected() ) if( item->GetParent() && item->GetParent()->IsSelected() )
continue; continue;
item->Move( (wxPoint)movement ); moveItem( item, movement );
item->SetFlags( IS_MOVED );
updateView( item ); updateView( item );
} }
@ -187,11 +190,12 @@ int SCH_EDIT_TOOL::Main( const TOOL_EVENT& aEvent )
{ {
SCH_ITEM* item = static_cast<SCH_ITEM*>( selection.GetItem( i ) ); SCH_ITEM* item = static_cast<SCH_ITEM*>( selection.GetItem( i ) );
// Don't double move footprint pads, fields, etc. // No need to save children of selected items
if( item->GetParent() && item->GetParent()->IsSelected() ) if( item->GetParent() && item->GetParent()->IsSelected() )
continue; continue;
m_frame->SaveCopyInUndoList( item, UR_CHANGED, i > 0 ); if( !item->IsNew() )
saveCopyInUndoList( item, UR_CHANGED, i > 0 );
} }
// Mark dangling pins at the edges of the block: // Mark dangling pins at the edges of the block:
@ -221,11 +225,12 @@ int SCH_EDIT_TOOL::Main( const TOOL_EVENT& aEvent )
{ {
SCH_ITEM* item = static_cast<SCH_ITEM*>( selection.GetItem( i ) ); SCH_ITEM* item = static_cast<SCH_ITEM*>( selection.GetItem( i ) );
// Don't double move footprint pads, fields, etc. // Don't double move pins, fields, etc.
if( item->GetParent() && item->GetParent()->IsSelected() ) if( item->GetParent() && item->GetParent()->IsSelected() )
continue; continue;
item->Move( (wxPoint)delta ); moveItem( item, delta );
updateView( item );
} }
selection.SetReferencePoint( m_cursor ); selection.SetReferencePoint( m_cursor );
@ -316,6 +321,19 @@ int SCH_EDIT_TOOL::Main( const TOOL_EVENT& aEvent )
} }
void SCH_EDIT_TOOL::moveItem( SCH_ITEM* aItem, VECTOR2I delta )
{
KICAD_T itemType = aItem->Type();
if( itemType == SCH_PIN_T || itemType == SCH_FIELD_T )
aItem->Move( wxPoint( delta.x, -delta.y ) );
else
aItem->Move( (wxPoint)delta );
aItem->SetFlags( IS_MOVED );
}
bool SCH_EDIT_TOOL::updateModificationPoint( SELECTION& aSelection ) bool SCH_EDIT_TOOL::updateModificationPoint( SELECTION& aSelection )
{ {
if( m_dragging && aSelection.HasReferencePoint() ) if( m_dragging && aSelection.HasReferencePoint() )
@ -325,16 +343,22 @@ bool SCH_EDIT_TOOL::updateModificationPoint( SELECTION& aSelection )
if( aSelection.Size() == 1 ) if( aSelection.Size() == 1 )
{ {
SCH_ITEM* item = static_cast<SCH_ITEM*>( aSelection.Front() ); SCH_ITEM* item = static_cast<SCH_ITEM*>( aSelection.Front() );
wxPoint pos = item->GetPosition();
aSelection.SetReferencePoint( pos ); // For some items, moving the cursor to anchor is not good (for instance large
} // hierarchical sheets or components can have the anchor outside the view)
// ...otherwise modify items with regard to the grid-snapped cursor position if( item->IsMovableFromAnchorPoint() )
else {
{ wxPoint pos = item->GetPosition();
m_cursor = getViewControls()->GetCursorPosition( true ); aSelection.SetReferencePoint( pos );
aSelection.SetReferencePoint( m_cursor );
return true;
}
} }
// ...otherwise modify items with regard to the grid-snapped cursor position
m_cursor = getViewControls()->GetCursorPosition( true );
aSelection.SetReferencePoint( m_cursor );
return true; return true;
} }
@ -356,7 +380,7 @@ int SCH_EDIT_TOOL::Rotate( const TOOL_EVENT& aEvent )
if( selection.GetSize() == 1 ) if( selection.GetSize() == 1 )
{ {
if( !moving ) if( !moving )
m_frame->SaveCopyInUndoList( item, UR_CHANGED ); saveCopyInUndoList( item, UR_CHANGED );
switch( item->Type() ) switch( item->Type() )
{ {
@ -449,7 +473,7 @@ int SCH_EDIT_TOOL::Rotate( const TOOL_EVENT& aEvent )
item = static_cast<SCH_ITEM*>( selection.GetItem( ii ) ); item = static_cast<SCH_ITEM*>( selection.GetItem( ii ) );
if( !moving ) if( !moving )
m_frame->SaveCopyInUndoList( item, UR_CHANGED, ii > 0 ); saveCopyInUndoList( item, UR_CHANGED, ii > 0 );
item->Rotate( rotPoint ); item->Rotate( rotPoint );
@ -490,7 +514,7 @@ int SCH_EDIT_TOOL::Mirror( const TOOL_EVENT& aEvent )
if( selection.GetSize() == 1 ) if( selection.GetSize() == 1 )
{ {
if( !moving ) if( !moving )
m_frame->SaveCopyInUndoList( item, UR_CHANGED ); saveCopyInUndoList( item, UR_CHANGED );
switch( item->Type() ) switch( item->Type() )
{ {
@ -588,7 +612,7 @@ int SCH_EDIT_TOOL::Mirror( const TOOL_EVENT& aEvent )
item = static_cast<SCH_ITEM*>( selection.GetItem( ii ) ); item = static_cast<SCH_ITEM*>( selection.GetItem( ii ) );
if( !moving ) if( !moving )
m_frame->SaveCopyInUndoList( item, UR_CHANGED, ii > 0 ); saveCopyInUndoList( item, UR_CHANGED, ii > 0 );
if( xAxis ) if( xAxis )
item->MirrorX( mirrorPoint.y ); item->MirrorX( mirrorPoint.y );
@ -635,7 +659,7 @@ int SCH_EDIT_TOOL::Duplicate( const TOOL_EVENT& aEvent )
SCH_ITEM* newItem = DuplicateStruct( oldItem ); SCH_ITEM* newItem = DuplicateStruct( oldItem );
newItems.push_back( newItem ); newItems.push_back( newItem );
m_frame->SaveCopyInUndoList( newItem, UR_NEW, ii > 0 ); saveCopyInUndoList( newItem, UR_NEW, ii > 0 );
switch( newItem->Type() ) switch( newItem->Type() )
{ {
@ -705,6 +729,58 @@ int SCH_EDIT_TOOL::Duplicate( const TOOL_EVENT& aEvent )
} }
int SCH_EDIT_TOOL::RepeatDrawItem( const TOOL_EVENT& aEvent )
{
SCH_ITEM* sourceItem = m_frame->GetRepeatItem();
if( !sourceItem )
return 0;
m_toolMgr->RunAction( SCH_ACTIONS::selectionClear, true );
SCH_ITEM* newItem = (SCH_ITEM*) sourceItem->Clone();
bool performDrag = false;
// If cloning a component then put into 'move' mode.
if( newItem->Type() == SCH_COMPONENT_T )
{
( (SCH_COMPONENT*) newItem )->SetTimeStamp( GetNewTimeStamp() );
newItem->Move( (wxPoint)m_controls->GetCursorPosition( true ) - newItem->GetPosition() );
performDrag = true;
}
else
{
if( newItem->CanIncrementLabel() )
( (SCH_TEXT*) newItem )->IncrementLabel( m_frame->GetRepeatDeltaLabel() );
newItem->Move( m_frame->GetRepeatStep() );
}
newItem->SetFlags( IS_NEW );
m_frame->AddToScreen( newItem );
m_frame->SaveCopyInUndoList( newItem, UR_NEW );
m_toolMgr->RunAction( SCH_ACTIONS::selectItem, true, newItem );
if( performDrag )
{
TOOL_EVENT evt = SCH_ACTIONS::move.MakeEvent();
Main( evt );
}
newItem->ClearFlags();
if( newItem->IsConnectable() )
m_frame->TestDanglingEnds();
// newItem newItem, now that it has been moved, thus saving new position.
m_frame->SetRepeatItem( newItem );
return 0;
}
int SCH_EDIT_TOOL::Remove( const TOOL_EVENT& aEvent ) int SCH_EDIT_TOOL::Remove( const TOOL_EVENT& aEvent )
{ {
SCH_SELECTION_TOOL* selTool = m_toolMgr->GetTool<SCH_SELECTION_TOOL>(); SCH_SELECTION_TOOL* selTool = m_toolMgr->GetTool<SCH_SELECTION_TOOL>();
@ -745,8 +821,19 @@ void SCH_EDIT_TOOL::updateView( EDA_ITEM* aItem )
if( itemType == SCH_PIN_T || itemType == SCH_FIELD_T || itemType == SCH_SHEET_PIN_T ) if( itemType == SCH_PIN_T || itemType == SCH_FIELD_T || itemType == SCH_SHEET_PIN_T )
getView()->Update( aItem->GetParent() ); getView()->Update( aItem->GetParent() );
getView()->Update( aItem );
}
void SCH_EDIT_TOOL::saveCopyInUndoList( SCH_ITEM* aItem, UNDO_REDO_T aType, bool aAppend )
{
KICAD_T itemType = aItem->Type();
if( itemType == SCH_PIN_T || itemType == SCH_FIELD_T || itemType == SCH_SHEET_PIN_T )
m_frame->SaveCopyInUndoList( (SCH_ITEM*)aItem->GetParent(), aType, aAppend );
else else
getView()->Update( aItem ); m_frame->SaveCopyInUndoList( aItem, aType, aAppend );
} }
@ -754,6 +841,7 @@ void SCH_EDIT_TOOL::setTransitions()
{ {
Go( &SCH_EDIT_TOOL::Main, SCH_ACTIONS::move.MakeEvent() ); Go( &SCH_EDIT_TOOL::Main, SCH_ACTIONS::move.MakeEvent() );
Go( &SCH_EDIT_TOOL::Duplicate, SCH_ACTIONS::duplicate.MakeEvent() ); Go( &SCH_EDIT_TOOL::Duplicate, SCH_ACTIONS::duplicate.MakeEvent() );
Go( &SCH_EDIT_TOOL::RepeatDrawItem, SCH_ACTIONS::repeatDrawItem.MakeEvent() );
Go( &SCH_EDIT_TOOL::Rotate, SCH_ACTIONS::rotateCW.MakeEvent() ); Go( &SCH_EDIT_TOOL::Rotate, SCH_ACTIONS::rotateCW.MakeEvent() );
Go( &SCH_EDIT_TOOL::Rotate, SCH_ACTIONS::rotateCCW.MakeEvent() ); Go( &SCH_EDIT_TOOL::Rotate, SCH_ACTIONS::rotateCCW.MakeEvent() );
Go( &SCH_EDIT_TOOL::Mirror, SCH_ACTIONS::mirrorX.MakeEvent() ); Go( &SCH_EDIT_TOOL::Mirror, SCH_ACTIONS::mirrorX.MakeEvent() );

View File

@ -62,6 +62,7 @@ public:
int Mirror( const TOOL_EVENT& aEvent ); int Mirror( const TOOL_EVENT& aEvent );
int Duplicate( const TOOL_EVENT& aEvent ); int Duplicate( const TOOL_EVENT& aEvent );
int RepeatDrawItem( const TOOL_EVENT& aEvent );
/** /**
* Function Remove() * Function Remove()
@ -71,6 +72,8 @@ public:
int Remove( const TOOL_EVENT& aEvent ); int Remove( const TOOL_EVENT& aEvent );
private: private:
void moveItem( SCH_ITEM* aItem, VECTOR2I delta );
///> Returns the right modification point (e.g. for rotation), depending on the number of ///> Returns the right modification point (e.g. for rotation), depending on the number of
///> selected items. ///> selected items.
bool updateModificationPoint( SELECTION& aSelection ); bool updateModificationPoint( SELECTION& aSelection );
@ -78,6 +81,10 @@ private:
///> Similar to getView()->Update(), but handles items that are redrawn by their parents. ///> Similar to getView()->Update(), but handles items that are redrawn by their parents.
void updateView( EDA_ITEM* ); void updateView( EDA_ITEM* );
///> Similar to m_frame->SaveCopyInUndoList(), but handles items that are owned by their
///> parents.
void saveCopyInUndoList( SCH_ITEM*, UNDO_REDO_T aType, bool aAppend = false );
///> Sets up handlers for various events. ///> Sets up handlers for various events.
void setTransitions() override; void setTransitions() override;