block.cpp 27.6 KB
Newer Older
plyatov's avatar
plyatov committed
1
/****************************************************/
2
/*  BLOCK.CPP                                       */
plyatov's avatar
plyatov committed
3 4 5
/****************************************************/

#include "fctsys.h"
6
#include "appl_wxstruct.h"
7
#include "gr_basic.h"
plyatov's avatar
plyatov committed
8
#include "common.h"
9 10 11 12
#include "class_drawpanel.h"
#include "confirm.h"
#include "block_commande.h"

plyatov's avatar
plyatov committed
13 14
#include "program.h"
#include "general.h"
15
#include "class_marker_sch.h"
16
#include "class_library.h"
17
#include "protos.h"
plyatov's avatar
plyatov committed
18

19

20
// Imported functions:
21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
void            MoveItemsInList( PICKED_ITEMS_LIST& aItemsList,
                                 const wxPoint      aMoveVector );
void            MirrorListOfItems( PICKED_ITEMS_LIST& aItemsList,
                                   wxPoint&           Center );
void            DeleteItemsInList( WinEDA_DrawPanel*  panel,
                                   PICKED_ITEMS_LIST& aItemsList );
void            DuplicateItemsInList( SCH_SCREEN*        screen,
                                      PICKED_ITEMS_LIST& aItemsList,
                                      const wxPoint      aMoveVector  );

static void     CollectStructsToDrag( SCH_SCREEN* screen );
static void     AddPickedItem( SCH_SCREEN* screen, wxPoint aPosition );
static LIB_PIN* GetNextPinPosition( SCH_COMPONENT* aDrawLibItem,
                                    wxPoint&       aPosition,
                                    bool           aSearchFirst );
static void     DrawMovingBlockOutlines( WinEDA_DrawPanel* panel,
                                         wxDC*             DC,
                                         bool              erase );
static void     SaveStructListForPaste( PICKED_ITEMS_LIST& aItemsList );
40

plyatov's avatar
plyatov committed
41 42

/* Return the block command (BLOCK_MOVE, BLOCK_COPY...) corresponding to
43 44
 *  the key (ALT, SHIFT ALT ..)
 */
45 46
int WinEDA_SchematicFrame::ReturnBlockCommand( int key )
{
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 72 73 74 75 76 77
    int cmd;

    switch( key )
    {
    default:
        cmd = key & 0xFF;
        break;

    case 0:
        cmd = BLOCK_MOVE;
        break;

    case GR_KB_ALT:
    case GR_KB_SHIFT:
        cmd = BLOCK_COPY;
        break;

    case GR_KB_CTRL:
        cmd = BLOCK_DRAG;
        break;

    case GR_KB_SHIFTCTRL:
        cmd = BLOCK_DELETE;
        break;

    case MOUSE_MIDDLE:
        cmd = BLOCK_ZOOM;
        break;
    }

    return cmd;
plyatov's avatar
plyatov committed
78 79
}

80

plyatov's avatar
plyatov committed
81
/* Init the parameters used by the block paste command
82
 */
83 84
void WinEDA_SchematicFrame::InitBlockPasteInfos()
{
85
    BLOCK_SELECTOR* block = &GetScreen()->m_BlockLocate;
plyatov's avatar
plyatov committed
86

87
    block->m_ItemsSelection.CopyList( g_BlockSaveDataList.m_ItemsSelection );
88
    DrawPanel->ManageCurseur = DrawMovingBlockOutlines;
plyatov's avatar
plyatov committed
89 90 91
}


92
/* Routine to handle the BLOCK PLACE command
93 94
 *  Last routine for block operation for:
 *  - block move & drag
95
 *  - block copy & paste
96
 */
