hotkeys_board_editor.cpp 28.6 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
/*
 * This program source code file is part of KiCad, a free EDA CAD application.
 *
 * Copyright (C) 2009 Jean-Pierre Charras, jp.charras@wanadoo.fr
 * Copyright (C) 1992-2011 KiCad Developers, see AUTHORS.txt for contributors.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, you may find one here:
 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
 * or you may search the http://www.gnu.org website for the version 2 license,
 * or you may write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
 */

25 26 27
/**
 * @file hotkeys_board_editor.cpp
 */
28

29 30 31 32 33
#include <fctsys.h>
#include <wxPcbStruct.h>
#include <class_drawpanel.h>
#include <confirm.h>
#include <pcbcommon.h>
34

35 36 37
#include <class_board.h>
#include <class_module.h>
#include <class_track.h>
38

39 40 41
#include <pcbnew.h>
#include <pcbnew_id.h>
#include <hotkeys.h>
42 43 44 45 46 47

/* How to add a new hotkey:
 * see hotkeys.cpp
 */


Andrey Fedorushkov's avatar
Andrey Fedorushkov committed
48 49
void PCB_EDIT_FRAME::RecordMacros(wxDC* aDC, int aNumber)
{
50 51
    wxASSERT( aNumber >= 0 && aNumber < 10 );
    wxString msg;
Andrey Fedorushkov's avatar
Andrey Fedorushkov committed
52 53 54

    if( m_RecordingMacros < 0 )
    {
55
        m_RecordingMacros = aNumber;
56
        m_Macros[aNumber].m_StartPosition = GetCrossHairPosition( false );
Andrey Fedorushkov's avatar
Andrey Fedorushkov committed
57 58
        m_Macros[aNumber].m_Record.clear();

59
        msg.Printf( _( "Recording macro %d" ), aNumber );
60
        SetStatusText( msg );
Andrey Fedorushkov's avatar
Andrey Fedorushkov committed
61 62 63 64 65
    }
    else
    {
        m_RecordingMacros = -1;

66
        msg.Printf( _( "Macro %d recorded" ), aNumber );
67
        SetStatusText( msg );
Andrey Fedorushkov's avatar
Andrey Fedorushkov committed
68 69 70 71
    }
}


72
void PCB_EDIT_FRAME::CallMacros( wxDC* aDC, const wxPoint& aPosition, int aNumber )
Andrey Fedorushkov's avatar
Andrey Fedorushkov committed
73 74 75 76 77
{
    wxPoint tPosition;

    wxString msg;

78
    msg.Printf( _( "Call macro %d" ), aNumber );
Andrey Fedorushkov's avatar
Andrey Fedorushkov committed
79 80 81 82 83
    SetStatusText( msg );

    wxCommandEvent cmd( wxEVT_COMMAND_MENU_SELECTED );
    cmd.SetEventObject( this );

84
    tPosition = GetNearestGridPosition( aPosition );
Andrey Fedorushkov's avatar
Andrey Fedorushkov committed
85

86
    m_canvas->CrossHairOff( aDC );
87
    SetMousePosition( tPosition );
Andrey Fedorushkov's avatar
Andrey Fedorushkov committed
88 89
    GeneralControl( aDC, tPosition );

90 91 92
    for( std::list<MACROS_RECORD>::iterator i = m_Macros[aNumber].m_Record.begin();
         i != m_Macros[aNumber].m_Record.end();
         i++ )
Andrey Fedorushkov's avatar
Andrey Fedorushkov committed
93
    {
94
        wxPoint tmpPos = GetNearestGridPosition( tPosition + i->m_Position );
Andrey Fedorushkov's avatar
Andrey Fedorushkov committed
95

96
        SetMousePosition( tmpPos );
Andrey Fedorushkov's avatar
Andrey Fedorushkov committed
97 98 99 100 101 102 103

        GeneralControl( aDC, tmpPos, i->m_HotkeyCode );
    }

    cmd.SetId( ID_ZOOM_REDRAW );
    GetEventHandler()->ProcessEvent( cmd );

104
    m_canvas->CrossHairOn( aDC );
Andrey Fedorushkov's avatar
Andrey Fedorushkov committed
105 106 107
}


108 109
void PCB_EDIT_FRAME::OnHotKey( wxDC* aDC, int aHotkeyCode, const wxPoint& aPosition,
                               EDA_ITEM* aItem )
