Implement undo/redo for drill and grid origins.

The undo/redo operations are essentially the same as for
UR_CHANGED: we store both the origin marker item and a copy
of it and flip back and forth between the two.  This also
required the implementation of clone() for the markers.

The ORIGIN_VIEWMARKER is moved from being a subclass of
EDA_ITEM to BOARD_ITEM to facilitate the use of a UR_CHANGE-
like implementation without having to know the internals
of the ORIGIN_VIEWMARKER.

In the command processors, the setting of the origins is
broken into two parts: one for UI-level access which includes
setting up undo, and one for low-level access which does not.
The undo/redo code itself of course uses the lower level.

Fixes: lp:1542018
* https://bugs.launchpad.net/kicad/+bug/1542018
This commit is contained in:
Jeff Young 2018-01-24 10:19:33 +00:00 committed by Wayne Stambaugh
parent f88c4ccb02
commit 4784ee7fe4
9 changed files with 98 additions and 20 deletions

View File

@ -144,6 +144,8 @@ void PICKED_ITEMS_LIST::ClearListAndDeleteItems()
case UR_CHANGED: case UR_CHANGED:
case UR_EXCHANGE_T: case UR_EXCHANGE_T:
case UR_DRILLORIGIN:
case UR_GRIDORIGIN:
delete wrapper.GetLink(); // the picker is owner of this item delete wrapper.GetLink(); // the picker is owner of this item
break; break;

View File