97 98
void WinEDA_SchematicFrame::HandleBlockPlace( wxDC* DC )
{
99 100
    bool            err   = FALSE;
    BLOCK_SELECTOR* block = &GetScreen()->m_BlockLocate;
101 102 103 104 105 106 107

    if( DrawPanel->ManageCurseur == NULL )
    {
        err = TRUE;
        DisplayError( this, wxT( "HandleBlockPLace() : ManageCurseur = NULL" ) );
    }

108
    if( block->GetCount() == 0 )
109 110 111
    {
        wxString msg;
        err = TRUE;
112 113
        msg.Printf( wxT( "HandleBlockPLace() error : no items to place (cmd \
%d, state %d)" ),
114 115 116 117 118 119 120 121
                    block->m_Command, block->m_State );
        DisplayError( this, msg );
    }

    block->m_State = STATE_BLOCK_STOP;

    switch( block->m_Command )
    {
122
    case BLOCK_IDLE:
123 124 125 126 127 128 129 130
        err = TRUE;
        break;

    case BLOCK_DRAG:        /* Drag */
    case BLOCK_MOVE:        /* Move */
        if( DrawPanel->ManageCurseur )
            DrawPanel->ManageCurseur( DrawPanel, DC, FALSE );

131 132 133
        SaveCopyInUndoList( block->m_ItemsSelection,
                            UR_MOVED,
                            block->m_MoveVector );
134

135
        MoveItemsInList( block->m_ItemsSelection, block->m_MoveVector );
136
        block->ClearItemsList();
137 138 139 140 141 142 143
        break;

    case BLOCK_COPY:                /* Copy */
    case BLOCK_PRESELECT_MOVE:      /* Move with preselection list*/
        if( DrawPanel->ManageCurseur )
            DrawPanel->ManageCurseur( DrawPanel, DC, FALSE );

144 145
        DuplicateItemsInList(
            GetScreen(), block->m_ItemsSelection, block->m_MoveVector );
146

147 148 149 150
        SaveCopyInUndoList(
            block->m_ItemsSelection,
            (block->m_Command ==
             BLOCK_PRESELECT_MOVE) ? UR_CHANGED : UR_NEW );
151

152
        block->ClearItemsList();
153 154
        break;

155
    case BLOCK_PASTE:
156 157
        if( DrawPanel->ManageCurseur )
            DrawPanel->ManageCurseur( DrawPanel, DC, FALSE );
158 159
        PasteListOfItems( DC );
        block->ClearItemsList();
160 161 162 163 164 165 166 167
        break;

    case BLOCK_ZOOM:        // Handled by HandleBlockEnd()
    case BLOCK_DELETE:
    case BLOCK_SAVE:
    case BLOCK_ROTATE:
    case BLOCK_MIRROR_X:
    case BLOCK_MIRROR_Y:
168
    case BLOCK_FLIP:
169 170 171 172 173 174 175 176
    case BLOCK_ABORT:
    case BLOCK_SELECT_ITEMS_ONLY:
        break;
    }

    GetScreen()->SetModify();

    /* clear struct.m_Flags  */
177
    SCH_ITEM* Struct;
178 179 180
    for( Struct = GetScreen()->EEDrawList;
        Struct != NULL;
        Struct = Struct->Next() )
181 182 183 184 185 186 187 188 189 190 191
        Struct->m_Flags = 0;

    DrawPanel->ManageCurseur = NULL;
    DrawPanel->ForceCloseManageCurseur = NULL;
    block->m_Flags   = 0;
    block->m_State   = STATE_NO_BLOCK;
    block->m_Command = BLOCK_IDLE;
    GetScreen()->SetCurItem( NULL );

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

192
    if( block->GetCount() )
193
    {
194 195
        DisplayError( this,
                      wxT( "HandleBlockPLace() error: some items left in buffer" ) );
196
        block->ClearItemsList();
197 198
    }

199 200
    SetToolID( m_ID_current_state, DrawPanel->m_PanelDefaultCursor,
               wxEmptyString );
201
    DrawPanel->Refresh();
plyatov's avatar
plyatov committed
202 203
}

204

205 206 207 208 209
/* Manage end block command
 * Returns:
 * 0 if no features selected
 * 1 otherwise
 * -1 If control ended and components selection (block delete, block save)
210
 */
