Commit 8ec8cf3f authored by charras's avatar charras
Browse files

Rework on undo/redo and block functions

parent 6d14766e
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -4,6 +4,14 @@ KiCad ChangeLog 2009
Please add newer entries at the top, list the date and your name with
email address.

2009-july-25 UPDATE Jean-Pierre Charras <jean-pierre.charras@gipsa-lab.inpg.fr>
================================================================================
++all
    Rework on undo/redo and block functions
    Better and simpler coding of block and undo/redo functions
    The goal is to have the same functions in eeschema and pcbnew.
    and have a full undo/redo in pcbnew.

2009-july-18 UPDATE Jean-Pierre Charras <jean-pierre.charras@gipsa-lab.inpg.fr>
================================================================================
++pcbnew
+112 −96
Original line number Diff line number Diff line
@@ -19,31 +19,30 @@


/*******************/
/* DrawBlockStruct */
/* BLOCK_SELECTOR */
/*******************/

/****************************************************************************/
DrawBlockStruct::DrawBlockStruct() :
    EDA_BaseStruct( BLOCK_LOCATE_STRUCT_TYPE )
    , EDA_Rect()
BLOCK_SELECTOR::BLOCK_SELECTOR() :
    EDA_BaseStruct( BLOCK_LOCATE_STRUCT_TYPE ),
    EDA_Rect()
/****************************************************************************/
{
    m_State   = STATE_NO_BLOCK; /* Etat (enum BlockState) du block */
    m_Command = BLOCK_IDLE;     /* Type (enum CmdBlockType) d'operation */
    m_BlockDrawStruct = NULL;   /* pointeur sur la structure */
    m_Color   = BROWN;
}


/****************************************/
DrawBlockStruct::~DrawBlockStruct()
BLOCK_SELECTOR::~BLOCK_SELECTOR()
/****************************************/
{
}


/***************************************************************/
void DrawBlockStruct::SetMessageBlock( WinEDA_DrawFrame* frame )
void BLOCK_SELECTOR::SetMessageBlock( WinEDA_DrawFrame* frame )
/***************************************************************/

/*
@@ -112,21 +111,69 @@ void DrawBlockStruct::SetMessageBlock( WinEDA_DrawFrame* frame )


/**************************************************************/
void DrawBlockStruct::Draw( WinEDA_DrawPanel* panel, wxDC* DC )
void BLOCK_SELECTOR::Draw( WinEDA_DrawPanel* aPanel, wxDC* aDC,
                           const wxPoint& aOffset,
                           int aDrawMode,
                           int aColor )
/**************************************************************/
{
    int w = panel->GetScreen()->Scale( GetWidth() );
    int h = panel->GetScreen()->Scale( GetHeight() );
    int w = aPanel->GetScreen()->Scale( GetWidth() );
    int h = aPanel->GetScreen()->Scale( GetHeight() );

    GRSetDrawMode( aDC, aDrawMode );
    if(  w == 0 || h == 0 )
        GRLine( &panel->m_ClipBox, DC, GetX(), GetY(),
                GetRight(), GetBottom(), 0, m_Color );
        GRLine( &aPanel->m_ClipBox, aDC, GetX() + aOffset.x, GetY() + aOffset.y,
                GetRight() + aOffset.x, GetBottom() + aOffset.y, 0, aColor );
    else
        GRRect( &panel->m_ClipBox, DC, GetX(), GetY(),
                GetRight(), GetBottom(), 0, m_Color );
        GRRect( &aPanel->m_ClipBox, aDC, GetX() + aOffset.x, GetY() + aOffset.y,
                GetRight() + aOffset.x, GetBottom() + aOffset.y, 0, aColor );
}


/*************************************************************************/
void BLOCK_SELECTOR::InitData( WinEDA_DrawPanel* aPanel, const wxPoint& startpos )
/*************************************************************************/

