bus-wire-junction.cpp 25.5 KB
Newer Older
1 2 3
/***************************************************************/
/* Code for handling creation of buses, wires, and junctions. */
/***************************************************************/
plyatov's avatar
plyatov committed
4 5 6 7

#include "fctsys.h"
#include "gr_basic.h"
#include "common.h"
8 9 10
#include "class_drawpanel.h"
#include "confirm.h"

plyatov's avatar
plyatov committed
11
#include "program.h"
12
#include "classes_body_items.h"
plyatov's avatar
plyatov committed
13 14 15 16 17
#include "general.h"
#include "protos.h"


/* Routines Locales */
18 19 20
static void Show_Polyline_in_Ghost( WinEDA_DrawPanel* panel,
                                    wxDC*             DC,
                                    bool              erase );
21 22 23 24
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 );
25
static void ComputeBreakPoint( SCH_LINE* segment, const wxPoint& new_pos );
26

27
SCH_ITEM* s_OldWiresList;
28
wxPoint   s_ConnexionStartPoint;
29

30

31 32 33 34 35 36 37
/* Extract the old wires, junctions and buses, an if CreateCopy replace them
 * by a copy.  Old ones must be put in undo list, and the new ones can be
 * modified by clean up safely.
 * If an abort 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.
38
 *
39 40
 * 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
SCH_ITEM* SCH_SCREEN::ExtractWires( bool CreateCopy )
{
44
    SCH_ITEM* item, * next_item, * new_item, * List = NULL;
45 46 47

    for( item = EEDrawList; item != NULL; item = next_item )
    {
48
        next_item = item->Next();
49

50
        switch( item->Type() )
51 52 53 54
        {
        case DRAW_JUNCTION_STRUCT_TYPE:
        case DRAW_SEGMENT_STRUCT_TYPE:
            RemoveFromDrawList( item );
55
            item->SetNext( List );
56 57 58
            List = item;
            if( CreateCopy )
            {
59
                if( item->Type() == DRAW_JUNCTION_STRUCT_TYPE )
60
                    new_item = ( (SCH_JUNCTION*) item )->GenCopy();
61
                else
62
                    new_item = ( (SCH_LINE*) item )->GenCopy();
63
                new_item->SetNext( EEDrawList );
64 65 66 67 68 69 70 71 72 73
                EEDrawList = new_item;
            }
            break;

        default:
            break;
        }
    }

    return List;
74 75 76 77
}


/* Replace the wires in screen->EEDrawList by s_OldWiresList wires.
78
 */
79 80
static void RestoreOldWires( SCH_SCREEN* screen )
{
81 82
    SCH_ITEM* item;
    SCH_ITEM* next_item;
83 84 85

    for( item = screen->EEDrawList; item != NULL; item = next_item )
    {
86
        next_item = item->Next();
87

88
        switch( item->Type() )
89 90 91 92 93 94 95 96 97 98 99 100 101 102
        {
        case DRAW_JUNCTION_STRUCT_TYPE:
        case DRAW_SEGMENT_STRUCT_TYPE:
            screen->RemoveFromDrawList( item );
            delete item;
            break;

        default:
            break;
        }
    }

    while( s_OldWiresList )
    {
103
        next_item = s_OldWiresList->Next();
104 105

        s_OldWiresList->SetNext( screen->EEDrawList );
106 107
        screen->EEDrawList = s_OldWiresList;
        s_OldWiresList     = next_item;
108
    }
plyatov's avatar
plyatov committed
109 110 111
}


charras's avatar
charras committed
112 113
/* Creates a new segment ( WIRE, BUS ),
 * or terminates the current segment
114 115
 * If the end of the current segment is on an other segment, place a junction
 * if needed and terminates the command
charras's avatar
charras committed
116 117
 * If the end of the current segment is on a pin, terminates the command
 * In others cases starts a new segment
118
 */