211 212
int WinEDA_SchematicFrame::HandleBlockEnd( wxDC* DC )
{
213 214 215
    int             ii = 0;
    bool            zoom_command = FALSE;
    BLOCK_SELECTOR* block = &GetScreen()->m_BlockLocate;
216

217
    if( block->GetCount() )
218 219 220 221 222 223 224 225 226
    {
        BlockState   state   = block->m_State;
        CmdBlockType command = block->m_Command;
        if( DrawPanel->ForceCloseManageCurseur )
            DrawPanel->ForceCloseManageCurseur( DrawPanel, DC );
        block->m_State   = state;
        block->m_Command = command;
        DrawPanel->ManageCurseur = DrawAndSizingBlockOutlines;
        DrawPanel->ForceCloseManageCurseur = AbortBlockCurrentCommand;
227
        GetScreen()->m_Curseur = block->GetEnd();
228 229 230 231 232 233 234
        if( block->m_Command != BLOCK_ABORT )
            DrawPanel->MouseToCursorSchema();
    }

    if( DrawPanel->ManageCurseur != NULL )
        switch( block->m_Command )
        {
235
        case BLOCK_IDLE:
236 237 238
            DisplayError( this, wxT( "Error in HandleBlockPLace()" ) );
            break;

239
        case BLOCK_DRAG:    /* Drag */
240
            BreakSegmentOnJunction( (SCH_SCREEN*) GetScreen() );
241

242 243
        case BLOCK_MOVE:    /* Move */
        case BLOCK_COPY:    /* Copy */
244
            PickItemsInBlock( GetScreen()->m_BlockLocate, GetScreen() );
245 246

        case BLOCK_PRESELECT_MOVE: /* Move with preselection list*/
247
            if( block->GetCount() )
248 249
            {
                ii = 1;
250
                CollectStructsToDrag( GetScreen() );
251 252 253 254 255 256 257 258 259 260 261 262 263 264
                DrawPanel->ManageCurseur( DrawPanel, DC, FALSE );
                DrawPanel->ManageCurseur = DrawMovingBlockOutlines;
                DrawPanel->ManageCurseur( DrawPanel, DC, FALSE );
                block->m_State = STATE_BLOCK_MOVE;
            }
            else
            {
                DrawPanel->ManageCurseur( DrawPanel, DC, FALSE );
                DrawPanel->ManageCurseur = NULL;
                DrawPanel->ForceCloseManageCurseur = NULL;
            }
            break;

        case BLOCK_DELETE: /* Delete */
265
            PickItemsInBlock( GetScreen()->m_BlockLocate, GetScreen() );
266
            DrawAndSizingBlockOutlines( DrawPanel, DC, FALSE );
267
            if( block->GetCount() )
268 269
            {
                ii = -1;
270
                DeleteItemsInList( DrawPanel, block->m_ItemsSelection );
271 272
                GetScreen()->SetModify();
            }
273
            block->ClearItemsList();
274
            TestDanglingEnds( GetScreen()->EEDrawList, DC );
275
            DrawPanel->Refresh();
276 277
            break;

278
        case BLOCK_SAVE:  /* Save */
279
            PickItemsInBlock( GetScreen()->m_BlockLocate, GetScreen() );
280
            DrawAndSizingBlockOutlines( DrawPanel, DC, FALSE );
281
            if( block->GetCount() )
282
            {
283 284
                wxPoint move_vector =
                    -GetScreen()->m_BlockLocate.m_BlockLastCursorPosition;
285
                SaveStructListForPaste( block->m_ItemsSelection );
286 287
                MoveItemsInList( g_BlockSaveDataList.m_ItemsSelection,
                                 move_vector );
288 289
                ii = -1;
            }
290
            block->ClearItemsList();
291 292 293 294 295 296
            break;

        case BLOCK_PASTE:
            block->m_State = STATE_BLOCK_MOVE;
            break;

297
        case BLOCK_FLIP: /* pcbnew only! */
298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314
            break;

        case BLOCK_ROTATE:
        case BLOCK_MIRROR_X:
        case BLOCK_MIRROR_Y:
            break;

        case BLOCK_ZOOM: /* Window Zoom */
            zoom_command = TRUE;
            break;

        case BLOCK_SELECT_ITEMS_ONLY:   /* Not used */
        case BLOCK_ABORT:               /* not executed here */
            break;
        }

    if( block->m_Command  == BLOCK_ABORT )
315 316
    {
        /* clear struct.m_Flags  */
317
        EDA_BaseStruct* Struct;
318 319 320
        for( Struct = GetScreen()->EEDrawList;
            Struct != NULL;
            Struct = Struct->Next() )
321 322 323 324 325 326 327 328 329 330 331
            Struct->m_Flags = 0;
    }

    if( ii <= 0 )
    {
        block->m_Flags   = 0;
        block->m_State   = STATE_NO_BLOCK;
        block->m_Command = BLOCK_IDLE;
        DrawPanel->ManageCurseur = NULL;
        DrawPanel->ForceCloseManageCurseur = NULL;
        GetScreen()->SetCurItem( NULL );
332 333 334
        SetToolID( m_ID_current_state,
                   DrawPanel->m_PanelDefaultCursor,
                   wxEmptyString );
335 336 337
    }

    if( zoom_command )
338
        Window_Zoom( GetScreen()->m_BlockLocate );
339 340

    return ii;
plyatov's avatar
plyatov committed
341 342 343
}


344 345 346
/* Manage end block command from context menu.
 * Called after HandleBlockEnd.
 * From the command block move can execute a command other than block move.
347
 */