/** function InitData
 *  Init the initial values of a BLOCK_SELECTOR, before starting a block command
 */
{
    m_State = STATE_BLOCK_INIT;
    SetOrigin( startpos );
    SetSize( wxSize( 0, 0 ) );
    m_ItemsSelection.ClearItemsList();
    aPanel->ManageCurseur = DrawAndSizingBlockOutlines;
    aPanel->ForceCloseManageCurseur = AbortBlockCurrentCommand;
}


/** Function ClearItemsList
 * delete only the list of EDA_BaseStruct * pointers, NOT the pointed data itself
 */
void BLOCK_SELECTOR::ClearItemsList()
{
    m_ItemsSelection.ClearItemsList();
}

/** Function ClearListAndDeleteItems
 * delete only the list of EDA_BaseStruct * pointers, AND the data pinted by m_Item
 */
void BLOCK_SELECTOR::ClearListAndDeleteItems()
{
     m_ItemsSelection.ClearListAndDeleteItems();
}

/** Function PushItem
 * Add aItem to the list of items
 * @param aItem = an ITEM_PICKER to add to the list
 */
void BLOCK_SELECTOR::PushItem( ITEM_PICKER& aItem )
{
    m_ItemsSelection.PushItem(  aItem );
}



/*************************************************************************/
bool WinEDA_DrawFrame::HandleBlockBegin( wxDC* DC, int key,
                                         const wxPoint& startpos )
