bus-wire-junction.cpp 27.8 KB
Newer Older
plyatov's avatar
plyatov committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
/*********************************************************/
/* Modules de creations de Traits, Wires, Bus, Junctions */
/*********************************************************/

#include "fctsys.h"
#include "gr_basic.h"

#include "common.h"
#include "program.h"
#include "libcmp.h"
#include "general.h"

#include "protos.h"


/* Routines Locales */
17 18 19 20 21 22
static void Show_Polyline_in_Ghost( WinEDA_DrawPanel* panel, wxDC* DC, bool erase );
static void Segment_in_Ghost( WinEDA_DrawPanel* panel, wxDC* DC, bool erase );
static void AbortCreateNewLine( WinEDA_DrawPanel* Panel, wxDC* DC );
static bool IsTerminalPoint( SCH_SCREEN* screen, const wxPoint& pos, int layer );
static bool IsJunctionNeeded( WinEDA_SchematicFrame* frame, wxPoint& pos );
static void ComputeBreakPoint( EDA_DrawLineStruct* segment, const wxPoint& new_pos );
23

24 25
EDA_BaseStruct* s_OldWiresList;
wxPoint         s_ConnexionStartPoint;
26 27

/*********************************************************/
28
EDA_BaseStruct* SCH_SCREEN::ExtractWires( bool CreateCopy )
29
/*********************************************************/
30

31
/* Extract the old wires, junctions and busses, an if CreateCopy replace them by a copy.
32 33 34 35 36 37 38 39 40
 *  Old ones must be put in undo list, and the new ones can be modified by clean up
 *  safely.
 *  If an abord command is made, old wires must be put in EEDrawList, and copies must be deleted
 *  This is because previously stored undo commands can handle pointers on wires or bus,
 *  and we do not delete wires or bus, we must put they in undo list.
 * 
 *  Because cleanup delete and/or modify bus and wires, the more easy is to put all wires in undo list
 *  and use a new copy of wires for cleanup
 */
41
{
42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
    EDA_BaseStruct* item, * next_item, * new_item, * List = NULL;

    for( item = EEDrawList; item != NULL; item = next_item )
    {
        next_item = item->Pnext;

        switch( item->m_StructType )
        {
        case DRAW_JUNCTION_STRUCT_TYPE:
        case DRAW_SEGMENT_STRUCT_TYPE:
            RemoveFromDrawList( item );
            item->Pnext = List;
            List = item;
            if( CreateCopy )
            {
                if( item->m_StructType == DRAW_JUNCTION_STRUCT_TYPE )
                    new_item = ( (DrawJunctionStruct*) item )->GenCopy();
                else
                    new_item = ( (EDA_DrawLineStruct*) item )->GenCopy();
                new_item->Pnext = EEDrawList;
                EEDrawList = new_item;
            }
            break;

        default:
            break;
        }
    }

    return List;
72 73 74 75
}


/*************************************************/
76
static void RestoreOldWires( SCH_SCREEN* screen )
77
/*************************************************/
78

79
/* Replace the wires in screen->EEDrawList by s_OldWiresList wires.
80
 */
81
{
82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107
    EDA_BaseStruct* item, * next_item;

    for( item = screen->EEDrawList; item != NULL; item = next_item )
    {
        next_item = item->Pnext;

        switch( item->m_StructType )
        {
        case DRAW_JUNCTION_STRUCT_TYPE:
        case DRAW_SEGMENT_STRUCT_TYPE:
            screen->RemoveFromDrawList( item );
            delete item;
            break;

        default:
            break;
        }
    }

    while( s_OldWiresList )
    {
        next_item = s_OldWiresList->Pnext;
        s_OldWiresList->Pnext = screen->EEDrawList,
        screen->EEDrawList    = s_OldWiresList;
        s_OldWiresList = next_item;
    }
plyatov's avatar
plyatov committed
108 109 110 111
}


/*************************************************************/
112
void WinEDA_SchematicFrame::BeginSegment( wxDC* DC, int type )
plyatov's avatar
plyatov committed
113
/*************************************************************/
114

plyatov's avatar
plyatov committed
115
/* Create a new segment ( WIRE, BUS ).
116
 */