348 349
void WinEDA_SchematicFrame::HandleBlockEndByPopUp( int Command, wxDC* DC )
{
350 351
    int             ii    = 0;
    BLOCK_SELECTOR* block = &GetScreen()->m_BlockLocate;
352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369

    if( block->m_Command != BLOCK_MOVE )
        return;
    if( Command == BLOCK_MOVE )
        return;

    block->m_Command = (CmdBlockType) Command;
    block->SetMessageBlock( this );

    switch( block->m_Command )
    {
    case BLOCK_COPY:     /* move to copy */
        block->m_State = STATE_BLOCK_MOVE;
        ii = 1;
        break;

    case BLOCK_DRAG:     /* move to Drag */

370
        /* ???
371 372 373
         * Effacement de la liste des structures de pointage,
         * qui est devenue erronnee
         */
374 375
        if( DrawPanel->ManageCurseur )
            DrawPanel->ManageCurseur( DrawPanel, DC, FALSE );
376 377 378 379
        block->ClearItemsList();

        BreakSegmentOnJunction( GetScreen() );

380
        PickItemsInBlock( GetScreen()->m_BlockLocate, GetScreen() );
381
        if( block->GetCount() )
382 383
        {
            ii = 1;
384
            CollectStructsToDrag( (SCH_SCREEN*) GetScreen() );
385 386 387 388 389 390 391 392 393
            if( DrawPanel->ManageCurseur )
                DrawPanel->ManageCurseur( DrawPanel, DC, FALSE );
            block->m_State = STATE_BLOCK_MOVE;
        }
        break;

    case BLOCK_DELETE:     /* move to Delete */
        if( DrawPanel->ManageCurseur )
            DrawPanel->ManageCurseur( DrawPanel, DC, FALSE );
394
        if( block->GetCount() )
395 396
        {
            ii = -1;
397
            DeleteItemsInList( DrawPanel, block->m_ItemsSelection );
398 399 400
            GetScreen()->SetModify();
        }
        TestDanglingEnds( GetScreen()->EEDrawList, DC );
401 402
        DrawPanel->Refresh();
        DrawPanel->Refresh();
403 404 405 406 407
        break;

    case BLOCK_SAVE:     /* Save */
        if( DrawPanel->ManageCurseur )
            DrawPanel->ManageCurseur( DrawPanel, DC, FALSE );
408
        if( block->GetCount() )
409
        {
410 411
            wxPoint move_vector =
                -GetScreen()->m_BlockLocate.m_BlockLastCursorPosition;
412
            SaveStructListForPaste( block->m_ItemsSelection );
413
            MoveItemsInList( g_BlockSaveDataList.m_ItemsSelection, move_vector );
414 415 416 417 418 419
            ii = -1;
        }
        break;

    case BLOCK_ZOOM:     /* Window Zoom */
        DrawPanel->ForceCloseManageCurseur( DrawPanel, DC );
420 421
        DrawPanel->SetCursor(
            DrawPanel->m_PanelCursor = DrawPanel->m_PanelDefaultCursor );
422
        Window_Zoom( GetScreen()->m_BlockLocate );
423 424 425 426 427 428 429 430 431 432
        break;


    case BLOCK_ROTATE:
        break;

    case BLOCK_MIRROR_X:
    case BLOCK_MIRROR_Y:
        if( DrawPanel->ManageCurseur )
            DrawPanel->ManageCurseur( DrawPanel, DC, FALSE );
433
        if( block->GetCount() )
434 435
        {
            ii = -1;
436
            /* Compute the mirror center and put it on grid */
437 438
            wxPoint mirrorPoint = block->Centre();
            PutOnGrid( &mirrorPoint );
439 440 441
            SaveCopyInUndoList( block->m_ItemsSelection,
                                UR_MIRRORED_Y,
                                mirrorPoint );
442
            MirrorListOfItems( block->m_ItemsSelection, mirrorPoint );
443 444 445
            GetScreen()->SetModify();
        }
        TestDanglingEnds( GetScreen()->EEDrawList, DC );
446
        DrawPanel->Refresh();
447 448 449 450 451 452 453 454
        break;

    default:
        break;
    }

    if( ii <= 0 )
    {
455
        block->ClearItemsList();
456 457 458 459 460 461
        block->m_Flags   = 0;
        block->m_State   = STATE_NO_BLOCK;
        block->m_Command = BLOCK_IDLE;
        DrawPanel->ManageCurseur = NULL;
        DrawPanel->ForceCloseManageCurseur = NULL;
        GetScreen()->SetCurItem( NULL );
462 463 464
        SetToolID( m_ID_current_state,
                   DrawPanel->m_PanelDefaultCursor,
                   wxEmptyString );
465
    }
plyatov's avatar
plyatov committed
466 467 468
}