110 111 112 113
{
    if( aHotkeyCode == 0 )
        return;

114
    bool itemCurrentlyEdited = GetCurItem() && GetCurItem()->GetFlags();
115 116
    MODULE* module = NULL;
    int evt_type = 0;       //Used to post a wxCommandEvent on demand
117
    PCB_SCREEN* screen = GetScreen();
118 119 120 121 122 123 124

    /* Convert lower to upper case
     * (the usual toupper function has problem with non ascii codes like function keys
     */
    if( (aHotkeyCode >= 'a') && (aHotkeyCode <= 'z') )
        aHotkeyCode += 'A' - 'a';

125
    EDA_HOTKEY* HK_Descr = GetDescriptorFromHotkey( aHotkeyCode, common_Hotkey_List );
126 127 128 129

    if( HK_Descr == NULL )
        HK_Descr = GetDescriptorFromHotkey( aHotkeyCode, board_edit_Hotkey_List );

130

131 132 133
    if( HK_Descr == NULL )
        return;

134 135 136 137
    int hk_id = HK_Descr->m_Idcommand;

    if( (m_RecordingMacros != -1) &&
        !( hk_id > HK_MACRO_ID_BEGIN && hk_id < HK_MACRO_ID_END) )
Andrey Fedorushkov's avatar
Andrey Fedorushkov committed
138 139 140 141
    {
        MACROS_RECORD macros_record;
        macros_record.m_HotkeyCode = aHotkeyCode;
        macros_record.m_Idcommand = HK_Descr->m_Idcommand;
142
        macros_record.m_Position  = GetNearestGridPosition( aPosition ) -
143
                                    m_Macros[m_RecordingMacros].m_StartPosition;
144
        m_Macros[m_RecordingMacros].m_Record.push_back( macros_record );
145 146 147
        wxString msg;
        msg.Printf( _( "Add key [%c] in macro %d" ), aHotkeyCode, m_RecordingMacros );
        SetStatusText( msg );
Andrey Fedorushkov's avatar
Andrey Fedorushkov committed
148 149
    }

150 151 152 153
    // Create a wxCommandEvent that will be posted in some hot keys functions
    wxCommandEvent cmd( wxEVT_COMMAND_MENU_SELECTED );
    cmd.SetEventObject( this );

154
    LAYER_NUM      ll;
Roman Bashkov's avatar
Roman Bashkov committed
155
    unsigned int   cnt;
156

157
    switch( hk_id )
158 159 160 161 162 163
    {
    default:
    case HK_NOT_FOUND:
        return;
        break;

Andrey Fedorushkov's avatar
Andrey Fedorushkov committed
164 165 166 167 168 169 170 171 172 173
    case HK_RECORD_MACROS_0:
    case HK_RECORD_MACROS_1:
    case HK_RECORD_MACROS_2:
    case HK_RECORD_MACROS_3:
    case HK_RECORD_MACROS_4:
    case HK_RECORD_MACROS_5:
    case HK_RECORD_MACROS_6:
    case HK_RECORD_MACROS_7:
    case HK_RECORD_MACROS_8:
    case HK_RECORD_MACROS_9:
174
        RecordMacros( aDC, hk_id - HK_RECORD_MACROS_0 );
Andrey Fedorushkov's avatar
Andrey Fedorushkov committed
175 176 177 178 179 180 181 182 183 184 185 186
        break;

    case HK_CALL_MACROS_0:
    case HK_CALL_MACROS_1:
    case HK_CALL_MACROS_2:
    case HK_CALL_MACROS_3:
    case HK_CALL_MACROS_4:
    case HK_CALL_MACROS_5:
    case HK_CALL_MACROS_6:
    case HK_CALL_MACROS_7:
    case HK_CALL_MACROS_8:
    case HK_CALL_MACROS_9:
187
        CallMacros( aDC, GetCrossHairPosition( false ), hk_id - HK_CALL_MACROS_0 );
Andrey Fedorushkov's avatar
Andrey Fedorushkov committed
188 189
        break;

Roman Bashkov's avatar
Roman Bashkov committed
190
    case HK_SWITCH_TRACK_WIDTH_TO_NEXT:
191 192
        if( GetCanvas()->IsMouseCaptured() )
            GetCanvas()->CallMouseCapture( aDC, wxDefaultPosition, false );
193

194
        if( GetBoard()->GetTrackWidthIndex() < GetBoard()->m_TrackWidthList.size() - 1 )
195 196 197
            GetBoard()->SetTrackWidthIndex( GetBoard()->GetTrackWidthIndex() + 1 );
        else
            GetBoard()->SetTrackWidthIndex( 0 );
198

199 200
        if( GetCanvas()->IsMouseCaptured() )
            GetCanvas()->CallMouseCapture( aDC, wxDefaultPosition, false );
201

Roman Bashkov's avatar
Roman Bashkov committed
202 203 204
        break;

    case HK_SWITCH_TRACK_WIDTH_TO_PREVIOUS:
205 206
        if( GetCanvas()->IsMouseCaptured() )
            GetCanvas()->CallMouseCapture( aDC, wxDefaultPosition, false );
207

208 209 210 211
        if( GetBoard()->GetTrackWidthIndex() <= 0 )
            GetBoard()->SetTrackWidthIndex( GetBoard()->m_TrackWidthList.size() -1 );
        else
            GetBoard()->SetTrackWidthIndex( GetBoard()->GetTrackWidthIndex() - 1 );
212

213 214
        if( GetCanvas()->IsMouseCaptured() )
            GetCanvas()->CallMouseCapture( aDC, wxDefaultPosition, false );
215

Roman Bashkov's avatar
Roman Bashkov committed
216 217 218
        break;

    case HK_SWITCH_GRID_TO_FASTGRID1:
219
        if( m_gridSelectBox )
Roman Bashkov's avatar
Roman Bashkov committed
220
        {
221
            m_gridSelectBox->SetSelection( m_FastGrid1 );
Roman Bashkov's avatar
Roman Bashkov committed
222 223 224
            cmd.SetEventType( wxEVT_COMMAND_COMBOBOX_SELECTED );
            OnSelectGrid( cmd );
        }
225

Roman Bashkov's avatar
Roman Bashkov committed
226 227 228
        break;

    case HK_SWITCH_GRID_TO_FASTGRID2:
229
        if( m_gridSelectBox )
Roman Bashkov's avatar
Roman Bashkov committed
230
        {
231
            m_gridSelectBox->SetSelection( m_FastGrid2 );
Roman Bashkov's avatar
Roman Bashkov committed
232 233 234
            cmd.SetEventType( wxEVT_COMMAND_COMBOBOX_SELECTED );
            OnSelectGrid( cmd );
        }
235

Roman Bashkov's avatar
Roman Bashkov committed
236 237 238
        break;

    case HK_SWITCH_GRID_TO_NEXT:
239
        if( m_gridSelectBox )
Roman Bashkov's avatar
Roman Bashkov committed
240
        {
241 242
            m_gridSelectBox->SetSelection( ( m_gridSelectBox->GetSelection() + 1 ) %
                                           m_gridSelectBox->GetCount() );
Roman Bashkov's avatar
Roman Bashkov committed
243 244 245 246 247 248
            cmd.SetEventType( wxEVT_COMMAND_COMBOBOX_SELECTED );
            OnSelectGrid( cmd );
        }
        break;

    case HK_SWITCH_GRID_TO_PREVIOUS:
249
        if( m_gridSelectBox )
Roman Bashkov's avatar
Roman Bashkov committed
250
        {
251
            cnt = m_gridSelectBox->GetSelection();
252

Roman Bashkov's avatar
Roman Bashkov committed
253
            if ( cnt == 0 )
254
                cnt = m_gridSelectBox->GetCount() - 1;
Roman Bashkov's avatar
Roman Bashkov committed
255 256
            else
                cnt--;
257

258
            m_gridSelectBox->SetSelection( cnt );
Roman Bashkov's avatar
Roman Bashkov committed
259 260 261
            cmd.SetEventType( wxEVT_COMMAND_COMBOBOX_SELECTED );
            OnSelectGrid( cmd );
        }
262

Roman Bashkov's avatar
Roman Bashkov committed
263 264
        break;

265
    case HK_SWITCH_LAYER_TO_PREVIOUS:
266
        ll = getActiveLayer();
267

268 269 270 271 272 273
        if( (ll <= LAYER_N_BACK) || (ll > LAYER_N_FRONT) )
            break;

        if( GetBoard()->GetCopperLayerCount() < 2 ) // Single layer
            ll = LAYER_N_BACK;
        else if( ll == LAYER_N_FRONT )
274
            ll = std::max( LAYER_N_BACK, FIRST_COPPER_LAYER + GetBoard()->GetCopperLayerCount() - 2 );
275
        else
276
            --ll;
277

278 279 280 281
        SwitchLayer( aDC, ll );
        break;

    case HK_SWITCH_LAYER_TO_NEXT:
282
        ll = getActiveLayer();
283

284 285
        if( (ll < LAYER_N_BACK) || (ll >= LAYER_N_FRONT) )
            break;
286

287 288 289 290 291
        if( GetBoard()->GetCopperLayerCount() < 2 ) // Single layer
            ll = LAYER_N_BACK;
        else if( ll >= GetBoard()->GetCopperLayerCount() - 2 )
            ll = LAYER_N_FRONT;
        else
292
            ++ll;
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
        SwitchLayer( aDC, ll );
        break;

    case HK_SWITCH_LAYER_TO_COMPONENT:
        SwitchLayer( aDC, LAYER_N_FRONT );
        break;

    case HK_SWITCH_LAYER_TO_COPPER:
        SwitchLayer( aDC, LAYER_N_BACK );
        break;

    case HK_SWITCH_LAYER_TO_INNER1:
        SwitchLayer( aDC, LAYER_N_2 );
        break;

    case HK_SWITCH_LAYER_TO_INNER2:
        SwitchLayer( aDC, LAYER_N_3 );
        break;

    case HK_SWITCH_LAYER_TO_INNER3:
        SwitchLayer( aDC, LAYER_N_4 );
        break;

    case HK_SWITCH_LAYER_TO_INNER4:
        SwitchLayer( aDC, LAYER_N_5 );
        break;

    case HK_SWITCH_LAYER_TO_INNER5:
        SwitchLayer( aDC, LAYER_N_6 );
        break;

    case HK_SWITCH_LAYER_TO_INNER6:
        SwitchLayer( aDC, LAYER_N_7 );
        break;

    case HK_HELP: // Display Current hotkey list
        DisplayHotkeyList( this, g_Board_Editor_Hokeys_Descr );
        break;

    case HK_ZOOM_IN:
        evt_type = ID_POPUP_ZOOM_IN;
        break;

    case HK_ZOOM_OUT:
        evt_type = ID_POPUP_ZOOM_OUT;
        break;

    case HK_ZOOM_REDRAW:
        evt_type = ID_ZOOM_REDRAW;
        break;

    case HK_ZOOM_AUTO:
        evt_type = ID_ZOOM_PAGE;
        break;

    case HK_ZOOM_CENTER:
        evt_type = ID_POPUP_ZOOM_CENTER;
        break;

    case HK_ADD_MODULE:
354
        evt_type = ID_PCB_MODULE_BUTT;
355 356 357 358 359 360
        break;

    case HK_UNDO:
    case HK_REDO:
        if( !itemCurrentlyEdited )
        {
361
            wxCommandEvent event( wxEVT_COMMAND_TOOL_CLICKED, HK_Descr->m_IdMenuEvent );
362 363
            wxPostEvent( this, event );
        }
364

365 366
        break;

367 368 369 370 371 372 373
    case HK_RESET_LOCAL_COORD:  // Set the relative coord
        GetScreen()->m_O_Curseur = GetCrossHairPosition();
        break;

    case HK_SET_GRID_ORIGIN:
        SetGridOrigin( GetCrossHairPosition() );
        OnModify();     // because grid origin is saved in board, show as modified
374 375 376 377 378 379
        m_canvas->Refresh();
        break;

    case HK_RESET_GRID_ORIGIN:
        SetGridOrigin( wxPoint(0,0) );
        OnModify();     // because grid origin is saved in board, show as modified
380
        m_canvas->Refresh();
381 382 383
        break;

    case HK_SWITCH_UNITS:
384 385
        evt_type = (g_UserUnit == INCHES) ?
                    ID_TB_OPTIONS_SELECT_UNIT_MM : ID_TB_OPTIONS_SELECT_UNIT_INCH;
386 387 388 389 390 391
        break;

    case HK_SWITCH_TRACK_DISPLAY_MODE:
        DisplayOpt.DisplayPcbTrackFill ^= 1;
        DisplayOpt.DisplayPcbTrackFill &= 1;
        m_DisplayPcbTrackFill = DisplayOpt.DisplayPcbTrackFill;
392
        m_canvas->Refresh();
393 394 395 396 397 398 399
        break;

    case HK_DELETE:
        OnHotkeyDeleteItem( aDC );
        break;

    case HK_BACK_SPACE:
400
        if( IsCopperLayer( getActiveLayer() ) )
401 402 403 404 405 406 407 408 409 410 411 412 413 414
        {
            if( !itemCurrentlyEdited )
            {
                // no track is currently being edited - select a segment and remove it.
                // @todo: possibly? pass the HK command code to PcbGeneralLocateAndDisplay()
                // so it can restrict its search to specific item types.
                BOARD_ITEM * item = PcbGeneralLocateAndDisplay();

                // don't let backspace delete modules!!
                if( item && item->IsTrack() )
                {
                    Delete_Segment( aDC, (TRACK*) item );
                    SetCurItem( NULL );
                }
415

416 417 418 419 420 421 422 423 424 425 426 427
                OnModify();
            }
            else if( GetCurItem()->IsTrack() )
            {
                // then an element is being edited - remove the last segment.
                // simple lines for debugger:
                TRACK* track = (TRACK*) GetCurItem();
                track = Delete_Segment( aDC, track );
                SetCurItem( track );
                OnModify();
            }
        }
428

429 430 431
        break;

    case HK_END_TRACK:
432
        if( itemCurrentlyEdited && GetCurItem()->IsTrack() && GetCurItem()->IsNew() )
433 434
        {
            // A new track is in progress: call to End_Route()
435
            m_canvas->MoveCursorToCrossHair();
436 437
            End_Route( (TRACK*) GetCurItem(), aDC );
        }
438

439 440 441 442 443
        break;

    case HK_GET_AND_MOVE_FOOTPRINT:
        if( !itemCurrentlyEdited )
            evt_type = ID_POPUP_PCB_GET_AND_MOVE_MODULE_REQUEST;
444

445 446 447 448 449
        break;

    case HK_FIND_ITEM:
        if( !itemCurrentlyEdited )
            evt_type = ID_FIND_ITEMS;
450

451 452 453 454 455
        break;

    case HK_LOAD_BOARD:
        if( !itemCurrentlyEdited )
            evt_type = ID_LOAD_FILE ;
456

457 458 459 460 461
        break;

    case HK_SAVE_BOARD:
        if( !itemCurrentlyEdited )
            evt_type = ID_SAVE_BOARD;
462

463 464 465
        break;

    case HK_ADD_MICROVIA: // Place a micro via if a track is in progress
466
        if( GetToolId() != ID_TRACK_BUTT )
467
            return;
468

469
        if( !itemCurrentlyEdited )                         // no track in progress: nothing to do
470
            break;
471

472
        if( GetCurItem()->Type() != PCB_TRACE_T )           // Should not occur
473
            return;
474

475
        if( !GetCurItem()->IsNew() )
476 477 478 479 480
            return;

        // place micro via and switch layer
        if( IsMicroViaAcceptable() )
            evt_type = ID_POPUP_PCB_PLACE_MICROVIA;
481

482 483
        break;

484 485 486
    case HK_ADD_BLIND_BURIED_VIA:
    case HK_ADD_THROUGH_VIA: // Switch to alternate layer and Place a via if a track is in progress
        if( GetBoard()->GetDesignSettings().m_BlindBuriedViaAllowed &&
487
            hk_id == HK_ADD_BLIND_BURIED_VIA  )
488 489 490 491
            GetBoard()->GetDesignSettings().m_CurrentViaType = VIA_BLIND_BURIED;
        else
            GetBoard()->GetDesignSettings().m_CurrentViaType = VIA_THROUGH;

492 493 494
        if( !itemCurrentlyEdited ) // no track in progress: switch layer only
        {
            Other_Layer_Route( NULL, aDC );
jean-pierre charras's avatar
jean-pierre charras committed
495
            if( DisplayOpt.ContrastModeDisplay )
496
                m_canvas->Refresh();
497 498
            break;
        }
499

500
        if( GetToolId() != ID_TRACK_BUTT )
501
            return;
502

503
        if( GetCurItem()->Type() != PCB_TRACE_T )
504
            return;
505

506
        if( !GetCurItem()->IsNew() )
507
            return;
508

509 510
        evt_type = hk_id == HK_ADD_BLIND_BURIED_VIA ?
            ID_POPUP_PCB_PLACE_BLIND_BURIED_VIA : ID_POPUP_PCB_PLACE_THROUGH_VIA;
511 512
        break;

513 514 515 516 517 518 519 520 521
    case HK_SEL_LAYER_AND_ADD_THROUGH_VIA:
    case HK_SEL_LAYER_AND_ADD_BLIND_BURIED_VIA:
        if( GetCurItem() == NULL || !GetCurItem()->IsNew() ||
            GetCurItem()->Type() != PCB_TRACE_T )
            break;

        evt_type = hk_id == HK_SEL_LAYER_AND_ADD_BLIND_BURIED_VIA ?
            ID_POPUP_PCB_SELECT_CU_LAYER_AND_PLACE_BLIND_BURIED_VIA :
            ID_POPUP_PCB_SELECT_CU_LAYER_AND_PLACE_THROUGH_VIA;
522 523 524 525 526 527 528 529 530
        break;

    case HK_SWITCH_TRACK_POSTURE:
        /* change the position of initial segment when creating new tracks
         * switch from _/  to -\ .
         */
        evt_type = ID_POPUP_PCB_SWITCH_TRACK_POSTURE ;
        break;

531 532 533 534
    case HK_DRAG_TRACK_KEEP_SLOPE:
        OnHotkeyMoveItem( HK_DRAG_TRACK_KEEP_SLOPE );
        break;

Andrey Fedorushkov's avatar
Andrey Fedorushkov committed
535 536 537 538
    case HK_PLACE_ITEM:
        OnHotkeyPlaceItem( aDC );
        break;

539 540
    case HK_ADD_NEW_TRACK: // Start new track, if possible
        OnHotkeyBeginRoute( aDC );
541 542 543 544 545 546 547 548 549 550
        break;

    case HK_EDIT_ITEM:      // Edit board item
        OnHotkeyEditItem( HK_EDIT_ITEM );
        break;

    // Footprint edition:
    case HK_LOCK_UNLOCK_FOOTPRINT: // toggle module "MODULE_is_LOCKED" status:
        // get any module, locked or not locked and toggle its locked status
        if( !itemCurrentlyEdited )
551
        {
552
            wxPoint pos = RefPos( true );
553
            module = GetBoard()->GetFootprint( pos, screen->m_Active_Layer, true );
554
        }
555
        else if( GetCurItem()->Type() == PCB_MODULE_T )
556
        {
557
            module = (MODULE*) GetCurItem();
558 559
        }

560 561 562 563
        if( module )
        {
            SetCurItem( module );
            module->SetLocked( !module->IsLocked() );
564
            OnModify();
565
            SetMsgPanel( module );
566 567 568 569 570 571 572 573 574 575 576
        }
        break;

    case HK_DRAG_ITEM:    // Start drag module or track segment
        OnHotkeyMoveItem( HK_DRAG_ITEM );
        break;

    case HK_MOVE_ITEM:                  // Start move item
        OnHotkeyMoveItem( HK_MOVE_ITEM );
        break;

577 578 579 580
    case HK_COPY_ITEM:
        evt_type = OnHotkeyCopyItem();
        break;

581 582 583 584
    case HK_ROTATE_ITEM:        // Rotation
        OnHotkeyRotateItem( HK_ROTATE_ITEM );
        break;

585 586
    case HK_FLIP_ITEM:
        OnHotkeyRotateItem( HK_FLIP_ITEM );
587
        break;
588

589 590
    case HK_SWITCH_HIGHCONTRAST_MODE: // switch to high contrast mode and refresh the canvas
        DisplayOpt.ContrastModeDisplay = !DisplayOpt.ContrastModeDisplay;
591
        m_canvas->Refresh();
592
        break;
593 594 595 596 597 598 599 600 601 602 603 604

    case HK_CANVAS_CAIRO:
        evt_type = ID_MENU_CANVAS_CAIRO;
        break;

    case HK_CANVAS_OPENGL:
        evt_type = ID_MENU_CANVAS_OPENGL;
        break;

    case HK_CANVAS_DEFAULT:
        evt_type = ID_MENU_CANVAS_DEFAULT;
        break;
605 606 607 608 609 610 611
    }

    if( evt_type != 0 )
    {
        wxCommandEvent evt( wxEVT_COMMAND_MENU_SELECTED );
        evt.SetEventObject( this );
        evt.SetId( evt_type );
Andrey Fedorushkov's avatar
Andrey Fedorushkov committed
612
        GetEventHandler()->ProcessEvent( evt );
613 614 615 616
    }
}


