Commit bee6b9f9 authored by Lorenzo Marcantonio's avatar Lorenzo Marcantonio
Browse files

Fixes #1186269

- Refactored the common part of cursor key movement and crosshair update
  in the various GeneralControl
- Add x10 movement with the keyboard (CTRL modifier)
- Avoid fixup of the cursor position by dummy mouse movements generated
  by cursor warping (original analysis and idea Chris Gibson)
- Do key handling in a way to permit sub-pixel cursor movement 
parent 00e18d21
Loading
Loading
Loading
Loading
+117 −0
Original line number Original line Diff line number Diff line
@@ -119,6 +119,7 @@ EDA_DRAW_FRAME::EDA_DRAW_FRAME( KIWAY* aKiway, wxWindow* aParent,
    m_GridColor           = DARKGRAY;   // Grid color
    m_GridColor           = DARKGRAY;   // Grid color
    m_snapToGrid          = true;
    m_snapToGrid          = true;
    m_MsgFrameHeight      = EDA_MSG_PANEL::GetRequiredHeight();
    m_MsgFrameHeight      = EDA_MSG_PANEL::GetRequiredHeight();
    m_movingCursorWithKeyboard = false;


    m_auimgr.SetFlags(wxAUI_MGR_DEFAULT|wxAUI_MGR_LIVE_RESIZE);
    m_auimgr.SetFlags(wxAUI_MGR_DEFAULT|wxAUI_MGR_LIVE_RESIZE);


@@ -1110,3 +1111,119 @@ void EDA_DRAW_FRAME::SetScrollCenterPosition( const wxPoint& aPoint )
}
}


//-----</BASE_SCREEN API moved here >--------------------------------------------
//-----</BASE_SCREEN API moved here >--------------------------------------------

void EDA_DRAW_FRAME::RefreshCrossHair( const wxPoint &aOldPos,
                                       const wxPoint &aEvtPos,
                                       wxDC* aDC )
{
    wxPoint newpos = GetCrossHairPosition();

    // Redraw the crosshair if it moved
    if( aOldPos != newpos )
    {
        SetCrossHairPosition( aOldPos, false );
        m_canvas->CrossHairOff( aDC );
        SetCrossHairPosition( newpos, false );
        m_canvas->CrossHairOn( aDC );

        if( m_canvas->IsMouseCaptured() )
        {
#ifdef USE_WX_OVERLAY
            wxDCOverlay oDC( m_overlay, (wxWindowDC*)aDC );
            oDC.Clear();
            m_canvas->CallMouseCapture( aDC, aEvtPos, false );
#else
            m_canvas->CallMouseCapture( aDC, aEvtPos, true );
#endif
        }
#ifdef USE_WX_OVERLAY
        else
        {
            m_overlay.Reset();
        }
#endif
    }
}