469 470
/* Traces the outline of the search block structures
 * The entire block follows the cursor
471
 */
472 473 474
static void DrawMovingBlockOutlines( WinEDA_DrawPanel* panel, wxDC* DC,
                                     bool erase )
{
475
    BLOCK_SELECTOR* block = &panel->GetScreen()->m_BlockLocate;;
476

477 478
    BASE_SCREEN*    screen = panel->GetScreen();
    SCH_ITEM*       schitem;
479

480
    /* Erase old block contents. */
481
    if( erase )
482
    {
483 484
        block->Draw( panel, DC, block->m_MoveVector, g_XorMode, block->m_Color );
        for( unsigned ii = 0; ii < block->GetCount(); ii++ )
485
        {
486
            schitem = (SCH_ITEM*) block->m_ItemsSelection.GetPickedItem( ii );
487
            DrawStructsInGhost( panel, DC, schitem, block->m_MoveVector );
488 489 490
        }
    }

491
    /* Repaint new view. */
492
    block->m_MoveVector = screen->m_Curseur - block->m_BlockLastCursorPosition;
493

494
    block->Draw( panel, DC, block->m_MoveVector, g_XorMode, block->m_Color );
495

496
    for( unsigned ii = 0; ii < block->GetCount(); ii++ )
497
    {
498
        schitem = (SCH_ITEM*) block->m_ItemsSelection.GetPickedItem( ii );
499
        DrawStructsInGhost( panel, DC, schitem, block->m_MoveVector );
500
    }
plyatov's avatar
plyatov committed
501 502 503 504
}


/* Routine to Save an object from global drawing object list.
505 506 507 508
 *  This routine is the same as delete but:
 *  - the original list is NOT removed.
 *  - List is saved in g_BlockSaveDataList
 */
509 510
void SaveStructListForPaste( PICKED_ITEMS_LIST& aItemsList )
{
511 512 513
    g_BlockSaveDataList.ClearListAndDeleteItems();      // delete previous
                                                        // saved list, if
                                                        // exists
514

515 516 517
    /* save the new list: */
    ITEM_PICKER item;
    for( unsigned ii = 0; ii < aItemsList.GetCount(); ii++ )
518
    {
519
        /* Make a copy of the original picked item. */
520 521
        SCH_ITEM* DrawStructCopy = DuplicateStruct(
             (SCH_ITEM*) aItemsList.GetPickedItem( ii ) );
522
        DrawStructCopy->SetParent( NULL );
523
        item.m_PickedItem = DrawStructCopy;
524
        g_BlockSaveDataList.PushItem( item );
525
    }
plyatov's avatar
plyatov committed
526 527 528 529
}


/*****************************************************************************
530
* Routine to paste a structure from the g_BlockSaveDataList stack.
531
*   This routine is the same as undelete but original list is NOT removed.
plyatov's avatar
plyatov committed
532
*****************************************************************************/
533
void WinEDA_SchematicFrame::PasteListOfItems( wxDC* DC )
plyatov's avatar
plyatov committed
534
{
535
    SCH_ITEM* Struct;
536

537
    if( g_BlockSaveDataList.GetCount() == 0 )
538 539 540 541 542
    {
        DisplayError( this, wxT( "No struct to paste" ) );
        return;
    }

543
    PICKED_ITEMS_LIST picklist;
544

545
    // Creates data, and push it as new data in undo item list buffer
546
    ITEM_PICKER       picker( NULL, UR_NEW );
547
    for( unsigned ii = 0; ii < g_BlockSaveDataList.GetCount(); ii++ )
548
    {
549 550 551
        Struct = DuplicateStruct(
             (SCH_ITEM*) g_BlockSaveDataList.m_ItemsSelection.GetPickedItem(
                ii ) );
552
        picker.m_PickedItem = Struct;
553
        picklist.PushItem( picker );
554

555 556
        // Clear annotation and init new time stamp for the new components:
        if( Struct->Type() == TYPE_SCH_COMPONENT )
557
        {
558 559
            ( (SCH_COMPONENT*) Struct )->m_TimeStamp = GetTimeStamp();
            ( (SCH_COMPONENT*) Struct )->ClearAnnotation( NULL );
560
        }
561 562 563 564
        SetaParent( Struct, GetScreen() );
        RedrawOneStruct( DrawPanel, DC, Struct, GR_DEFAULT_DRAWMODE );
        Struct->SetNext( GetScreen()->EEDrawList );
        GetScreen()->EEDrawList = Struct;
565 566
    }

567
    SaveCopyInUndoList( picklist, UR_NEW );
568

569
    MoveItemsInList( picklist, GetScreen()->m_BlockLocate.m_MoveVector );
570

571
    /* clear .m_Flags member for all items */
572 573 574
    for( Struct = GetScreen()->EEDrawList;
        Struct != NULL;
        Struct = Struct->Next() )
575 576 577 578 579
        Struct->m_Flags = 0;

    GetScreen()->SetModify();

    return;
plyatov's avatar
plyatov committed
580 581 582
}