617
bool PCB_EDIT_FRAME::OnHotkeyDeleteItem( wxDC* aDC )
618 619
{
    BOARD_ITEM* item = GetCurItem();
620
    bool ItemFree = (item == NULL) || (item->GetFlags() == 0);
621

622
    switch( GetToolId() )
623 624
    {
    case ID_TRACK_BUTT:
625
        if( getActiveLayer() > LAYER_N_FRONT )
626
            return false;
627

628 629 630
        if( ItemFree )
        {
            item = PcbGeneralLocateAndDisplay();
631

632
            if( item && !item->IsTrack() )
633
                return false;
634

635 636 637 638 639 640 641 642 643 644 645 646 647
            Delete_Track( aDC, (TRACK*) item );
        }
        else if( item->IsTrack( ) )
        {
            // simple lines for debugger:
            TRACK* track = (TRACK*) item;
            track = Delete_Segment( aDC, track );
            SetCurItem( track );
            OnModify();
            return true;
        }
        break;

648
    case ID_PCB_MODULE_BUTT:
649 650
        if( ItemFree )
        {
651
            wxPoint pos    = RefPos( false );
652
            MODULE* module = GetBoard()->GetFootprint( pos, UNDEFINED_LAYER, false );
653

654 655
            if( module == NULL )
                return false;
656

657 658 659 660 661 662 663 664 665 666
            RemoveStruct( module, aDC );
        }
        else
            return false;
        break;

    default:
        if( ItemFree )
        {
            item = PcbGeneralLocateAndDisplay();
667

668 669
            if( item == NULL )
                return false;
670

671 672 673
            RemoveStruct( item, aDC );
        }
        else
674
        return false;
675 676 677 678 679 680 681
    }

    OnModify();
    SetCurItem( NULL );
    return true;
}

