Esempio n. 1
0
bool PCB_EDIT_FRAME::OnHotkeyPlaceItem( wxDC* aDC )
{
    BOARD_ITEM* item = GetCurItem();
    bool no_tool = GetToolId() == ID_NO_TOOL_SELECTED;
    bool itemCurrentlyEdited = item && item->GetFlags();

    m_canvas->SetAutoPanRequest( false );

    if( itemCurrentlyEdited )
    {
        m_canvas->SetIgnoreMouseEvents( true );
        m_canvas->CrossHairOff( aDC );

        switch( item->Type() )
        {
        case PCB_TRACE_T:
        case PCB_VIA_T:
            if( item->IsDragging() )
                PlaceDraggedOrMovedTrackSegment( static_cast<TRACK*>( item ), aDC );

            break;

        case PCB_TEXT_T:
            Place_Texte_Pcb( static_cast<TEXTE_PCB*>( item ), aDC );
            break;

        case PCB_MODULE_TEXT_T:
            PlaceTexteModule( static_cast<TEXTE_MODULE*>( item ), aDC );
            break;

        case PCB_PAD_T:
            PlacePad( static_cast<D_PAD*>( item ), aDC );
            break;

        case PCB_MODULE_T:
            PlaceModule( static_cast<MODULE*>( item ), aDC );
            break;

        case PCB_TARGET_T:
            PlaceTarget( static_cast<PCB_TARGET*>( item ), aDC );
            break;

        case PCB_LINE_T:
            if( no_tool )   // when no tools: existing item moving.
                Place_DrawItem( static_cast<DRAWSEGMENT*>( item ), aDC );

            break;

        default:
            break;
        }

        m_canvas->SetIgnoreMouseEvents( false );
        m_canvas->CrossHairOn( aDC );

        return true;
    }

    return false;
}
void WinEDA_ModuleEditFrame::OnLeftClick(wxDC * DC, const wxPoint& MousePos)
/*************************************************************************/
/* Traite les commandes declenchée par le bouton gauche de la souris,
	quand un outil est deja selectionné
*/
{
EDA_BaseStruct * DrawStruct = m_CurrentScreen->m_CurrentItem;

	GetScreen()->CursorOff(DrawPanel, DC);
	if ( m_ID_current_state == 0 )
		{
		if ( DrawStruct && DrawStruct->m_Flags ) // Commande "POPUP" en cours
			{
			switch (DrawStruct->m_StructType )
				{
				case TYPETEXTEMODULE:
					SaveCopyInUndoList();
					PlaceTexteModule( (TEXTE_MODULE *) DrawStruct, DC);
					break;

				case TYPEEDGEMODULE:
					SaveCopyInUndoList();
					Place_EdgeMod( (EDGE_MODULE *) DrawStruct, DC);
					break;

				case TYPEPAD:
					PlacePad((D_PAD *)DrawStruct, DC);
					break;

				default:
					{
					wxString msg;
					msg.Printf(
wxT("WinEDA_ModEditFrame::ProcessCommand err: m_Flags != 0\nStruct @%p, type %d m_Flag %X")
, DrawStruct, DrawStruct->m_StructType, DrawStruct->m_Flags);
					DisplayError(this, msg);
					DrawStruct->m_Flags = 0;
					break;
					}
				}
			}
		}

	DrawStruct = m_CurrentScreen->m_CurrentItem;
	if ( ! DrawStruct || (DrawStruct->m_Flags == 0) )
		{
		m_CurrentScreen->m_CurrentItem = DrawStruct = ModeditLocateAndDisplay();
		}

	switch ( m_ID_current_state )
		{
		case 0:
			break;

		case ID_NO_SELECT_BUTT:
			break;

		case ID_PCB_CIRCLE_BUTT:
		case ID_PCB_ARC_BUTT:
		case ID_LINE_COMMENT_BUTT:
			if ( ! DrawStruct || DrawStruct->m_Flags == 0)
				{
				int shape = S_SEGMENT;
				if ( m_ID_current_state == ID_PCB_CIRCLE_BUTT) shape = S_CIRCLE;
				if ( m_ID_current_state == ID_PCB_ARC_BUTT) shape = S_ARC;

				m_CurrentScreen->m_CurrentItem =
					Begin_Edge_Module((EDGE_MODULE *) NULL, DC, shape);
				}

			else if ( (DrawStruct->m_Flags & IS_NEW) )
				{
				if ( ((EDGE_MODULE*)DrawStruct)->m_Shape == S_CIRCLE )
					{
					End_Edge_Module((EDGE_MODULE *) DrawStruct, DC);
					m_CurrentScreen->m_CurrentItem = NULL;
					}
				else if ( ((EDGE_MODULE*)DrawStruct)->m_Shape == S_ARC )
					{
					End_Edge_Module((EDGE_MODULE *) DrawStruct, DC);
					m_CurrentScreen->m_CurrentItem = NULL;
					}
				else if ( ((EDGE_MODULE*)DrawStruct)->m_Shape == S_SEGMENT )
					{
					m_CurrentScreen->m_CurrentItem =
						Begin_Edge_Module((EDGE_MODULE *) DrawStruct, DC, 0);
					}
				else  DisplayError(this, wxT("ProcessCommand error: DrawStruct/ flags error"));
				}
			break;

		case ID_MODEDIT_DELETE_ITEM_BUTT:
			if ( !DrawStruct || (DrawStruct->m_Flags == 0) )
				{
				DrawStruct = ModeditLocateAndDisplay();
				if ( DrawStruct && (DrawStruct->m_Flags == 0) )
					{
					SaveCopyInUndoList();
					RemoveStruct(DrawStruct, DC);
					m_CurrentScreen->m_CurrentItem = DrawStruct = NULL;
					}
				}
			break;

		case ID_MODEDIT_PLACE_ANCHOR:
			SaveCopyInUndoList();
			Place_Ancre(m_Pcb->m_Modules, DC);
			m_Pcb->m_Modules->m_Flags = 0;
			m_CurrentScreen->m_Curseur = wxPoint(0,0);
			Recadre_Trace(TRUE);
			Place_Module(m_Pcb->m_Modules, DC);
			RedrawActiveWindow(DC, TRUE);
			SetToolID( 0, wxCURSOR_ARROW, wxEmptyString);
			m_CurrentScreen->m_CurrentItem = NULL;
			break;

		case ID_TEXT_COMMENT_BUTT:
			SaveCopyInUndoList();
			CreateTextModule(m_Pcb->m_Modules, DC);
			break;

		case ID_MODEDIT_ADD_PAD:
			if ( m_Pcb->m_Modules )
			{
				SaveCopyInUndoList();
				AddPad(m_Pcb->m_Modules, DC);
			}
			break;

		default :
				DrawPanel->SetCursor(wxCURSOR_ARROW);
				DisplayError(this, wxT("WinEDA_ModuleEditFrame::ProcessCommand error"));
				m_ID_current_state = 0;
				break;
		}
	GetScreen()->CursorOn(DrawPanel, DC);
}
void FOOTPRINT_EDIT_FRAME::OnLeftClick( wxDC* DC, const wxPoint& MousePos )
{
    BOARD_ITEM* item = GetCurItem();

    m_canvas->CrossHairOff( DC );

    if( GetToolId() == ID_NO_TOOL_SELECTED )
    {
        if( item && item->GetFlags() ) // Move item command in progress
        {
            switch( item->Type() )
            {
            case PCB_MODULE_TEXT_T:
                PlaceTexteModule( static_cast<TEXTE_MODULE*>( item ), DC );
                break;

            case PCB_MODULE_EDGE_T:
                SaveCopyInUndoList( GetBoard()->m_Modules, UR_MODEDIT );
                Place_EdgeMod( static_cast<EDGE_MODULE*>( item ) );
                break;

            case PCB_PAD_T:
                PlacePad( static_cast<D_PAD*>( item ), DC );
                break;

            default:
            {
                wxString msg;
                msg.Printf( wxT( "WinEDA_ModEditFrame::OnLeftClick err:Struct %d, m_Flag %X" ),
                            item->Type(), item->GetFlags() );
                DisplayError( this, msg );
                item->ClearFlags();
                break;
            }
            }
        }

        else
        {
            if( !wxGetKeyState( WXK_SHIFT ) && !wxGetKeyState( WXK_ALT )
                    && !wxGetKeyState( WXK_CONTROL ) )
                item = ModeditLocateAndDisplay();

            SetCurItem( item );
        }
    }

    item = GetCurItem();
    bool no_item_edited = item == NULL || item->GetFlags() == 0;

    switch( GetToolId() )
    {
    case ID_NO_TOOL_SELECTED:
        break;

    case ID_MODEDIT_CIRCLE_TOOL:
    case ID_MODEDIT_ARC_TOOL:
    case ID_MODEDIT_LINE_TOOL:
        if( no_item_edited )
        {
            STROKE_T shape = S_SEGMENT;

            if( GetToolId() == ID_MODEDIT_CIRCLE_TOOL )
                shape = S_CIRCLE;

            if( GetToolId() == ID_MODEDIT_ARC_TOOL )
                shape = S_ARC;

            SetCurItem( Begin_Edge_Module( (EDGE_MODULE*) NULL, DC, shape ) );
        }
        else if( item->IsNew() )
        {
            if( ( (EDGE_MODULE*) item )->GetShape() == S_CIRCLE )
            {
                End_Edge_Module( (EDGE_MODULE*) item );
                SetCurItem( NULL );
                m_canvas->Refresh();
            }
            else if( ( (EDGE_MODULE*) item )->GetShape() == S_ARC )
            {
                End_Edge_Module( (EDGE_MODULE*) item );
                SetCurItem( NULL );
                m_canvas->Refresh();
            }
            else if( ( (EDGE_MODULE*) item )->GetShape() == S_SEGMENT )
            {
                SetCurItem( Begin_Edge_Module( (EDGE_MODULE*) item, DC, S_SEGMENT ) );
            }
            else
            {
                wxMessageBox( wxT( "ProcessCommand error: unknown shape" ) );
            }
        }
        break;

    case ID_MODEDIT_DELETE_TOOL:
        if( ! no_item_edited )    // Item in edit, cannot delete it
            break;

        item = ModeditLocateAndDisplay();

        if( item && item->Type() != PCB_MODULE_T ) // Cannot delete the module itself
        {
            SaveCopyInUndoList( GetBoard()->m_Modules, UR_MODEDIT );
            RemoveStruct( item );
            SetCurItem( NULL );
        }

        break;

    case ID_MODEDIT_ANCHOR_TOOL:
    {
        MODULE* module = GetBoard()->m_Modules;

        if( module == NULL    // No module loaded
                || (module->GetFlags() != 0) )
            break;

        SaveCopyInUndoList( module, UR_MODEDIT );

        // set the new relative internal local coordinates of footprint items
        wxPoint moveVector = module->GetPosition() - GetCrossHairPosition();
        module->MoveAnchorPosition( moveVector );

        // Usually, we do not need to change twice the anchor position,
        // so deselect the active tool
        SetToolID( ID_NO_TOOL_SELECTED, m_canvas->GetDefaultCursor(), wxEmptyString );
        SetCurItem( NULL );
        m_canvas->Refresh();
    }
    break;

    case ID_MODEDIT_PLACE_GRID_COORD:
        m_canvas->DrawGridAxis( DC, GR_XOR, GetBoard()->GetGridOrigin() );
        SetGridOrigin( GetCrossHairPosition() );
        m_canvas->DrawGridAxis( DC, GR_COPY, GetBoard()->GetGridOrigin() );
        GetScreen()->SetModify();
        break;

    case ID_MODEDIT_TEXT_TOOL:
        if( GetBoard()->m_Modules == NULL )
            break;

        SaveCopyInUndoList( GetBoard()->m_Modules, UR_MODEDIT );
        CreateTextModule( GetBoard()->m_Modules, DC );
        break;

    case ID_MODEDIT_PAD_TOOL:
        if( GetBoard()->m_Modules )
        {
            SaveCopyInUndoList( GetBoard()->m_Modules, UR_MODEDIT );
            AddPad( GetBoard()->m_Modules, true );
        }

        break;

    default:
        DisplayError( this, wxT( "FOOTPRINT_EDIT_FRAME::ProcessCommand error" ) );
        SetToolID( ID_NO_TOOL_SELECTED, m_canvas->GetDefaultCursor(), wxEmptyString );
    }

    m_canvas->CrossHairOn( DC );
}
Esempio n. 4
0
/* Route a trace on the BOARD.
 * Parameters:
 * 1 side / 2 sides (0 / 1)
 * Coord source (row, col)
 * Coord destination (row, col)
 * Net_code
 * Pointer to the ratsnest reference
 *
 * Returns:
 * SUCCESS if routed
 * TRIVIAL_SUCCESS if pads are connected by overlay (no track needed)
 * If failure NOSUCCESS
 * Escape STOP_FROM_ESC if demand
 * ERR_MEMORY if memory allocation failed.
 */