void EDA_DRAW_FRAME::GeneralControlKeyMovement( int aHotKey, wxPoint *aPos,
                                                bool aSnapToGrid )
{

    // If requested snap the current position to the grid
    if( aSnapToGrid )
        *aPos = GetNearestGridPosition( *aPos );

    switch( aHotKey )
    {
        // All these keys have almost the same treatment
    case GR_KB_CTRL | WXK_NUMPAD8: case GR_KB_CTRL | WXK_UP:
    case GR_KB_CTRL | WXK_NUMPAD2: case GR_KB_CTRL | WXK_DOWN:
    case GR_KB_CTRL | WXK_NUMPAD4: case GR_KB_CTRL | WXK_LEFT:
    case GR_KB_CTRL | WXK_NUMPAD6: case GR_KB_CTRL | WXK_RIGHT:
    case WXK_NUMPAD8: case WXK_UP: case WXK_NUMPAD2: case WXK_DOWN:
    case WXK_NUMPAD4: case WXK_LEFT: case WXK_NUMPAD6: case WXK_RIGHT:
        {
            /* Here's a tricky part: when doing cursor key movement, the
             * 'previous' point should be taken from memory, *not* from the
             * freshly computed position in the event. Otherwise you can't do
             * sub-pixel movement. The m_movingCursorWithKeyboard oneshot 'eats'
             * the automatic motion event generated by cursor warping */
            wxRealPoint gridSize = GetScreen()->GetGridSize();
            *aPos = GetCrossHairPosition();

            // Bonus: ^key moves faster (x10)
            switch( aHotKey )
            {
            case GR_KB_CTRL|WXK_NUMPAD8:
            case GR_KB_CTRL|WXK_UP:
                aPos->y -= KiROUND( 10 * gridSize.y );
                break;

            case GR_KB_CTRL|WXK_NUMPAD2:
            case GR_KB_CTRL|WXK_DOWN:
                aPos->y += KiROUND( 10 * gridSize.y );
                break;

            case GR_KB_CTRL|WXK_NUMPAD4:
            case GR_KB_CTRL|WXK_LEFT:
                aPos->x -= KiROUND( 10 * gridSize.x );
                break;

            case GR_KB_CTRL|WXK_NUMPAD6:
            case GR_KB_CTRL|WXK_RIGHT:
                aPos->x += KiROUND( 10 * gridSize.x );
                break;

            case WXK_NUMPAD8:
            case WXK_UP:
                aPos->y -= KiROUND( gridSize.y );
                break;

            case WXK_NUMPAD2:
            case WXK_DOWN:
                aPos->y += KiROUND( gridSize.y );
                break;

            case WXK_NUMPAD4:
            case WXK_LEFT:
                aPos->x -= KiROUND( gridSize.x );
                break;

            case WXK_NUMPAD6:
            case WXK_RIGHT:
                aPos->x += KiROUND( gridSize.x );
                break;

            default: /* Can't happen since we entered the statement */
                break;
            }
            m_canvas->MoveCursor( *aPos );
            m_movingCursorWithKeyboard = true;
        }
        break;

    default:
        break;
    }
}
+11 −46
Original line number Original line Diff line number Diff line
@@ -327,17 +327,19 @@ void DISPLAY_FOOTPRINTS_FRAME::OnSelectOptionToolbar( wxCommandEvent& event )