682

683
bool PCB_EDIT_FRAME::OnHotkeyEditItem( int aIdCommand )
684 685
{
    BOARD_ITEM* item = GetCurItem();
686
    bool itemCurrentlyEdited = item && item->GetFlags();
687 688 689 690 691 692 693 694 695 696 697 698 699 700 701

    if( itemCurrentlyEdited )
        return false;

    item = PcbGeneralLocateAndDisplay();

    if( item == NULL )
        return false;

    SetCurItem( item );

    int evt_type = 0;       //Used to post a wxCommandEvent on demand

    switch( item->Type() )
    {
702 703
    case PCB_TRACE_T:
    case PCB_VIA_T:
704 705
        if( aIdCommand == HK_EDIT_ITEM )
            evt_type = ID_POPUP_PCB_EDIT_TRACKSEG;
706

707 708
        break;

709
    case PCB_TEXT_T:
710 711
        if( aIdCommand == HK_EDIT_ITEM )
            evt_type = ID_POPUP_PCB_EDIT_TEXTEPCB;
712

713 714
        break;

715
    case PCB_MODULE_T:
716
        if( aIdCommand == HK_EDIT_ITEM )
717
            evt_type = ID_POPUP_PCB_EDIT_MODULE_PRMS;
718

719 720
        break;

721
    case PCB_PAD_T:
722
        // Until dec 2012 a EDIT_MODULE event is posted here to prevent pads
723
        // from being edited by hotkeys.
724 725 726 727 728
        // Process_Special_Functions takes care of finding the parent.
        // After dec 2012 a EDIT_PAD event is posted, because there is no
        // reason to not allow pad edit by hotkey
        // (pad coordinates are no more modified by rounding, in nanometer version
        // when using inches or mm in dialog)
729
        if( aIdCommand == HK_EDIT_ITEM )
730
            evt_type = ID_POPUP_PCB_EDIT_PAD;
731

732 733
        break;

734
    case PCB_TARGET_T:
735 736
        if( aIdCommand == HK_EDIT_ITEM )
            evt_type = ID_POPUP_PCB_EDIT_MIRE;
737

738 739
        break;

740
    case PCB_DIMENSION_T:
741 742
        if( aIdCommand == HK_EDIT_ITEM )
            evt_type = ID_POPUP_PCB_EDIT_DIMENSION;
743

744 745
        break;

746
    case PCB_MODULE_TEXT_T:
747 748
        if( aIdCommand == HK_EDIT_ITEM )
            evt_type = ID_POPUP_PCB_EDIT_TEXTMODULE;
749

750 751
        break;

752
    case PCB_LINE_T:
753 754
        if( aIdCommand == HK_EDIT_ITEM )
            evt_type = ID_POPUP_PCB_EDIT_DRAWING;
755

756 757
        break;

758
    case PCB_ZONE_AREA_T:
759 760
        if( aIdCommand == HK_EDIT_ITEM )
            evt_type = ID_POPUP_PCB_EDIT_ZONE_PARAMS;
761

762 763 764 765 766 767 768 769 770 771 772
        break;

    default:
        break;
    }

    if( evt_type != 0 )
    {
        wxCommandEvent evt( wxEVT_COMMAND_MENU_SELECTED );
        evt.SetEventObject( this );
        evt.SetId( evt_type );
Andrey Fedorushkov's avatar
Andrey Fedorushkov committed
773
        GetEventHandler()->ProcessEvent( evt );
774 775 776 777 778 779
        return true;
    }

    return false;
}

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
int PCB_EDIT_FRAME::OnHotkeyCopyItem()
{
    BOARD_ITEM* item = GetCurItem();
    bool itemCurrentlyEdited = item && item->GetFlags();

    if( itemCurrentlyEdited )
        return 0;

    item = PcbGeneralLocateAndDisplay();

    if( item == NULL )
        return 0;

    SetCurItem( item );

    int eventId = 0;

    switch( item->Type() )
    {
    case PCB_TEXT_T:
        eventId = ID_POPUP_PCB_COPY_TEXTEPCB;
        break;
    default:
        eventId = 0;
        break;
    }

    return eventId;
}


