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_EXCHANGE_T:
case UR_DRILLORIGIN:
case UR_GRIDORIGIN:
delete wrapper.GetLink(); // the picker is owner of this item
break;

View File

@ -22,18 +22,26 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include <class_drawpanel.h>
#include <draw_frame.h>
#include <origin_viewitem.h>
#include <gal/graphics_abstraction_layer.h>
using namespace KIGFX;
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 )
{
}
ORIGIN_VIEWITEM* ORIGIN_VIEWITEM::Clone() const
{
return new ORIGIN_VIEWITEM( m_color, m_style, m_size, m_position );
}
const BOX2I ORIGIN_VIEWITEM::ViewBBox() const
{
BOX2I bbox;
@ -41,7 +49,6 @@ const BOX2I ORIGIN_VIEWITEM::ViewBBox() const
return bbox;
}
void ORIGIN_VIEWITEM::ViewDraw( int, VIEW* aView ) const
{
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
// of the current component when changed)
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
///< data structure is insufficient to restor the change.
UR_EXCHANGE_T, ///< Use for changing the schematic text type where swapping
///< 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 {
class ORIGIN_VIEWITEM : public EDA_ITEM
class ORIGIN_VIEWITEM : public BOARD_ITEM
{
public:
///> Marker symbol styles
@ -48,10 +48,18 @@ public:
MARKER_STYLE aStyle = CIRCLE_X, int aSize = 16,
const VECTOR2D& aPosition = VECTOR2D( 0, 0 ) );
ORIGIN_VIEWITEM* Clone() const override;
const BOX2I ViewBBox() 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
{
aLayers[0] = LAYER_GP_OVERLAY;
@ -88,9 +96,14 @@ public:
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 )

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,
KIGFX::ORIGIN_VIEWITEM* aItem, const VECTOR2D& aPosition )
bool PCB_EDITOR_CONTROL::DoSetDrillOrigin( KIGFX::VIEW* aView, PCB_BASE_FRAME* aFrame,
BOARD_ITEM* originViewItem, const VECTOR2D& aPosition )
{
aFrame->SetAuxOrigin( wxPoint( aPosition.x, aPosition.y ) );
aItem->SetPosition( aPosition );
originViewItem->SetPosition( wxPoint( aPosition.x, aPosition.y ) );
aView->MarkDirty();
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 )
{
Activate();
@ -850,7 +858,7 @@ int PCB_EDITOR_CONTROL::DrillOrigin( const TOOL_EVENT& aEvent )
assert( picker );
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();
Wait();

View File

@ -89,9 +89,17 @@ public:
///> Reacts to selection change in eeschema.
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 );
///> 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.
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,
KIGFX::ORIGIN_VIEWITEM* aItem, const VECTOR2D& aPoint )
bool PCBNEW_CONTROL::DoSetGridOrigin( KIGFX::VIEW* aView, PCB_BASE_FRAME* aFrame,
BOARD_ITEM* originViewItem, const VECTOR2D& aPoint )
{
aFrame->SetGridOrigin( wxPoint( aPoint.x, aPoint.y ) );
aView->GetGAL()->SetGridOrigin( aPoint );
aItem->SetPosition( aPoint );
originViewItem->SetPosition( wxPoint( aPoint.x, aPoint.y ) );
aView->MarkDirty();
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 )
{
VECTOR2D* origin = aEvent.Parameter<VECTOR2D*>();
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;
}
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..
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();
Wait();
}
@ -638,8 +648,7 @@ int PCBNEW_CONTROL::GridSetOrigin( const TOOL_EVENT& aEvent )
int PCBNEW_CONTROL::GridResetOrigin( const TOOL_EVENT& aEvent )
{
board()->SetGridOrigin( wxPoint( 0, 0 ) );
m_gridOrigin->SetPosition( VECTOR2D( 0, 0 ) );
SetGridOrigin( getView(), m_frame, m_gridOrigin.get(), VECTOR2D( 0, 0 ) );
return 0;
}

View File

@ -76,6 +76,14 @@ public:
int GridSetOrigin( 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
int ResetCoords( 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_zone.h>
#include <class_edge_mod.h>
#include <origin_viewitem.h>
#include <connectivity_data.h>
#include <tools/selection_tool.h>
#include <tools/pcbnew_control.h>
#include <tools/pcb_editor_control.h>
#include <tool/tool_manager.h>
#include <view/view.h>
@ -295,6 +298,8 @@ void PCB_BASE_EDIT_FRAME::SaveCopyInUndoList( const PICKED_ITEMS_LIST& aItemsLis
switch( command )
{
case UR_CHANGED:
case UR_DRILLORIGIN:
case UR_GRIDORIGIN:
/* If needed, create a copy of item, and put in undo list
* 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 );
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 )
// 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 );
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:
{
wxString msg;