119 120 121 122
void WinEDA_SchematicFrame::BeginSegment( wxDC* DC, int type )
{
    SCH_LINE* oldsegment, * newsegment, * nextsegment;
    wxPoint   cursorpos = GetScreen()->m_Curseur;
123 124 125 126 127 128

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

    if( GetScreen()->GetCurItem() )
    {
129
        switch( GetScreen()->GetCurItem()->Type() )
130 131 132 133 134 135 136 137 138 139
        {
        case DRAW_SEGMENT_STRUCT_TYPE:
        case DRAW_POLYLINE_STRUCT_TYPE:
            break;

        default:
            return;
        }
    }

140
    oldsegment = newsegment = (SCH_LINE*) GetScreen()->GetCurItem();
141

142
    if( !newsegment )  /* first point : Create first wire or bus */
143 144
    {
        s_ConnexionStartPoint = cursorpos;
145 146
        s_OldWiresList = ( (SCH_SCREEN*) GetScreen() )->ExtractWires( TRUE );
        ( (SCH_SCREEN*) GetScreen() )->SchematicCleanUp( NULL );
147 148 149 150

        switch( type )
        {
        default:
151
            newsegment = new SCH_LINE( cursorpos, LAYER_NOTES );
152 153 154
            break;

        case LAYER_WIRE:
155
            newsegment = new SCH_LINE( cursorpos, LAYER_WIRE );
156

157 158
            /* A junction will be created later, when we'll know the
             * segment end position, and if the junction is really needed */
159 160 161
            break;

        case LAYER_BUS:
162
            newsegment = new SCH_LINE( cursorpos, LAYER_BUS );
163 164 165 166
            break;
        }

        newsegment->m_Flags = IS_NEW;
167 168
        if( g_HVLines ) // We need 2 segments to go from a given start pint to
                        // an end point
169 170 171
        {
            nextsegment = newsegment->GenCopy();
            nextsegment->m_Flags = IS_NEW;
172 173
            newsegment->SetNext( nextsegment );
            nextsegment->SetBack( newsegment );
174 175 176 177 178 179
        }
        GetScreen()->SetCurItem( newsegment );
        DrawPanel->ManageCurseur = Segment_in_Ghost;
        DrawPanel->ForceCloseManageCurseur = AbortCreateNewLine;
        g_ItemToRepeat = NULL;
    }
180 181
    else    /* A segment is in progress: terminates the current segment and add
             * a new segment */
182
    {
183
        nextsegment = oldsegment->Next();
184 185 186
        if( !g_HVLines ) /* if only one segment is needed and the current is
                          * has len = 0, do not create a new one */
        {
187 188 189 190 191
            if( oldsegment->IsNull() )
                return;
        }
        else
        {
192 193
            /* if we want 2 segment and the last two have len = 0, do not
             * create a new one */
194 195 196 197 198 199
            if( oldsegment->IsNull() && nextsegment && nextsegment->IsNull() )
                return;
        }

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

charras's avatar
charras committed
200
        /* Creates the new segment, or terminates the command
201
         * if the end point is on a pin, junction or an other wire or bus */
charras's avatar
charras committed
202
        if( IsTerminalPoint( GetScreen(), cursorpos, oldsegment->GetLayer() ) )
203 204 205 206
        {
            EndSegment( DC ); return;
        }

207
        oldsegment->SetNext( GetScreen()->EEDrawList );
208 209 210 211 212 213 214 215 216 217
        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;
218 219 220 221
            nextsegment->SetNext( NULL );
            nextsegment->SetBack( newsegment );
            newsegment->SetNext( nextsegment );
            newsegment->SetBack( NULL );
222 223 224 225 226 227 228 229 230 231 232
        }
        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 );
233 234 235 236 237

        /* 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)*/
238
        if( oldsegment->m_Start == s_ConnexionStartPoint )
239
        {
240 241 242 243
            if( IsJunctionNeeded( this, s_ConnexionStartPoint ) )
                CreateNewJunctionStruct( DC, s_ConnexionStartPoint );
        }
    }
plyatov's avatar
plyatov committed
244 245 246 247
}


/* Called to terminate a bus, wire, or line creation
248
 */