void DISPLAY_FOOTPRINTS_FRAME::GeneralControl( wxDC* aDC, const wxPoint& aPosition, int aHotKey )
void DISPLAY_FOOTPRINTS_FRAME::GeneralControl( wxDC* aDC, const wxPoint& aPosition, int aHotKey )
{
{
    wxRealPoint gridSize;
    // Filter out the 'fake' mouse motion after a keyboard movement
    wxPoint     oldpos;
    if( !aHotKey && m_movingCursorWithKeyboard )
    PCB_SCREEN* screen = GetScreen();
    {
    wxPoint     pos = aPosition;
        m_movingCursorWithKeyboard = false;
        return;
    }


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


    pos = GetNearestGridPosition( pos );
    wxPoint pos = aPosition;
    oldpos = GetCrossHairPosition();
    wxPoint oldpos = GetCrossHairPosition();
    gridSize = screen->GetGridSize();
    GeneralControlKeyMovement( aHotKey, &pos, true );


    switch( aHotKey )
    switch( aHotKey )
    {
    {
@@ -367,49 +369,12 @@ void DISPLAY_FOOTPRINTS_FRAME::GeneralControl( wxDC* aDC, const wxPoint& aPositi
        break;
        break;


    case ' ':
    case ' ':
        screen->m_O_Curseur = GetCrossHairPosition();
        GetScreen()->m_O_Curseur = GetCrossHairPosition();
        break;

    case WXK_NUMPAD8:       /* cursor moved up */
    case WXK_UP:
        pos.y -= KiROUND( gridSize.y );
        m_canvas->MoveCursor( pos );
        break;

    case WXK_NUMPAD2:       /* cursor moved down */
    case WXK_DOWN:
        pos.y += KiROUND( gridSize.y );
        m_canvas->MoveCursor( pos );
        break;

    case WXK_NUMPAD4:       /*  cursor moved left */
    case WXK_LEFT:
        pos.x -= KiROUND( gridSize.x );
        m_canvas->MoveCursor( pos );
        break;

    case WXK_NUMPAD6:      /*  cursor moved right */
    case WXK_RIGHT:
        pos.x += KiROUND( gridSize.x );
        m_canvas->MoveCursor( pos );
        break;
        break;
    }
    }


    SetCrossHairPosition( pos );
    SetCrossHairPosition( pos );

    RefreshCrossHair( oldpos, aPosition, aDC );
    if( oldpos != GetCrossHairPosition() )
    {
        pos = GetCrossHairPosition();
        SetCrossHairPosition( oldpos );
        m_canvas->CrossHairOff( aDC );
        SetCrossHairPosition( pos );
        m_canvas->CrossHairOn( aDC );

        if( m_canvas->IsMouseCaptured() )
        {
            m_canvas->CallMouseCapture( aDC, aPosition, 0 );
        }
    }


    UpdateStatusBar();    /* Display new cursor coordinates */
    UpdateStatusBar();    /* Display new cursor coordinates */
}
}
+35 −190
Original line number Original line Diff line number Diff line
@@ -205,10 +205,12 @@ SCH_ITEM* SCH_EDIT_FRAME::LocateItem( const wxPoint& aPosition, const KICAD_T aF


void SCH_EDIT_FRAME::GeneralControl( wxDC* aDC, const wxPoint& aPosition, int aHotKey )
void SCH_EDIT_FRAME::GeneralControl( wxDC* aDC, const wxPoint& aPosition, int aHotKey )
{
{
    wxRealPoint gridSize;
    // Filter out the 'fake' mouse motion after a keyboard movement
    SCH_SCREEN* screen = GetScreen();
    if( !aHotKey && m_movingCursorWithKeyboard )
    wxPoint     oldpos;
    {
    wxPoint     pos = aPosition;
        m_movingCursorWithKeyboard = false;
        return;
    }


    // when moving mouse, use the "magnetic" grid, unless the shift+ctrl keys is pressed
    // when moving mouse, use the "magnetic" grid, unless the shift+ctrl keys is pressed
    // for next cursor position
    // for next cursor position
@@ -221,76 +223,18 @@ void SCH_EDIT_FRAME::GeneralControl( wxDC* aDC, const wxPoint& aPosition, int aH
    if( GetScreen()->m_BlockLocate.GetState() != STATE_NO_BLOCK )
    if( GetScreen()->m_BlockLocate.GetState() != STATE_NO_BLOCK )
        snapToGrid = true;
        snapToGrid = true;


    if( snapToGrid )
    wxPoint pos = aPosition;
        pos = GetNearestGridPosition( pos );
    wxPoint oldpos = GetCrossHairPosition();

    GeneralControlKeyMovement( aHotKey, &pos, snapToGrid );
    oldpos   = GetCrossHairPosition();
    gridSize = screen->GetGridSize();

    switch( aHotKey )
    {
    case 0:
        break;

    case WXK_NUMPAD8:
    case WXK_UP:
        pos.y -= KiROUND( gridSize.y );
        m_canvas->MoveCursor( pos );
        break;

    case WXK_NUMPAD2:
    case WXK_DOWN:
        pos.y += KiROUND( gridSize.y );
        m_canvas->MoveCursor( pos );
        break;

    case WXK_NUMPAD4:
    case WXK_LEFT:
        pos.x -= KiROUND( gridSize.x );
        m_canvas->MoveCursor( pos );
        break;

    case WXK_NUMPAD6:
    case WXK_RIGHT:
        pos.x += KiROUND( gridSize.x );
        m_canvas->MoveCursor( pos );
        break;

    default:
        break;
    }


    // Update cursor position.
    // Update cursor position.
    SetCrossHairPosition( pos, snapToGrid );
    SetCrossHairPosition( pos, snapToGrid );

    RefreshCrossHair( oldpos, aPosition, aDC );
    if( oldpos != GetCrossHairPosition() )
    {
        pos = GetCrossHairPosition();
        SetCrossHairPosition( oldpos, false);
        m_canvas->CrossHairOff( aDC );
        SetCrossHairPosition( pos, snapToGrid );
        m_canvas->CrossHairOn( aDC );

        if( m_canvas->IsMouseCaptured() )
        {
#ifdef USE_WX_OVERLAY
            wxDCOverlay oDC( m_overlay, (wxWindowDC*)aDC );
            oDC.Clear();
            m_canvas->CallMouseCapture( aDC, aPosition, false );
#else
            m_canvas->CallMouseCapture( aDC, aPosition, true );
#endif
        }
#ifdef USE_WX_OVERLAY
        else
        {
            m_overlay.Reset();
        }
#endif
    }


    if( aHotKey )
    if( aHotKey )
    {
    {
        SCH_SCREEN* screen = GetScreen();

        if( screen->GetCurItem() && screen->GetCurItem()->GetFlags() )
        if( screen->GetCurItem() && screen->GetCurItem()->GetFlags() )
            OnHotKey( aDC, aHotKey, aPosition, screen->GetCurItem() );
            OnHotKey( aDC, aHotKey, aPosition, screen->GetCurItem() );
        else
        else
@@ -303,9 +247,12 @@ void SCH_EDIT_FRAME::GeneralControl( wxDC* aDC, const wxPoint& aPosition, int aH


void LIB_EDIT_FRAME::GeneralControl( wxDC* aDC, const wxPoint& aPosition, int aHotKey )
void LIB_EDIT_FRAME::GeneralControl( wxDC* aDC, const wxPoint& aPosition, int aHotKey )
{
{
    wxRealPoint gridSize;
    // Filter out the 'fake' mouse motion after a keyboard movement
    wxPoint     oldpos;
    if( !aHotKey && m_movingCursorWithKeyboard )
    wxPoint     pos = aPosition;
    {
        m_movingCursorWithKeyboard = false;
        return;
    }


    // when moving mouse, use the "magnetic" grid, unless the shift+ctrl keys is pressed
    // when moving mouse, use the "magnetic" grid, unless the shift+ctrl keys is pressed
    // for next cursor position
    // for next cursor position
@@ -318,73 +265,13 @@ void LIB_EDIT_FRAME::GeneralControl( wxDC* aDC, const wxPoint& aPosition, int aH
    if( GetScreen()->m_BlockLocate.GetState() != STATE_NO_BLOCK )
    if( GetScreen()->m_BlockLocate.GetState() != STATE_NO_BLOCK )
        snapToGrid = true;
        snapToGrid = true;


    if( snapToGrid )
    wxPoint pos = aPosition;
        pos = GetNearestGridPosition( pos );
    wxPoint oldpos = GetCrossHairPosition();

    GeneralControlKeyMovement( aHotKey, &pos, snapToGrid );
    oldpos   = GetCrossHairPosition();
    gridSize = GetScreen()->GetGridSize();

    switch( aHotKey )
    {
    case 0:
        break;

    case WXK_NUMPAD8:
    case WXK_UP:
        pos.y -= KiROUND( gridSize.y );
        m_canvas->MoveCursor( pos );
        break;

    case WXK_NUMPAD2:
    case WXK_DOWN:
        pos.y += KiROUND( gridSize.y );
        m_canvas->MoveCursor( pos );
        break;

    case WXK_NUMPAD4:
    case WXK_LEFT:
        pos.x -= KiROUND( gridSize.x );
        m_canvas->MoveCursor( pos );
        break;

    case WXK_NUMPAD6:
    case WXK_RIGHT:
        pos.x += KiROUND( gridSize.x );
        m_canvas->MoveCursor( pos );
        break;

    default:
        break;
    }


    // Update the cursor position.
    // Update the cursor position.
    SetCrossHairPosition( pos, snapToGrid );
    SetCrossHairPosition( pos, snapToGrid );

    RefreshCrossHair( oldpos, aPosition, aDC );
    if( oldpos != GetCrossHairPosition() )
    {
        pos = GetCrossHairPosition();
        SetCrossHairPosition( oldpos, false );
        m_canvas->CrossHairOff( aDC );
        SetCrossHairPosition( pos, snapToGrid );
        m_canvas->CrossHairOn( aDC );

        if( m_canvas->IsMouseCaptured() )
        {
#ifdef USE_WX_OVERLAY
            wxDCOverlay oDC( m_overlay, (wxWindowDC*)aDC );
            oDC.Clear();
            m_canvas->CallMouseCapture( aDC, aPosition, false );
#else
            m_canvas->CallMouseCapture( aDC, aPosition, true );
#endif
        }
#ifdef USE_WX_OVERLAY
        else
        {
            m_overlay.Reset();
        }
#endif
    }


    if( aHotKey )
    if( aHotKey )
    {
    {
@@ -397,72 +284,30 @@ void LIB_EDIT_FRAME::GeneralControl( wxDC* aDC, const wxPoint& aPosition, int aH


void LIB_VIEW_FRAME::GeneralControl( wxDC* aDC, const wxPoint& aPosition, int aHotKey )
void LIB_VIEW_FRAME::GeneralControl( wxDC* aDC, const wxPoint& aPosition, int aHotKey )
{
{
    wxRealPoint gridSize;
    // Filter out the 'fake' mouse motion after a keyboard movement
    SCH_SCREEN* screen = GetScreen();
    if( !aHotKey && m_movingCursorWithKeyboard )
    wxPoint     oldpos;
    wxPoint     pos = aPosition;

    pos    = GetNearestGridPosition( pos );
    oldpos = GetCrossHairPosition();
    gridSize = screen->GetGridSize();

    switch( aHotKey )
    {
    {
    case 0:
        m_movingCursorWithKeyboard = false;
        break;
        return;

    case WXK_NUMPAD8:
    case WXK_UP:
        pos.y -= KiROUND( gridSize.y );
        m_canvas->MoveCursor( pos );
        break;

    case WXK_NUMPAD2:
    case WXK_DOWN:
        pos.y += KiROUND( gridSize.y );
        m_canvas->MoveCursor( pos );
        break;

    case WXK_NUMPAD4:
    case WXK_LEFT:
        pos.x -= KiROUND( gridSize.x );
        m_canvas->MoveCursor( pos );
        break;

    case WXK_NUMPAD6:
    case WXK_RIGHT:
        pos.x += KiROUND( gridSize.x );
        m_canvas->MoveCursor( pos );
        break;

    default:
        break;
    }
    }


    // Update cursor position.
    wxPoint pos = aPosition;
    SetCrossHairPosition( pos );
    wxPoint oldpos = GetCrossHairPosition();

    GeneralControlKeyMovement( aHotKey, &pos, true );
    if( oldpos != GetCrossHairPosition() )
    {
        pos = GetCrossHairPosition();
        SetCrossHairPosition( oldpos );
        m_canvas->CrossHairOff( aDC );
        SetCrossHairPosition( pos );
        m_canvas->CrossHairOn( aDC );


        if( m_canvas->IsMouseCaptured() )
    // Update cursor position.
        {
    SetCrossHairPosition( pos, true );
            m_canvas->CallMouseCapture( aDC, aPosition, true );
    RefreshCrossHair( oldpos, aPosition, aDC );
        }
    }


    if( aHotKey )
    if( aHotKey )
    {
    {
        SCH_SCREEN* screen = GetScreen();

        if( screen->GetCurItem() && screen->GetCurItem()->GetFlags() )
        if( screen->GetCurItem() && screen->GetCurItem()->GetFlags() )
            OnHotKey( aDC, aHotKey, aPosition, screen->GetCurItem() );
            OnHotKey( aDC, aHotKey, aPosition, screen->GetCurItem() );
        else
        else
            OnHotKey( aDC, aHotKey, aPosition, NULL );
            OnHotKey( aDC, aHotKey, aPosition, NULL );
    }
    }


    UpdateStatusBar();
    UpdateStatusBar();    /* Display cursor coordinates info */
}
}
+9 −63
Original line number Original line Diff line number Diff line
@@ -34,73 +34,19 @@


void GERBVIEW_FRAME::GeneralControl( wxDC* aDC, const wxPoint& aPosition, int aHotKey )
void GERBVIEW_FRAME::GeneralControl( wxDC* aDC, const wxPoint& aPosition, int aHotKey )
{
{
    wxRealPoint gridSize;
    // Filter out the 'fake' mouse motion after a keyboard movement
    wxPoint     oldpos;
    if( !aHotKey && m_movingCursorWithKeyboard )
    wxPoint     pos = aPosition;

    pos = GetNearestGridPosition( pos );

    oldpos   = GetCrossHairPosition();
    gridSize = GetScreen()->GetGridSize();

    switch( aHotKey )
    {
    {
    case WXK_NUMPAD8:
        m_movingCursorWithKeyboard = false;
    case WXK_UP:
        return;
        pos.y -= KiROUND( gridSize.y );
        m_canvas->MoveCursor( pos );
        break;

    case WXK_NUMPAD2:
    case WXK_DOWN:
        pos.y += KiROUND( gridSize.y );
        m_canvas->MoveCursor( pos );
        break;

    case WXK_NUMPAD4:
    case WXK_LEFT:
        pos.x -= KiROUND( gridSize.x );
        m_canvas->MoveCursor( pos );
        break;

    case WXK_NUMPAD6:
    case WXK_RIGHT:
        pos.x += KiROUND( gridSize.x );
        m_canvas->MoveCursor( pos );
        break;

    default:
        break;
    }
    }


    SetCrossHairPosition( pos );
    wxPoint pos = aPosition;
    wxPoint oldpos = GetCrossHairPosition();
    GeneralControlKeyMovement( aHotKey, &pos, true );


    if( oldpos != GetCrossHairPosition() )
    {
        pos = GetCrossHairPosition();
        SetCrossHairPosition( oldpos );
        m_canvas->CrossHairOff( aDC );
    SetCrossHairPosition( pos );
    SetCrossHairPosition( pos );
        m_canvas->CrossHairOn( aDC );
    RefreshCrossHair( oldpos, aPosition, aDC );

        if( m_canvas->IsMouseCaptured() )
        {
#ifdef USE_WX_OVERLAY
            wxDCOverlay oDC( m_overlay, (wxWindowDC*)aDC );
            oDC.Clear();
            m_canvas->CallMouseCapture( aDC, aPosition, false );
#else
            m_canvas->CallMouseCapture( aDC, aPosition, true );
#endif
        }
#ifdef USE_WX_OVERLAY
        else
        {
            m_overlay.Reset();
        }
#endif

    }


    if( aHotKey )
    if( aHotKey )
    {
    {
+14 −0
Original line number Original line Diff line number Diff line
@@ -105,6 +105,9 @@ protected:
    wxOverlay       m_overlay;
    wxOverlay       m_overlay;
#endif
#endif


    /// One-shot to avoid a recursive mouse event during hotkey movement
    bool            m_movingCursorWithKeyboard;

    void SetScreen( BASE_SCREEN* aScreen )  { m_currentScreen = aScreen; }
    void SetScreen( BASE_SCREEN* aScreen )  { m_currentScreen = aScreen; }


    /**
    /**
@@ -116,6 +119,17 @@ protected:
     */
     */
    virtual void unitsChangeRefresh();
    virtual void unitsChangeRefresh();


    /**
     * Function GeneralControlKeyMovement
     * Handle the common part of GeneralControl dedicated to global
     * cursor keys (i.e. cursor movement by keyboard) */
    void GeneralControlKeyMovement( int aHotKey, wxPoint *aPos, bool aSnapToGrid );

    /* Function RefreshCrosshair
     * Move and refresh the crosshair after movement; also call the
     * mouse capture function, if active.
     */
    void RefreshCrossHair( const wxPoint &aOldPos, const wxPoint &aEvtPos, wxDC* aDC );
public:
public:
    EDA_DRAW_FRAME( KIWAY* aKiway, wxWindow* aParent,
    EDA_DRAW_FRAME( KIWAY* aKiway, wxWindow* aParent,
                    FRAME_T aFrameType,
                    FRAME_T aFrameType,
Loading