static int Autoroute_One_Track( PCB_EDIT_FRAME* pcbframe,
                                wxDC*           DC,
                                int             two_sides,
                                int             row_source,
                                int             col_source,
                                int             row_target,
                                int             col_target,
                                RATSNEST_ITEM*  pt_rat )
{
    int          r, c, side, d, apx_dist, nr, nc;
    int          result, skip;
    int          i;
    long         curcell, newcell, buddy, lastopen, lastclos, lastmove;
    int          newdist, olddir, _self;
    int          current_net_code;
    int          marge;
    LSET         padLayerMaskStart;    // Mask layers belonging to the starting pad.
    LSET         padLayerMaskEnd;      // Mask layers belonging to the ending pad.

    LSET         topLayerMask( g_Route_Layer_TOP );

    LSET         bottomLayerMask( g_Route_Layer_BOTTOM );

    LSET         routeLayerMask;       // Mask two layers for routing.

    LSET         tab_mask[2];           // Enables the calculation of the mask layer being
                                        // tested. (side = TOP or BOTTOM)
    int          start_mask_layer = 0;
    wxString     msg;

    // @todo this could be a bottle neck
    LSET all_cu = LSET::AllCuMask( pcbframe->GetBoard()->GetCopperLayerCount() );

    wxBusyCursor dummy_cursor;      // Set an hourglass cursor while routing a
                                    // track

    result = NOSUCCESS;

    marge = s_Clearance + ( pcbframe->GetDesignSettings().GetCurrentTrackWidth() / 2 );

    // clear direction flags
    i = RoutingMatrix.m_Nrows * RoutingMatrix.m_Ncols * sizeof(DIR_CELL);

    if( two_sides )
        memset( RoutingMatrix.m_DirSide[TOP], FROM_NOWHERE, i );
    memset( RoutingMatrix.m_DirSide[BOTTOM], FROM_NOWHERE, i );

    lastopen = lastclos = lastmove = 0;

    // Set tab_masque[side] for final test of routing.
    if( two_sides )
        tab_mask[TOP] = topLayerMask;
    tab_mask[BOTTOM] = bottomLayerMask;

    // Set active layers mask.
    routeLayerMask = topLayerMask | bottomLayerMask;

    pt_cur_ch = pt_rat;

    current_net_code  = pt_rat->GetNet();
    padLayerMaskStart = pt_cur_ch->m_PadStart->GetLayerSet();

    padLayerMaskEnd = pt_cur_ch->m_PadEnd->GetLayerSet();


    /* First Test if routing possible ie if the pads are accessible
     * on the routing layers.
     */
    if( ( routeLayerMask & padLayerMaskStart ) == 0 )
        goto end_of_route;

    if( ( routeLayerMask & padLayerMaskEnd ) == 0 )
        goto end_of_route;

    /* Then test if routing possible ie if the pads are accessible
     * On the routing grid (1 grid point must be in the pad)
     */
    {
        int cX = ( RoutingMatrix.m_GridRouting * col_source )
                 + pcbframe->GetBoard()->GetBoundingBox().GetX();
        int cY = ( RoutingMatrix.m_GridRouting * row_source )
                 + pcbframe->GetBoard()->GetBoundingBox().GetY();
        int dx = pt_cur_ch->m_PadStart->GetSize().x / 2;
        int dy = pt_cur_ch->m_PadStart->GetSize().y / 2;
        int px = pt_cur_ch->m_PadStart->GetPosition().x;
        int py = pt_cur_ch->m_PadStart->GetPosition().y;

        if( ( ( int( pt_cur_ch->m_PadStart->GetOrientation() ) / 900 ) & 1 ) != 0 )
            std::swap( dx, dy );

        if( ( abs( cX - px ) > dx ) || ( abs( cY - py ) > dy ) )
            goto end_of_route;

        cX = ( RoutingMatrix.m_GridRouting * col_target )
             + pcbframe->GetBoard()->GetBoundingBox().GetX();
        cY = ( RoutingMatrix.m_GridRouting * row_target )
             + pcbframe->GetBoard()->GetBoundingBox().GetY();
        dx = pt_cur_ch->m_PadEnd->GetSize().x / 2;
        dy = pt_cur_ch->m_PadEnd->GetSize().y / 2;
        px = pt_cur_ch->m_PadEnd->GetPosition().x;
        py = pt_cur_ch->m_PadEnd->GetPosition().y;

        if( ( ( int( pt_cur_ch->m_PadEnd->GetOrientation() ) / 900) & 1 ) != 0 )
            std::swap( dx, dy );

        if( ( abs( cX - px ) > dx ) || ( abs( cY - py ) > dy ) )
            goto end_of_route;
    }

    // Test the trivial case: direct connection overlay pads.
    if( row_source == row_target  && col_source == col_target &&
            ( padLayerMaskEnd & padLayerMaskStart & all_cu ).any() )
    {
        result = TRIVIAL_SUCCESS;
        goto end_of_route;
    }

    // Placing the bit to remove obstacles on 2 pads to a link.
    pcbframe->SetStatusText( wxT( "Gen Cells" ) );

    PlacePad( pt_cur_ch->m_PadStart, CURRENT_PAD, marge, WRITE_OR_CELL );
    PlacePad( pt_cur_ch->m_PadEnd, CURRENT_PAD, marge, WRITE_OR_CELL );

    // Regenerates the remaining barriers (which may encroach on the
    // placement bits precedent)
    i = pcbframe->GetBoard()->GetPadCount();

    for( unsigned ii = 0; ii < pcbframe->GetBoard()->GetPadCount(); ii++ )
    {
        D_PAD* ptr = pcbframe->GetBoard()->GetPad( ii );

        if( ( pt_cur_ch->m_PadStart != ptr ) && ( pt_cur_ch->m_PadEnd != ptr ) )
        {
            PlacePad( ptr, ~CURRENT_PAD, marge, WRITE_AND_CELL );
        }
    }

    InitQueue(); // initialize the search queue
    apx_dist = RoutingMatrix.GetApxDist( row_source, col_source, row_target, col_target );

    // Initialize first search.
    if( two_sides )   // Preferred orientation.
    {
        if( abs( row_target - row_source ) > abs( col_target - col_source ) )
        {
            if( ( padLayerMaskStart & topLayerMask ).any() )
            {
                start_mask_layer = 2;

                if( SetQueue( row_source, col_source, TOP, 0, apx_dist,
                              row_target, col_target ) == 0 )
                {
                    return ERR_MEMORY;
                }
            }

            if( ( padLayerMaskStart & bottomLayerMask ).any() )
            {
                start_mask_layer |= 1;

                if( SetQueue( row_source, col_source, BOTTOM, 0, apx_dist,
                              row_target, col_target ) == 0 )
                {
                    return ERR_MEMORY;
                }
            }
        }
        else
        {
            if( ( padLayerMaskStart & bottomLayerMask ).any() )
            {
                start_mask_layer = 1;

                if( SetQueue( row_source, col_source, BOTTOM, 0, apx_dist,
                              row_target, col_target ) == 0 )
                {
                    return ERR_MEMORY;
                }
            }

            if( ( padLayerMaskStart & topLayerMask ).any() )
            {
                start_mask_layer |= 2;

                if( SetQueue( row_source, col_source, TOP, 0, apx_dist,
                              row_target, col_target ) == 0 )
                {
                    return ERR_MEMORY;
                }
            }
        }
    }
    else if( ( padLayerMaskStart & bottomLayerMask ).any() )
    {
        start_mask_layer = 1;

        if( SetQueue( row_source, col_source, BOTTOM, 0, apx_dist, row_target, col_target ) == 0 )
        {
            return ERR_MEMORY;
        }
    }

    // search until success or we exhaust all possibilities
    GetQueue( &r, &c, &side, &d, &apx_dist );

    for( ; r != ILLEGAL; GetQueue( &r, &c, &side, &d, &apx_dist ) )
    {
        curcell = RoutingMatrix.GetCell( r, c, side );

        if( curcell & CURRENT_PAD )
            curcell &= ~HOLE;

        if( (r == row_target) && (c == col_target)  // success if layer OK
           && (tab_mask[side] & padLayerMaskEnd).any() )
        {
            // Remove link.
            GRSetDrawMode( DC, GR_XOR );
            GRLine( pcbframe->GetCanvas()->GetClipBox(),
                    DC,
                    segm_oX,
                    segm_oY,
                    segm_fX,
                    segm_fY,
                    0,
                    WHITE );

            // Generate trace.
            if( Retrace( pcbframe, DC, row_source, col_source,
                         row_target, col_target, side, current_net_code ) )
            {
                result = SUCCESS;   // Success : Route OK
            }

            break;                  // Routing complete.
        }

        if( pcbframe->GetCanvas()->GetAbortRequest() )
        {
            result = STOP_FROM_ESC;
            break;
        }

        // report every COUNT new nodes or so
        #define COUNT 20000

        if( ( OpenNodes - lastopen > COUNT )
           || ( ClosNodes - lastclos > COUNT )
           || ( MoveNodes - lastmove > COUNT ) )
        {
            lastopen = OpenNodes;
            lastclos = ClosNodes;
            lastmove = MoveNodes;
            msg.Printf( wxT( "Activity: Open %d   Closed %d   Moved %d" ),
                        OpenNodes, ClosNodes, MoveNodes );
            pcbframe->SetStatusText( msg );
        }

        _self = 0;

        if( curcell & HOLE )
        {
            _self = 5;

            // set 'present' bits
            for( i = 0; i < 8; i++ )
            {
                selfok2[i].present = 0;

                if( curcell & selfok2[i].trace )
                    selfok2[i].present = 1;
            }
        }

        for( i = 0; i < 8; i++ ) // consider neighbors
        {
            nr = r + delta[i][0];
            nc = c + delta[i][1];

            // off the edge?
            if( nr < 0 || nr >= RoutingMatrix.m_Nrows ||
                nc < 0 || nc >= RoutingMatrix.m_Ncols )
                continue;  // off the edge

            if( _self == 5 && selfok2[i].present )
                continue;

            newcell = RoutingMatrix.GetCell( nr, nc, side );

            if( newcell & CURRENT_PAD )
                newcell &= ~HOLE;

            // check for non-target hole
            if( newcell & HOLE )
            {
                if( nr != row_target || nc != col_target )
                    continue;
            }
            // check for traces
            else if( newcell & HOLE & ~(newmask[i]) )
            {
                continue;
            }

            // check blocking on corner neighbors
            if( delta[i][0] && delta[i][1] )
            {
                // check first buddy
                buddy = RoutingMatrix.GetCell( r + blocking[i].r1, c + blocking[i].c1, side );

                if( buddy & CURRENT_PAD )
                    buddy &= ~HOLE;

                if( buddy & HOLE )
                    continue;

//              if (buddy & (blocking[i].b1)) continue;
                // check second buddy
                buddy = RoutingMatrix.GetCell( r + blocking[i].r2, c + blocking[i].c2, side );

                if( buddy & CURRENT_PAD )
                    buddy &= ~HOLE;

                if( buddy & HOLE )
                    continue;

//              if (buddy & (blocking[i].b2)) continue;
            }

            olddir  = RoutingMatrix.GetDir( r, c, side );
            newdist = d + RoutingMatrix.CalcDist( ndir[i], olddir,
                                    ( olddir == FROM_OTHERSIDE ) ?
                                    RoutingMatrix.GetDir( r, c, 1 - side ) : 0, side );

            // if (a) not visited yet, or (b) we have
            // found a better path, add it to queue
            if( !RoutingMatrix.GetDir( nr, nc, side ) )
            {
                RoutingMatrix.SetDir( nr, nc, side, ndir[i] );
                RoutingMatrix.SetDist( nr, nc, side, newdist );

                if( SetQueue( nr, nc, side, newdist,
                              RoutingMatrix.GetApxDist( nr, nc, row_target, col_target ),
                              row_target, col_target ) == 0 )
                {
                    return ERR_MEMORY;
                }
            }
            else if( newdist < RoutingMatrix.GetDist( nr, nc, side ) )
            {
                RoutingMatrix.SetDir( nr, nc, side, ndir[i] );
                RoutingMatrix.SetDist( nr, nc, side, newdist );
                ReSetQueue( nr, nc, side, newdist,
                            RoutingMatrix.GetApxDist( nr, nc, row_target, col_target ),
                            row_target, col_target );
            }
        }

        //* Test the other layer. *
        if( two_sides )
        {
            olddir = RoutingMatrix.GetDir( r, c, side );

            if( olddir == FROM_OTHERSIDE )
                continue;   // useless move, so don't bother

            if( curcell )   // can't drill via if anything here
                continue;

            // check for holes or traces on other side
            if( ( newcell = RoutingMatrix.GetCell( r, c, 1 - side ) ) != 0 )
                continue;

            // check for nearby holes or traces on both sides
            for( skip = 0, i = 0; i < 8; i++ )
            {
                nr = r + delta[i][0]; nc = c + delta[i][1];

                if( nr < 0 || nr >= RoutingMatrix.m_Nrows ||
                    nc < 0 || nc >= RoutingMatrix.m_Ncols )
                    continue;  // off the edge !!

                if( RoutingMatrix.GetCell( nr, nc, side ) /* & blocking2[i] */ )
                {
                    skip = 1; // can't drill via here
                    break;
                }

                if( RoutingMatrix.GetCell( nr, nc, 1 - side ) /* & blocking2[i] */ )
                {
                    skip = 1; // can't drill via here
                    break;
                }
            }

            if( skip )      // neighboring hole or trace?
                continue;   // yes, can't drill via here

            newdist = d + RoutingMatrix.CalcDist( FROM_OTHERSIDE, olddir, 0, side );

            /*  if (a) not visited yet,
             *  or (b) we have found a better path,
             *  add it to queue */
            if( !RoutingMatrix.GetDir( r, c, 1 - side ) )
            {
                RoutingMatrix.SetDir( r, c, 1 - side, FROM_OTHERSIDE );
                RoutingMatrix.SetDist( r, c, 1 - side, newdist );

                if( SetQueue( r, c, 1 - side, newdist, apx_dist, row_target, col_target ) == 0 )
                {
                    return ERR_MEMORY;
                }
            }
            else if( newdist < RoutingMatrix.GetDist( r, c, 1 - side ) )
            {
                RoutingMatrix.SetDir( r, c, 1 - side, FROM_OTHERSIDE );
                RoutingMatrix.SetDist( r, c, 1 - side, newdist );
                ReSetQueue( r, c,
                            1 - side,
                            newdist,
                            apx_dist,
                            row_target,
                            col_target );
            }
        }     // Finished attempt to route on other layer.
    }

end_of_route:
    PlacePad( pt_cur_ch->m_PadStart, ~CURRENT_PAD, marge, WRITE_AND_CELL );
    PlacePad( pt_cur_ch->m_PadEnd, ~CURRENT_PAD, marge, WRITE_AND_CELL );

    msg.Printf( wxT( "Activity: Open %d   Closed %d   Moved %d"),
                OpenNodes, ClosNodes, MoveNodes );
    pcbframe->SetStatusText( msg );

    return result;
}
/* Handle the left button mouse click, when a tool is active
 */