plyatov's avatar
plyatov committed
117
{
118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235
    EDA_DrawLineStruct* oldsegment, * newsegment, * nextsegment;
    wxPoint             cursorpos = GetScreen()->m_Curseur;

    if( GetScreen()->GetCurItem() && (GetScreen()->GetCurItem()->m_Flags == 0) )
        GetScreen()->SetCurItem( NULL );

    if( GetScreen()->GetCurItem() )
    {
        switch( GetScreen()->GetCurItem()->m_StructType )
        {
        case DRAW_SEGMENT_STRUCT_TYPE:
        case DRAW_POLYLINE_STRUCT_TYPE:
            break;

        default:
            return;
        }
    }

    oldsegment = newsegment =
                     (EDA_DrawLineStruct*) GetScreen()->GetCurItem();

    if( !newsegment )  /* first point : Create first wire ou bus */
    {
        s_ConnexionStartPoint = cursorpos;
        s_OldWiresList = GetScreen()->ExtractWires( TRUE );
        GetScreen()->SchematicCleanUp( NULL );

        switch( type )
        {
        default:
            newsegment = new EDA_DrawLineStruct( cursorpos, LAYER_NOTES );
            break;

        case LAYER_WIRE:
            newsegment = new EDA_DrawLineStruct( cursorpos, LAYER_WIRE );

            /* A junction will be created later, when w'll know the
             *  segment end position, and if the junction is really needed */
            break;

        case LAYER_BUS:
            newsegment = new EDA_DrawLineStruct( cursorpos, LAYER_BUS );
            break;
        }

        newsegment->m_Flags = IS_NEW;
        if( g_HVLines ) // We need 2 segments to go from a given start pint to an end point
        {
            nextsegment = newsegment->GenCopy();
            nextsegment->m_Flags = IS_NEW;
            newsegment->Pnext    = nextsegment;
            nextsegment->Pback   = newsegment;
        }
        GetScreen()->SetCurItem( newsegment );
        DrawPanel->ManageCurseur = Segment_in_Ghost;
        DrawPanel->ForceCloseManageCurseur = AbortCreateNewLine;
        g_ItemToRepeat = NULL;
    }
    else    /* Trace en cours: Placement d'un point supplementaire */
    {
        nextsegment = (EDA_DrawLineStruct*) oldsegment->Pnext;
        if( !g_HVLines )
        { /* if only one segment is needed and the current is has len = 0, do not create a new one*/
            if( oldsegment->IsNull() )
                return;
        }
        else
        {
            /* if we want 2 segment and the last two have len = 0, do not create a new one*/
            if( oldsegment->IsNull() && nextsegment && nextsegment->IsNull() )
                return;
        }

        DrawPanel->ManageCurseur( DrawPanel, DC, FALSE );

        /* Creation du segment suivant ou fin de trac si point sur pin, jonction ...*/
        if( IsTerminalPoint( GetScreen(), cursorpos, oldsegment->m_Layer ) )
        {
            EndSegment( DC ); return;
        }

        /* Placement en liste generale */
        oldsegment->Pnext = GetScreen()->EEDrawList;
        GetScreen()->EEDrawList = oldsegment;
        DrawPanel->CursorOff( DC );     // Erase schematic cursor
        RedrawOneStruct( DrawPanel, DC, oldsegment, GR_DEFAULT_DRAWMODE );
        DrawPanel->CursorOn( DC );      // Display schematic cursor

        /* Create a new segment, and chain it after the current new segment */
        if( nextsegment )
        {
            newsegment = nextsegment->GenCopy();
            nextsegment->m_Start = newsegment->m_End;
            nextsegment->Pnext   = NULL;
            nextsegment->Pback   = newsegment;
            newsegment->Pnext    = nextsegment;
            newsegment->Pback    = NULL;
        }
        else
        {
            newsegment = oldsegment->GenCopy();
            newsegment->m_Start = oldsegment->m_End;
        }
        newsegment->m_End   = cursorpos;
        oldsegment->m_Flags = SELECTED;
        newsegment->m_Flags = IS_NEW;
        GetScreen()->SetCurItem( newsegment );
        DrawPanel->ManageCurseur( DrawPanel, DC, FALSE );
        if( oldsegment->m_Start == s_ConnexionStartPoint )
        {   /* This is the first segment: Now we know the start segment position.
             *  Create a junction if needed. Note: a junction can be needed
             *  later, if the new segment is merged (after a cleanup) with an older one
             *  (tested when the connection will be finished)*/
            if( IsJunctionNeeded( this, s_ConnexionStartPoint ) )
                CreateNewJunctionStruct( DC, s_ConnexionStartPoint );
        }
    }
plyatov's avatar
plyatov committed
236 237 238 239
}