@ -22,18 +22,26 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/ */
#include <class_drawpanel.h>
#include <draw_frame.h>
#include <origin_viewitem.h> #include <origin_viewitem.h>
#include <gal/graphics_abstraction_layer.h> #include <gal/graphics_abstraction_layer.h>
using namespace KIGFX; using namespace KIGFX;
ORIGIN_VIEWITEM::ORIGIN_VIEWITEM( const COLOR4D& aColor, MARKER_STYLE aStyle, int aSize, const VECTOR2D& aPosition ) : ORIGIN_VIEWITEM::ORIGIN_VIEWITEM( const COLOR4D& aColor, MARKER_STYLE aStyle, int aSize, const VECTOR2D& aPosition ) :
EDA_ITEM( NOT_USED ), // this item is never added to a BOARD so it needs no type BOARD_ITEM( nullptr, NOT_USED ), // this item is never added to a BOARD so it needs no type
m_position( aPosition ), m_size( aSize ), m_color( aColor ), m_style( aStyle ), m_drawAtZero( false ) m_position( aPosition ), m_size( aSize ), m_color( aColor ), m_style( aStyle ), m_drawAtZero( false )
{ {
} }
ORIGIN_VIEWITEM* ORIGIN_VIEWITEM::Clone() const
{
return new ORIGIN_VIEWITEM( m_color, m_style, m_size, m_position );
}
const BOX2I ORIGIN_VIEWITEM::ViewBBox() const const BOX2I ORIGIN_VIEWITEM::ViewBBox() const
{ {
BOX2I bbox; BOX2I bbox;
@ -41,7 +49,6 @@ const BOX2I ORIGIN_VIEWITEM::ViewBBox() const
return bbox; return bbox;
} }
void ORIGIN_VIEWITEM::ViewDraw( int, VIEW* aView ) const void ORIGIN_VIEWITEM::ViewDraw( int, VIEW* aView ) const
{ {
auto gal = aView->GetGAL(); auto gal = aView->GetGAL();

View File

@ -72,8 +72,10 @@ enum UNDO_REDO_T {
UR_LIBEDIT, // Specific to the component editor (libedit creates a full copy UR_LIBEDIT, // Specific to the component editor (libedit creates a full copy
// of the current component when changed) // of the current component when changed)
UR_LIB_RENAME, // As UR_LIBEDIT, but old copy should be removed from library UR_LIB_RENAME, // As UR_LIBEDIT, but old copy should be removed from library
UR_EXCHANGE_T ///< Use for changing the schematic text type where swapping UR_EXCHANGE_T, ///< Use for changing the schematic text type where swapping
///< data structure is insufficient to restor the change. ///< data structure is insufficient to restore the change.
UR_DRILLORIGIN, // origin changed (like UR_CHANGED, contains the origin and a copy)
UR_GRIDORIGIN // origin changed (like UR_CHANGED, contains the origin and a copy)
}; };

View File

@ -38,7 +38,7 @@
*/ */
namespace KIGFX { namespace KIGFX {
class ORIGIN_VIEWITEM : public EDA_ITEM class ORIGIN_VIEWITEM : public BOARD_ITEM
{ {
public: public:
///> Marker symbol styles ///> Marker symbol styles
@ -48,10 +48,18 @@ public:
MARKER_STYLE aStyle = CIRCLE_X, int aSize = 16, MARKER_STYLE aStyle = CIRCLE_X, int aSize = 16,
const VECTOR2D& aPosition = VECTOR2D( 0, 0 ) ); const VECTOR2D& aPosition = VECTOR2D( 0, 0 ) );
ORIGIN_VIEWITEM* Clone() const override;
const BOX2I ViewBBox() const override; const BOX2I ViewBBox() const override;
void ViewDraw( int aLayer, VIEW* aView ) const override; void ViewDraw( int aLayer, VIEW* aView ) const override;
void Draw( EDA_DRAW_PANEL* panel, wxDC* DC,
GR_DRAWMODE aDrawMode, const wxPoint& offset = ZeroOffset ) override
{
wxASSERT( 0 ); // ORIGIN_VIEWITEM never added to BOARD; drawn directly through ViewDraw().
}
void ViewGetLayers( int aLayers[], int& aCount ) const override void ViewGetLayers( int aLayers[], int& aCount ) const override
{ {
aLayers[0] = LAYER_GP_OVERLAY; aLayers[0] = LAYER_GP_OVERLAY;
@ -88,9 +96,14 @@ public:
m_position = aPosition; m_position = aPosition;
} }
inline const VECTOR2D& GetPosition() const inline void SetPosition( const wxPoint& aPosition ) override
{ {
return m_position; m_position = VECTOR2D( aPosition );
}
inline const wxPoint GetPosition() const override
{
return wxPoint( m_position.x, m_position.y );
} }
inline void SetSize( int aSize ) inline void SetSize( int aSize )

View File

@ -831,17 +831,25 @@ int PCB_EDITOR_CONTROL::CrossProbeSchToPcb( const TOOL_EVENT& aEvent )
} }
static bool setDrillOrigin( KIGFX::VIEW* aView, PCB_BASE_FRAME* aFrame, bool PCB_EDITOR_CONTROL::DoSetDrillOrigin( KIGFX::VIEW* aView, PCB_BASE_FRAME* aFrame,
KIGFX::ORIGIN_VIEWITEM* aItem, const VECTOR2D& aPosition ) BOARD_ITEM* originViewItem, const VECTOR2D& aPosition )
{ {
aFrame->SetAuxOrigin( wxPoint( aPosition.x, aPosition.y ) ); aFrame->SetAuxOrigin( wxPoint( aPosition.x, aPosition.y ) );
aItem->SetPosition( aPosition ); originViewItem->SetPosition( wxPoint( aPosition.x, aPosition.y ) );
aView->MarkDirty(); aView->MarkDirty();
return true; return true;
} }
bool PCB_EDITOR_CONTROL::SetDrillOrigin( KIGFX::VIEW* aView, PCB_BASE_FRAME* aFrame,
BOARD_ITEM* originViewItem, const VECTOR2D& aPosition )
{
aFrame->SaveCopyInUndoList( originViewItem, UR_DRILLORIGIN );
DoSetDrillOrigin( aView, aFrame, originViewItem, aPosition );
}
int PCB_EDITOR_CONTROL::DrillOrigin( const TOOL_EVENT& aEvent ) int PCB_EDITOR_CONTROL::DrillOrigin( const TOOL_EVENT& aEvent )
{ {
Activate(); Activate();
@ -850,7 +858,7 @@ int PCB_EDITOR_CONTROL::DrillOrigin( const TOOL_EVENT& aEvent )
assert( picker ); assert( picker );
m_frame->SetToolID( ID_PCB_PLACE_OFFSET_COORD_BUTT, wxCURSOR_HAND, _( "Adjust zero" ) ); m_frame->SetToolID( ID_PCB_PLACE_OFFSET_COORD_BUTT, wxCURSOR_HAND, _( "Adjust zero" ) );
picker->SetClickHandler( std::bind( setDrillOrigin, getView(), m_frame, m_placeOrigin.get(), _1 ) ); picker->SetClickHandler( std::bind( SetDrillOrigin, getView(), m_frame, m_placeOrigin.get(), _1 ) );
picker->Activate(); picker->Activate();
Wait(); Wait();

View File

@ -89,9 +89,17 @@ public:
///> Reacts to selection change in eeschema. ///> Reacts to selection change in eeschema.
int CrossProbeSchToPcb( const TOOL_EVENT& aEvent ); int CrossProbeSchToPcb( const TOOL_EVENT& aEvent );
///> Places the origin point for drill and pick-and-place files. ///> Runs the drill origin tool for setting the origin for drill and pick-and-place files.
int DrillOrigin( const TOOL_EVENT& aEvent ); int DrillOrigin( const TOOL_EVENT& aEvent );
///> UI-level access (including undo) to setting the drill origin
static bool SetDrillOrigin( KIGFX::VIEW* aView, PCB_BASE_FRAME* aFrame,
BOARD_ITEM* aItem, const VECTOR2D& aPoint );
///> Low-level access (below undo) to setting the drill origin
static bool DoSetDrillOrigin( KIGFX::VIEW* aView, PCB_BASE_FRAME* aFrame,
BOARD_ITEM* aItem, const VECTOR2D& aPoint );
///> Highlights net belonging to the item under the cursor. ///> Highlights net belonging to the item under the cursor.
int HighlightNet( const TOOL_EVENT& aEvent ); int HighlightNet( const TOOL_EVENT& aEvent );

View File

@ -597,25 +597,35 @@ int PCBNEW_CONTROL::GridFast2( const TOOL_EVENT& aEvent )
} }
static bool setOrigin( KIGFX::VIEW* aView, PCB_BASE_FRAME* aFrame, bool PCBNEW_CONTROL::DoSetGridOrigin( KIGFX::VIEW* aView, PCB_BASE_FRAME* aFrame,
KIGFX::ORIGIN_VIEWITEM* aItem, const VECTOR2D& aPoint ) BOARD_ITEM* originViewItem, const VECTOR2D& aPoint )
{ {
aFrame->SetGridOrigin( wxPoint( aPoint.x, aPoint.y ) ); aFrame->SetGridOrigin( wxPoint( aPoint.x, aPoint.y ) );
aView->GetGAL()->SetGridOrigin( aPoint ); aView->GetGAL()->SetGridOrigin( aPoint );
aItem->SetPosition( aPoint ); originViewItem->SetPosition( wxPoint( aPoint.x, aPoint.y ) );
aView->MarkDirty(); aView->MarkDirty();
return true; return true;
} }
bool PCBNEW_CONTROL::SetGridOrigin( KIGFX::VIEW* aView, PCB_BASE_FRAME* aFrame,
BOARD_ITEM* originViewItem, const VECTOR2D& aPoint )
{
aFrame->SaveCopyInUndoList( originViewItem, UR_GRIDORIGIN );
return DoSetGridOrigin( aView, aFrame, originViewItem, aPoint );
}
int PCBNEW_CONTROL::GridSetOrigin( const TOOL_EVENT& aEvent ) int PCBNEW_CONTROL::GridSetOrigin( const TOOL_EVENT& aEvent )
{ {
VECTOR2D* origin = aEvent.Parameter<VECTOR2D*>(); VECTOR2D* origin = aEvent.Parameter<VECTOR2D*>();
if( origin ) if( origin )
{ {
setOrigin( getView(), m_frame, m_gridOrigin.get(), *origin ); // We can't undo the other grid dialog settings, so no sense undoing just the origin
DoSetGridOrigin( getView(), m_frame, m_gridOrigin.get(), *origin );
delete origin; delete origin;
} }
else else
@ -627,7 +637,7 @@ int PCBNEW_CONTROL::GridSetOrigin( const TOOL_EVENT& aEvent )
// TODO it will not check the toolbar button in module editor, as it uses a different ID.. // TODO it will not check the toolbar button in module editor, as it uses a different ID..
m_frame->SetToolID( ID_PCB_PLACE_GRID_COORD_BUTT, wxCURSOR_PENCIL, _( "Adjust grid origin" ) ); m_frame->SetToolID( ID_PCB_PLACE_GRID_COORD_BUTT, wxCURSOR_PENCIL, _( "Adjust grid origin" ) );
picker->SetClickHandler( std::bind( setOrigin, getView(), m_frame, m_gridOrigin.get(), _1 ) ); picker->SetClickHandler( std::bind( SetGridOrigin, getView(), m_frame, m_gridOrigin.get(), _1 ) );
picker->Activate(); picker->Activate();
Wait(); Wait();
} }
@ -638,8 +648,7 @@ int PCBNEW_CONTROL::GridSetOrigin( const TOOL_EVENT& aEvent )
int PCBNEW_CONTROL::GridResetOrigin( const TOOL_EVENT& aEvent ) int PCBNEW_CONTROL::GridResetOrigin( const TOOL_EVENT& aEvent )
{ {
board()->SetGridOrigin( wxPoint( 0, 0 ) ); SetGridOrigin( getView(), m_frame, m_gridOrigin.get(), VECTOR2D( 0, 0 ) );
m_gridOrigin->SetPosition( VECTOR2D( 0, 0 ) );
return 0; return 0;
} }

View File

@ -76,6 +76,14 @@ public:
int GridSetOrigin( const TOOL_EVENT& aEvent ); int GridSetOrigin( const TOOL_EVENT& aEvent );
int GridResetOrigin( const TOOL_EVENT& aEvent ); int GridResetOrigin( const TOOL_EVENT& aEvent );
// UI-level access (including undo) to setting the grid origin
static bool SetGridOrigin( KIGFX::VIEW* aView, PCB_BASE_FRAME* aFrame,
BOARD_ITEM* originViewItem, const VECTOR2D& aPoint );
// Low-level access (below undo) to setting the grid origin
static bool DoSetGridOrigin( KIGFX::VIEW* aView, PCB_BASE_FRAME* aFrame,
BOARD_ITEM* originViewItem, const VECTOR2D& aPoint );
// Miscellaneous // Miscellaneous
int ResetCoords( const TOOL_EVENT& aEvent ); int ResetCoords( const TOOL_EVENT& aEvent );
int SwitchCursor( const TOOL_EVENT& aEvent ); int SwitchCursor( const TOOL_EVENT& aEvent );

View File

@ -44,10 +44,13 @@ using namespace std::placeholders;
#include <class_dimension.h> #include <class_dimension.h>
#include <class_zone.h> #include <class_zone.h>
#include <class_edge_mod.h> #include <class_edge_mod.h>
#include <origin_viewitem.h>
#include <connectivity_data.h> #include <connectivity_data.h>
#include <tools/selection_tool.h> #include <tools/selection_tool.h>
#include <tools/pcbnew_control.h>
#include <tools/pcb_editor_control.h>
#include <tool/tool_manager.h> #include <tool/tool_manager.h>
#include <view/view.h> #include <view/view.h>
@ -295,6 +298,8 @@ void PCB_BASE_EDIT_FRAME::SaveCopyInUndoList( const PICKED_ITEMS_LIST& aItemsLis
switch( command ) switch( command )
{ {
case UR_CHANGED: case UR_CHANGED:
case UR_DRILLORIGIN:
case UR_GRIDORIGIN:
/* If needed, create a copy of item, and put in undo list /* If needed, create a copy of item, and put in undo list
* in the picker, as link * in the picker, as link
@ -432,7 +437,9 @@ void PCB_BASE_EDIT_FRAME::PutDataInPreviousState( PICKED_ITEMS_LIST* aList, bool
*/ */
UNDO_REDO_T status = aList->GetPickedItemStatus( ii ); UNDO_REDO_T status = aList->GetPickedItemStatus( ii );
if( status != UR_DELETED ) if( status != UR_DELETED
&& status != UR_DRILLORIGIN // origin markers never on board
&& status != UR_GRIDORIGIN ) // origin markers never on board
{ {
if( build_item_list ) if( build_item_list )
// Build list of existing items, for integrity test // Build list of existing items, for integrity test
@ -547,6 +554,20 @@ void PCB_BASE_EDIT_FRAME::PutDataInPreviousState( PICKED_ITEMS_LIST* aList, bool
connectivity->Update( item ); connectivity->Update( item );
break; break;
case UR_DRILLORIGIN:
case UR_GRIDORIGIN:
{
BOARD_ITEM* image = (BOARD_ITEM*) aList->GetPickedItemLink( ii );
VECTOR2D origin = image->GetPosition();
image->SetPosition( item->GetPosition() );
if( aList->GetPickedItemStatus( ii ) == UR_DRILLORIGIN )
PCB_EDITOR_CONTROL::DoSetDrillOrigin( view, this, item, origin );
else
PCBNEW_CONTROL::DoSetGridOrigin( view, this, item, origin );
}
break;
default: default:
{ {
wxString msg; wxString msg;