812
bool PCB_EDIT_FRAME::OnHotkeyMoveItem( int aIdCommand )
813 814
{
    BOARD_ITEM* item = GetCurItem();
815
    bool itemCurrentlyEdited = item && item->GetFlags();
816 817 818 819 820 821 822 823 824 825 826

    if( itemCurrentlyEdited )
        return false;

    item = PcbGeneralLocateAndDisplay();

    if( item == NULL )
        return false;

    SetCurItem( item );

827
    int evt_type = 0;       // Used to post a wxCommandEvent on demand
828 829 830

    switch( item->Type() )
    {
831 832
    case PCB_TRACE_T:
    case PCB_VIA_T:
833 834
        if( aIdCommand == HK_MOVE_ITEM )
            evt_type = ID_POPUP_PCB_MOVE_TRACK_NODE;
835

836 837
        if( aIdCommand == HK_DRAG_ITEM )
            evt_type = ID_POPUP_PCB_DRAG_TRACK_SEGMENT;
838

839 840
        if( aIdCommand == HK_DRAG_TRACK_KEEP_SLOPE )
            evt_type = ID_POPUP_PCB_DRAG_TRACK_SEGMENT_KEEP_SLOPE;
841

842 843
        break;

844
    case PCB_MODULE_T:
845 846 847
        {
            if( aIdCommand == HK_MOVE_ITEM )
                evt_type = ID_POPUP_PCB_MOVE_MODULE_REQUEST;
848

849 850 851 852
            if( aIdCommand == HK_DRAG_ITEM )
                evt_type = ID_POPUP_PCB_DRAG_MODULE_REQUEST;
        }
        break;
853

854
    case PCB_PAD_T:
855 856 857 858 859 860
        // Post MODULE_REQUEST events here to prevent pads
        // from being moved or dragged by hotkeys.
        // Process_Special_Functions takes care of finding
        // the parent.
        if( aIdCommand == HK_MOVE_ITEM )
            evt_type = ID_POPUP_PCB_MOVE_MODULE_REQUEST;
861

862 863
        if( aIdCommand == HK_DRAG_ITEM )
            evt_type = ID_POPUP_PCB_DRAG_MODULE_REQUEST;
864

865 866
        break;

867
    case PCB_TEXT_T:
868 869
        if( aIdCommand == HK_MOVE_ITEM )
            evt_type = ID_POPUP_PCB_MOVE_TEXTEPCB_REQUEST;
870

871 872
        break;

873
    case PCB_TARGET_T:
874 875
        if( aIdCommand == HK_MOVE_ITEM )
            evt_type = ID_POPUP_PCB_MOVE_MIRE_REQUEST;
876

877 878
        break;

879
    case PCB_ZONE_AREA_T:
880 881
        if( aIdCommand == HK_MOVE_ITEM )
            evt_type = ID_POPUP_PCB_MOVE_ZONE_OUTLINES;
882

883 884
        if( aIdCommand == HK_DRAG_ITEM )
            evt_type = ID_POPUP_PCB_DRAG_ZONE_OUTLINE_SEGMENT;
885

886 887
        break;

888
    case PCB_MODULE_TEXT_T:
889 890
        if( aIdCommand == HK_MOVE_ITEM )
            evt_type = ID_POPUP_PCB_MOVE_TEXTMODULE_REQUEST;
891

892 893
        break;

894
    case PCB_LINE_T:
895 896
        if( aIdCommand == HK_MOVE_ITEM )
            evt_type = ID_POPUP_PCB_MOVE_DRAWING_REQUEST;
897

898 899
        break;

900 901 902 903 904
    case PCB_DIMENSION_T:
        if( aIdCommand == HK_MOVE_ITEM )
            evt_type = ID_POPUP_PCB_MOVE_TEXT_DIMENSION_REQUEST;
        break;

905 906 907 908 909 910 911 912 913
    default:
        break;
    }

    if( evt_type != 0 )
    {
        wxCommandEvent evt( wxEVT_COMMAND_MENU_SELECTED );
        evt.SetEventObject( this );
        evt.SetId( evt_type );
Andrey Fedorushkov's avatar
Andrey Fedorushkov committed
914
        GetEventHandler()->ProcessEvent( evt );
915 916 917 918 919 920
        return true;
    }

    return false;
}