@@ -136,7 +183,7 @@ bool WinEDA_DrawFrame::HandleBlockBegin( wxDC* DC, int key,
 *  Init the Block infos: command type, initial position, and other variables..
 */
{
    DrawBlockStruct* Block = & GetBaseScreen()->BlockLocate;
    BLOCK_SELECTOR* Block = &GetBaseScreen()->m_BlockLocate;

    if( ( Block->m_Command != BLOCK_IDLE )
       || ( Block->m_State != STATE_NO_BLOCK ) )
@@ -163,24 +210,24 @@ bool WinEDA_DrawFrame::HandleBlockBegin( wxDC* DC, int key,
    case BLOCK_MIRROR_X:
    case BLOCK_MIRROR_Y:            /* mirror */
    case BLOCK_PRESELECT_MOVE:      /* Move with preselection list*/
        InitBlockLocateDatas( DrawPanel, startpos );
        Block->InitData( DrawPanel, startpos );
        break;

    case BLOCK_PASTE:
        InitBlockLocateDatas( DrawPanel, startpos );
        Block->InitData( DrawPanel, startpos );
        Block->m_BlockLastCursorPosition.x = 0;
        Block->m_BlockLastCursorPosition.y = 0;
        InitBlockPasteInfos();
        if( Block->m_BlockDrawStruct == NULL )      /* No data to paste */
        if( Block->m_ItemsSelection.GetCount() == 0 )      /* No data to paste */
        {
            DisplayError( this, wxT( "No Block to paste" ), 20 );
            GetBaseScreen()->BlockLocate.m_Command = BLOCK_IDLE;
            GetBaseScreen()->m_BlockLocate.m_Command = BLOCK_IDLE;
            DrawPanel->ManageCurseur = NULL;
            return TRUE;
        }
        if( DrawPanel->ManageCurseur == NULL )
        {
            Block->m_BlockDrawStruct = NULL;
            Block->m_ItemsSelection.ClearItemsList();
            DisplayError( this,
                         wxT( "WinEDA_DrawFrame::HandleBlockBegin() Err: ManageCurseur NULL" ) );
            return TRUE;
@@ -203,95 +250,30 @@ bool WinEDA_DrawFrame::HandleBlockBegin( wxDC* DC, int key,
    return TRUE;
}


/******************************************************************/
void AbortBlockCurrentCommand( WinEDA_DrawPanel* Panel, wxDC* DC )
/******************************************************************/

/*
 *  Cancel Current block operation.
 */
{
    BASE_SCREEN* screen = Panel->GetScreen();

    if( Panel->ManageCurseur )                      /* Erase current drawing on screen */
    {
        Panel->ManageCurseur( Panel, DC, FALSE );   /* Efface dessin fantome */
        Panel->ManageCurseur = NULL;
        Panel->ForceCloseManageCurseur = NULL;
        screen->SetCurItem( NULL );

        /* Delete the picked wrapper if this is a picked list. */
        if( (screen->BlockLocate.m_Command != BLOCK_PASTE)
           && screen->BlockLocate.m_BlockDrawStruct )
        {
            if( screen->BlockLocate.m_BlockDrawStruct->Type() == DRAW_PICK_ITEM_STRUCT_TYPE )
            {
                DrawPickedStruct* PickedList;
                PickedList = (DrawPickedStruct*) screen->BlockLocate.m_BlockDrawStruct;
                PickedList->DeleteWrapperList();
            }
            screen->BlockLocate.m_BlockDrawStruct = NULL;
        }
    }

    screen->BlockLocate.m_Flags = 0;
    screen->BlockLocate.m_State = STATE_NO_BLOCK;

    screen->BlockLocate.m_Command = BLOCK_ABORT;
    Panel->m_Parent->HandleBlockEnd( DC );

    screen->BlockLocate.m_Command = BLOCK_IDLE;
    Panel->m_Parent->DisplayToolMsg( wxEmptyString );
}


/*************************************************************************/
void InitBlockLocateDatas( WinEDA_DrawPanel* Panel, const wxPoint& startpos )
/*************************************************************************/

/*
 *  Init the initial values of a BlockLocate, before starting a block command
 */
{
    BASE_SCREEN* screen = Panel->GetScreen();

    screen->BlockLocate.m_State = STATE_BLOCK_INIT;
    screen->BlockLocate.SetOrigin( startpos );
    screen->BlockLocate.SetSize( wxSize( 0, 0 ) );
    screen->BlockLocate.SetNext( NULL );
    screen->BlockLocate.m_BlockDrawStruct = NULL;
    Panel->ManageCurseur = DrawAndSizingBlockOutlines;
    Panel->ForceCloseManageCurseur = AbortBlockCurrentCommand;
}


/********************************************************************************/
void DrawAndSizingBlockOutlines( WinEDA_DrawPanel* panel, wxDC* DC, bool erase )
/********************************************************************************/

/* Redraw the outlines of the block which shows the search area for block commands
 *  The first point of the rectangle showing the area is initialised
 *  by InitBlockLocateDatas().
 *  by Initm_BlockLocateDatas().
 *  The other point of the rectangle is the mouse cursor
 */
{
    DrawBlockStruct* PtBlock;
    BLOCK_SELECTOR* PtBlock;

    PtBlock = &panel->GetScreen()->BlockLocate;
    PtBlock = &panel->GetScreen()->m_BlockLocate;

    PtBlock->m_MoveVector = wxPoint( 0, 0 );

    GRSetDrawMode( DC, g_XorMode );

    /* Effacement ancien cadre */
    if( erase )
        PtBlock->Draw( panel, DC );
        PtBlock->Draw( panel, DC, wxPoint( 0, 0 ), g_XorMode, PtBlock->m_Color );

    PtBlock->m_BlockLastCursorPosition = panel->GetScreen()->m_Curseur;
    PtBlock->SetEnd( panel->GetScreen()->m_Curseur );

    PtBlock->Draw( panel, DC );
    PtBlock->Draw( panel, DC, wxPoint( 0, 0 ), g_XorMode, PtBlock->m_Color );

    if( PtBlock->m_State == STATE_BLOCK_INIT )
    {
@@ -300,3 +282,37 @@ void DrawAndSizingBlockOutlines( WinEDA_DrawPanel* panel, wxDC* DC, bool erase )
            PtBlock->m_State = STATE_BLOCK_END;
    }
}


/******************************************************************/
void AbortBlockCurrentCommand( WinEDA_DrawPanel* Panel, wxDC* DC )
/******************************************************************/

/*
 *  Cancel Current block operation.
 */
{
    BASE_SCREEN* screen = Panel->GetScreen();

    if( Panel->ManageCurseur )                      /* Erase current drawing on screen */
    {
        Panel->ManageCurseur( Panel, DC, FALSE );   /* Efface dessin fantome */
        Panel->ManageCurseur = NULL;
        Panel->ForceCloseManageCurseur = NULL;
        screen->SetCurItem( NULL );

        /* Delete the picked wrapper if this is a picked list. */
        if( screen->m_BlockLocate.m_Command != BLOCK_PASTE )
            screen->m_BlockLocate.ClearItemsList();
    }

    screen->m_BlockLocate.m_Flags = 0;
    screen->m_BlockLocate.m_State = STATE_NO_BLOCK;

    screen->m_BlockLocate.m_Command = BLOCK_ABORT;
    Panel->m_Parent->HandleBlockEnd( DC );

    screen->m_BlockLocate.m_Command = BLOCK_IDLE;
    Panel->m_Parent->DisplayToolMsg( wxEmptyString );
}
+22 −0
Original line number Diff line number Diff line
@@ -67,6 +67,14 @@ void PICKED_ITEMS_LIST::PICKED_ITEMS_LIST::ClearItemsList()
    m_ItemsList.clear();
}

void PICKED_ITEMS_LIST::ClearListAndDeleteItems()
{
    for(unsigned ii = 0; ii < m_ItemsList.size(); ii++ )
        delete m_ItemsList[ii].m_Item;
    m_ItemsList.clear();
}


ITEM_PICKER PICKED_ITEMS_LIST::GetItemWrapper( unsigned int aIdx )
{
    ITEM_PICKER picker;
@@ -160,6 +168,20 @@ bool PICKED_ITEMS_LIST::RemoveItem( unsigned aIdx )
    return true;
}

/** Function CopyList
 * copy all data from aSource
 * Items picked are not copied. just pointer on them are copied
 */
void PICKED_ITEMS_LIST::CopyList(const PICKED_ITEMS_LIST & aSource)
{
    ITEM_PICKER picker;
    for(unsigned ii = 0; ii < aSource.GetCount(); ii++ )
    {
        picker = aSource.m_ItemsList[ii];
        PushItem(picker);
    }
}


/**********************************************/
/********** UNDO_REDO_CONTAINER ***************/
+6 −6
Original line number Diff line number Diff line
@@ -35,7 +35,7 @@ void WinEDA_DrawFrame::CopyToClipboard( wxCommandEvent& event )

    if(  event.GetId() == ID_GEN_COPY_BLOCK_TO_CLIPBOARD )
    {
        if( GetBaseScreen()->BlockLocate.m_Command != BLOCK_IDLE )
        if( GetBaseScreen()->m_BlockLocate.m_Command != BLOCK_IDLE )
            DrawPanel->SetCursor( wxCursor( DrawPanel->m_PanelCursor =
                        DrawPanel->m_PanelDefaultCursor ) );

@@ -74,13 +74,13 @@ bool DrawPage( WinEDA_DrawPanel* panel )
    /* scale is the ratio resolution/internal units */
    float   scale = 82.0 / panel->m_Parent->m_InternalUnits;

    if( ActiveScreen->BlockLocate.m_Command != BLOCK_IDLE )
    if( ActiveScreen->m_BlockLocate.m_Command != BLOCK_IDLE )
    {
        DrawBlock = TRUE;
        DrawArea.SetX( (int) ( ActiveScreen->BlockLocate.GetX() ) );
        DrawArea.SetY( (int) ( ActiveScreen->BlockLocate.GetY() ) );
        DrawArea.SetWidth( (int) ( ActiveScreen->BlockLocate.GetWidth() ) );
        DrawArea.SetHeight( (int) ( ActiveScreen->BlockLocate.GetHeight() ) );
        DrawArea.SetX( ActiveScreen->m_BlockLocate.GetX() );
        DrawArea.SetY( ActiveScreen->m_BlockLocate.GetY() );
        DrawArea.SetWidth( ActiveScreen->m_BlockLocate.GetWidth() );
        DrawArea.SetHeight( ActiveScreen->m_BlockLocate.GetHeight() );
    }

    /* modification des cadrages et reglages locaux */
+44 −10
Original line number Diff line number Diff line
@@ -488,7 +488,7 @@ int WinEDA_DrawFrame::ReturnBlockCommand( int key )

void WinEDA_DrawFrame::InitBlockPasteInfos()
{
    GetBaseScreen()->BlockLocate.m_BlockDrawStruct = NULL;
    GetBaseScreen()->m_BlockLocate.ClearItemsList();
    DrawPanel->ManageCurseur = NULL;
}

@@ -652,7 +652,31 @@ void WinEDA_DrawFrame::SetLanguage( wxCommandEvent& event )
    }
}

/* used in UpdateStatusBar() when coordinates are in mm
 * try to approximate a coordinate (in 0.001 mm) to an easy to read number
 * ie round the unit value to 0 if unit is 1 or 2, or 8 or 9
 */
double Round_To_0(double x)
{
    long long ix = wxRound(x * 1000); // ix is in 0.001 mm
    if ( x < 0 ) NEGATE(ix);

    int remainder = ix%10;  // remainder is in 0.001 mm
    if ( remainder <= 2 )
        ix -= remainder;    // truncate to the near number
    else if (remainder >= 8 )
        ix += 10 - remainder;   // round to near number

    if ( x < 0 ) NEGATE(ix);
    return (double)ix/1000.0;
}

/** Function UpdateStatusBar()
 * Displays in the bottom of the main window a stust:
 *  - Absolute Cursor coordinates
 *  - Relative Cursor coordinates (relative to the last coordinate stored when actiavte the space bar)
 * ( in this status is also displayed the zoom level, but this is not made by this function)
 */
void WinEDA_DrawFrame::UpdateStatusBar()
{
    wxString        Line;
@@ -670,20 +694,30 @@ void WinEDA_DrawFrame::UpdateStatusBar()
    SetStatusText( Line, 1 );

    /* Display absolute coordinates:  */
    Line.Printf( g_UnitMetric ? wxT( "X %.3f  Y %.3f" ) : wxT( "X %.4f  Y %.4f" ),
                 To_User_Unit( g_UnitMetric, screen->m_Curseur.x,
                               m_InternalUnits ),
                 To_User_Unit( g_UnitMetric, screen->m_Curseur.y,
                               m_InternalUnits ) );
    double dXpos = To_User_Unit( g_UnitMetric, screen->m_Curseur.x, m_InternalUnits );
    double dYpos = To_User_Unit( g_UnitMetric, screen->m_Curseur.y, m_InternalUnits );
    /* When using mm the conversion from 1/10000 inch to mm can give some non easy to read numbers,
     * like 1.999 or 2.001 that be better if displayed 2.000, so small diffs are filtered here.
    */
    if ( g_UnitMetric )
    {
        dXpos = Round_To_0(dXpos);
        dYpos = Round_To_0(dYpos);
    }
    Line.Printf( g_UnitMetric ? wxT( "X %.3f  Y %.3f" ) : wxT( "X %.4f  Y %.4f" ), dXpos, dYpos );
    SetStatusText( Line, 2 );

    /* Display relative coordinates:  */
    dx = screen->m_Curseur.x - screen->m_O_Curseur.x;
    dy = screen->m_Curseur.y - screen->m_O_Curseur.y;

    Line.Printf( g_UnitMetric ? wxT( "x %.3f  y %.3f" ) : wxT( "x %.4f  y %.4f" ),
                 To_User_Unit( g_UnitMetric, dx, m_InternalUnits ),
                 To_User_Unit( g_UnitMetric, dy, m_InternalUnits ) );
    dXpos = To_User_Unit( g_UnitMetric, dx, m_InternalUnits );
    dYpos = To_User_Unit( g_UnitMetric, dy, m_InternalUnits );
    if ( g_UnitMetric )
    {
        dXpos = Round_To_0(dXpos);
        dYpos = Round_To_0(dYpos);
    }
    Line.Printf( g_UnitMetric ? wxT( "x %.3f  y %.3f" ) : wxT( "x %.4f  y %.4f" ), dXpos, dYpos );

    SetStatusText( Line, 3 );
}
Loading