/***********************************************/
240
void WinEDA_SchematicFrame::EndSegment( wxDC* DC )
plyatov's avatar
plyatov committed
241
/***********************************************/
242

plyatov's avatar
plyatov committed
243
/* Called to terminate a bus, wire, or line creation
244
 */
plyatov's avatar
plyatov committed
245
{
246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360
    EDA_DrawLineStruct* firstsegment = (EDA_DrawLineStruct*) GetScreen()->GetCurItem();
    EDA_DrawLineStruct* lastsegment  = firstsegment;
    EDA_DrawLineStruct* segment;

    if( firstsegment == NULL )
        return;
    if( (firstsegment->m_Flags & IS_NEW) == 0 )
        return;

    /* Delete Null segments and Put line it in Drawlist */
    lastsegment = firstsegment;
    while( lastsegment )
    {
        EDA_DrawLineStruct* nextsegment = (EDA_DrawLineStruct*) lastsegment->Pnext;
        if( lastsegment->IsNull() )
        {
            EDA_DrawLineStruct* previous_segment = (EDA_DrawLineStruct*) lastsegment->Pback;
            if( firstsegment == lastsegment )
                firstsegment = nextsegment;
            if( nextsegment )
                nextsegment->Pback = NULL;
            if( previous_segment )
                previous_segment->Pnext = nextsegment;
            delete lastsegment;
        }
        lastsegment = nextsegment;
    }

    /* put the segment list to the main linked list */
    segment = lastsegment = firstsegment;
    while( segment )
    {
        lastsegment = segment;
        segment = (EDA_DrawLineStruct*) segment->Pnext;
        lastsegment->Pnext      = GetScreen()->EEDrawList;
        GetScreen()->EEDrawList = lastsegment;
    }

    /* Fin de trace */
    DrawPanel->ManageCurseur = NULL;
    DrawPanel->ForceCloseManageCurseur = NULL;
    GetScreen()->SetCurItem( NULL );

    wxPoint end_point, alt_end_point;

    /* A junction can be needed to connect the last segment
     *  usually to m_End coordinate.
     *  But if the last segment is removed by a cleanup, because od redundancy,
     *  a junction can be needed to connect the previous segment m_End coordinate
     *  with is also the lastsegment->m_Start coordinate */
    if( lastsegment )
    {
        end_point     = lastsegment->m_End;
        alt_end_point = lastsegment->m_Start;
    }

    GetScreen()->SchematicCleanUp( NULL );

    /* clear flags and find last segment entered, for repeat function */
    segment = (EDA_DrawLineStruct*) GetScreen()->EEDrawList;
    while( segment )
    {
        if( segment->m_Flags )
        {
            if( !g_ItemToRepeat )
                g_ItemToRepeat = segment;
        }
        segment->m_Flags = 0;
        segment = (EDA_DrawLineStruct*) segment->Pnext;
    }

    // Automatic place of a junction on the end point, if needed
    if( lastsegment )
    {
        if( IsJunctionNeeded( this, end_point ) )
            CreateNewJunctionStruct( DC, end_point );

        else if( IsJunctionNeeded( this, alt_end_point ) )
            CreateNewJunctionStruct( DC, alt_end_point );
    }

    /* Automatic place of a junction on the start point if necessary because the
     *  Cleanup can suppress intermediate points by merging wire segments*/
    if( IsJunctionNeeded( this, s_ConnexionStartPoint ) )
        CreateNewJunctionStruct( DC, s_ConnexionStartPoint );

    TestDanglingEnds( GetScreen()->EEDrawList, DC );


    /* Redraw wires and junctions which can be changed by TestDanglingEnds() */
    DrawPanel->CursorOff( DC );   // Erase schematic cursor
    EDA_BaseStruct* item = GetScreen()->EEDrawList;
    while( item )
    {
        switch( item->m_StructType )
        {
        case DRAW_JUNCTION_STRUCT_TYPE:
        case DRAW_SEGMENT_STRUCT_TYPE:
            RedrawOneStruct( DrawPanel, DC, item, GR_DEFAULT_DRAWMODE );
            break;

        default:
            break;
        }

        item = item->Pnext;
    }


    DrawPanel->CursorOn( DC );    // Display schematic cursor

    SaveCopyInUndoList( s_OldWiresList, IS_WIRE_IMAGE );
    s_OldWiresList = NULL;

    GetScreen()->SetModify();
plyatov's avatar
plyatov committed
361 362
}

363