921

Andrey Fedorushkov's avatar
Andrey Fedorushkov committed
922 923 924 925
bool PCB_EDIT_FRAME::OnHotkeyPlaceItem( wxDC* aDC )
{
    BOARD_ITEM* item = GetCurItem();
    bool no_tool = GetToolId() == ID_NO_TOOL_SELECTED;
926
    bool itemCurrentlyEdited = item && item->GetFlags();
Andrey Fedorushkov's avatar
Andrey Fedorushkov committed
927

928
    m_canvas->SetAutoPanRequest( false );
Andrey Fedorushkov's avatar
Andrey Fedorushkov committed
929 930 931

    if( itemCurrentlyEdited )
    {
932
        m_canvas->SetIgnoreMouseEvents( true );
933
        m_canvas->CrossHairOff( aDC );
Andrey Fedorushkov's avatar
Andrey Fedorushkov committed
934 935 936

        switch( item->Type() )
        {
937 938
        case PCB_TRACE_T:
        case PCB_VIA_T:
939
            if( item->IsDragging() )
Andrey Fedorushkov's avatar
Andrey Fedorushkov committed
940
                PlaceDraggedOrMovedTrackSegment( (TRACK*) item, aDC );
941

Andrey Fedorushkov's avatar
Andrey Fedorushkov committed
942 943
            break;

944
        case PCB_TEXT_T:
Andrey Fedorushkov's avatar
Andrey Fedorushkov committed
945 946 947
            Place_Texte_Pcb( (TEXTE_PCB*) item, aDC );
            break;

948
        case PCB_MODULE_TEXT_T:
Andrey Fedorushkov's avatar
Andrey Fedorushkov committed
949 950 951
            PlaceTexteModule( (TEXTE_MODULE*) item, aDC );
            break;

952
        case PCB_PAD_T:
Andrey Fedorushkov's avatar
Andrey Fedorushkov committed
953 954 955
            PlacePad( (D_PAD*) item, aDC );
            break;

956
        case PCB_MODULE_T:
957
            PlaceModule( (MODULE*) item, aDC );
Andrey Fedorushkov's avatar
Andrey Fedorushkov committed
958 959
            break;

960 961
        case PCB_TARGET_T:
            PlaceTarget( (PCB_TARGET*) item, aDC );
Andrey Fedorushkov's avatar
Andrey Fedorushkov committed
962 963
            break;

964
        case PCB_LINE_T:
Andrey Fedorushkov's avatar
Andrey Fedorushkov committed
965 966
            if( no_tool )   // when no tools: existing item moving.
                Place_DrawItem( (DRAWSEGMENT*) item, aDC );
967

Andrey Fedorushkov's avatar
Andrey Fedorushkov committed
968 969 970 971 972 973
            break;

        default:
            break;
        }

974
        m_canvas->SetIgnoreMouseEvents( false );
975
        m_canvas->CrossHairOn( aDC );
Andrey Fedorushkov's avatar
Andrey Fedorushkov committed
976 977 978

        return true;
    }
979

Andrey Fedorushkov's avatar
Andrey Fedorushkov committed
980 981
    return false;
}
982