583
/* creates the list of items found when a drag block is initiated.
584 585
 * items are those selected in window block an some items outside this area but
 * connected to a selected item (connected wires to a component or an entry )
586
 */
587 588 589 590
static void CollectStructsToDrag( SCH_SCREEN* screen )
{
    SCH_ITEM* Struct;
    SCH_LINE* SegmStruct;
591

592 593 594 595 596 597
    PICKED_ITEMS_LIST*  pickedlist = &screen->m_BlockLocate.m_ItemsSelection;

    if( pickedlist->GetCount() == 0 )
        return;

    /* .m_Flags member is used to handle how a wire is exactly selected
598 599
     * (fully selected, or partially selected by an end point )
     */
600
    for( Struct = screen->EEDrawList; Struct != NULL; Struct = Struct->Next() )
601 602
        Struct->m_Flags = 0;

603 604
    // Sel .m_Flags to selected for a wire or bus in selected area if there is
    // only one item:
605 606
    if( pickedlist->GetCount() == 1 )
    {
607
        Struct = (SCH_ITEM*) pickedlist->GetPickedItem( 0 );
608 609 610
        if( Struct->Type() == DRAW_SEGMENT_STRUCT_TYPE )
            Struct->m_Flags = SELECTED;
    }
611 612
    // Sel .m_Flags to selected for a wire or bus in selected area for a list
    // of items:
613
    else
614
    {
615
        for( unsigned ii = 0; ii < pickedlist->GetCount(); ii++ )
616
        {
617
            Struct = (SCH_ITEM*) pickedlist->GetPickedItem( ii );
618 619 620 621
            Struct->m_Flags = SELECTED;
        }
    }

622
    if( screen->m_BlockLocate.m_Command != BLOCK_DRAG )
623 624 625
        return;


626
    /* Remove the displacement of segment and undo the selection. */
627
    for( unsigned ii = 0; ii < pickedlist->GetCount(); ii++ )
628
    {
629
        Struct = (SCH_ITEM*) (SCH_ITEM*) pickedlist->GetPickedItem( ii );
630
        if( Struct->Type() == DRAW_SEGMENT_STRUCT_TYPE )
631
        {
632
            SegmStruct = (SCH_LINE*) Struct;
633
            if( !screen->m_BlockLocate.Inside( SegmStruct->m_Start ) )
634 635
                SegmStruct->m_Flags |= STARTPOINT;

636
            if( !screen->m_BlockLocate.Inside( SegmStruct->m_End ) )
637
                SegmStruct->m_Flags |= ENDPOINT;
638 639

            // Save m_Flags for Undo/redo drag operations:
640
            pickedlist->SetPickerFlags( SegmStruct->m_Flags, ii );
641 642 643
        }
    }

644 645
    /* Search for other items to drag. They are end wires connected to selected
     * items
646
     */
647

648
    for( unsigned ii = 0; ii < pickedlist->GetCount(); ii++ )
649
    {
650
        Struct = (SCH_ITEM*) (SCH_ITEM*) pickedlist->GetPickedItem( ii );
651
        if( Struct->Type() == TYPE_SCH_COMPONENT )
652 653
        {
            // Add all pins of the selected component to list
654
            LIB_PIN* pin;
655
            wxPoint  pos;
656 657
            pin = GetNextPinPosition( (SCH_COMPONENT*) Struct, pos, true );
            while( pin )
658
            {
659
                if( !screen->m_BlockLocate.Inside( pos ) )
660 661
                {
                    // This pin is outside area,
662 663
                    // but because it it the pin of a selected component
                    // we must also select connected items to this pin
664
                    AddPickedItem( screen, pos );
665
                }
666

667
                pin = GetNextPinPosition( (SCH_COMPONENT*) Struct, pos, false );
668 669 670
            }
        }

671
        if( Struct->Type() == DRAW_SHEET_STRUCT_TYPE )
672 673
        {
            // Add all pins sheets of a selected hierarchical sheet to the list
674
            SCH_SHEET_PIN* SLabel = ( (SCH_SHEET*) Struct )->m_Label;
675 676
            while( SLabel )
            {
charras's avatar
charras committed
677
                if( SLabel->Type() == DRAW_HIERARCHICAL_PIN_SHEET_STRUCT_TYPE )
678
                    AddPickedItem( screen, SLabel->m_Pos );
679
                SLabel = (SCH_SHEET_PIN*) SLabel->Next();
680 681 682
            }
        }

683
        if( Struct->Type() == DRAW_BUSENTRY_STRUCT_TYPE )
684
        {
685
            SCH_BUS_ENTRY* item = (SCH_BUS_ENTRY*) Struct;
686 687
            AddPickedItem( screen, item->m_Pos );
            AddPickedItem( screen, item->m_End() );
688 689
        }
    }
plyatov's avatar
plyatov committed
690 691 692
}


