Uniformly use a single facility for location-less prime events.

Also implements a uniform mechanism for avoiding auto-scroll after
a prime event or dialog which results in a mouse position at the
edge of the canvas.

Fixes https://gitlab.com/kicad/code/kicad/issues/11057
This commit is contained in:
Jeff Young 2022-05-16 23:41:30 +01:00
parent b00bf2bc6b
commit 23fb4c7433
11 changed files with 223 additions and 159 deletions

View File

@ -703,7 +703,7 @@ void WX_VIEW_CONTROLS::SetCursorPosition( const VECTOR2D& aPosition, bool aWarpV
m_cursorWarped = true; m_cursorWarped = true;
} }
WarpCursor( clampedPosition, true, aWarpView ); WarpMouseCursor( clampedPosition, true, aWarpView );
m_cursorPos = clampedPosition; m_cursorPos = clampedPosition;
} }
@ -726,8 +726,8 @@ void WX_VIEW_CONTROLS::SetCrossHairCursorPosition( const VECTOR2D& aPosition,
} }
void WX_VIEW_CONTROLS::WarpCursor( const VECTOR2D& aPosition, bool aWorldCoordinates, void WX_VIEW_CONTROLS::WarpMouseCursor( const VECTOR2D& aPosition, bool aWorldCoordinates,
bool aWarpView ) bool aWarpView )
{ {
if( aWorldCoordinates ) if( aWorldCoordinates )
{ {
@ -771,6 +771,38 @@ void WX_VIEW_CONTROLS::CenterOnCursor() const
} }
void WX_VIEW_CONTROLS::PinCursorInsideNonAutoscrollArea( bool aWarpMouseCursor )
{
int border = std::min( m_settings.m_autoPanMargin * m_view->GetScreenPixelSize().x,
m_settings.m_autoPanMargin * m_view->GetScreenPixelSize().y );
border += 2;
VECTOR2D topLeft( border, border );
VECTOR2D botRight( m_view->GetScreenPixelSize().x - border,
m_view->GetScreenPixelSize().y - border );
topLeft = m_view->ToWorld( topLeft );
botRight = m_view->ToWorld( botRight );
VECTOR2D pos = GetMousePosition( true );
if( pos.x < topLeft.x )
pos.x = topLeft.x;
else if( pos.x > botRight.x )
pos.x = botRight.x;
if( pos.y < topLeft.y )
pos.y = topLeft.y;
else if( pos.y > botRight.y )
pos.y = botRight.y;
SetCursorPosition( pos, false, false, 0 );
if( aWarpMouseCursor )
WarpMouseCursor( pos, true );
}
bool WX_VIEW_CONTROLS::handleAutoPanning( const wxMouseEvent& aEvent ) bool WX_VIEW_CONTROLS::handleAutoPanning( const wxMouseEvent& aEvent )
{ {
VECTOR2I p( aEvent.GetX(), aEvent.GetY() ); VECTOR2I p( aEvent.GetX(), aEvent.GetY() );

View File

@ -260,7 +260,7 @@ void SCH_BASE_FRAME::CenterScreen( const VECTOR2I& aCenterPoint, bool aWarpPoint
GetCanvas()->GetView()->SetCenter( aCenterPoint ); GetCanvas()->GetView()->SetCenter( aCenterPoint );
if( aWarpPointer ) if( aWarpPointer )
GetCanvas()->GetViewControls()->WarpCursor( aCenterPoint, true ); GetCanvas()->GetViewControls()->WarpMouseCursor( aCenterPoint, true );
GetCanvas()->Refresh(); GetCanvas()->Refresh();
} }

View File

@ -95,29 +95,14 @@ bool SCH_DRAWING_TOOLS::Init()
} }
EDA_RECT SCH_DRAWING_TOOLS::GetCanvasFreeAreaPixels()
{
// calculate the area of the canvas in pixels that create no autopan when
// is inside this area the mouse cursor
wxSize canvas_size = m_frame->GetCanvas()->GetSize();
EDA_RECT canvas_area( wxPoint( 0, 0 ), canvas_size );
const KIGFX::VC_SETTINGS& v_settings = getViewControls()->GetSettings();
if( v_settings.m_autoPanEnabled )
canvas_area.Inflate( - v_settings.m_autoPanMargin );
// Gives a margin of 2 pixels
canvas_area.Inflate( -2 );
return canvas_area;
}
int SCH_DRAWING_TOOLS::PlaceSymbol( const TOOL_EVENT& aEvent ) int SCH_DRAWING_TOOLS::PlaceSymbol( const TOOL_EVENT& aEvent )
{ {
SCH_SYMBOL* symbol = aEvent.Parameter<SCH_SYMBOL*>(); SCH_SYMBOL* symbol = aEvent.Parameter<SCH_SYMBOL*>();
SYMBOL_LIBRARY_FILTER filter; SYMBOL_LIBRARY_FILTER filter;
std::vector<PICKED_SYMBOL>* historyList = nullptr; std::vector<PICKED_SYMBOL>* historyList = nullptr;
bool ignorePrimePosition = false;
COMMON_SETTINGS* common_settings = Pgm().GetCommonSettings();
EE_GRID_HELPER grid( m_toolMgr );
if( m_inPlaceSymbol ) if( m_inPlaceSymbol )
return 0; return 0;
@ -183,17 +168,25 @@ int SCH_DRAWING_TOOLS::PlaceSymbol( const TOOL_EVENT& aEvent )
if( symbol ) if( symbol )
{ {
addSymbol( symbol ); addSymbol( symbol );
getViewControls()->WarpCursor( getViewControls()->GetMousePosition( false ) ); getViewControls()->WarpMouseCursor( getViewControls()->GetMousePosition( false ));
} }
else if( !aEvent.IsReactivate() ) else if( aEvent.HasPosition() )
{ {
m_toolMgr->PrimeTool( aEvent.Position() ); m_toolMgr->PrimeTool( aEvent.Position() );
} }
else if( common_settings->m_Input.immediate_actions && !aEvent.IsReactivate() )
{
m_toolMgr->PrimeTool( { 0, 0 } );
ignorePrimePosition = true;
}
// Main loop: keep receiving events // Main loop: keep receiving events
while( TOOL_EVENT* evt = Wait() ) while( TOOL_EVENT* evt = Wait() )
{ {
setCursor(); setCursor();
grid.SetSnap( !evt->Modifier( MD_SHIFT ) );
grid.SetUseGrid( getView()->GetGAL()->GetGridSnapping() && !evt->DisableGridSnapping() );
VECTOR2I cursorPos = getViewControls()->GetCursorPosition( !evt->DisableGridSnapping() ); VECTOR2I cursorPos = getViewControls()->GetCursorPosition( !evt->DisableGridSnapping() );
if( evt->IsCancelInteractive() ) if( evt->IsCancelInteractive() )
@ -243,39 +236,32 @@ int SCH_DRAWING_TOOLS::PlaceSymbol( const TOOL_EVENT& aEvent )
{ {
m_toolMgr->RunAction( EE_ACTIONS::clearSelection, true ); m_toolMgr->RunAction( EE_ACTIONS::clearSelection, true );
// Store the mouse position: if it is outside the canvas,
// (happens when clicking on a toolbar tool) one cannot
// use the last stored cursor position to place the new symbol
// (Current mouse pos after closing the dialog will be used)
KIGFX::VIEW_CONTROLS* controls = getViewControls();
VECTOR2D initialMousePos = controls->GetMousePosition(false);
// Build the rectangle area acceptable to move the cursor without
// having an auto-pan
EDA_RECT canvas_area = GetCanvasFreeAreaPixels();
// Pick the footprint to be placed // Pick the footprint to be placed
bool footprintPreviews = m_frame->eeconfig()->m_Appearance.footprint_preview; bool footprintPreviews = m_frame->eeconfig()->m_Appearance.footprint_preview;
PICKED_SYMBOL sel = m_frame->PickSymbolFromLibTree( &filter, *historyList, true, PICKED_SYMBOL sel = m_frame->PickSymbolFromLibTree( &filter, *historyList, true,
1, 1, footprintPreviews ); 1, 1, footprintPreviews );
// Restore cursor position after closing the dialog,
// but only if it has meaning (i.e inside the canvas)
VECTOR2D newMousePos = controls->GetMousePosition(false);
if( canvas_area.Contains( VECTOR2I( initialMousePos ) ) ) LIB_SYMBOL* libSymbol = sel.LibId.IsValid() ? m_frame->GetLibSymbol( sel.LibId )
controls->WarpCursor( controls->GetCursorPosition(), true ); : nullptr;
else if( !canvas_area.Contains( VECTOR2I( newMousePos ) ) )
// The mouse is outside the canvas area, after closing the dialog,
// thus can creating autopan issues. Warp the mouse to the canvas center
controls->WarpCursor( canvas_area.Centre(), false );
LIB_SYMBOL* libSymbol = sel.LibId.IsValid() ?
m_frame->GetLibSymbol( sel.LibId ) : nullptr;
if( !libSymbol ) if( !libSymbol )
continue; continue;
VECTOR2I pos( cursorPos ); // If we started with a hotkey which has a position then warp back to that.
symbol = new SCH_SYMBOL( *libSymbol, &m_frame->GetCurrentSheet(), sel, pos ); // Otherwise update to the current mouse position pinned inside the autoscroll
// boundaries.
if( evt->IsPrime() && !ignorePrimePosition )
{
cursorPos = grid.Align( evt->Position() );
getViewControls()->WarpMouseCursor( cursorPos, true );
}
else
{
getViewControls()->PinCursorInsideNonAutoscrollArea( true );
cursorPos = getViewControls()->GetMousePosition();
}
symbol = new SCH_SYMBOL( *libSymbol, &m_frame->GetCurrentSheet(), sel, cursorPos );
addSymbol( symbol ); addSymbol( symbol );
// Update cursor now that we have a symbol // Update cursor now that we have a symbol
@ -380,9 +366,11 @@ int SCH_DRAWING_TOOLS::PlaceSymbol( const TOOL_EVENT& aEvent )
int SCH_DRAWING_TOOLS::PlaceImage( const TOOL_EVENT& aEvent ) int SCH_DRAWING_TOOLS::PlaceImage( const TOOL_EVENT& aEvent )
{ {
SCH_BITMAP* image = aEvent.Parameter<SCH_BITMAP*>(); SCH_BITMAP* image = aEvent.Parameter<SCH_BITMAP*>();
bool immediateMode = image; bool immediateMode = image != nullptr;
VECTOR2I cursorPos = getViewControls()->GetCursorPosition(); EE_GRID_HELPER grid( m_toolMgr );
bool ignorePrimePosition = false;
COMMON_SETTINGS* common_settings = Pgm().GetCommonSettings();
if( m_inPlaceImage ) if( m_inPlaceImage )
return 0; return 0;
@ -394,7 +382,7 @@ int SCH_DRAWING_TOOLS::PlaceImage( const TOOL_EVENT& aEvent )
// Add all the drawable symbols to preview // Add all the drawable symbols to preview
if( image ) if( image )
{ {
image->SetPosition( cursorPos ); image->SetPosition( getViewControls()->GetCursorPosition() );
m_view->ClearPreview(); m_view->ClearPreview();
m_view->AddToPreview( image->Clone() ); m_view->AddToPreview( image->Clone() );
} }
@ -428,15 +416,24 @@ int SCH_DRAWING_TOOLS::PlaceImage( const TOOL_EVENT& aEvent )
// Prime the pump // Prime the pump
if( image ) if( image )
{
m_toolMgr->RunAction( ACTIONS::refreshPreview ); m_toolMgr->RunAction( ACTIONS::refreshPreview );
else if( !aEvent.IsReactivate() ) }
else if( aEvent.HasPosition() )
{
m_toolMgr->PrimeTool( aEvent.Position() ); m_toolMgr->PrimeTool( aEvent.Position() );
}
else if( common_settings->m_Input.immediate_actions && !aEvent.IsReactivate() )
{
m_toolMgr->PrimeTool( { 0, 0 } );
ignorePrimePosition = true;
}
// Main loop: keep receiving events // Main loop: keep receiving events
while( TOOL_EVENT* evt = Wait() ) while( TOOL_EVENT* evt = Wait() )
{ {
setCursor(); setCursor();
cursorPos = getViewControls()->GetCursorPosition( !evt->DisableGridSnapping() ); VECTOR2I cursorPos = getViewControls()->GetCursorPosition( !evt->DisableGridSnapping() );
if( evt->IsCancelInteractive() ) if( evt->IsCancelInteractive() )
{ {
@ -491,17 +488,6 @@ int SCH_DRAWING_TOOLS::PlaceImage( const TOOL_EVENT& aEvent )
{ {
m_toolMgr->RunAction( EE_ACTIONS::clearSelection, true ); m_toolMgr->RunAction( EE_ACTIONS::clearSelection, true );
// Store the mouse position: if it is outside the canvas,
// (happens when clicking on a toolbar tool) one cannot
// use the last stored cursor position to place the new symbol
// (Current mouse pos after closing the dialog will be used)
KIGFX::VIEW_CONTROLS* controls = getViewControls();
VECTOR2D initialMousePos = controls->GetMousePosition(false);
// Build the rectangle area acceptable to move the cursor without
// having an auto-pan
EDA_RECT canvas_area = GetCanvasFreeAreaPixels();
wxFileDialog dlg( m_frame, _( "Choose Image" ), m_mruPath, wxEmptyString, wxFileDialog dlg( m_frame, _( "Choose Image" ), m_mruPath, wxEmptyString,
_( "Image Files" ) + wxS( " " ) + wxImage::GetImageExtWildcard(), _( "Image Files" ) + wxS( " " ) + wxImage::GetImageExtWildcard(),
wxFD_OPEN ); wxFD_OPEN );
@ -509,18 +495,19 @@ int SCH_DRAWING_TOOLS::PlaceImage( const TOOL_EVENT& aEvent )
if( dlg.ShowModal() != wxID_OK ) if( dlg.ShowModal() != wxID_OK )
continue; continue;
// Restore cursor position after closing the dialog, // If we started with a hotkey which has a position then warp back to that.
// but only if it has meaning (i.e inside the canvas) // Otherwise update to the current mouse position pinned inside the autoscroll
VECTOR2D newMousePos = controls->GetMousePosition( false ); // boundaries.
if( evt->IsPrime() && !ignorePrimePosition )
if( canvas_area.Contains( VECTOR2I( initialMousePos ) ) ) {
controls->WarpCursor( controls->GetCursorPosition(), true ); cursorPos = grid.Align( evt->Position() );
else if( !canvas_area.Contains( VECTOR2I( newMousePos ) ) ) getViewControls()->WarpMouseCursor( cursorPos, true );
// The mouse is outside the canvas area, after closing the dialog, }
// thus can creating autopan issues. Warp the mouse to the canvas center else
controls->WarpCursor( canvas_area.Centre(), false ); {
getViewControls()->PinCursorInsideNonAutoscrollArea( true );
cursorPos = controls->GetMousePosition( true ); cursorPos = getViewControls()->GetMousePosition();
}
wxString fullFilename = dlg.GetPath(); wxString fullFilename = dlg.GetPath();
m_mruPath = wxPathOnly( fullFilename ); m_mruPath = wxPathOnly( fullFilename );
@ -626,7 +613,7 @@ int SCH_DRAWING_TOOLS::SingleClickPlace( const TOOL_EVENT& aEvent )
SEG seg( wire->GetStartPoint(), wire->GetEndPoint() ); SEG seg( wire->GetStartPoint(), wire->GetEndPoint() );
VECTOR2I nearest = seg.NearestPoint( getViewControls()->GetCursorPosition() ); VECTOR2I nearest = seg.NearestPoint( getViewControls()->GetCursorPosition() );
getViewControls()->SetCrossHairCursorPosition( nearest, false ); getViewControls()->SetCrossHairCursorPosition( nearest, false );
getViewControls()->WarpCursor( getViewControls()->GetCursorPosition(), true ); getViewControls()->WarpMouseCursor( getViewControls()->GetCursorPosition(), true );
} }
} }
@ -1124,7 +1111,7 @@ int SCH_DRAWING_TOOLS::TwoClickPlace( const TOOL_EVENT& aEvent )
grid.SetSnap( !evt->Modifier( MD_SHIFT ) ); grid.SetSnap( !evt->Modifier( MD_SHIFT ) );
grid.SetUseGrid( getView()->GetGAL()->GetGridSnapping() && !evt->DisableGridSnapping() ); grid.SetUseGrid( getView()->GetGAL()->GetGridSnapping() && !evt->DisableGridSnapping() );
VECTOR2I cursorPos = evt->IsPrime() ? evt->Position() : controls->GetMousePosition(); VECTOR2I cursorPos = controls->GetMousePosition();
cursorPos = grid.BestSnapAnchor( cursorPos, snapLayer, item ); cursorPos = grid.BestSnapAnchor( cursorPos, snapLayer, item );
controls->ForceCursorPosition( true, cursorPos ); controls->ForceCursorPosition( true, cursorPos );
@ -1288,12 +1275,19 @@ int SCH_DRAWING_TOOLS::TwoClickPlace( const TOOL_EVENT& aEvent )
} }
} }
// If we started with a click on a tool button or menu then continue with the // If we started with a hotkey which has a position then warp back to that.
// current mouse position. Otherwise warp back to the original click position. // Otherwise update to the current mouse position pinned inside the autoscroll
if( evt->IsPrime() && ignorePrimePosition ) // boundaries.
cursorPos = grid.Align( controls->GetMousePosition() ); if( evt->IsPrime() && !ignorePrimePosition )
{
cursorPos = grid.Align( evt->Position() );
getViewControls()->WarpMouseCursor( cursorPos, true );
}
else else
controls->WarpCursor( cursorPos, true ); {
getViewControls()->PinCursorInsideNonAutoscrollArea( true );
cursorPos = getViewControls()->GetMousePosition();
}
if( item ) if( item )
{ {
@ -1305,6 +1299,8 @@ int SCH_DRAWING_TOOLS::TwoClickPlace( const TOOL_EVENT& aEvent )
m_selectionTool->AddItemToSel( item ); m_selectionTool->AddItemToSel( item );
m_toolMgr->RunAction( ACTIONS::refreshPreview );
// update the cursor so it looks correct before another event // update the cursor so it looks correct before another event
setCursor(); setCursor();
} }

View File

@ -79,6 +79,7 @@ int SYMBOL_EDITOR_DRAWING_TOOLS::TwoClickPlace( const TOOL_EVENT& aEvent )
bool ignorePrimePosition = false; bool ignorePrimePosition = false;
LIB_ITEM* item = nullptr; LIB_ITEM* item = nullptr;
bool isText = aEvent.IsAction( &EE_ACTIONS::placeSymbolText ); bool isText = aEvent.IsAction( &EE_ACTIONS::placeSymbolText );
COMMON_SETTINGS* common_settings = Pgm().GetCommonSettings();
m_toolMgr->RunAction( EE_ACTIONS::clearSelection, true ); m_toolMgr->RunAction( EE_ACTIONS::clearSelection, true );
@ -115,7 +116,7 @@ int SYMBOL_EDITOR_DRAWING_TOOLS::TwoClickPlace( const TOOL_EVENT& aEvent )
{ {
m_toolMgr->PrimeTool( aEvent.Position() ); m_toolMgr->PrimeTool( aEvent.Position() );
} }
else if( !aEvent.IsReactivate() ) else if( common_settings->m_Input.immediate_actions && !aEvent.IsReactivate() )
{ {
m_toolMgr->PrimeTool( { 0, 0 } ); m_toolMgr->PrimeTool( { 0, 0 } );
ignorePrimePosition = true; ignorePrimePosition = true;
@ -217,12 +218,19 @@ int SYMBOL_EDITOR_DRAWING_TOOLS::TwoClickPlace( const TOOL_EVENT& aEvent )
wxFAIL_MSG( "TwoClickPlace(): unknown type" ); wxFAIL_MSG( "TwoClickPlace(): unknown type" );
} }
// If we started with a click on a tool button or menu then continue with the // If we started with a hotkey which has a position then warp back to that.
// current mouse position. Otherwise warp back to the original click position. // Otherwise update to the current mouse position pinned inside the autoscroll
if( evt->IsPrime() && ignorePrimePosition ) // boundaries.
cursorPos = grid.Align( controls->GetMousePosition() ); if( evt->IsPrime() && !ignorePrimePosition )
{
cursorPos = grid.Align( evt->Position() );
getViewControls()->WarpMouseCursor( cursorPos, true );
}
else else
controls->WarpCursor( cursorPos, true ); {
getViewControls()->PinCursorInsideNonAutoscrollArea( true );
cursorPos = getViewControls()->GetMousePosition();
}
if( item ) if( item )
{ {

View File

@ -209,7 +209,7 @@ int SYMBOL_EDITOR_MOVE_TOOL::Main( const TOOL_EVENT& aEvent )
VECTOR2I itemPos = selection.GetTopLeftItem()->GetPosition(); VECTOR2I itemPos = selection.GetTopLeftItem()->GetPosition();
m_anchorPos = VECTOR2I( itemPos.x, -itemPos.y ); m_anchorPos = VECTOR2I( itemPos.x, -itemPos.y );
getViewControls()->WarpCursor( m_anchorPos, true, true ); getViewControls()->WarpMouseCursor( m_anchorPos, true, true );
m_cursor = m_anchorPos; m_cursor = m_anchorPos;
} }
else else

View File

@ -198,6 +198,8 @@ public:
m_settings.m_autoPanMargin = aMargin; m_settings.m_autoPanMargin = aMargin;
} }
virtual void PinCursorInsideNonAutoscrollArea( bool aWarpMouseCursor ) = 0;
/** /**
* Return the current mouse pointer position. * Return the current mouse pointer position.
* *
@ -324,8 +326,8 @@ public:
* specified in the world coordinates and its not visible in the current * specified in the world coordinates and its not visible in the current
* viewport). * viewport).
*/ */
virtual void WarpCursor( const VECTOR2D& aPosition, bool aWorldCoordinates = false, virtual void WarpMouseCursor( const VECTOR2D& aPosition, bool aWorldCoordinates = false,
bool aWarpView = false ) = 0; bool aWarpView = false ) = 0;
/** /**
* Enable or disable warping the cursor. * Enable or disable warping the cursor.

View File

@ -76,6 +76,8 @@ public:
void CaptureCursor( bool aEnabled ) override; void CaptureCursor( bool aEnabled ) override;
void PinCursorInsideNonAutoscrollArea( bool aWarpMouseCursor ) override;
///< @copydoc VIEW_CONTROLS::GetMousePosition() ///< @copydoc VIEW_CONTROLS::GetMousePosition()
VECTOR2D GetMousePosition( bool aWorldCoordinates = true ) const override; VECTOR2D GetMousePosition( bool aWorldCoordinates = true ) const override;
@ -94,8 +96,8 @@ public:
void SetCrossHairCursorPosition( const VECTOR2D& aPosition, bool aWarpView ) override; void SetCrossHairCursorPosition( const VECTOR2D& aPosition, bool aWarpView ) override;
///< @copydoc VIEW_CONTROLS::CursorWarp() ///< @copydoc VIEW_CONTROLS::CursorWarp()
void WarpCursor( const VECTOR2D& aPosition, bool aWorldCoordinates = false, void WarpMouseCursor( const VECTOR2D& aPosition, bool aWorldCoordinates = false,
bool aWarpView = false ) override; bool aWarpView = false ) override;
///< @copydoc VIEW_CONTROLS::CenterOnCursor() ///< @copydoc VIEW_CONTROLS::CenterOnCursor()
void CenterOnCursor() const override; void CenterOnCursor() const override;

View File

@ -2,7 +2,7 @@
* This program source code file is part of KiCad, a free EDA CAD application. * This program source code file is part of KiCad, a free EDA CAD application.
* *
* Copyright (C) 2019 CERN * Copyright (C) 2019 CERN
* Copyright (C) 2019 KiCad Developers, see AUTHORS.txt for contributors. * Copyright (C) 2019-2022 KiCad Developers, see AUTHORS.txt for contributors.
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
@ -24,21 +24,17 @@
#include <class_draw_panel_gal.h> #include <class_draw_panel_gal.h>
#include <confirm.h> #include <confirm.h>
#include <view/view_group.h>
#include <view/view_controls.h> #include <view/view_controls.h>
#include <view/view.h>
#include <tool/tool_manager.h> #include <tool/tool_manager.h>
#include <bitmaps.h> #include <bitmaps.h>
#include <drawing_sheet/ds_draw_item.h> #include <drawing_sheet/ds_draw_item.h>
#include <drawing_sheet/ds_data_item.h> #include <drawing_sheet/ds_data_item.h>
#include "invoke_pl_editor_dialog.h"
#include "pl_editor_frame.h" #include "pl_editor_frame.h"
#include "pl_editor_id.h"
#include "pl_point_editor.h"
#include "tools/pl_actions.h" #include "tools/pl_actions.h"
#include "tools/pl_selection_tool.h" #include "tools/pl_selection_tool.h"
#include "tools/pl_drawing_tools.h" #include "tools/pl_drawing_tools.h"
#include "pgm_base.h"
PL_DRAWING_TOOLS::PL_DRAWING_TOOLS() : PL_DRAWING_TOOLS::PL_DRAWING_TOOLS() :
TOOL_INTERACTIVE( "plEditor.InteractiveDrawing" ), TOOL_INTERACTIVE( "plEditor.InteractiveDrawing" ),
@ -94,6 +90,16 @@ int PL_DRAWING_TOOLS::PlaceItem( const TOOL_EVENT& aEvent )
m_frame->GetCanvas()->SetCurrentCursor( isText ? KICURSOR::TEXT : KICURSOR::PENCIL ); m_frame->GetCanvas()->SetCurrentCursor( isText ? KICURSOR::TEXT : KICURSOR::PENCIL );
}; };
auto cleanup =
[&] ()
{
m_toolMgr->RunAction( PL_ACTIONS::clearSelection, true );
item = nullptr;
// There's nothing to roll-back, but we still need to pop the undo stack
// This also deletes the item being placed.
m_frame->RollbackFromUndo();
};
Activate(); Activate();
// Must be done after Activate() so that it gets set into the correct context // Must be done after Activate() so that it gets set into the correct context
@ -101,27 +107,15 @@ int PL_DRAWING_TOOLS::PlaceItem( const TOOL_EVENT& aEvent )
// Set initial cursor // Set initial cursor
setCursor(); setCursor();
if( aEvent.HasPosition() || ( !aEvent.IsReactivate() && isText ) ) if( aEvent.HasPosition() )
m_toolMgr->PrimeTool( aEvent.Position() ); m_toolMgr->PrimeTool( aEvent.Position() );
// Main loop: keep receiving events // Main loop: keep receiving events
while( TOOL_EVENT* evt = Wait() ) while( TOOL_EVENT* evt = Wait() )
{ {
setCursor(); setCursor();
cursorPos = getViewControls()->GetCursorPosition( !evt->DisableGridSnapping() ); cursorPos = getViewControls()->GetCursorPosition( !evt->DisableGridSnapping() );
auto cleanup =
[&] ()
{
m_toolMgr->RunAction( PL_ACTIONS::clearSelection, true );
item = nullptr;
// There's nothing to roll-back, but we still need to pop the undo stack
// This also deletes the item being placed.
m_frame->RollbackFromUndo();
};
if( evt->IsCancelInteractive() ) if( evt->IsCancelInteractive() )
{ {
if( item ) if( item )

View File

@ -26,6 +26,7 @@
#include <functional> #include <functional>
#include <memory> #include <memory>
#include <pgm_base.h>
#include <advanced_config.h> #include <advanced_config.h>
#include "board_editor_control.h" #include "board_editor_control.h"
#include <bitmaps.h> #include <bitmaps.h>
@ -996,9 +997,11 @@ int BOARD_EDITOR_CONTROL::PlaceFootprint( const TOOL_EVENT& aEvent )
REENTRANCY_GUARD guard( &m_inPlaceFootprint ); REENTRANCY_GUARD guard( &m_inPlaceFootprint );
FOOTPRINT* fp = aEvent.Parameter<FOOTPRINT*>(); FOOTPRINT* fp = aEvent.Parameter<FOOTPRINT*>();
bool fromOtherCommand = fp != nullptr;
KIGFX::VIEW_CONTROLS* controls = getViewControls(); KIGFX::VIEW_CONTROLS* controls = getViewControls();
BOARD_COMMIT commit( m_frame ); BOARD_COMMIT commit( m_frame );
BOARD* board = getModel<BOARD>(); BOARD* board = getModel<BOARD>();
COMMON_SETTINGS* common_settings = Pgm().GetCommonSettings();
m_toolMgr->RunAction( PCB_ACTIONS::selectionClear, true ); m_toolMgr->RunAction( PCB_ACTIONS::selectionClear, true );
@ -1011,6 +1014,28 @@ int BOARD_EDITOR_CONTROL::PlaceFootprint( const TOOL_EVENT& aEvent )
m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::PENCIL ); m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::PENCIL );
}; };
auto cleanup =
[&] ()
{
m_toolMgr->RunAction( PCB_ACTIONS::selectionClear, true );
commit.Revert();
if( fromOtherCommand )
{
PICKED_ITEMS_LIST* undo = m_frame->PopCommandFromUndoList();
if( undo )
{
m_frame->PutDataInPreviousState( undo );
undo->ClearListAndDeleteItems();
delete undo;
}
}
fp = nullptr;
m_placingFootprint = false;
};
Activate(); Activate();
// Must be done after Activate() so that it gets set into the correct context // Must be done after Activate() so that it gets set into the correct context
controls->ShowCursor( true ); controls->ShowCursor( true );
@ -1018,22 +1043,26 @@ int BOARD_EDITOR_CONTROL::PlaceFootprint( const TOOL_EVENT& aEvent )
setCursor(); setCursor();
VECTOR2I cursorPos = controls->GetCursorPosition(); VECTOR2I cursorPos = controls->GetCursorPosition();
bool ignorePrimePosition = false;
bool reselect = false; bool reselect = false;
bool fromOtherCommand = fp != nullptr;
bool resetCursor = aEvent.HasPosition(); // Detect if activated from a hotkey.
// Prime the pump // Prime the pump
if( fp ) if( fp )
{ {
m_placingFootprint = true; m_placingFootprint = true;
fp->SetPosition( wxPoint( cursorPos.x, cursorPos.y ) ); fp->SetPosition( cursorPos );
m_toolMgr->RunAction( PCB_ACTIONS::selectItem, true, fp ); m_toolMgr->RunAction( PCB_ACTIONS::selectItem, true, fp );
m_toolMgr->RunAction( ACTIONS::refreshPreview ); m_toolMgr->RunAction( ACTIONS::refreshPreview );
} }
else if( !aEvent.IsReactivate() ) else if( aEvent.HasPosition() )
{ {
m_toolMgr->PrimeTool( aEvent.Position() ); m_toolMgr->PrimeTool( aEvent.Position() );
} }
else if( common_settings->m_Input.immediate_actions && !aEvent.IsReactivate() )
{
m_toolMgr->PrimeTool( { 0, 0 } );
ignorePrimePosition = true;
}
// Main loop: keep receiving events // Main loop: keep receiving events
while( TOOL_EVENT* evt = Wait() ) while( TOOL_EVENT* evt = Wait() )
@ -1044,28 +1073,6 @@ int BOARD_EDITOR_CONTROL::PlaceFootprint( const TOOL_EVENT& aEvent )
if( reselect && fp ) if( reselect && fp )
m_toolMgr->RunAction( PCB_ACTIONS::selectItem, true, fp ); m_toolMgr->RunAction( PCB_ACTIONS::selectItem, true, fp );
auto cleanup =
[&] ()
{
m_toolMgr->RunAction( PCB_ACTIONS::selectionClear, true );
commit.Revert();
if( fromOtherCommand )
{
PICKED_ITEMS_LIST* undo = m_frame->PopCommandFromUndoList();
if( undo )
{
m_frame->PutDataInPreviousState( undo );
undo->ClearListAndDeleteItems();
delete undo;
}
}
fp = nullptr;
m_placingFootprint = false;
};
if( evt->IsCancelInteractive() ) if( evt->IsCancelInteractive() )
{ {
if( fp ) if( fp )
@ -1104,6 +1111,20 @@ int BOARD_EDITOR_CONTROL::PlaceFootprint( const TOOL_EVENT& aEvent )
if( fp == nullptr ) if( fp == nullptr )
continue; continue;
// If we started with a hotkey which has a position then warp back to that.
// Otherwise update to the current mouse position pinned inside the autoscroll
// boundaries.
if( evt->IsPrime() && !ignorePrimePosition )
{
cursorPos = evt->Position();
getViewControls()->WarpMouseCursor( cursorPos, true );
}
else
{
getViewControls()->PinCursorInsideNonAutoscrollArea( true );
cursorPos = getViewControls()->GetMousePosition();
}
m_placingFootprint = true; m_placingFootprint = true;
fp->SetLink( niluuid ); fp->SetLink( niluuid );
@ -1127,18 +1148,11 @@ int BOARD_EDITOR_CONTROL::PlaceFootprint( const TOOL_EVENT& aEvent )
fp->Flip( fp->GetPosition(), m_frame->Settings().m_FlipLeftRight ); fp->Flip( fp->GetPosition(), m_frame->Settings().m_FlipLeftRight );
fp->SetOrientation( ANGLE_0 ); fp->SetOrientation( ANGLE_0 );
fp->SetPosition( wxPoint( cursorPos.x, cursorPos.y ) ); fp->SetPosition( cursorPos );
commit.Add( fp ); commit.Add( fp );
m_toolMgr->RunAction( PCB_ACTIONS::selectItem, true, fp ); m_toolMgr->RunAction( PCB_ACTIONS::selectItem, true, fp );
// Reset cursor to the position before the dialog opened if activated from hotkey
if( resetCursor )
controls->SetCursorPosition( cursorPos, false );
// Other events must be from hotkeys or mouse clicks, so always reset cursor
resetCursor = true;
m_toolMgr->RunAction( ACTIONS::refreshPreview ); m_toolMgr->RunAction( ACTIONS::refreshPreview );
} }
else else
@ -1155,7 +1169,7 @@ int BOARD_EDITOR_CONTROL::PlaceFootprint( const TOOL_EVENT& aEvent )
} }
else if( fp && ( evt->IsMotion() || evt->IsAction( &ACTIONS::refreshPreview ) ) ) else if( fp && ( evt->IsMotion() || evt->IsAction( &ACTIONS::refreshPreview ) ) )
{ {
fp->SetPosition( wxPoint( cursorPos.x, cursorPos.y ) ); fp->SetPosition( cursorPos );
selection().SetReferencePoint( cursorPos ); selection().SetReferencePoint( cursorPos );
getView()->Update( &selection() ); getView()->Update( &selection() );
getView()->Update( fp ); getView()->Update( fp );

View File

@ -518,13 +518,13 @@ int DRAWING_TOOL::PlaceText( const TOOL_EVENT& aEvent )
REENTRANCY_GUARD guard( &m_inDrawingTool ); REENTRANCY_GUARD guard( &m_inDrawingTool );
COMMON_SETTINGS* common_settings = Pgm().GetCommonSettings();
BOARD_ITEM* text = nullptr; BOARD_ITEM* text = nullptr;
bool ignorePrimePosition = false;
const BOARD_DESIGN_SETTINGS& dsnSettings = m_frame->GetDesignSettings(); const BOARD_DESIGN_SETTINGS& dsnSettings = m_frame->GetDesignSettings();
BOARD_COMMIT commit( m_frame ); BOARD_COMMIT commit( m_frame );
SCOPED_DRAW_MODE scopedDrawMode( m_mode, MODE::TEXT ); SCOPED_DRAW_MODE scopedDrawMode( m_mode, MODE::TEXT );
bool resetCursor = aEvent.HasPosition(); // Detect if activated from a hotkey.
auto cleanup = auto cleanup =
[&]() [&]()
{ {
@ -559,8 +559,15 @@ int DRAWING_TOOL::PlaceText( const TOOL_EVENT& aEvent )
// Set initial cursor // Set initial cursor
setCursor(); setCursor();
if( !aEvent.IsReactivate() ) if( aEvent.HasPosition() )
{
m_toolMgr->PrimeTool( aEvent.Position() ); m_toolMgr->PrimeTool( aEvent.Position() );
}
else if( common_settings->m_Input.immediate_actions && !aEvent.IsReactivate() )
{
m_toolMgr->PrimeTool( { 0, 0 } );
ignorePrimePosition = true;
}
// Main loop: keep receiving events // Main loop: keep receiving events
while( TOOL_EVENT* evt = Wait() ) while( TOOL_EVENT* evt = Wait() )
@ -710,18 +717,27 @@ int DRAWING_TOOL::PlaceText( const TOOL_EVENT& aEvent )
m_controls->ForceCursorPosition( false ); m_controls->ForceCursorPosition( false );
// Reset cursor to the position before the dialog opened if activated from hotkey // If we started with a hotkey which has a position then warp back to that.
if( resetCursor ) // Otherwise update to the current mouse position pinned inside the autoscroll
m_controls->SetCursorPosition( cursorPos, false ); // boundaries.
if( evt->IsPrime() && !ignorePrimePosition )
{
cursorPos = evt->Position();
m_controls->WarpMouseCursor( cursorPos, true );
}
else
{
m_controls->PinCursorInsideNonAutoscrollArea( true );
cursorPos = m_controls->GetMousePosition();
}
// Other events must be from hotkeys or mouse clicks, so always reset cursor m_toolMgr->RunAction( PCB_ACTIONS::refreshPreview );
resetCursor = true;
m_controls->ShowCursor( true ); m_controls->ShowCursor( true );
m_controls->CaptureCursor( text != nullptr ); m_controls->CaptureCursor( text != nullptr );
m_controls->SetAutoPan( text != nullptr ); m_controls->SetAutoPan( text != nullptr );
} }
else if( text && evt->IsMotion() ) else if( text && ( evt->IsMotion() || evt->IsAction( &PCB_ACTIONS::refreshPreview ) ) )
{ {
text->SetPosition( cursorPos ); text->SetPosition( cursorPos );
selection().SetReferencePoint( cursorPos ); selection().SetReferencePoint( cursorPos );

View File

@ -102,7 +102,7 @@ std::unique_ptr<ZONE> ZONE_CREATE_HELPER::createNewZone( bool aKeepout )
if( dialogResult == wxID_CANCEL ) if( dialogResult == wxID_CANCEL )
return nullptr; return nullptr;
controls->WarpCursor( controls->GetCursorPosition(), true ); controls->WarpMouseCursor( controls->GetCursorPosition(), true );
} }
// The new zone is a ZONE if created in the board editor and a FP_ZONE if created in the // The new zone is a ZONE if created in the board editor and a FP_ZONE if created in the