plyatov's avatar
plyatov committed
364
/****************************************************************************/
365
static void Segment_in_Ghost( WinEDA_DrawPanel* panel, wxDC* DC, bool erase )
plyatov's avatar
plyatov committed
366
/****************************************************************************/
367

plyatov's avatar
plyatov committed
368
/*  Redraw the segment (g_HVLines == FALSE ) or the two segments (g_HVLines == TRUE )
369 370
 *  from the start point to the cursor, when moving the mouse
 */
plyatov's avatar
plyatov committed
371
{
372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407
    EDA_DrawLineStruct* CurrentLine =
        (EDA_DrawLineStruct*) panel->m_Parent->GetScreen()->GetCurItem();
    EDA_DrawLineStruct* segment;
    int color;

    if( CurrentLine == NULL )
        return;

    color = ReturnLayerColor( CurrentLine->m_Layer ) ^ HIGHT_LIGHT_FLAG;

    if( erase )
    {
        segment = CurrentLine;
        while( segment )
        {
            if( !segment->IsNull() )  // Redraw if segment lengtht != 0
                RedrawOneStruct( panel, DC, segment, g_XorMode, color );
            segment = (EDA_DrawLineStruct*) segment->Pnext;
        }
    }

    wxPoint endpos = panel->m_Parent->GetScreen()->m_Curseur;
    if( g_HVLines ) /* Coerce the line to vertical or horizontal one: */
    {
        ComputeBreakPoint( CurrentLine, endpos );
    }
    else
        CurrentLine->m_End = endpos;

    segment = CurrentLine;
    while( segment )
    {
        if( !segment->IsNull() )  // Redraw if segment lengtht != 0
            RedrawOneStruct( panel, DC, segment, g_XorMode, color );
        segment = (EDA_DrawLineStruct*) segment->Pnext;
    }
plyatov's avatar
plyatov committed
408 409 410 411
}


/**************************************************************************************/
412
static void ComputeBreakPoint( EDA_DrawLineStruct* segment, const wxPoint& new_pos )
plyatov's avatar
plyatov committed
413
/**************************************************************************************/
414

plyatov's avatar
plyatov committed
415
/* compute the middle coordinate for 2 segments, from the start point to new_pos
416 417
 *  with the 2 segments kept H or V only
 */
plyatov's avatar
plyatov committed
418
{
419 420 421 422 423 424 425 426 427 428 429
    EDA_DrawLineStruct* nextsegment     = (EDA_DrawLineStruct*) segment->Pnext;
    wxPoint             middle_position = new_pos;

    if( nextsegment == NULL )
        return;
#if 0
    if( ABS( middle_position.x - segment->m_Start.x ) <
       ABS( middle_position.y - segment->m_Start.y ) )
        middle_position.x = segment->m_Start.x;
    else
        middle_position.y = segment->m_Start.y;
plyatov's avatar
plyatov committed
430
#else
431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448
    int iDx = segment->m_End.x - segment->m_Start.x;
    int iDy = segment->m_End.y - segment->m_Start.y;
    if( iDy != 0 )         // keep the first segment orientation (currently horizontal)
    {
        middle_position.x = segment->m_Start.x;
    }
    else if( iDx != 0 )    // keep the first segment orientation (currently vertical)
    {
        middle_position.y = segment->m_Start.y;
    }
    else
    {
        if( ABS( middle_position.x - segment->m_Start.x ) <
           ABS( middle_position.y - segment->m_Start.y ) )
            middle_position.x = segment->m_Start.x;
        else
            middle_position.y = segment->m_Start.y;
    }
plyatov's avatar
plyatov committed
449
#endif
450 451 452 453 454

    segment->m_End = middle_position;

    nextsegment->m_Start = middle_position;
    nextsegment->m_End   = new_pos;
plyatov's avatar
plyatov committed
455 456
}

457

plyatov's avatar
plyatov committed
458
/*****************************************************************************/
459
static void Show_Polyline_in_Ghost( WinEDA_DrawPanel* panel, wxDC* DC, bool erase )
plyatov's avatar
plyatov committed
460
/*****************************************************************************/
461

plyatov's avatar
plyatov committed
462
/*  Dessin du du Polyline Fantome lors des deplacements du curseur
463
 */