693
/** AddPickedItem
694 695
 * add to the picked list in screen->m_BlockLocate items found at location
 * position
696 697 698
 * @param screen = the screen to consider
 * @param position = the wxPoint where items must be located to be select
 */
699 700
static void AddPickedItem( SCH_SCREEN* screen, wxPoint position )
{
701
    SCH_ITEM*          Struct;
702

703
    /* Review the list of already selected elements. */
704 705 706
    PICKED_ITEMS_LIST* pickedlist = &screen->m_BlockLocate.m_ItemsSelection;

    for( unsigned ii = 0; ii < pickedlist->GetCount(); ii++ )
707
    {
708
        Struct = (SCH_ITEM*) pickedlist->GetPickedItem( ii );
709

710
        switch( Struct->Type() )
711 712 713
        {
        case DRAW_SEGMENT_STRUCT_TYPE:
                #undef STRUCT
714
                #define STRUCT ( (SCH_LINE*) Struct )
715
            if( STRUCT->m_Start == position )
716 717
                STRUCT->m_Flags &= ~STARTPOINT;

718
            if( STRUCT->m_End == position )
719
                STRUCT->m_Flags &= ~ENDPOINT;
720 721

            // Save m_Flags for Undo/redo drag operations:
722
            pickedlist->SetPickerFlags( STRUCT->m_Flags, ii );
723 724 725 726 727 728 729
            break;

        default:
            break;
        }
    }

730
    /* Review the list of elements not selected. */
731

732
    ITEM_PICKER picker;
733 734 735
    Struct = screen->EEDrawList;
    while( Struct )
    {
736
        picker.m_PickedItem     = Struct;
737
        picker.m_PickedItemType = Struct->Type();
738
        switch( Struct->Type() )
739 740 741 742 743 744
        {
        case TYPE_NOT_INIT:
            break;

        case DRAW_POLYLINE_STRUCT_TYPE:
            if( Struct->m_Flags & SELECTED )
745
                break;
746 747 748 749
            break;

        case DRAW_JUNCTION_STRUCT_TYPE:
                #undef STRUCT
750
                #define STRUCT ( (SCH_JUNCTION*) Struct )
751
            if( Struct->m_Flags & SELECTED )
752
                break;
753
            if( STRUCT->m_Pos != position )
754
                break;
755
            pickedlist->PushItem( picker );
756 757 758 759
            break;

        case DRAW_SEGMENT_STRUCT_TYPE:
                #undef STRUCT
760
                #define STRUCT ( (SCH_LINE*) Struct )
761
            if( Struct->m_Flags & SELECTED )
762
                break;
763
            if( STRUCT->m_Start == position )
764 765 766
            {
                Struct->m_Flags  = SELECTED | ENDPOINT | STARTPOINT;
                Struct->m_Flags &= ~STARTPOINT;
767

768
                // Save m_Flags for Undo/redo drag operations:
769
                picker.m_PickerFlags = Struct->m_Flags;
770
                pickedlist->PushItem( picker );
771
            }
772
            else if( STRUCT->m_End == position )
773 774 775
            {
                Struct->m_Flags  = SELECTED | ENDPOINT | STARTPOINT;
                Struct->m_Flags &= ~ENDPOINT;
776

777
                // Save m_Flags for Undo/redo drag operations:
778
                picker.m_PickerFlags = Struct->m_Flags;
779
                pickedlist->PushItem( picker );
780 781 782 783 784 785
            }
            break;

        case DRAW_BUSENTRY_STRUCT_TYPE:
            break;

786
        case TYPE_SCH_TEXT:
787 788
            break;

789
        case TYPE_SCH_LABEL:
790
                #undef STRUCT
791
                #define STRUCT ( (SCH_LABEL*) Struct )
792
            if( Struct->m_Flags & SELECTED )
793
                break;  /* Already in list */
794
            if( STRUCT->m_Pos != position )
795 796
                break;
            Struct->m_Flags |= SELECTED;
797
            pickedlist->PushItem( picker );
798 799
            break;

800 801
        case TYPE_SCH_HIERLABEL:
        case TYPE_SCH_GLOBALLABEL:
802
                #undef STRUCT
803
                #define STRUCT ( (SCH_LABEL*) Struct )
804
            if( Struct->m_Flags & SELECTED )
805
                break;  /* Already in list */
806
            if( STRUCT->m_Pos != position )
807 808
                break;
            Struct->m_Flags |= SELECTED;
809
            pickedlist->PushItem( picker );
810 811
            break;

812
        case TYPE_SCH_COMPONENT:
813
        case DRAW_SHEET_STRUCT_TYPE:
charras's avatar
charras committed
814
        case DRAW_HIERARCHICAL_PIN_SHEET_STRUCT_TYPE:
815 816
            break;

817
        case TYPE_SCH_MARKER:
818
                #undef STRUCT
819
                #define STRUCT ( (SCH_MARKER*) Struct )
820
            if( Struct->m_Flags & SELECTED )
821
                break;  /* Already in list */
822
            if( STRUCT->m_Pos != position )
823 824
                break;
            Struct->m_Flags |= SELECTED;
825
            pickedlist->PushItem( picker );
826 827 828 829
            break;

        case DRAW_NOCONNECT_STRUCT_TYPE:
                #undef STRUCT
830
                #define STRUCT ( (SCH_NO_CONNECT*) Struct )
831
            if( Struct->m_Flags & SELECTED )
832
                break;  /* Already in list */
833
            if( STRUCT->m_Pos != position )
834 835
                break;
            Struct->m_Flags |= SELECTED;
836
            pickedlist->PushItem( picker );
837 838 839 840 841
            break;

        default:
            break;
        }
842
        Struct = Struct->Next();
843
    }
plyatov's avatar
plyatov committed
844 845
}