249 250 251 252 253
void WinEDA_SchematicFrame::EndSegment( wxDC* DC )
{
    SCH_LINE* firstsegment = (SCH_LINE*) GetScreen()->GetCurItem();
    SCH_LINE* lastsegment = firstsegment;
    SCH_LINE* segment;
254 255 256

    if( firstsegment == NULL )
        return;
257
    if( ( firstsegment->m_Flags & IS_NEW ) == 0 )
258 259 260 261 262 263
        return;

    /* Delete Null segments and Put line it in Drawlist */
    lastsegment = firstsegment;
    while( lastsegment )
    {
264
        SCH_LINE* nextsegment = lastsegment->Next();
265 266
        if( lastsegment->IsNull() )
        {
267
            SCH_LINE* previous_segment = lastsegment->Back();
268 269 270
            if( firstsegment == lastsegment )
                firstsegment = nextsegment;
            if( nextsegment )
271
                nextsegment->SetBack( NULL );
272
            if( previous_segment )
273
                previous_segment->SetNext( nextsegment );
274 275 276 277 278 279 280 281 282 283
            delete lastsegment;
        }
        lastsegment = nextsegment;
    }

    /* put the segment list to the main linked list */
    segment = lastsegment = firstsegment;
    while( segment )
    {
        lastsegment = segment;
284
        segment     = segment->Next();
285
        lastsegment->SetNext( GetScreen()->EEDrawList );
286 287 288 289 290 291 292 293 294 295 296
        GetScreen()->EEDrawList = lastsegment;
    }

    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.
297 298 299
     *  But if the last segment is removed by a cleanup, because of redundancy,
     * a junction can be needed to connect the previous segment m_End
     * coordinate with is also the lastsegment->m_Start coordinate */
300 301 302 303 304 305
    if( lastsegment )
    {
        end_point     = lastsegment->m_End;
        alt_end_point = lastsegment->m_Start;
    }

306
    ( (SCH_SCREEN*) GetScreen() )->SchematicCleanUp( NULL );
307 308

    /* clear flags and find last segment entered, for repeat function */
309
    segment = (SCH_LINE*) GetScreen()->EEDrawList;
310 311 312 313 314 315 316 317
    while( segment )
    {
        if( segment->m_Flags )
        {
            if( !g_ItemToRepeat )
                g_ItemToRepeat = segment;
        }
        segment->m_Flags = 0;
318
        segment = segment->Next();
319 320 321 322 323 324 325 326 327 328 329 330
    }

    // 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 );
    }

331 332
    /* Automatic place of a junction on the start point if necessary because
     * the cleanup can suppress intermediate points by merging wire segments */
333 334 335 336 337 338 339 340 341 342 343
    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 )
    {
344
        switch( item->Type() )
345 346 347
        {
        case DRAW_JUNCTION_STRUCT_TYPE:
        case DRAW_SEGMENT_STRUCT_TYPE:
348
            DrawPanel->PostDirtyRect( item->GetBoundingBox() );
349 350 351 352 353 354
            break;

        default:
            break;
        }

355
        item = item->Next();
356 357 358 359 360
    }


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

361
    SaveCopyInUndoList( s_OldWiresList, UR_WIRE_IMAGE );
362 363 364
    s_OldWiresList = NULL;

    GetScreen()->SetModify();
plyatov's avatar
plyatov committed
365 366
}

367

368
/* Redraw the segment (g_HVLines == FALSE ) or the two segments (g_HVLines ==
369
 * TRUE )
370 371
 *  from the start point to the cursor, when moving the mouse
 */
372 373 374 375
static void Segment_in_Ghost( WinEDA_DrawPanel* panel, wxDC* DC, bool erase )
{
    SCH_LINE* CurrentLine = (SCH_LINE*) panel->GetScreen()->GetCurItem();
    SCH_LINE* segment;
376 377 378 379 380
    int color;

    if( CurrentLine == NULL )
        return;

381
    color = ReturnLayerColor( CurrentLine->GetLayer() ) ^ HIGHT_LIGHT_FLAG;
382 383 384 385 386 387

    if( erase )
    {
        segment = CurrentLine;
        while( segment )
        {
388
            if( !segment->IsNull() )  // Redraw if segment length != 0
389
                RedrawOneStruct( panel, DC, segment, g_XorMode, color );
390
            segment = segment->Next();
391 392 393
        }
    }

394
    wxPoint endpos = panel->GetScreen()->m_Curseur;
395 396 397 398 399 400 401 402 403 404
    if( g_HVLines ) /* Coerce the line to vertical or horizontal one: */
    {
        ComputeBreakPoint( CurrentLine, endpos );
    }
    else
        CurrentLine->m_End = endpos;

    segment = CurrentLine;
    while( segment )
    {
405
        if( !segment->IsNull() )  // Redraw if segment length != 0
406
            RedrawOneStruct( panel, DC, segment, g_XorMode, color );
407
        segment = segment->Next();
408
    }
plyatov's avatar
plyatov committed
409 410 411
}