plyatov's avatar
plyatov committed
464
{
465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492
    DrawPolylineStruct* NewPoly =
        (DrawPolylineStruct*) panel->m_Parent->GetScreen()->GetCurItem();
    int color;
    wxPoint             endpos;

    endpos = panel->m_Parent->GetScreen()->m_Curseur;
    color  = ReturnLayerColor( NewPoly->m_Layer );

    GRSetDrawMode( DC, g_XorMode );

    if( g_HVLines )
    {
        /* Coerce the line to vertical or horizontal one: */
        if( ABS( endpos.x - NewPoly->m_Points[NewPoly->m_NumOfPoints * 2 - 2] ) <
           ABS( endpos.y - NewPoly->m_Points[NewPoly->m_NumOfPoints * 2 - 1] ) )
            endpos.x = NewPoly->m_Points[NewPoly->m_NumOfPoints * 2 - 2];
        else
            endpos.y = NewPoly->m_Points[NewPoly->m_NumOfPoints * 2 - 1];
    }

    NewPoly->m_NumOfPoints++;
    if( erase )
        RedrawOneStruct( panel, DC, NewPoly, g_XorMode, color );

    NewPoly->m_Points[NewPoly->m_NumOfPoints * 2 - 2] = endpos.x;
    NewPoly->m_Points[NewPoly->m_NumOfPoints * 2 - 1] = endpos.y;
    RedrawOneStruct( panel, DC, NewPoly, g_XorMode, color );
    NewPoly->m_NumOfPoints--;
plyatov's avatar
plyatov committed
493 494
}

495

plyatov's avatar
plyatov committed
496
/**********************************************************/
497
void WinEDA_SchematicFrame::DeleteCurrentSegment( wxDC* DC )
plyatov's avatar
plyatov committed
498
/**********************************************************/
499

plyatov's avatar
plyatov committed
500
/*
501 502
 *  Routine effacant le dernier trait trace, ou l'element pointe par la souris
 */
plyatov's avatar
plyatov committed
503
{
504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524
    g_ItemToRepeat = NULL;

    if( (GetScreen()->GetCurItem() == NULL)
       || ( (GetScreen()->GetCurItem()->m_Flags & IS_NEW) == 0 ) )
    {
        return;
    }

    /* Trace en cours: annulation */
    if( GetScreen()->GetCurItem()->m_StructType == DRAW_POLYLINE_STRUCT_TYPE )
    {
        Show_Polyline_in_Ghost( DrawPanel, DC, FALSE ); /* Effacement du trace en cours */
    }
    else
    {
        Segment_in_Ghost( DrawPanel, DC, FALSE ); /* Effacement du trace en cours */
    }

    EraseStruct( GetScreen()->GetCurItem(), GetScreen() );
    DrawPanel->ManageCurseur = NULL;
    GetScreen()->SetCurItem( NULL );
plyatov's avatar
plyatov committed
525 526 527 528
}


/***************************************************************************/
529 530
DrawJunctionStruct* WinEDA_SchematicFrame::CreateNewJunctionStruct(
    wxDC* DC, const wxPoint& pos, bool PutInUndoList )
plyatov's avatar
plyatov committed
531
/***************************************************************************/
532

plyatov's avatar
plyatov committed
533
/* Routine to create new connection struct.
534
 */
plyatov's avatar
plyatov committed
535
{
536
    DrawJunctionStruct* NewJunction;
plyatov's avatar
plyatov committed
537

538
    NewJunction = new DrawJunctionStruct( pos );
plyatov's avatar
plyatov committed
539

540
    g_ItemToRepeat = NewJunction;
plyatov's avatar
plyatov committed
541

542 543 544
    DrawPanel->CursorOff( DC );     // Erase schematic cursor
    RedrawOneStruct( DrawPanel, DC, NewJunction, GR_DEFAULT_DRAWMODE );
    DrawPanel->CursorOn( DC );      // Display schematic cursor
plyatov's avatar
plyatov committed
545

546 547 548 549 550 551
    NewJunction->Pnext      = GetScreen()->EEDrawList;
    GetScreen()->EEDrawList = NewJunction;
    GetScreen()->SetModify();
    if( PutInUndoList )
        SaveCopyInUndoList( NewJunction, IS_NEW );
    return NewJunction;
plyatov's avatar
plyatov committed
552 553
}

554

plyatov's avatar
plyatov committed
555
/**************************************************************************/
556
EDA_BaseStruct* WinEDA_SchematicFrame::CreateNewNoConnectStruct( wxDC* DC )
plyatov's avatar
plyatov committed
557
/**************************************************************************/
558

plyatov's avatar
plyatov committed
559
/*Routine to create new NoConnect struct. ( Symbole de Non Connexion)
560
 */