void PCB_EDIT_FRAME::OnLeftClick( wxDC* aDC, const wxPoint& aPosition )
{
    BOARD_ITEM* DrawStruct = GetCurItem();
    bool        exit = false;
    bool no_tool = GetToolId() == ID_NO_TOOL_SELECTED;

    if( no_tool || ( DrawStruct && DrawStruct->GetFlags() ) )
    {
        m_canvas->SetAutoPanRequest( false );

        if( DrawStruct && DrawStruct->GetFlags() ) // Command in progress
        {
            m_canvas->SetIgnoreMouseEvents( true );
            m_canvas->CrossHairOff( aDC );

            switch( DrawStruct->Type() )
            {
            case PCB_ZONE_AREA_T:
                if( DrawStruct->IsNew() )
                {
                    m_canvas->SetAutoPanRequest( true );
                    Begin_Zone( aDC );
                }
                else
                {
                    End_Move_Zone_Corner_Or_Outlines( aDC, (ZONE_CONTAINER*) DrawStruct );
                }

                exit = true;
                break;

            case PCB_TRACE_T:
            case PCB_VIA_T:
                if( DrawStruct->IsDragging() )
                {
                    PlaceDraggedOrMovedTrackSegment( (TRACK*) DrawStruct, aDC );
                    exit = true;
                }

                break;

            case PCB_TEXT_T:
                Place_Texte_Pcb( (TEXTE_PCB*) DrawStruct, aDC );
                exit = true;
                break;

            case PCB_MODULE_TEXT_T:
                PlaceTexteModule( (TEXTE_MODULE*) DrawStruct, aDC );
                exit = true;
                break;

            case PCB_PAD_T:
                PlacePad( (D_PAD*) DrawStruct, aDC );
                exit = true;
                break;

            case PCB_MODULE_T:
                PlaceModule( (MODULE*) DrawStruct, aDC );
                exit = true;
                break;

            case PCB_TARGET_T:
                PlaceTarget( (PCB_TARGET*) DrawStruct, aDC );
                exit = true;
                break;

            case PCB_LINE_T:
                if( no_tool )   // when no tools: existing item moving.
                {
                    Place_DrawItem( (DRAWSEGMENT*) DrawStruct, aDC );
                    exit = true;
                }

                break;

            case PCB_DIMENSION_T:
                if( ! DrawStruct->IsNew() )
                {   // We are moving the text of an existing dimension. Place it
                    PlaceDimensionText( (DIMENSION*) DrawStruct, aDC );
                    exit = true;
                }
                break;

            default:
                DisplayError( this,
                              wxT( "PCB_EDIT_FRAME::OnLeftClick() err: DrawType %d m_Flags != 0" ),
                              DrawStruct->Type() );
                exit = true;
                break;
            }

            m_canvas->SetIgnoreMouseEvents( false );
            m_canvas->CrossHairOn( aDC );

            if( exit )
                return;
        }
        else if( !wxGetKeyState( WXK_SHIFT ) && !wxGetKeyState( WXK_ALT )
                && !wxGetKeyState( WXK_CONTROL ) )
        {
            DrawStruct = PcbGeneralLocateAndDisplay();

            if( DrawStruct )
                SendMessageToEESCHEMA( DrawStruct );
        }
    }

    if( DrawStruct ) // display netclass info for zones, tracks and pads
    {
        switch( DrawStruct->Type() )
        {
        case PCB_ZONE_AREA_T:
        case PCB_TRACE_T:
        case PCB_VIA_T:
        case PCB_PAD_T:
            GetDesignSettings().SetCurrentNetClass(
                ((BOARD_CONNECTED_ITEM*)DrawStruct)->GetNetClassName() );
            updateTraceWidthSelectBox();
            updateViaSizeSelectBox();
            break;

        default:
           break;
        }
    }

    switch( GetToolId() )
    {
    case ID_MAIN_MENUBAR:
    case ID_NO_TOOL_SELECTED:
        break;

    case ID_PCB_MUWAVE_TOOL_SELF_CMD:
    case ID_PCB_MUWAVE_TOOL_GAP_CMD:
    case ID_PCB_MUWAVE_TOOL_STUB_CMD:
    case ID_PCB_MUWAVE_TOOL_STUB_ARC_CMD:
    case ID_PCB_MUWAVE_TOOL_FUNCTION_SHAPE_CMD:
        MuWaveCommand( aDC, aPosition );
        break;

    case ID_PCB_HIGHLIGHT_BUTT:
    {
        int netcode = SelectHighLight( aDC );

        if( netcode < 0 )
            SetMsgPanel( GetBoard() );
        else
        {
            NETINFO_ITEM* net = GetBoard()->FindNet( netcode );

            if( net )
            {
                MSG_PANEL_ITEMS items;
                net->GetMsgPanelInfo( items );
                SetMsgPanel( items );
            }
        }
    }
    break;

    case ID_PCB_SHOW_1_RATSNEST_BUTT:
        DrawStruct = PcbGeneralLocateAndDisplay();
        Show_1_Ratsnest( DrawStruct, aDC );

        if( DrawStruct )
            SendMessageToEESCHEMA( DrawStruct );

        break;

    case ID_PCB_MIRE_BUTT:
        if( (DrawStruct == NULL) || (DrawStruct->GetFlags() == 0) )
        {
            SetCurItem( (BOARD_ITEM*) CreateTarget( aDC ) );
            m_canvas->MoveCursorToCrossHair();
        }
        else if( DrawStruct->Type() == PCB_TARGET_T )
        {
            PlaceTarget( (PCB_TARGET*) DrawStruct, aDC );
        }
        else
        {
            DisplayError( this, wxT( "OnLeftClick err: not a PCB_TARGET_T" ) );
        }

        break;

    case ID_PCB_CIRCLE_BUTT:
    case ID_PCB_ARC_BUTT:
    case ID_PCB_ADD_LINE_BUTT:
        {
            STROKE_T shape = S_SEGMENT;

            if( GetToolId() == ID_PCB_CIRCLE_BUTT )
                shape = S_CIRCLE;

            if( GetToolId() == ID_PCB_ARC_BUTT )
                shape = S_ARC;

            if( IsCopperLayer( GetActiveLayer() ) )
            {
                DisplayError( this, _( "Graphic not allowed on Copper layers" ) );
                break;
            }

            if( (DrawStruct == NULL) || (DrawStruct->GetFlags() == 0) )
            {
                DrawStruct = (BOARD_ITEM*) Begin_DrawSegment( NULL, shape, aDC );
                SetCurItem( DrawStruct );
                m_canvas->SetAutoPanRequest( true );
            }
            else if( DrawStruct
                   && (DrawStruct->Type() == PCB_LINE_T)
                   && DrawStruct->IsNew() )
            {
                DrawStruct = (BOARD_ITEM*) Begin_DrawSegment( (DRAWSEGMENT*) DrawStruct, shape, aDC );
                SetCurItem( DrawStruct );
                m_canvas->SetAutoPanRequest( true );
            }
        }
        break;

    case ID_TRACK_BUTT:
        if( !IsCopperLayer( GetActiveLayer() ) )
        {
            DisplayError( this, _( "Tracks on Copper layers only " ) );
            break;
        }

        if( (DrawStruct == NULL) || (DrawStruct->GetFlags() == 0) )
        {
            DrawStruct = (BOARD_ITEM*) Begin_Route( NULL, aDC );
            SetCurItem( DrawStruct );

            if( DrawStruct )
                m_canvas->SetAutoPanRequest( true );
        }
        else if( DrawStruct && DrawStruct->IsNew() )
        {
            TRACK* track = Begin_Route( (TRACK*) DrawStruct, aDC );

            // SetCurItem() must not write to the msg panel
            // because a track info is displayed while moving the mouse cursor
            if( track )  // A new segment was created
                SetCurItem( DrawStruct = (BOARD_ITEM*) track, false );

            m_canvas->SetAutoPanRequest( true );
        }

        break;

    case ID_PCB_ZONES_BUTT:
    case ID_PCB_KEEPOUT_AREA_BUTT:
        /* ZONE or KEEPOUT Tool is selected. Determine action for a left click:
         *  this can be start a new zone or select and move an existing zone outline corner
         *  if found near the mouse cursor
         */
        if( (DrawStruct == NULL) || (DrawStruct->GetFlags() == 0) )
        {
            if( Begin_Zone( aDC ) )
            {
                m_canvas->SetAutoPanRequest( true );
                DrawStruct = GetBoard()->m_CurrentZoneContour;
                GetScreen()->SetCurItem( DrawStruct );
            }
        }
        else if( DrawStruct && (DrawStruct->Type() == PCB_ZONE_AREA_T) && DrawStruct->IsNew() )
        {   // Add a new corner to the current outline being created:
            m_canvas->SetAutoPanRequest( true );
            Begin_Zone( aDC );
            DrawStruct = GetBoard()->m_CurrentZoneContour;
            GetScreen()->SetCurItem( DrawStruct );
        }
        else
        {
            DisplayError( this, wxT( "PCB_EDIT_FRAME::OnLeftClick() zone internal error" ) );
        }

        break;

    case ID_PCB_ADD_TEXT_BUTT:
        if( IsLayerInList( EDGE_LAYER, GetActiveLayer() ) )
        {
            DisplayError( this,
                          _( "Texts not allowed on Edge Cut layer" ) );
            break;
        }

        if( (DrawStruct == NULL) || (DrawStruct->GetFlags() == 0) )
        {
            SetCurItem( CreateTextePcb( aDC ) );
            m_canvas->MoveCursorToCrossHair();
            m_canvas->SetAutoPanRequest( true );
        }
        else if( DrawStruct->Type() == PCB_TEXT_T )
        {
            Place_Texte_Pcb( (TEXTE_PCB*) DrawStruct, aDC );
            m_canvas->SetAutoPanRequest( false );
        }
        else
        {
            DisplayError( this, wxT( "OnLeftClick err: not a PCB_TEXT_T" ) );
        }

        break;

    case ID_PCB_MODULE_BUTT:
        if( (DrawStruct == NULL) || (DrawStruct->GetFlags() == 0) )
        {
            m_canvas->MoveCursorToCrossHair();
            DrawStruct = (BOARD_ITEM*) LoadModuleFromLibrary(
                    wxEmptyString, Prj().PcbFootprintLibs(), true, aDC );

            SetCurItem( DrawStruct );

            if( DrawStruct )
                StartMoveModule( (MODULE*) DrawStruct, aDC, false );
        }
        else if( DrawStruct->Type() == PCB_MODULE_T )
        {
            PlaceModule( (MODULE*) DrawStruct, aDC );
            m_canvas->SetAutoPanRequest( false );
        }
        else
        {
            DisplayError( this, wxT( "Internal err: Struct not PCB_MODULE_T" ) );
        }

        break;

    case ID_PCB_DIMENSION_BUTT:
        if( IsLayerInList( EDGE_LAYER|ALL_CU_LAYERS, GetActiveLayer() ) )
        {
            DisplayError( this,
                          _( "Dimension not allowed on Copper or Edge Cut layers" ) );
            break;
        }

        if( (DrawStruct == NULL) || (DrawStruct->GetFlags() == 0) )
        {
            DrawStruct = (BOARD_ITEM*) EditDimension( NULL, aDC );
            SetCurItem( DrawStruct );
            m_canvas->SetAutoPanRequest( true );
        }
        else if( DrawStruct && (DrawStruct->Type() == PCB_DIMENSION_T) && DrawStruct->IsNew() )
        {
            DrawStruct = (BOARD_ITEM*) EditDimension( (DIMENSION*) DrawStruct, aDC );
            SetCurItem( DrawStruct );
            m_canvas->SetAutoPanRequest( true );
        }
        else
        {
            DisplayError( this,
                          wxT( "PCB_EDIT_FRAME::OnLeftClick() error item is not a DIMENSION" ) );
        }

        break;

    case ID_PCB_DELETE_ITEM_BUTT:
        if( !DrawStruct || !DrawStruct->GetFlags() )
        {
            DrawStruct = PcbGeneralLocateAndDisplay();

            if( DrawStruct && (DrawStruct->GetFlags() == 0) )
            {
                RemoveStruct( DrawStruct, aDC );
                SetCurItem( DrawStruct = NULL );
            }
        }

        break;

    case ID_PCB_PLACE_OFFSET_COORD_BUTT:
        m_canvas->DrawAuxiliaryAxis( aDC, GR_XOR );
        SetAuxOrigin( GetCrossHairPosition() );
        m_canvas->DrawAuxiliaryAxis( aDC, GR_COPY );
        OnModify();
        break;

    case ID_PCB_PLACE_GRID_COORD_BUTT:
        m_canvas->DrawGridAxis( aDC, GR_XOR, GetBoard()->GetGridOrigin() );
        SetGridOrigin( GetCrossHairPosition() );
        m_canvas->DrawGridAxis( aDC, GR_COPY, GetBoard()->GetGridOrigin() );
        break;

    default:
        DisplayError( this, wxT( "PCB_EDIT_FRAME::OnLeftClick() id error" ) );
        SetToolID( ID_NO_TOOL_SELECTED, m_canvas->GetDefaultCursor(), wxEmptyString );
        break;
    }
}
Esempio n. 6
0
void WinEDA_PcbFrame::OnLeftClick(wxDC * DC, const wxPoint& MousePos)
/********************************************************************/
/* Traite les commandes declenchée par le bouton gauche de la souris,
	quand un outil est deja selectionné
*/
{
    EDA_BaseStruct * DrawStruct = CURRENT_ITEM;

    if ( (m_ID_current_state == 0) || ( DrawStruct && DrawStruct->m_Flags ))
    {
        DrawPanel->m_AutoPAN_Request = FALSE;
        if ( DrawStruct && DrawStruct->m_Flags ) // Commande "POPUP" en cours
        {
            switch (DrawStruct->m_StructType )
            {
            case TYPETRACK:
            case TYPEVIA:
                if ( CURRENT_ITEM->m_Flags & IS_DRAGGED )
                {
                    PlaceDraggedTrackSegment((TRACK *)DrawStruct, DC);
                    return;
                }
                break;

            case TYPETEXTE:
                Place_Texte_Pcb((TEXTE_PCB *)DrawStruct, DC);
                return;
                break;

            case TYPETEXTEMODULE:
                PlaceTexteModule( (TEXTE_MODULE *) DrawStruct, DC);
                return;
                break;

            case TYPEPAD:
                PlacePad((D_PAD *)DrawStruct, DC);
                return;
                break;

            case TYPEMODULE:
                Place_Module((MODULE *)DrawStruct, DC);
                return;
                break;

            case TYPEMIRE:
                Place_Mire((MIREPCB *)DrawStruct, DC);
                return;
                break;

            case TYPEDRAWSEGMENT:
                if (m_ID_current_state == 0)
                {
                    Place_DrawItem( (DRAWSEGMENT * )DrawStruct, DC);
                    return;
                }
                break;

            default:
                if (m_ID_current_state == 0)
                {
                    DisplayError(this,
                                 wxT("WinEDA_PcbFrame::OnLeftClick() err: m_Flags != 0") );
                    return;
                }
            }
        }
        else
        {
            DrawStruct = PcbGeneralLocateAndDisplay();
        }
    }

    switch ( m_ID_current_state )
    {
    case ID_MAIN_MENUBAR:
    case 0:
        break;

    case ID_NO_SELECT_BUTT:
        break;


    case ID_PCB_MUWAVE_TOOL_SELF_CMD:
    case ID_PCB_MUWAVE_TOOL_GAP_CMD:
    case ID_PCB_MUWAVE_TOOL_STUB_CMD:
    case ID_PCB_MUWAVE_TOOL_STUB_ARC_CMD:
    case ID_PCB_MUWAVE_TOOL_FUNCTION_SHAPE_CMD:
        MuWaveCommand(DC, MousePos);
        break;


    case ID_PCB_HIGHLIGHT_BUTT:
    {
        int netcode = Select_High_Light(DC);
        if ( netcode < 0 ) Affiche_Infos_Status_Pcb(this);
        else Affiche_Infos_Equipot(netcode, this);
    }
    break;

    case ID_PCB_SHOW_1_RATSNEST_BUTT:
        DrawStruct = PcbGeneralLocateAndDisplay();
        Show_1_Ratsnest(DrawStruct, DC);
        break;

    case ID_PCB_MIRE_BUTT:
        if ( (DrawStruct == NULL) || (DrawStruct->m_Flags == 0) )
        {
            GetScreen()->m_CurrentItem = Create_Mire( DC );
            DrawPanel->MouseToCursorSchema();
        }
        else if (DrawStruct->m_StructType == TYPEMIRE )
        {
            Place_Mire((MIREPCB *)DrawStruct, DC);
        }
        else DisplayError(this, wxT("Internal err: Struct not TYPEMIRE"));
        break;

    case ID_PCB_CIRCLE_BUTT:
    case ID_PCB_ARC_BUTT:
    case ID_LINE_COMMENT_BUTT:
    {
        int shape = S_SEGMENT;
        if ( m_ID_current_state == ID_PCB_CIRCLE_BUTT) shape = S_CIRCLE;
        if ( m_ID_current_state == ID_PCB_ARC_BUTT) shape = S_ARC;

        if ( GetScreen()->m_Active_Layer <= CMP_N )
        {
            DisplayError(this, _("Graphic not autorized on Copper layers"));
            break;
        }
        if ( (DrawStruct == NULL) || (DrawStruct->m_Flags == 0) )
        {
            GetScreen()->m_CurrentItem = DrawStruct =
                                             Begin_DrawSegment(NULL, shape, DC);
            DrawPanel->m_AutoPAN_Request = TRUE;
        }
        else if (DrawStruct &&
                 (DrawStruct->m_StructType == TYPEDRAWSEGMENT) &&
                 (DrawStruct->m_Flags & IS_NEW) )
        {
            GetScreen()->m_CurrentItem = DrawStruct =
                                             Begin_DrawSegment((DRAWSEGMENT *)DrawStruct, shape, DC);
            DrawPanel->m_AutoPAN_Request = TRUE;
        }
        break;
    }

    case ID_TRACK_BUTT:
        if ( GetScreen()->m_Active_Layer > CMP_N )
        {
            DisplayError(this, _("Tracks on Copper layers only "));
            break;
        }

        if ( (DrawStruct == NULL) || (DrawStruct->m_Flags == 0) )
        {
            GetScreen()->m_CurrentItem = DrawStruct =
                                             Begin_Route(NULL, DC);
            if ( DrawStruct ) DrawPanel->m_AutoPAN_Request = TRUE;
        }
        else if (DrawStruct &&
//					(DrawStruct->m_StructType == TYPETRACK) &&
                 (DrawStruct->m_Flags & IS_NEW) )
        {
            TRACK * track = Begin_Route((TRACK *) DrawStruct, DC);
            if ( track )	// c'est a dire si OK
                GetScreen()->m_CurrentItem = DrawStruct = track;
            DrawPanel->m_AutoPAN_Request = TRUE;
        }
        break;


    case ID_PCB_ZONES_BUTT:
        if ( (DrawStruct == NULL) || (DrawStruct->m_Flags == 0) )
        {
            GetScreen()->m_CurrentItem = DrawStruct =
                                             Begin_Zone();
        }
        else if (DrawStruct &&
                 (DrawStruct->m_StructType == TYPEEDGEZONE) &&
                 (DrawStruct->m_Flags & IS_NEW) )
        {
            GetScreen()->m_CurrentItem = DrawStruct =
                                             Begin_Zone();
        }
        else DisplayError(this, wxT("Edit: zone internal error"));
        break;

    case ID_TEXT_COMMENT_BUTT:
        if ( (DrawStruct == NULL) || (DrawStruct->m_Flags == 0) )
        {
            GetScreen()->m_CurrentItem = Create_Texte_Pcb( DC );
            DrawPanel->MouseToCursorSchema();
            DrawPanel->m_AutoPAN_Request = TRUE;
        }
        else if (DrawStruct->m_StructType == TYPETEXTE )
        {
            Place_Texte_Pcb((TEXTE_PCB *)DrawStruct, DC);
            DrawPanel->m_AutoPAN_Request = FALSE;
        }
        else DisplayError(this, wxT("Internal err: Struct not TYPETEXTE"));
        break;

    case ID_COMPONENT_BUTT:
        if ( (DrawStruct == NULL) || (DrawStruct->m_Flags == 0) )
        {
            DrawPanel->MouseToCursorSchema();
            GetScreen()->m_CurrentItem = DrawStruct =
                                             Load_Module_From_Library(wxEmptyString, DC);
            if ( DrawStruct )
                StartMove_Module((MODULE *)DrawStruct, DC);
        }
        else if (DrawStruct->m_StructType == TYPEMODULE )
        {
            Place_Module((MODULE *)DrawStruct, DC);
            DrawPanel->m_AutoPAN_Request = FALSE;
        }
        else DisplayError(this, wxT("Internal err: Struct not TYPEMODULE"));
        break;

    case ID_PCB_COTATION_BUTT:
        if ( GetScreen()->m_Active_Layer <= CMP_N )
        {
            DisplayError(this, _("Cotation not autorized on Copper layers"));
            break;
        }
        if ( (DrawStruct == NULL) || (DrawStruct->m_Flags == 0) )
        {
            GetScreen()->m_CurrentItem = DrawStruct =
                                             Begin_Cotation(NULL, DC);
            DrawPanel->m_AutoPAN_Request = TRUE;
        }
        else if (DrawStruct &&
                 (DrawStruct->m_StructType == TYPECOTATION) &&
                 (DrawStruct->m_Flags & IS_NEW) )
        {
            GetScreen()->m_CurrentItem = DrawStruct =
                                             Begin_Cotation((COTATION * )DrawStruct, DC);
            DrawPanel->m_AutoPAN_Request = TRUE;
        }
        else DisplayError(this, wxT("Internal err: Struct not COTATION"));
        break;

    case ID_PCB_DELETE_ITEM_BUTT:
        if ( !DrawStruct || (DrawStruct->m_Flags == 0) )
        {
            DrawStruct = PcbGeneralLocateAndDisplay();
            if ( DrawStruct && (DrawStruct->m_Flags == 0) )
            {
                RemoveStruct(DrawStruct, DC);
                GetScreen()->m_CurrentItem = DrawStruct = NULL;
            }
        }
        break;

    case ID_PCB_PLACE_OFFSET_COORD_BUTT:
        GetScreen()->Trace_Curseur(DrawPanel, DC);
        DrawPanel->m_Draw_Auxiliary_Axe(DC, GR_XOR);
        m_Auxiliary_Axe_Position = GetScreen()->m_Curseur;
        DrawPanel->m_Draw_Auxiliary_Axe( DC, GR_COPY);
        GetScreen()->Trace_Curseur(DrawPanel, DC);
        break;

    default :
        DrawPanel->SetCursor(wxCURSOR_ARROW);
        DisplayError(this, wxT("WinEDA_PcbFrame::OnLeftClick() id error"));
        SetToolID(0, wxCURSOR_ARROW,wxEmptyString);
        break;
    }
}