412 413
/* compute the middle coordinate for 2 segments, from the start point to
 * new_pos
414 415
 *  with the 2 segments kept H or V only
 */
416 417 418 419
static void ComputeBreakPoint( SCH_LINE* segment, const wxPoint& new_pos )
{
    SCH_LINE* nextsegment     = segment->Next();
    wxPoint   middle_position = new_pos;
420 421 422 423 424

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

    segment->m_End = middle_position;

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

458

459 460
/*  Drawing Polyline phantom at the displacement of the cursor
 */
461 462 463 464
static void Show_Polyline_in_Ghost( WinEDA_DrawPanel* panel,
                                    wxDC*             DC,
                                    bool              erase )
{
465 466 467
    SCH_POLYLINE* NewPoly = (SCH_POLYLINE*) panel->GetScreen()->GetCurItem();
    int           color;
    wxPoint       endpos;
468

469
    endpos = panel->GetScreen()->m_Curseur;
470
    color  = ReturnLayerColor( NewPoly->GetLayer() );
471 472 473

    GRSetDrawMode( DC, g_XorMode );

charras's avatar
charras committed
474
    int idx = NewPoly->GetCornerCount() - 1;
475 476 477
    if( g_HVLines )
    {
        /* Coerce the line to vertical or horizontal one: */
charras's avatar
charras committed
478 479 480
        if( ABS( endpos.x - NewPoly->m_PolyPoints[idx].x ) <
           ABS( endpos.y - NewPoly->m_PolyPoints[idx].y ) )
            endpos.x = NewPoly->m_PolyPoints[idx].x;
481
        else
charras's avatar
charras committed
482
            endpos.y = NewPoly->m_PolyPoints[idx].y;
483 484 485 486 487
    }

    if( erase )
        RedrawOneStruct( panel, DC, NewPoly, g_XorMode, color );

charras's avatar
charras committed
488
    NewPoly->m_PolyPoints[idx] = endpos;
489
    RedrawOneStruct( panel, DC, NewPoly, g_XorMode, color );
plyatov's avatar
plyatov committed
490 491
}

492

plyatov's avatar
plyatov committed
493
/*
494
 *  Erase the last trace or the element at the current mouse position.
495
 */
496 497
void WinEDA_SchematicFrame::DeleteCurrentSegment( wxDC* DC )
{
498 499
    g_ItemToRepeat = NULL;

500 501
    if( ( GetScreen()->GetCurItem() == NULL )
       || ( ( GetScreen()->GetCurItem()->m_Flags & IS_NEW ) == 0 ) )
502 503 504 505
    {
        return;
    }

506
    /* Cancel trace in progress */
507
    if( GetScreen()->GetCurItem()->Type() == DRAW_POLYLINE_STRUCT_TYPE )
508
    {
509
        Show_Polyline_in_Ghost( DrawPanel, DC, FALSE );
510 511 512
    }
    else
    {
513
        Segment_in_Ghost( DrawPanel, DC, FALSE );
514 515
    }

516 517
    EraseStruct( (SCH_ITEM*) GetScreen()->GetCurItem(),
                (SCH_SCREEN*) GetScreen() );
518 519
    DrawPanel->ManageCurseur = NULL;
    GetScreen()->SetCurItem( NULL );
plyatov's avatar
plyatov committed
520 521 522 523
}


/* Routine to create new connection struct.
524
 */
525 526 527 528
SCH_JUNCTION* WinEDA_SchematicFrame::CreateNewJunctionStruct(
    wxDC* DC, const wxPoint& pos, bool PutInUndoList )
{
    SCH_JUNCTION* NewJunction;
plyatov's avatar
plyatov committed
529

530
    NewJunction = new SCH_JUNCTION( pos );
plyatov's avatar
plyatov committed
531

532
    g_ItemToRepeat = NewJunction;
plyatov's avatar
plyatov committed
533

534 535 536
    DrawPanel->CursorOff( DC );     // Erase schematic cursor
    RedrawOneStruct( DrawPanel, DC, NewJunction, GR_DEFAULT_DRAWMODE );
    DrawPanel->CursorOn( DC );      // Display schematic cursor
plyatov's avatar
plyatov committed
537

538
    NewJunction->SetNext( GetScreen()->EEDrawList );
539 540 541
    GetScreen()->EEDrawList = NewJunction;
    GetScreen()->SetModify();
    if( PutInUndoList )
542
        SaveCopyInUndoList( NewJunction, UR_NEW );
543
    return NewJunction;
plyatov's avatar
plyatov committed
544 545
}

546

547
/* Routine to create new NoConnect struct. */
548 549 550
SCH_NO_CONNECT* WinEDA_SchematicFrame::CreateNewNoConnectStruct( wxDC* DC )
{
    SCH_NO_CONNECT* NewNoConnect;
plyatov's avatar
plyatov committed
551

552
    NewNoConnect   = new SCH_NO_CONNECT( GetScreen()->m_Curseur );
553
    g_ItemToRepeat = NewNoConnect;
plyatov's avatar
plyatov committed
554

555 556 557
    DrawPanel->CursorOff( DC );     // Erase schematic cursor
    RedrawOneStruct( DrawPanel, DC, NewNoConnect, GR_DEFAULT_DRAWMODE );
    DrawPanel->CursorOn( DC );      // Display schematic cursor
plyatov's avatar
plyatov committed
558

559
    NewNoConnect->SetNext( GetScreen()->EEDrawList );
560 561
    GetScreen()->EEDrawList = NewNoConnect;
    GetScreen()->SetModify();
562
    SaveCopyInUndoList( NewNoConnect, UR_NEW );
563
    return NewNoConnect;
plyatov's avatar
plyatov committed
564 565 566 567
}


/* Abort function for wire, bus or line creation
568
 */
569 570
static void AbortCreateNewLine( WinEDA_DrawPanel* Panel, wxDC* DC )
{
571 572
    SCH_SCREEN* Screen = (SCH_SCREEN*) Panel->GetScreen();

573
    if( Screen->GetCurItem() )
574 575 576
    {
        Panel->ManageCurseur = NULL;
        Panel->ForceCloseManageCurseur = NULL;
577
        EraseStruct( (SCH_ITEM*) Screen->GetCurItem(), (SCH_SCREEN*) Screen );
578 579
        Screen->SetCurItem( NULL );
        RestoreOldWires( Screen );
580
        Panel->Refresh();
581 582
    }
    else
583
        g_ItemToRepeat = NULL;
584

585
    /* Clear m_Flags which is used in edit functions: */
586
    SCH_ITEM* item = Screen->EEDrawList;
587 588 589
    while( item )
    {
        item->m_Flags = 0;
590
        item = item->Next();
591
    }
plyatov's avatar
plyatov committed
592 593 594
}


595 596 597
/* Repeat the last item placement.
 * Bus lines, text, labels
 * Labels that end with a number will be incremented.
598
 */
599 600
void WinEDA_SchematicFrame::RepeatDrawItem( wxDC* DC )
{
601 602 603 604 605
    wxPoint new_pos;

    if( g_ItemToRepeat == NULL )
        return;

606
    switch( g_ItemToRepeat->Type() )
607 608
    {
    case DRAW_JUNCTION_STRUCT_TYPE:
609
        #undef STRUCT
610
        #define STRUCT ( (SCH_JUNCTION*) g_ItemToRepeat )
611 612 613 614 615 616
        g_ItemToRepeat = STRUCT->GenCopy();
        STRUCT->m_Pos += g_RepeatStep;
        new_pos = STRUCT->m_Pos;
        break;

    case DRAW_NOCONNECT_STRUCT_TYPE:
617
        #undef STRUCT
618
        #define STRUCT ( (SCH_NO_CONNECT*) g_ItemToRepeat )
619 620 621 622 623
        g_ItemToRepeat = STRUCT->GenCopy();
        STRUCT->m_Pos += g_RepeatStep;
        new_pos = STRUCT->m_Pos;
        break;

624
    case TYPE_SCH_TEXT:
625 626
        #undef STRUCT
        #define STRUCT ( (SCH_TEXT*) g_ItemToRepeat )
627 628 629 630 631 632 633
        g_ItemToRepeat = STRUCT->GenCopy();
        STRUCT->m_Pos += g_RepeatStep;
        new_pos = STRUCT->m_Pos;
        IncrementLabelMember( STRUCT->m_Text );
        break;


634
    case TYPE_SCH_LABEL:
635 636
        #undef STRUCT
        #define STRUCT ( (SCH_LABEL*) g_ItemToRepeat )
637 638 639 640 641 642 643
        g_ItemToRepeat = STRUCT->GenCopy();
        STRUCT->m_Pos += g_RepeatStep;
        new_pos = STRUCT->m_Pos;
        IncrementLabelMember( STRUCT->m_Text );
        break;


644
    case TYPE_SCH_HIERLABEL:
645 646
        #undef STRUCT
        #define STRUCT ( (SCH_HIERLABEL*) g_ItemToRepeat )
647 648 649 650 651
        g_ItemToRepeat = STRUCT->GenCopy();
        STRUCT->m_Pos += g_RepeatStep;
        new_pos = STRUCT->m_Pos;
        IncrementLabelMember( STRUCT->m_Text );
        break;
652 653

    case TYPE_SCH_GLOBALLABEL:
654 655
        #undef STRUCT
        #define STRUCT ( (SCH_GLOBALLABEL*) g_ItemToRepeat )
656 657 658 659 660 661 662
        g_ItemToRepeat = STRUCT->GenCopy();
        STRUCT->m_Pos += g_RepeatStep;
        new_pos = STRUCT->m_Pos;
        IncrementLabelMember( STRUCT->m_Text );
        break;

    case DRAW_SEGMENT_STRUCT_TYPE:
663
        #undef STRUCT
664
        #define STRUCT ( (SCH_LINE*) g_ItemToRepeat )
665 666 667 668 669 670 671 672
        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
673
            #define STRUCT ( (SCH_BUS_ENTRY*) g_ItemToRepeat )
674 675 676 677 678
        g_ItemToRepeat = STRUCT->GenCopy();
        STRUCT->m_Pos += g_RepeatStep;
        new_pos = STRUCT->m_Pos;
        break;

679 680
    case TYPE_SCH_COMPONENT:     // In repeat command the new component is put
                                 // in move mode
681 682
        #undef STRUCT
        #define STRUCT ( (SCH_COMPONENT*) g_ItemToRepeat )
683 684 685

        // Create the duplicate component, position = mouse cursor
        g_ItemToRepeat = STRUCT->GenCopy();
686 687 688
        new_pos.x = GetScreen()->m_Curseur.x - STRUCT->m_Pos.x;
        new_pos.y = GetScreen()->m_Curseur.y - STRUCT->m_Pos.y;
        STRUCT->m_Pos = GetScreen()->m_Curseur;
689
        STRUCT->m_Flags     = IS_NEW;
690
        STRUCT->m_TimeStamp = GetTimeStamp();
691 692

        for( int ii = 0; ii < STRUCT->GetFieldCount(); ii++ )
693
        {
694
            STRUCT->GetField( ii )->m_Pos += new_pos;
695 696 697 698 699 700 701 702 703 704 705 706 707 708 709
        }

        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 )
    {
710
        g_ItemToRepeat->SetNext( GetScreen()->EEDrawList );
711 712 713
        GetScreen()->EEDrawList = g_ItemToRepeat;
        TestDanglingEnds( GetScreen()->EEDrawList, NULL );
        RedrawOneStruct( DrawPanel, DC, g_ItemToRepeat, GR_DEFAULT_DRAWMODE );
714
        SaveCopyInUndoList( g_ItemToRepeat, UR_NEW );
715 716
        g_ItemToRepeat->m_Flags = 0;

717 718
//      GetScreen()->Curseur = new_pos;
//      DrawPanel->MouseTo( DrawPanel->CursorScreenPosition() );
719
    }
plyatov's avatar
plyatov committed
720 721 722
}


723 724
/* Routine incrementing labels, ie for the text ending with a number, adding
 * that a number <RepeatDeltaLabel>
725
 */
726 727
void IncrementLabelMember( wxString& name )
{
728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746
    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
747 748
}

749

charras's avatar
charras committed
750 751 752 753 754 755
/* Return TRUE if pos can be a terminal point for a wire or a bus
 * i.e. :
 *  for a WIRE, if at pos is found:
 *      - a junction
 *      - or a pin
 *      - or an other wire
756
 *
charras's avatar
charras committed
757 758
 *  - for a BUS, if at pos is found:
 *      - a BUS
759
 */
760 761
static bool IsTerminalPoint( SCH_SCREEN* screen, const wxPoint& pos, int layer )
{
762 763 764
    EDA_BaseStruct* item;
    LIB_PIN*        pin;
    SCH_COMPONENT*  LibItem = NULL;
765
    SCH_SHEET_PIN*  pinsheet;
766
    wxPoint         itempos;
767 768 769 770

    switch( layer )
    {
    case LAYER_BUS:
771
        item = PickStruct( pos, screen, BUSITEM );
772 773 774 775 776 777 778 779 780 781 782 783
        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:
784
        item = PickStruct( pos, screen, DRAWITEM );
785 786 787 788 789
        if( item )
            return TRUE;
        break;

    case LAYER_WIRE:
790
        item = PickStruct( pos, screen, RACCORDITEM | JUNCTIONITEM );
791 792 793 794 795 796
        if( item )
            return TRUE;

        pin = LocateAnyPin( screen->EEDrawList, pos, &LibItem );
        if( pin && LibItem )
        {
797 798
            // Calculate the exact position of the connection point of the pin,
            // depending on orientation of the component.
799 800 801
            itempos    = LibItem->GetScreenCoord( pin->m_Pos );
            itempos.x += LibItem->m_Pos.x;
            itempos.y += LibItem->m_Pos.y;
802
            if( ( itempos.x == pos.x ) && ( itempos.y == pos.y ) )
803 804 805
                return TRUE;
        }

806
        item = PickStruct( pos, screen, WIREITEM );
807 808 809
        if( item )
            return TRUE;

810
        item = PickStruct( pos, screen, LABELITEM );
811 812 813
        if( item && (item->Type() != TYPE_SCH_TEXT)
           && ( ( (SCH_GLOBALLABEL*) item )->m_Pos.x == pos.x )
           && ( ( (SCH_GLOBALLABEL*) item )->m_Pos.y == pos.y ) )
814 815
            return TRUE;

816
        pinsheet = LocateAnyPinSheet( pos, screen->EEDrawList );
817 818 819
        if( pinsheet && !IsBusLabel( pinsheet->m_Text ) )
        {
            itempos = pinsheet->m_Pos;
820
            if( ( itempos.x == pos.x ) && ( itempos.y == pos.y ) )
821 822 823 824 825 826 827 828 829 830
                return TRUE;
        }

        break;

    default:
        break;
    }

    return FALSE;
plyatov's avatar
plyatov committed
831 832 833 834
}


/* Return True when a wire is located at pos "pos" if
835 836 837 838 839 840 841
 *  - 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
 */
842 843
bool IsJunctionNeeded( WinEDA_SchematicFrame* frame, wxPoint& pos )
{
844
    if( PickStruct( pos, frame->GetScreen(), JUNCTIONITEM ) )
845 846
        return FALSE;

847 848
    if( PickStruct( pos, frame->GetScreen(), WIREITEM |
                    EXCLUDE_WIRE_BUS_ENDPOINTS ) )
849
    {
850 851
        if( PickStruct( pos, frame->GetScreen(), WIREITEM |
                        WIRE_BUS_ENDPOINTS_ONLY ) )
852
            return TRUE;
853
        if( frame->LocatePinEnd( frame->GetScreen()->EEDrawList, pos ) )
854 855 856 857
            return TRUE;
    }

    return FALSE;
plyatov's avatar
plyatov committed
858
}