plyatov's avatar
plyatov committed
561
{
562
    DrawNoConnectStruct* NewNoConnect;
plyatov's avatar
plyatov committed
563

564 565
    NewNoConnect   = new DrawNoConnectStruct( GetScreen()->m_Curseur );
    g_ItemToRepeat = NewNoConnect;
plyatov's avatar
plyatov committed
566

567 568 569
    DrawPanel->CursorOff( DC );     // Erase schematic cursor
    RedrawOneStruct( DrawPanel, DC, NewNoConnect, GR_DEFAULT_DRAWMODE );
    DrawPanel->CursorOn( DC );      // Display schematic cursor
plyatov's avatar
plyatov committed
570

571 572 573 574 575
    NewNoConnect->Pnext     = GetScreen()->EEDrawList;
    GetScreen()->EEDrawList = NewNoConnect;
    GetScreen()->SetModify();
    SaveCopyInUndoList( NewNoConnect, IS_NEW );
    return NewNoConnect;
plyatov's avatar
plyatov committed
576 577 578 579
}


/*****************************************************************/
580
static void AbortCreateNewLine( WinEDA_DrawPanel* Panel, wxDC* DC )
plyatov's avatar
plyatov committed
581
/*****************************************************************/
582

plyatov's avatar
plyatov committed
583
/* Abort function for wire, bus or line creation
584
 */
plyatov's avatar
plyatov committed
585
{
586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606
    SCH_SCREEN* Screen = (SCH_SCREEN*) Panel->GetScreen();

    if( Screen->GetCurItem() )  /* trace en cours */
    {
        Panel->ManageCurseur( Panel, DC, FALSE );
        Panel->ManageCurseur = NULL;
        Panel->ForceCloseManageCurseur = NULL;
        EraseStruct( Screen->GetCurItem(), (SCH_SCREEN*) Screen );
        Screen->SetCurItem( NULL );
        RestoreOldWires( Screen );
    }
    else
        g_ItemToRepeat = NULL;  // Fin de commande generale

    /* Clear m_Flags wich is used in edit functions: */
    EDA_BaseStruct* item = Screen->EEDrawList;
    while( item )
    {
        item->m_Flags = 0;
        item = item->Pnext;
    }
plyatov's avatar
plyatov committed
607 608 609 610
}


/***************************************************/
611
void WinEDA_SchematicFrame::RepeatDrawItem( wxDC* DC )
plyatov's avatar
plyatov committed
612
/***************************************************/
613

plyatov's avatar
plyatov committed
614
/* Routine de recopie du dernier element dessine
615 616 617 618
 *  Les elements duplicables sont
 *      fils, bus, traits, textes, labels
 *      Les labels termines par un nombre seront incrementes
 */