983

984 985
TRACK * PCB_EDIT_FRAME::OnHotkeyBeginRoute( wxDC* aDC )
{
986
    if( getActiveLayer() > LAYER_N_FRONT )
987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026
        return NULL;

    bool itemCurrentlyEdited = (GetCurItem() && GetCurItem()->GetFlags());

    // Ensure the track tool is active
    if( GetToolId() != ID_TRACK_BUTT && !itemCurrentlyEdited )
    {
        wxCommandEvent cmd( wxEVT_COMMAND_MENU_SELECTED );
        cmd.SetEventObject( this );
        cmd.SetId( ID_TRACK_BUTT );
        GetEventHandler()->ProcessEvent( cmd );
    }

    if( GetToolId() != ID_TRACK_BUTT )
        return NULL;

    TRACK* track = NULL;

    if( !itemCurrentlyEdited )     // no track in progress:
    {
        track = Begin_Route( NULL, aDC );
        SetCurItem( track );

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

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

        m_canvas->SetAutoPanRequest( true );
    }

    return track;
}
1027

1028
bool PCB_EDIT_FRAME::OnHotkeyRotateItem( int aIdCommand )
1029 1030
{
    BOARD_ITEM* item = GetCurItem();
1031
    bool        itemCurrentlyEdited = item && item->GetFlags();
1032 1033
    int         evt_type = 0; // Used to post a wxCommandEvent on demand

1034 1035 1036 1037 1038 1039 1040 1041 1042
    // Allows block rotate operation on hot key.
    if( GetScreen()->m_BlockLocate.GetState() != STATE_NO_BLOCK )
    {
        evt_type = ID_POPUP_ROTATE_BLOCK;
    }
    else
    {
        if( !itemCurrentlyEdited )
            item = PcbGeneralLocateAndDisplay();
1043

1044 1045
        if( item == NULL )
            return false;
1046

1047
        SetCurItem( item );
1048

1049 1050 1051 1052 1053
        switch( item->Type() )
        {
        case PCB_MODULE_T:
            if( aIdCommand == HK_ROTATE_ITEM )                      // Rotation
                evt_type = ID_POPUP_PCB_ROTATE_MODULE_COUNTERCLOCKWISE;
1054

1055 1056 1057
            if( aIdCommand == HK_FLIP_ITEM )                        // move to other side
                evt_type = ID_POPUP_PCB_CHANGE_SIDE_MODULE;
            break;
1058

1059 1060 1061 1062 1063
        case PCB_TEXT_T:
            if( aIdCommand == HK_ROTATE_ITEM )                      // Rotation
                evt_type = ID_POPUP_PCB_ROTATE_TEXTEPCB;
            else if( aIdCommand == HK_FLIP_ITEM )
                evt_type = ID_POPUP_PCB_FLIP_TEXTEPCB;
1064

1065
            break;
1066

1067 1068 1069
        case PCB_MODULE_TEXT_T:
            if( aIdCommand == HK_ROTATE_ITEM )                      // Rotation
                evt_type = ID_POPUP_PCB_ROTATE_TEXTMODULE;
1070

1071
            break;
1072

1073 1074 1075
        default:
            break;
        }
1076 1077 1078 1079 1080 1081 1082
    }

    if( evt_type != 0 )
    {
        wxCommandEvent evt( wxEVT_COMMAND_MENU_SELECTED );
        evt.SetEventObject( this );
        evt.SetId( evt_type );
Andrey Fedorushkov's avatar
Andrey Fedorushkov committed
1083
        GetEventHandler()->ProcessEvent( evt );
1084 1085 1086 1087 1088
        return true;
    }

    return false;
}