846

847 848
/** GetNextPinPosition()
 * calculate position of the "next" pin of the aDrawLibItem component
849
 * @param aDrawLibItem = component to test.
850 851
 * @param aPosition = the calculated pin position, according to the component
 * orientation and position
852
 * @param aSearchFirst = if true, search for the first pin
853 854
 * @return a pointer to the pin
 */
855 856 857 858
static LIB_PIN* GetNextPinPosition( SCH_COMPONENT* aDrawLibItem,
                                    wxPoint&       aPosition,
                                    bool           aSearchFirst )
{
859
    static LIB_COMPONENT* Entry;
860 861
    static int Multi, convert, TransMat[2][2];
    static wxPoint CmpPosition;
862
    static LIB_PIN* Pin;
863

864
    if( aSearchFirst )
865
    {
866
        Entry = CMP_LIBRARY::FindLibraryComponent( aDrawLibItem->m_ChipName );
867 868

        if( Entry == NULL )
869
            return NULL;
870

871 872
        Pin   = Entry->GetNextPin();
        Multi = aDrawLibItem->m_Multi;
873 874
        convert     = aDrawLibItem->m_Convert;
        CmpPosition = aDrawLibItem->m_Pos;
charras's avatar
charras committed
875
        memcpy( TransMat, aDrawLibItem->m_Transform, sizeof(TransMat) );
876 877
    }
    else
878
        Pin = Entry->GetNextPin( Pin );
879

880
    for( ; Pin != NULL; Pin = Entry->GetNextPin( Pin ) )
881
    {
882 883
        wxASSERT( Pin->Type() == COMPONENT_PIN_DRAW_TYPE );

884
        /* Skip items not used for this part */
885
        if( Multi && Pin->m_Unit && ( Pin->m_Unit != Multi ) )
886
            continue;
887
        if( convert && Pin->m_Convert && ( Pin->m_Convert != convert ) )
888 889
            continue;

890
        /* Calculate the pin position (according to the component orientation)
891
         */
892
        aPosition = TransformCoordinate( TransMat, Pin->m_Pos ) + CmpPosition;
893
        return Pin;
894
    }
895

896
    return NULL;
plyatov's avatar
plyatov committed
897
}