plyatov's avatar
plyatov committed
619
{
620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728
    wxPoint new_pos;

    if( g_ItemToRepeat == NULL )
        return;

    switch( g_ItemToRepeat->m_StructType )
    {
    case DRAW_JUNCTION_STRUCT_TYPE:
            #undef STRUCT
            #define STRUCT ( (DrawJunctionStruct*) g_ItemToRepeat )
        g_ItemToRepeat = STRUCT->GenCopy();
        STRUCT->m_Pos += g_RepeatStep;
        new_pos = STRUCT->m_Pos;
        break;

    case DRAW_NOCONNECT_STRUCT_TYPE:
            #undef STRUCT
            #define STRUCT ( (DrawNoConnectStruct*) g_ItemToRepeat )
        g_ItemToRepeat = STRUCT->GenCopy();
        STRUCT->m_Pos += g_RepeatStep;
        new_pos = STRUCT->m_Pos;
        break;

    case DRAW_TEXT_STRUCT_TYPE:
            #undef STRUCT
            #define STRUCT ( (DrawTextStruct*) g_ItemToRepeat )
        g_ItemToRepeat = STRUCT->GenCopy();
        STRUCT->m_Pos += g_RepeatStep;
        new_pos = STRUCT->m_Pos;
        /*** Increment du numero de label ***/
        IncrementLabelMember( STRUCT->m_Text );
        break;


    case DRAW_LABEL_STRUCT_TYPE:
            #undef STRUCT
            #define STRUCT ( (DrawLabelStruct*) g_ItemToRepeat )
        g_ItemToRepeat = STRUCT->GenCopy();
        STRUCT->m_Pos += g_RepeatStep;
        new_pos = STRUCT->m_Pos;
        /*** Increment du numero de label ***/
        IncrementLabelMember( STRUCT->m_Text );
        break;


    case DRAW_GLOBAL_LABEL_STRUCT_TYPE:
            #undef STRUCT
            #define STRUCT ( (DrawGlobalLabelStruct*) g_ItemToRepeat )
        g_ItemToRepeat = STRUCT->GenCopy();
        STRUCT->m_Pos += g_RepeatStep;
        new_pos = STRUCT->m_Pos;
        /*** Increment du numero de label ***/
        IncrementLabelMember( STRUCT->m_Text );
        break;

    case DRAW_SEGMENT_STRUCT_TYPE:
            #undef STRUCT
            #define STRUCT ( (EDA_DrawLineStruct*) g_ItemToRepeat )
        g_ItemToRepeat   = STRUCT->GenCopy();
        STRUCT->m_Start += g_RepeatStep;
        new_pos = STRUCT->m_Start;
        STRUCT->m_End += g_RepeatStep;
        break;

    case DRAW_BUSENTRY_STRUCT_TYPE:
            #undef STRUCT
            #define STRUCT ( (DrawBusEntryStruct*) g_ItemToRepeat )
        g_ItemToRepeat = STRUCT->GenCopy();
        STRUCT->m_Pos += g_RepeatStep;
        new_pos = STRUCT->m_Pos;
        break;

    case DRAW_LIB_ITEM_STRUCT_TYPE:     // In repeat command the new component is put in move mode
            #undef STRUCT
            #define STRUCT ( (EDA_SchComponentStruct*) g_ItemToRepeat )

        // Create the duplicate component, position = mouse cursor
        g_ItemToRepeat = STRUCT->GenCopy();
        new_pos.x           = m_CurrentScreen->m_Curseur.x - STRUCT->m_Pos.x;
        new_pos.y           = m_CurrentScreen->m_Curseur.y - STRUCT->m_Pos.y;
        STRUCT->m_Pos       = m_CurrentScreen->m_Curseur;
        STRUCT->m_Flags     = IS_NEW;
        STRUCT->m_TimeStamp = GetTimeStamp();
        for( int ii = 0; ii < NUMBER_OF_FIELDS; ii++ )
        {
            STRUCT->m_Field[ii].m_Pos += new_pos;
        }

        RedrawOneStruct( DrawPanel, DC, STRUCT, g_XorMode );
        StartMovePart( STRUCT, DC );
        return;
        break;

    default:
        g_ItemToRepeat = NULL;
        DisplayError( this, wxT( "Repeat Type Error" ), 10 );
        break;
    }

    if( g_ItemToRepeat )
    {
        g_ItemToRepeat->Pnext   = GetScreen()->EEDrawList;
        GetScreen()->EEDrawList = g_ItemToRepeat;
        TestDanglingEnds( GetScreen()->EEDrawList, NULL );
        RedrawOneStruct( DrawPanel, DC, g_ItemToRepeat, GR_DEFAULT_DRAWMODE );
        SaveCopyInUndoList( g_ItemToRepeat, IS_NEW );
        g_ItemToRepeat->m_Flags = 0;

//		GetScreen()->Curseur = new_pos;
plyatov's avatar
plyatov committed
729
//		GRMouseWarp(DrawPanel, DrawPanel->CursorScreenPosition() );
730
    }
plyatov's avatar
plyatov committed
731 732 733 734
}


/******************************************/
735
void IncrementLabelMember( wxString& name )
plyatov's avatar
plyatov committed
736
/******************************************/
737

plyatov's avatar
plyatov committed
738
/* Routine incrementant les labels, c'est a dire pour les textes finissant
739 740
 *  par un nombre, ajoutant <RepeatDeltaLabel> a ce nombre
 */
plyatov's avatar
plyatov committed
741
{
742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760
    int  ii, nn;
    long number = 0;

    ii = name.Len() - 1; nn = 0;
    if( !isdigit( name.GetChar( ii ) ) )
        return;

    while( (ii >= 0) && isdigit( name.GetChar( ii ) ) )
    {
        ii--; nn++;
    }

    ii++;   /* digits are starting at ii position */
    wxString litt_number = name.Right( nn );
    if( litt_number.ToLong( &number ) )
    {
        number += g_RepeatDeltaLabel;
        name.Remove( ii ); name << number;
    }
plyatov's avatar
plyatov committed
761 762
}

763

plyatov's avatar
plyatov committed
764
/***************************************************************************/
765
static bool IsTerminalPoint( SCH_SCREEN* screen, const wxPoint& pos, int layer )
plyatov's avatar
plyatov committed
766
/***************************************************************************/
767

plyatov's avatar
plyatov committed
768
/* Returne TRUE si pos est un point possible pour terminer automatiquement un
769 770 771 772 773 774 775 776 777
 *  segment, c'est a dire pour
 *  - type WIRE, si il y a
 *      - une jonction
 *      - ou une pin
 *      - ou une extrmit unique de fil
 * 
 *  - type BUS, si il y a
 *      - ou une extrmit unique de BUS
 */
plyatov's avatar
plyatov committed
778
{
779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847
    EDA_BaseStruct*         item;
    LibDrawPin*             pin;
    EDA_SchComponentStruct* LibItem = NULL;
    DrawSheetLabelStruct*   pinsheet;
    wxPoint itempos;

    switch( layer )
    {
    case LAYER_BUS:
        item = PickStruct( pos, screen->EEDrawList, BUSITEM );
        if( item )
            return TRUE;
        pinsheet = LocateAnyPinSheet( pos, screen->EEDrawList );
        if( pinsheet && IsBusLabel( pinsheet->m_Text ) )
        {
            itempos = pinsheet->m_Pos;
            if( (itempos.x == pos.x) && (itempos.y == pos.y) )
                return TRUE;
        }
        break;

    case LAYER_NOTES:
        item = PickStruct( pos, screen->EEDrawList, DRAWITEM );
        if( item )
            return TRUE;
        break;

    case LAYER_WIRE:
        item = PickStruct( pos, screen->EEDrawList, RACCORDITEM | JUNCTIONITEM );
        if( item )
            return TRUE;

        pin = LocateAnyPin( screen->EEDrawList, pos, &LibItem );
        if( pin && LibItem )
        {
            // calcul de la position exacte du point de connexion de la pin,
            // selon orientation du composant:
            itempos    = LibItem->GetScreenCoord( pin->m_Pos );
            itempos.x += LibItem->m_Pos.x;
            itempos.y += LibItem->m_Pos.y;
            if( (itempos.x == pos.x) && (itempos.y == pos.y) )
                return TRUE;
        }

        item = PickStruct( pos, screen->EEDrawList, WIREITEM );
        if( item )
            return TRUE;

        item = PickStruct( pos, screen->EEDrawList, LABELITEM );
        if( item && (item->m_StructType != DRAW_TEXT_STRUCT_TYPE)
           && ( ( (DrawGlobalLabelStruct*) item )->m_Pos.x == pos.x )
           && ( ( (DrawGlobalLabelStruct*) item )->m_Pos.y == pos.y ) )
            return TRUE;

        pinsheet = LocateAnyPinSheet( pos, screen->EEDrawList );
        if( pinsheet && !IsBusLabel( pinsheet->m_Text ) )
        {
            itempos = pinsheet->m_Pos;
            if( (itempos.x == pos.x) && (itempos.y == pos.y) )
                return TRUE;
        }

        break;

    default:
        break;
    }

    return FALSE;
plyatov's avatar
plyatov committed
848 849 850 851
}


/****************************************************************/
852
bool IsJunctionNeeded( WinEDA_SchematicFrame* frame, wxPoint& pos )
plyatov's avatar
plyatov committed
853
/****************************************************************/
854

plyatov's avatar
plyatov committed
855
/* Return True when a wire is located at pos "pos" if
856 857 858 859 860 861 862
 *  - there is no junction.
 *  - The wire has no ends at pos "pos",
 *      and therefore it is considered as no connected.
 *  - One (or more) wire has one end at pos "pos"
 *  or
 *  - a pin is on location pos
 */
plyatov's avatar
plyatov committed
863
{
864 865 866 867 868 869 870 871 872 873 874 875
    if( PickStruct( pos, frame->GetScreen()->EEDrawList, JUNCTIONITEM ) )
        return FALSE;

    if( PickStruct( pos, frame->GetScreen()->EEDrawList, WIREITEM | EXCLUDE_WIRE_BUS_ENDPOINTS ) )
    {
        if( PickStruct( pos, frame->GetScreen()->EEDrawList, WIREITEM | WIRE_BUS_ENDPOINTS_ONLY ) )
            return TRUE;
        if( frame->LocatePinEnd( frame->GetScreen()->EEDrawList, pos ) )
            return TRUE;
    }

    return FALSE;
plyatov's avatar
plyatov committed
876
}