Start transitioning block operations to modern toolset.

This commit is contained in:
Jeff Young 2019-04-23 18:40:29 +01:00
parent 6d918ea1f1
commit f200c61897
28 changed files with 681 additions and 816 deletions

View File

@ -544,11 +544,6 @@ void EDA_DRAW_FRAME::OnMouseEvent( wxMouseEvent& event )
}
void EDA_DRAW_FRAME::OnLeftDClick( wxDC* DC, const wxPoint& MousePos )
{
}
void EDA_DRAW_FRAME::DisplayToolMsg( const wxString& msg )
{
SetStatusText( msg, 5 );
@ -1192,18 +1187,6 @@ bool EDA_DRAW_FRAME::GeneralControlKeyMovement( int aHotKey, wxPoint *aPos, bool
}
bool EDA_DRAW_FRAME::isBusy() const
{
const BASE_SCREEN* screen = GetScreen();
if( !screen )
return false;
return ( screen->GetCurItem() && screen->GetCurItem()->GetEditFlags() )
|| ( screen->m_BlockLocate.GetState() != STATE_NO_BLOCK );
}
const BOX2I EDA_DRAW_FRAME::GetDocumentExtents() const
{
return BOX2I();

View File

@ -586,11 +586,6 @@ void EDA_DRAW_FRAME::OnMouseEvent( wxMouseEvent& event )
}
void EDA_DRAW_FRAME::OnLeftDClick( wxDC* DC, const wxPoint& MousePos )
{
}
void EDA_DRAW_FRAME::DisplayToolMsg( const wxString& msg )
{
SetStatusText( msg, 5 );

View File

@ -33,71 +33,6 @@
#include <sch_view.h>
bool SCH_EDIT_FRAME::GeneralControl( wxDC* aDC, const wxPoint& aPosition, EDA_KEY aHotKey )
{
// Filter out the 'fake' mouse motion after a keyboard movement
if( !aHotKey && m_movingCursorWithKeyboard )
{
m_movingCursorWithKeyboard = false;
return false;
}
// when moving mouse, use the "magnetic" grid, unless the shift+ctrl keys is pressed
// for next cursor position
// ( shift or ctrl key down are PAN command with mouse wheel)
bool snapToGrid = true;
if( !aHotKey && wxGetKeyState( WXK_SHIFT ) && wxGetKeyState( WXK_CONTROL ) )
snapToGrid = false;
// Cursor is left off grid only if no block in progress
if( GetScreen()->m_BlockLocate.GetState() != STATE_NO_BLOCK )
snapToGrid = true;
wxPoint pos = aPosition;
bool keyHandled = GeneralControlKeyMovement( aHotKey, &pos, snapToGrid );
if( GetToolId() == ID_NO_TOOL_SELECTED )
m_canvas->CrossHairOff( aDC );
else
m_canvas->CrossHairOn( aDC );
GetGalCanvas()->GetViewControls()->SetSnapping( snapToGrid );
SetCrossHairPosition( pos, snapToGrid );
if( m_canvas->IsMouseCaptured() )
m_canvas->CallMouseCapture( aDC, aPosition, true );
if( aHotKey )
{
if( m_movingCursorWithKeyboard ) // The hotkey was a move crossahir cursor command
{
// The crossair was moved. move the mouse cursor to the new crosshair position:
GetGalCanvas()->GetViewControls()->WarpCursor( GetCrossHairPosition(), true );
m_movingCursorWithKeyboard = 0;
}
else
{
SCH_SCREEN* screen = GetScreen();
bool hk_handled;
if( screen->GetCurItem() && screen->GetCurItem()->GetEditFlags() )
hk_handled = OnHotKey( aDC, aHotKey, aPosition, screen->GetCurItem() );
else
hk_handled = OnHotKey( aDC, aHotKey, aPosition, NULL );
if( hk_handled )
keyHandled = true;
}
}
UpdateStatusBar(); /* Display cursor coordinates info */
return keyHandled;
}
bool LIB_VIEW_FRAME::GeneralControl( wxDC* aDC, const wxPoint& aPosition, EDA_KEY aHotKey )
{
bool eventHandled = true;

View File

@ -72,18 +72,6 @@ SCH_BITMAP* SCH_EDIT_FRAME::CreateNewImage()
}
void SCH_EDIT_FRAME::RotateImage( SCH_BITMAP* aItem )
{
if( aItem->GetEditFlags( ) == 0 )
SaveCopyInUndoList( aItem, UR_ROTATED, false, aItem->GetPosition() );
aItem->Rotate( aItem->GetPosition() );
RefreshItem( aItem );
OnModify();
}
void SCH_EDIT_FRAME::MirrorImage( SCH_BITMAP* aItem, bool Is_X_axis )
{
if( aItem->GetEditFlags( ) == 0 )

View File

@ -92,27 +92,6 @@ void SCH_EDIT_FRAME::EditComponentFieldText( SCH_FIELD* aField )
}
void SCH_EDIT_FRAME::RotateField( SCH_FIELD* aField )
{
wxCHECK_RET( aField != NULL && aField->Type() == SCH_FIELD_T && !aField->GetText().IsEmpty(),
wxT( "Cannot rotate invalid schematic field." ) );
SCH_COMPONENT* component = (SCH_COMPONENT*) aField->GetParent();
// Save old component in undo list if not already in edit, or moving.
if( aField->GetEditFlags() == 0 )
SaveCopyInUndoList( component, UR_CHANGED );
if( aField->GetTextAngle() == TEXT_ANGLE_HORIZ )
aField->SetTextAngle( TEXT_ANGLE_VERT );
else
aField->SetTextAngle( TEXT_ANGLE_HORIZ );
RefreshItem( aField );
OnModify();
}
void SCH_EDIT_FRAME::EditComponent( SCH_COMPONENT* aComponent )
{
wxCHECK_RET( aComponent != nullptr && aComponent->Type() == SCH_COMPONENT_T,

View File

@ -47,24 +47,6 @@ static bool lastTextBold = false;
static bool lastTextItalic = false;
void SCH_EDIT_FRAME::ChangeTextOrient( SCH_TEXT* aTextItem )
{
wxCHECK_RET( (aTextItem != NULL) && aTextItem->CanIncrementLabel(),
wxT( "Invalid schematic text item." ) );
int orient = ( aTextItem->GetLabelSpinStyle() + 1 ) & 3;
// Save current text orientation in undo list if is not already in edit.
if( aTextItem->GetEditFlags() == 0 )
SaveCopyInUndoList( aTextItem, UR_CHANGED );
aTextItem->SetLabelSpinStyle( orient );
RefreshItem( aTextItem );
OnModify();
}
SCH_TEXT* SCH_EDIT_FRAME::CreateNewText( int aType )
{
SCH_TEXT* textItem = NULL;

View File

@ -208,6 +208,7 @@ SCH_BASE_FRAME::COMPONENT_SELECTION SCH_BASE_FRAME::SelectComponentFromLibTree(
}
// JEY TODO: obsolete once mover to modern toolset is complete
void SCH_EDIT_FRAME::OrientComponent( COMPONENT_ORIENTATION_T aOrientation )
{
SCH_SCREEN* screen = GetScreen();

View File

@ -478,23 +478,6 @@ bool SCH_EDIT_FRAME::OnHotKey( wxDC* aDC, int aHotKey, const wxPoint& aPosition,
}
break;
case HK_LEFT_CLICK:
case HK_LEFT_DCLICK: // Simulate a double left click: generate 2 events
if( screen->m_BlockLocate.GetState() == STATE_BLOCK_MOVE )
{
GetCanvas()->SetAutoPanRequest( false );
HandleBlockPlace( aDC );
}
else if( screen->m_BlockLocate.GetState() == STATE_NO_BLOCK )
{
auto pos = GetCrossHairPosition();
OnLeftClick( aDC, pos );
if( hotKey->m_Idcommand == HK_LEFT_DCLICK )
OnLeftDClick( aDC, pos );
}
break;
case HK_ZOOM_IN:
case HK_ZOOM_OUT:
case HK_ZOOM_REDRAW:

View File

@ -32,7 +32,6 @@ class SCH_SCREEN;
class PICKED_ITEMS_LIST;
void SetSchItemParent( SCH_ITEM* Struct, SCH_SCREEN* Screen );
void RotateListOfItems( PICKED_ITEMS_LIST& aItemsList, const wxPoint& rotationPoint );
void MirrorY( PICKED_ITEMS_LIST& aItemsList, const wxPoint& aMirrorPoint );
void MirrorX( PICKED_ITEMS_LIST& aItemsList, const wxPoint& aMirrorPoint );

View File

@ -35,57 +35,6 @@
#include <tool/tool_manager.h>
#include <tools/sch_selection_tool.h>
void SCH_EDIT_FRAME::OnLeftClick( wxDC* aDC, const wxPoint& aPosition )
{
SCH_ITEM* item = GetScreen()->GetCurItem();
SCH_SELECTION_TOOL* selTool = GetToolManager()->GetTool<SCH_SELECTION_TOOL>();
if( GetToolId() == ID_NO_TOOL_SELECTED )
{
m_canvas->SetAutoPanRequest( false );
SetRepeatItem( NULL );
// item_flags != 0 means a current item in edit
if( item && item->GetEditFlags() )
{
switch( item->Type() )
{
case SCH_LABEL_T:
case SCH_GLOBAL_LABEL_T:
case SCH_HIER_LABEL_T:
case SCH_TEXT_T:
case SCH_SHEET_PIN_T:
case SCH_SHEET_T:
case SCH_BUS_WIRE_ENTRY_T:
case SCH_BUS_BUS_ENTRY_T:
case SCH_JUNCTION_T:
case SCH_COMPONENT_T:
case SCH_FIELD_T:
case SCH_BITMAP_T:
case SCH_NO_CONNECT_T:
AddItemToScreen( item );
GetCanvas()->GetView()->ClearPreview();
GetCanvas()->GetView()->ClearHiddenFlags();
return;
default:
wxFAIL_MSG( wxT( "SCH_EDIT_FRAME::OnLeftClick error. Item type <" ) +
item->GetClass() + wxT( "> is already being edited." ) );
item->ClearFlags();
break;
}
}
else
{
item = selTool->SelectPoint( aPosition );
}
}
if( !item ) // If clicked on a empty area, clear any highligthed symbol
GetCanvas()->GetView()->HighlightItem( nullptr, nullptr );
}
/**
* Function OnLeftDClick
* called on a double click event from the drawpanel mouse handler
@ -95,7 +44,7 @@ void SCH_EDIT_FRAME::OnLeftClick( wxDC* aDC, const wxPoint& aPosition )
* validate and finish the command
*/
void SCH_EDIT_FRAME::OnLeftDClick( wxDC* aDC, const wxPoint& aPosition )
// JEY TODO: move to selection tool double-click handling....
{
SCH_SELECTION_TOOL* selTool = GetToolManager()->GetTool<SCH_SELECTION_TOOL>();
EDA_ITEM* item = GetScreen()->GetCurItem();

View File

@ -72,17 +72,6 @@ void SetSchItemParent( SCH_ITEM* Struct, SCH_SCREEN* Screen )
}
void RotateListOfItems( PICKED_ITEMS_LIST& aItemsList, const wxPoint& rotationPoint )
{
for( unsigned ii = 0; ii < aItemsList.GetCount(); ii++ )
{
SCH_ITEM* item = static_cast<SCH_ITEM*>( aItemsList.GetPickedItem( ii ) );
item->Rotate( rotationPoint ); // Place it in its new position.
item->ClearFlags();
}
}
void MirrorY( PICKED_ITEMS_LIST& aItemsList, const wxPoint& aMirrorPoint )
{
for( unsigned ii = 0; ii < aItemsList.GetCount(); ii++ )
@ -302,5 +291,23 @@ SCH_ITEM* DuplicateStruct( SCH_ITEM* aDrawStruct, bool aClone )
if( aClone )
NewDrawStruct->SetTimeStamp( aDrawStruct->GetTimeStamp() );
NewDrawStruct->ClearFlags( SELECTED | HIGHLIGHTED | BRIGHTENED );
if( NewDrawStruct->Type() == SCH_COMPONENT_T )
{
SCH_PINS& pins = static_cast<SCH_COMPONENT*>( NewDrawStruct )->GetPins();
for( SCH_PIN& pin : pins )
pin.ClearFlags( SELECTED | HIGHLIGHTED | BRIGHTENED );
std::vector<SCH_FIELD*> fields;
static_cast<SCH_COMPONENT*>( NewDrawStruct )->GetFields( fields, false );
for( SCH_FIELD* field : fields )
field->ClearFlags( SELECTED | HIGHLIGHTED | BRIGHTENED );
}
// JEY TODO: sheets and sheet pins?
return NewDrawStruct;
}

View File

@ -121,8 +121,7 @@ void SCH_BASE_FRAME::setupTools()
m_toolManager->InitTools();
// Run the selection tool, it is supposed to be always active
// JEY TODO: enable when we move event loop over to modern toolset...
//m_toolManager->InvokeTool( "eeschema.InteractiveSelection" );
m_toolManager->InvokeTool( "eeschema.InteractiveSelection" );
GetCanvas()->SetEventDispatcher( m_toolDispatcher );
}

View File

@ -82,17 +82,6 @@ SCH_DRAW_PANEL::SCH_DRAW_PANEL( wxWindow* aParentWindow, wxWindowID aWindowId,
// on updated viewport data.
m_viewControls = new KIGFX::WX_VIEW_CONTROLS( m_view, this );
const wxEventType events[] =
{
wxEVT_LEFT_UP, wxEVT_LEFT_DOWN, wxEVT_LEFT_DCLICK,
wxEVT_RIGHT_UP, wxEVT_RIGHT_DOWN, wxEVT_RIGHT_DCLICK,
wxEVT_MIDDLE_UP, wxEVT_MIDDLE_DOWN, wxEVT_MIDDLE_DCLICK,
wxEVT_MOTION, wxEVT_MOUSEWHEEL,
};
for( auto e : events )
Connect( e, wxMouseEventHandler( SCH_DRAW_PANEL::OnMouseEvent ), NULL, this );
Connect( wxEVT_CHAR, wxKeyEventHandler( SCH_DRAW_PANEL::OnKeyEvent ), NULL, this );
Connect( wxEVT_CHAR_HOOK, wxKeyEventHandler( SCH_DRAW_PANEL::OnCharHook ), NULL, this );
@ -100,7 +89,6 @@ SCH_DRAW_PANEL::SCH_DRAW_PANEL( wxWindow* aParentWindow, wxWindowID aWindowId,
Pgm().CommonSettings()->Read( ENBL_ZOOM_NO_CENTER_KEY, &m_enableZoomNoCenter, false );
Pgm().CommonSettings()->Read( ENBL_AUTO_PAN_KEY, &m_enableAutoPan, true );
m_canStartBlock = -1; // Command block can start if >= 0
m_abortRequest = false;
m_ignoreMouseEvents = false;
// Be sure a mouse release button event will be ignored when creating the canvas
@ -111,7 +99,6 @@ SCH_DRAW_PANEL::SCH_DRAW_PANEL( wxWindow* aParentWindow, wxWindowID aWindowId,
m_mouseCaptureCallback = NULL;
m_endMouseCaptureCallback = NULL;
m_enableBlockCommands = false;
m_minDragEventCount = 0;
m_cursorLevel = 0;
@ -256,260 +243,6 @@ EDA_DRAW_FRAME* SCH_DRAW_PANEL::GetParent() const
}
void SCH_DRAW_PANEL::OnMouseEvent( wxMouseEvent& event )
{
int localbutt = 0;
BASE_SCREEN* screen = GetScreen();
auto controls = GetViewControls();
auto vmp = VECTOR2I( controls->GetMousePosition() );
wxPoint mousePos ( vmp.x, vmp.y );
event.Skip();
if( !screen )
return;
/* Adjust value to filter mouse displacement before consider the drag
* mouse is really a drag command, not just a movement while click
*/
#define MIN_DRAG_COUNT_FOR_START_BLOCK_COMMAND 5
if( event.Leaving() )
m_canStartBlock = -1;
if( !IsMouseCaptured() && !controls->GetSettings().m_cursorCaptured )
SetAutoPanRequest( false );
if( GetParent()->IsActive() )
SetFocus();
else
return;
if( !event.IsButton() && !event.Moving() && !event.Dragging() )
return;
if( event.RightUp() )
{
OnRightClick( event );
return;
}
if( m_ignoreMouseEvents )
return;
if( event.LeftDown() )
localbutt = GR_M_LEFT_DOWN;
if( event.ButtonDClick( 1 ) )
localbutt = GR_M_LEFT_DOWN | GR_M_DCLICK;
if( event.MiddleDown() )
localbutt = GR_M_MIDDLE_DOWN;
// Compute the cursor position in drawing (logical) units.
//GetParent()->SetMousePosition( event.GetLogicalPosition( DC ) );
int kbstat = 0;
if( event.ShiftDown() )
kbstat |= GR_KB_SHIFT;
if( event.ControlDown() )
kbstat |= GR_KB_CTRL;
if( event.AltDown() )
kbstat |= GR_KB_ALT;
// Calling Double Click and Click functions :
if( localbutt == (int) ( GR_M_LEFT_DOWN | GR_M_DCLICK ) )
{
GetParent()->OnLeftDClick( nullptr, mousePos );
// inhibit a response to the mouse left button release,
// because we have a double click, and we do not want a new
// OnLeftClick command at end of this Double Click
m_ignoreNextLeftButtonRelease = true;
}
else if( event.LeftUp() )
{
// A block command is in progress: a left up is the end of block
// or this is the end of a double click, already seen
// Note also m_ignoreNextLeftButtonRelease can be set by
// the call to OnLeftClick(), so do not change it after calling OnLeftClick
bool ignoreEvt = m_ignoreNextLeftButtonRelease;
m_ignoreNextLeftButtonRelease = false;
if( screen->m_BlockLocate.GetState() == STATE_NO_BLOCK && !ignoreEvt )
GetParent()->OnLeftClick( nullptr, mousePos );
}
else if( !event.LeftIsDown() )
{
/* be sure there is a response to a left button release command
* even when a LeftUp event is not seen. This happens when a
* double click opens a dialog box, and the release mouse button
* is made when the dialog box is opened.
*/
m_ignoreNextLeftButtonRelease = false;
}
if( event.ButtonDown( wxMOUSE_BTN_MIDDLE ) )
{
m_PanStartCenter = GetParent()->GetScrollCenterPosition();
m_PanStartEventPosition = event.GetPosition();
CrossHairOff( );
SetCurrentCursor( wxCURSOR_SIZING );
}
if( event.ButtonUp( wxMOUSE_BTN_MIDDLE ) )
{
CrossHairOn();
SetDefaultCursor();
}
if( event.MiddleIsDown() )
{
// already managed by EDA_DRAW_PANEL_GAL mouse event handler.
return;
}
// Calling the general function on mouse changes (and pseudo key commands)
GetParent()->GeneralControl( nullptr, mousePos );
/*******************************/
/* Control of block commands : */
/*******************************/
// Command block can't start if mouse is dragging a new panel
static SCH_DRAW_PANEL* lastPanel;
if( lastPanel != this )
{
m_minDragEventCount = 0;
m_canStartBlock = -1;
}
/* A new command block can start after a release buttons
* and if the drag is enough
* This is to avoid a false start block when a dialog box is dismissed,
* or when changing panels in hierarchy navigation
* or when clicking while and moving mouse
*/
if( !event.LeftIsDown() && !event.MiddleIsDown() )
{
m_minDragEventCount = 0;
m_canStartBlock = 0;
/* Remember the last cursor position when a drag mouse starts
* this is the last position ** before ** clicking a button
* this is useful to start a block command from the point where the
* mouse was clicked first
* (a filter creates a delay for the real block command start, and
* we must remember this point)
*/
m_CursorStartPos = GetParent()->GetCrossHairPosition();
}
if( m_enableBlockCommands && !(localbutt & GR_M_DCLICK) )
{
if( !screen->IsBlockActive() )
{
screen->m_BlockLocate.SetOrigin( m_CursorStartPos );
}
if( event.LeftDown() )
{
if( screen->m_BlockLocate.GetState() == STATE_BLOCK_MOVE )
{
SetAutoPanRequest( false );
GetParent()->HandleBlockPlace( nullptr );
m_ignoreNextLeftButtonRelease = true;
}
}
else if( ( m_canStartBlock >= 0 ) && event.LeftIsDown() && !IsMouseCaptured() )
{
// Mouse is dragging: if no block in progress, start a block command.
if( screen->m_BlockLocate.GetState() == STATE_NO_BLOCK )
{
// Start a block command
int cmd_type = kbstat;
// A block command is started if the drag is enough. A small
// drag is ignored (it is certainly a little mouse move when
// clicking) not really a drag mouse
if( m_minDragEventCount < MIN_DRAG_COUNT_FOR_START_BLOCK_COMMAND )
m_minDragEventCount++;
else
{
auto cmd = (GetParent()->GetToolId() == ID_ZOOM_SELECTION) ? BLOCK_ZOOM : 0;
DBG(printf("start block\n");)
if( !GetParent()->HandleBlockBegin( nullptr, cmd_type, m_CursorStartPos, cmd ) )
{
// should not occur: error
GetParent()->DisplayToolMsg(
wxT( "EDA_DRAW_PANEL::OnMouseEvent() Block Error" ) );
}
else
{
SetAutoPanRequest( true );
SetCursor( wxCURSOR_SIZING );
}
}
}
}
if( event.ButtonUp( wxMOUSE_BTN_LEFT ) )
{
/* Release the mouse button: end of block.
* The command can finish (DELETE) or have a next command (MOVE,
* COPY). However the block command is canceled if the block
* size is small because a block command filtering is already
* made, this case happens, but only when the on grid cursor has
* not moved.
*/
#define BLOCK_MINSIZE_LIMIT 1
bool BlockIsSmall =
( std::abs( screen->m_BlockLocate.GetWidth() ) < BLOCK_MINSIZE_LIMIT )
&& ( std::abs( screen->m_BlockLocate.GetHeight() ) < BLOCK_MINSIZE_LIMIT );
if( (screen->m_BlockLocate.GetState() != STATE_NO_BLOCK) && BlockIsSmall )
{
if( m_endMouseCaptureCallback )
{
m_endMouseCaptureCallback( this, nullptr );
SetAutoPanRequest( false );
}
//SetCursor( (wxStockCursor) m_currentCursor );
}
else if( screen->m_BlockLocate.GetState() == STATE_BLOCK_END )
{
SetAutoPanRequest( false );
GetParent()->HandleBlockEnd( nullptr );
//SetCursor( (wxStockCursor) m_currentCursor );
if( screen->m_BlockLocate.GetState() == STATE_BLOCK_MOVE )
{
SetAutoPanRequest( true );
SetCursor( wxCURSOR_HAND );
}
}
}
}
// End of block command on a double click
// To avoid an unwanted block move command if the mouse is moved while double clicking
if( localbutt == (int) ( GR_M_LEFT_DOWN | GR_M_DCLICK ) )
{
if( !screen->IsBlockActive() && IsMouseCaptured() )
m_endMouseCaptureCallback( this, nullptr );
}
lastPanel = this;
}
bool SCH_DRAW_PANEL::OnRightClick( wxMouseEvent& event )
{
auto controls = GetViewControls();

View File

@ -286,8 +286,6 @@ BEGIN_EVENT_TABLE( SCH_EDIT_FRAME, EDA_DRAW_FRAME )
EVT_MENU( ID_CANCEL_CURRENT_COMMAND, SCH_EDIT_FRAME::OnCancelCurrentCommand )
EVT_MENU( ID_SCH_DRAG_ITEM, SCH_EDIT_FRAME::OnDragItem )
EVT_MENU_RANGE( ID_SCH_ROTATE_CLOCKWISE, ID_SCH_ROTATE_COUNTERCLOCKWISE,
SCH_EDIT_FRAME::OnRotate )
EVT_MENU_RANGE( ID_SCH_EDIT_ITEM, ID_SCH_EDIT_COMPONENT_FOOTPRINT,
SCH_EDIT_FRAME::OnEditItem )
EVT_MENU_RANGE( ID_SCH_MIRROR_X, ID_SCH_ORIENT_NORMAL, SCH_EDIT_FRAME::OnOrient )

View File

@ -265,8 +265,6 @@ public:
*/
wxMenu* GetUnfoldBusMenu( SCH_LINE* aBus );
bool GeneralControl( wxDC* aDC, const wxPoint& aPosition, EDA_KEY aHotKey ) override;
/**
* Return the project file parameter list for Eeschema.
*
@ -375,7 +373,6 @@ public:
void KiwayMailIn( KIWAY_EXPRESS& aEvent ) override;
void OnLeftClick( wxDC* aDC, const wxPoint& aPosition ) override;
void OnLeftDClick( wxDC* aDC, const wxPoint& aPosition ) override;
bool OnRightClick( const wxPoint& aPosition, wxMenu* PopMenu ) override;
void OnSelectOptionToolbar( wxCommandEvent& event );
@ -796,12 +793,6 @@ private:
*/
void OnMoveItem( wxCommandEvent& aEvent );
/**
* Handle the #ID_SCH_ROTATE_CLOCKWISE and #ID_SCH_ROTATE_COUNTERCLOCKWISE events
* used to rotate schematic items and blocks.
*/
void OnRotate( wxCommandEvent& aEvent );
/**
* Handle the #ID_SCH_EDIT_ITEM event used to edit schematic items.
*/
@ -937,7 +928,6 @@ private:
// Text, label, glabel
void EditSchematicText( SCH_TEXT* TextStruct );
void ChangeTextOrient( SCH_TEXT* aTextItem );
/**
* Command event handler to change a text type to another one.
@ -961,9 +951,6 @@ private:
*/
void DeleteConnection( bool DeleteFullConnection );
// Images:
void RotateImage( SCH_BITMAP* aItem );
/**
* Mirror a bitmap.
*
@ -983,17 +970,6 @@ private:
// Hierarchical Sheet & PinSheet
void InstallHierarchyFrame( wxPoint& pos );
/**
* Rotate a sheet object.
*
* Sheets do not have a anchor point. Because rotating it from its origin or its end is
* not friendly, the rotation is made around its center.
*
* @param aSheet the hierarchical sheet to rotate
* @param aRotCCW = true to rotate CCW, false to rotate CW
*/
void RotateHierarchicalSheet( SCH_SHEET* aSheet, bool aRotCCW );
/**
* Mirror a hierarchical sheet.
*
@ -1144,8 +1120,6 @@ private:
*/
void EditComponentFieldText( SCH_FIELD* aField );
void RotateField( SCH_FIELD* aField );
/**
* Paste a list of items from the block stack.
*/
@ -1247,8 +1221,6 @@ private:
void addJunctionMenuEntries( wxMenu* aMenu, SCH_JUNCTION* aJunction );
public:
void Key( wxDC* DC, int hotkey, EDA_ITEM* DrawStruct );
/**
* Initialize the parameters used by the block paste command.
*/
@ -1327,6 +1299,12 @@ public:
*/
void SaveUndoItemInUndoList( SCH_ITEM* aItem );
/**
* Performs an undo of the last edit WITHOUT logging a corresponding redo. Used to cancel
* an in-progress operation.
*/
void RollbackSchematicFromUndo();
/**
* Create a symbol library file with the name of the root document plus the '-cache' suffix,
*

View File

@ -235,11 +235,6 @@ COLOR4D SCH_PAINTER::getRenderColor( const EDA_ITEM* aItem, int aLayer, bool aOn
{
return color.Brightened( 0.5 );
}
// JEY TODO: IsMoving checks can go away after seleciton model is fully implemented...
else if( aItem->IsMoving() )
{
return color.Brightened( 0.5 );
}
else if( aItem->IsHighlighted() )
{
if ( aOnBackgroundLayer )
@ -329,10 +324,6 @@ bool SCH_PAINTER::setColors( const LIB_ITEM* aItem, int aLayer )
{
COLOR4D color = getRenderColor( aItem, LAYER_DEVICE, false );
// These actions place the item over others, so allow a modest transparency here
if( aItem->IsMoving() || aItem->IsDragging() || aItem->IsResized() )
color = color.WithAlpha( 0.75 );
m_gal->SetStrokeColor( color );
m_gal->SetIsFill( aItem->GetFillMode() == FILLED_SHAPE );
m_gal->SetFillColor( color );
@ -1102,7 +1093,10 @@ void SCH_PAINTER::draw( SCH_COMPONENT *aComp, int aLayer )
orientPart( &tempPart, aComp->GetOrientation());
for( auto& tempItem : tempPart.GetDrawItems() )
{
tempItem.SetFlags( aComp->GetFlags() ); // SELECTED, HIGHLIGHTED, BRIGHTENED
tempItem.Move( tempItem.GetPosition() + (wxPoint) mapCoords( aComp->GetPosition() ) );
}
// Copy the pin info from the component to the temp pins
LIB_PINS tempPins;
@ -1287,7 +1281,7 @@ void SCH_PAINTER::draw( SCH_SHEET *aSheet, int aLayer )
}
else if( aLayer == LAYER_SHEET )
{
m_gal->SetStrokeColor( m_schSettings.GetLayerColor( LAYER_SHEET ) );
m_gal->SetStrokeColor( getRenderColor( aSheet, LAYER_SHEET, false ) );
m_gal->SetIsStroke( true );
m_gal->SetIsFill( false );
@ -1302,7 +1296,7 @@ void SCH_PAINTER::draw( SCH_SHEET *aSheet, int aLayer )
if( aSheet->IsVerticalOrientation() )
nameAngle = -M_PI/2;
m_gal->SetStrokeColor( m_schSettings.GetLayerColor( LAYER_SHEETNAME ) );
m_gal->SetStrokeColor( getRenderColor( aSheet, LAYER_SHEETNAME, false ) );
auto text = wxT( "Sheet: " ) + aSheet->GetName();
@ -1319,7 +1313,7 @@ void SCH_PAINTER::draw( SCH_SHEET *aSheet, int aLayer )
txtSize = aSheet->GetFileNameSize();
m_gal->SetGlyphSize( VECTOR2D( txtSize, txtSize ) );
m_gal->SetStrokeColor( m_schSettings.GetLayerColor( LAYER_SHEETFILENAME ) );
m_gal->SetStrokeColor( getRenderColor( aSheet, LAYER_SHEETFILENAME, false ) );
m_gal->SetVerticalJustify( GR_TEXT_VJUSTIFY_TOP );
text = wxT( "File: " ) + aSheet->GetFileName();

View File

@ -110,24 +110,19 @@ wxPoint SCH_PIN::GetTransformedPosition() const
const EDA_RECT SCH_PIN::GetBoundingBox() const
{
// Due to pins being relative to their component parent's position, this is unlikely
// to do what a caller wants. Use HitTest() directly instead.
wxFAIL_MSG( "SCH_PINs bounding box is relative to parent component" );
TRANSFORM t = GetParentComponent()->GetTransform();
EDA_RECT r = m_libPin->GetBoundingBox();
return m_libPin->GetBoundingBox();
r = t.TransformCoordinate( r );
r.Offset( GetParentComponent()->GetPosition() );
return r;
}
bool SCH_PIN::HitTest( const wxPoint& aPosition ) const
{
// Pin hit testing is relative to the components position and orientation in the
// schematic. The hit test position must be converted to library coordinates.
TRANSFORM t = GetParentComponent()->GetTransform().InverseTransform();
wxPoint pos = t.TransformCoordinate( aPosition - GetParentComponent()->GetPosition() );
pos.y *= -1; // Y axis polarity in schematic is inverted from library.
return m_libPin->GetBoundingBox().Contains( pos );
return GetBoundingBox().Contains( aPosition );
}

View File

@ -652,139 +652,6 @@ void SCH_EDIT_FRAME::SelectAllFromSheet( wxCommandEvent& aEvent )
}
void SCH_EDIT_FRAME::OnRotate( wxCommandEvent& aEvent )
{
SCH_SELECTION_TOOL* selTool = GetToolManager()->GetTool<SCH_SELECTION_TOOL>();
SCH_SCREEN* screen = GetScreen();
SCH_ITEM* item = screen->GetCurItem();
BLOCK_SELECTOR& block = screen->m_BlockLocate;
// Allows block rotate operation on hot key.
if( block.GetState() != STATE_NO_BLOCK )
{
// Compute the rotation center and put it on grid:
wxPoint rotationPoint = GetNearestGridPosition( block.Centre() );
if( block.GetCommand() != BLOCK_DUPLICATE && block.GetCommand() != BLOCK_PASTE )
{
SaveCopyInUndoList( block.GetItems(), UR_ROTATED, block.AppendUndo(), rotationPoint );
block.SetAppendUndo();
}
RotateListOfItems( block.GetItems(), rotationPoint );
m_canvas->CallMouseCapture( nullptr, wxDefaultPosition, false );
m_canvas->Refresh();
return;
}
if( item == NULL )
{
// If we didn't get here by a hot key, then something has gone wrong.
if( aEvent.GetInt() == 0 )
return;
EDA_HOTKEY_CLIENT_DATA* data = (EDA_HOTKEY_CLIENT_DATA*) aEvent.GetClientObject();
wxCHECK_RET( data != NULL, wxT( "Invalid hot key client object." ) );
item = selTool->SelectPoint( data->GetPosition(), SCH_COLLECTOR::RotatableItems );
// Exit if no item found at the current location or the item is already being edited.
if( item == NULL || item->GetEditFlags() != 0 )
return;
}
switch( item->Type() )
{
case SCH_COMPONENT_T:
{
SCH_COMPONENT* component = static_cast<SCH_COMPONENT*>( item );
if( aEvent.GetId() == ID_SCH_ROTATE_CLOCKWISE )
OrientComponent( CMP_ROTATE_CLOCKWISE );
else if( aEvent.GetId() == ID_SCH_ROTATE_COUNTERCLOCKWISE )
OrientComponent( CMP_ROTATE_COUNTERCLOCKWISE );
else
wxFAIL_MSG( wxT( "Unknown rotate item command ID." ) );
if( m_autoplaceFields )
component->AutoAutoplaceFields( GetScreen() );
break;
}
case SCH_TEXT_T:
case SCH_LABEL_T:
case SCH_GLOBAL_LABEL_T:
case SCH_HIER_LABEL_T:
m_canvas->MoveCursorToCrossHair();
ChangeTextOrient( (SCH_TEXT*) item );
break;
case SCH_BUS_BUS_ENTRY_T:
case SCH_BUS_WIRE_ENTRY_T:
m_canvas->MoveCursorToCrossHair();
SaveCopyInUndoList( item, UR_CHANGED );
item->Rotate( m_canvas->GetParent()->GetCrossHairPosition() );
break;
case SCH_FIELD_T:
m_canvas->MoveCursorToCrossHair();
RotateField( (SCH_FIELD*) item );
if( item->GetParent()->Type() == SCH_COMPONENT_T )
{
// Now that we're moving a field, they're no longer autoplaced.
SCH_COMPONENT *parent = static_cast<SCH_COMPONENT*>( item->GetParent() );
parent->ClearFieldsAutoplaced();
}
break;
case SCH_BITMAP_T:
RotateImage( (SCH_BITMAP*) item );
// The bitmap is cached in Opengl: clear the cache, because
// the cache data is invalid
GetCanvas()->GetView()->RecacheAllItems();
break;
case SCH_SHEET_T:
if( !item->IsNew() ) // rotate a sheet during its creation has no sense
{
bool retCCW = ( aEvent.GetId() == ID_SCH_ROTATE_COUNTERCLOCKWISE );
RotateHierarchicalSheet( static_cast<SCH_SHEET*>( item ), retCCW );
}
break;
case SCH_JUNCTION_T:
case SCH_NO_CONNECT_T:
// these items are not rotated, because rotation does not change them.
break;
default:
// Other items (wires...) cannot be rotated, at least during creation
if( item->IsNew() )
break;
wxFAIL_MSG( wxString::Format( wxT( "Cannot rotate schematic item type %s." ),
GetChars( item->GetClass() ) ) );
}
RefreshItem( item );
if( item->IsMoving() )
{
if( m_canvas->IsMouseCaptured() )
m_canvas->CallMouseCapture( nullptr, wxDefaultPosition, false );
else
m_toolManager->RunAction( SCH_ACTIONS::refreshPreview, true );
}
if( item->GetEditFlags() == 0 )
screen->SetCurItem( nullptr );
}
void SCH_EDIT_FRAME::OnEditItem( wxCommandEvent& aEvent )
{
SCH_SELECTION_TOOL* selTool = GetToolManager()->GetTool<SCH_SELECTION_TOOL>();

View File

@ -111,7 +111,7 @@ void SCH_EDIT_FRAME::SaveCopyInUndoList( SCH_ITEM* aItem,
bool aAppend,
const wxPoint& aTransformPoint )
{
PICKED_ITEMS_LIST* commandToUndo = NULL;
PICKED_ITEMS_LIST* commandToUndo = NULL;
if( aItem == NULL )
return;
@ -349,7 +349,7 @@ void SCH_EDIT_FRAME::PutDataInPreviousState( PICKED_ITEMS_LIST* aList, bool aRed
void SCH_EDIT_FRAME::GetSchematicFromUndoList( wxCommandEvent& event )
{
if( GetScreen()->GetUndoCommandCount() <= 0 || isBusy() )
if( GetScreen()->GetUndoCommandCount() <= 0 )
return;
/* Get the old list */
@ -373,7 +373,7 @@ void SCH_EDIT_FRAME::GetSchematicFromUndoList( wxCommandEvent& event )
void SCH_EDIT_FRAME::GetSchematicFromRedoList( wxCommandEvent& event )
{
if( GetScreen()->GetRedoCommandCount() == 0 || isBusy() )
if( GetScreen()->GetRedoCommandCount() == 0 )
return;
/* Get the old list */
@ -394,3 +394,20 @@ void SCH_EDIT_FRAME::GetSchematicFromRedoList( wxCommandEvent& event )
GetCanvas()->Refresh();
OnModify();
}
void SCH_EDIT_FRAME::RollbackSchematicFromUndo()
{
PICKED_ITEMS_LIST* undo = GetScreen()->PopCommandFromUndoList();
PutDataInPreviousState( undo, false );
undo->ClearListAndDeleteItems();
delete undo;
SetSheetNumberAndCount();
TestDanglingEnds();
SyncView();
GetCanvas()->Refresh();
}

View File

@ -304,37 +304,6 @@ bool SCH_EDIT_FRAME::EditSheet( SCH_SHEET* aSheet, SCH_SHEET_PATH* aHierarchy,
}
void SCH_EDIT_FRAME::RotateHierarchicalSheet( SCH_SHEET* aSheet, bool aRotCCW )
{
if( aSheet == NULL )
return;
// Save old sheet in undo list if not already in edit, or moving.
if( aSheet->GetEditFlags() == 0 )
SaveCopyInUndoList( aSheet, UR_CHANGED );
// Rotate the sheet on itself. Sheets do not have a anchor point.
// Rotation is made around it center
wxPoint rotPoint = aSheet->GetBoundingBox().Centre();
// Keep this rotation point on the grid, otherwise all items of this sheet
// will be moved off grid
rotPoint = GetNearestGridPosition( rotPoint );
// rotate CCW, or CW. to rotate CW, rotate 3 times
aSheet->Rotate( rotPoint );
if( !aRotCCW )
{
aSheet->Rotate( rotPoint );
aSheet->Rotate( rotPoint );
}
GetCanvas()->GetView()->Update( aSheet );
OnModify();
}
void SCH_EDIT_FRAME::MirrorSheet( SCH_SHEET* aSheet, bool aFromXaxis )
{
if( aSheet == NULL )

View File

@ -37,6 +37,9 @@ OPT<TOOL_EVENT> SCH_ACTIONS::TranslateLegacyId( int aId )
{
switch( aId )
{
case ID_NO_TOOL_SELECTED:
return SCH_ACTIONS::selectionActivate.MakeEvent();
case ID_CANCEL_CURRENT_COMMAND:
return ACTIONS::cancelInteractive.MakeEvent();
@ -176,6 +179,10 @@ OPT<TOOL_EVENT> SCH_ACTIONS::TranslateLegacyId( int aId )
case ID_SCHEMATIC_DELETE_ITEM_BUTT:
return SCH_ACTIONS::deleteItemCursor.MakeEvent();
case ID_POPUP_MOVE_BLOCK:
case ID_SCH_MOVE_ITEM:
return SCH_ACTIONS::move.MakeEvent();
case ID_POPUP_SCH_DELETE:
return SCH_ACTIONS::remove.MakeEvent();
@ -184,6 +191,12 @@ OPT<TOOL_EVENT> SCH_ACTIONS::TranslateLegacyId( int aId )
case ID_SIM_TUNE:
return SCH_ACTIONS::simTune.MakeEvent();
case ID_SCH_ROTATE_CLOCKWISE:
return SCH_ACTIONS::rotateCW.MakeEvent();
case ID_SCH_ROTATE_COUNTERCLOCKWISE:
return SCH_ACTIONS::rotateCCW.MakeEvent();
}
return OPT<TOOL_EVENT>();

View File

@ -115,7 +115,8 @@ public:
static TOOL_ACTION editActivate;
static TOOL_ACTION move;
static TOOL_ACTION duplicate;
static TOOL_ACTION rotate;
static TOOL_ACTION rotateCW;
static TOOL_ACTION rotateCCW;
static TOOL_ACTION properties;
static TOOL_ACTION remove;
static TOOL_ACTION addJunction;

View File

@ -27,7 +27,12 @@
#include <sch_actions.h>
#include <hotkeys.h>
#include <bitmaps.h>
#include <confirm.h>
#include <sch_item_struct.h>
#include <sch_component.h>
#include <sch_sheet.h>
#include <sch_text.h>
#include <sch_bitmap.h>
#include <sch_view.h>
#include <sch_item_struct.h>
#include <sch_edit_frame.h>
@ -45,9 +50,14 @@ TOOL_ACTION SCH_ACTIONS::duplicate( "eeschema.InteractiveEdit.duplicate",
AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_DUPLICATE_ITEM ),
_( "Duplicate" ), _( "Duplicates the selected item(s)" ), duplicate_xpm );
TOOL_ACTION SCH_ACTIONS::rotate( "eeschema.InteractiveEdit.rotate",
TOOL_ACTION SCH_ACTIONS::rotateCW( "eeschema.InteractiveEdit.rotateCW",
AS_GLOBAL, 0,
_( "Rotate Clockwise" ), _( "Rotates selected item(s) clockwise" ),
rotate_cw_xpm, AF_NONE );
TOOL_ACTION SCH_ACTIONS::rotateCCW( "eeschema.InteractiveEdit.rotateCCW",
AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_ROTATE ),
_( "Rotate" ), _( "Rotates selected item(s)" ),
_( "Rotate" ), _( "Rotates selected item(s) counter-clockwise" ),
rotate_ccw_xpm, AF_NONE );
TOOL_ACTION SCH_ACTIONS::properties( "eeschema.InteractiveEdit.properties",
@ -61,10 +71,12 @@ TOOL_ACTION SCH_ACTIONS::remove( "eeschema.InteractiveEdit.remove",
SCH_EDIT_TOOL::SCH_EDIT_TOOL() :
TOOL_INTERACTIVE( "eeschema.InteractiveEdit" ),
m_selectionTool( nullptr ),
m_view( nullptr ),
m_controls( nullptr ),
m_frame( nullptr ),
m_menu( *this )
m_menu( *this ),
m_dragging( false )
{
};
@ -76,6 +88,15 @@ SCH_EDIT_TOOL::~SCH_EDIT_TOOL()
bool SCH_EDIT_TOOL::Init()
{
// Find the selection tool, so they can cooperate
m_selectionTool = m_toolMgr->GetTool<SCH_SELECTION_TOOL>();
if( !m_selectionTool )
{
DisplayError( NULL, _( "eeshema.InteractiveSelection tool is not available" ) );
return false;
}
auto activeToolFunctor = [ this ] ( const SELECTION& aSel ) {
return ( m_frame->GetToolId() != ID_NO_TOOL_SELECTED );
};
@ -92,6 +113,8 @@ bool SCH_EDIT_TOOL::Init()
void SCH_EDIT_TOOL::Reset( RESET_REASON aReason )
{
m_dragging = false;
// Init variables used by every drawing tool
m_view = static_cast<KIGFX::SCH_VIEW*>( getView() );
m_controls = getViewControls();
@ -99,12 +122,344 @@ void SCH_EDIT_TOOL::Reset( RESET_REASON aReason )
}
int SCH_EDIT_TOOL::Main( const TOOL_EVENT& aEvent )
{
KIGFX::VIEW_CONTROLS* controls = getViewControls();
controls->SetSnapping( true );
VECTOR2I originalCursorPos = controls->GetCursorPosition();
// Be sure that there is at least one item that we can modify. If nothing was selected before,
// try looking for the stuff under mouse cursor (i.e. Kicad old-style hover selection)
SELECTION& selection = m_selectionTool->RequestSelection( SCH_COLLECTOR::DraggableItems );
bool unselect = selection.IsHover();
if( m_dragging || selection.Empty() )
return 0;
Activate();
controls->ShowCursor( true );
controls->SetAutoPan( true );
bool restore_state = false;
VECTOR2I totalMovement;
OPT_TOOL_EVENT evt = aEvent;
VECTOR2I prevPos;
// Main loop: keep receiving events
do
{
controls->SetSnapping( !evt->Modifier( MD_ALT ) );
if( evt->IsAction( &SCH_ACTIONS::editActivate ) || evt->IsAction( &SCH_ACTIONS::move )
|| evt->IsMotion() || evt->IsDrag( BUT_LEFT ) )
{
if( m_dragging && evt->Category() == TC_MOUSE )
{
m_cursor = controls->GetCursorPosition();
VECTOR2I movement( m_cursor - prevPos );
selection.SetReferencePoint( m_cursor );
totalMovement += movement;
prevPos = m_cursor;
// Drag items to the current cursor position
for( int i = 0; i < selection.GetSize(); ++i )
{
SCH_ITEM* item = static_cast<SCH_ITEM*>( selection.GetItem( i ) );
// Don't double move footprint pads, fields, etc.
if( item->GetParent() && item->GetParent()->IsSelected() )
continue;
item->Move( (wxPoint)movement );
item->SetFlags( IS_MOVED );
updateView( item );
}
m_frame->UpdateMsgPanel();
}
else if( !m_dragging ) // Prepare to start dragging
{
// Save items, so changes can be undone
for( int i = 0; i < selection.GetSize(); ++i )
{
SCH_ITEM* item = static_cast<SCH_ITEM*>( selection.GetItem( i ) );
// Don't double move footprint pads, fields, etc.
if( item->GetParent() && item->GetParent()->IsSelected() )
continue;
m_frame->SaveCopyInUndoList( item, UR_CHANGED, i > 0 );
}
m_cursor = controls->GetCursorPosition();
if( selection.HasReferencePoint() )
{
// start moving with the reference point attached to the cursor
VECTOR2I delta = m_cursor - selection.GetReferencePoint();
// Drag items to the current cursor position
for( int i = 0; i < selection.GetSize(); ++i )
{
SCH_ITEM* item = static_cast<SCH_ITEM*>( selection.GetItem( i ) );
// Don't double move footprint pads, fields, etc.
if( item->GetParent() && item->GetParent()->IsSelected() )
continue;
item->Move( (wxPoint)delta );
}
selection.SetReferencePoint( m_cursor );
}
else if( selection.Size() == 1 )
{
// Set the current cursor position to the first dragged item origin, so the
// movement vector could be computed later
updateModificationPoint( selection );
m_cursor = originalCursorPos;
}
else
{
updateModificationPoint( selection );
}
controls->SetCursorPosition( m_cursor, false );
prevPos = m_cursor;
controls->SetAutoPan( true );
m_dragging = true;
}
}
else if( evt->IsAction( &ACTIONS::cancelInteractive ) || evt->IsCancel() || evt->IsActivate() )
{
if( m_dragging )
restore_state = true;
break;
}
else if( evt->Action() == TA_UNDO_REDO_PRE )
{
unselect = true;
break;
}
// Dispatch TOOL_ACTIONs
else if( evt->Category() == TC_COMMAND )
{
if( evt->IsAction( &SCH_ACTIONS::remove ) )
{
// exit the loop, as there is no further processing for removed items
break;
}
else if( evt->IsAction( &SCH_ACTIONS::duplicate ) )
{
// On duplicate, stop moving this item
// The duplicate tool should then select the new item and start
// a new move procedure
break;
}
}
else if( evt->IsMouseUp( BUT_LEFT ) || evt->IsClick( BUT_LEFT ) )
{
break; // Finish
}
} while( ( evt = Wait() ) ); //Should be assignment not equality test
controls->ForceCursorPosition( false );
controls->ShowCursor( false );
controls->SetSnapping( false );
controls->SetAutoPan( false );
m_dragging = false;
// Discard reference point when selection is "dropped" onto the board (ie: not dragging anymore)
selection.ClearReferencePoint();
for( auto item : selection )
item->ClearFlags( IS_MOVED );
//if( unselect || restore_state )
m_toolMgr->RunAction( SCH_ACTIONS::selectionClear, true );
if( restore_state )
m_frame->RollbackSchematicFromUndo();
else
m_frame->OnModify();
return 0;
}
bool SCH_EDIT_TOOL::updateModificationPoint( SELECTION& aSelection )
{
if( m_dragging && aSelection.HasReferencePoint() )
return false;
// When there is only one item selected, the reference point is its position...
if( aSelection.Size() == 1 )
{
SCH_ITEM* item = static_cast<SCH_ITEM*>( aSelection.Front() );
wxPoint pos = item->GetPosition();
aSelection.SetReferencePoint( pos );
}
// ...otherwise modify items with regard to the grid-snapped cursor position
else
{
m_cursor = getViewControls()->GetCursorPosition( true );
aSelection.SetReferencePoint( m_cursor );
}
return true;
}
int SCH_EDIT_TOOL::Rotate( const TOOL_EVENT& aEvent )
{
SCH_SELECTION_TOOL* selTool = m_toolMgr->GetTool<SCH_SELECTION_TOOL>();
SELECTION selection = selTool->RequestSelection( SCH_COLLECTOR::RotatableItems );
if( selection.GetSize() == 0 )
return 0;
wxPoint rotPoint;
bool clockwise = ( aEvent.Matches( SCH_ACTIONS::rotateCW.MakeEvent() ) );
SCH_ITEM* item = static_cast<SCH_ITEM*>( selection.GetItem( 0 ) );
bool connections = false;
bool moving = item->IsMoving();
if( selection.GetSize() == 1 )
{
if( !moving )
m_frame->SaveCopyInUndoList( item, UR_CHANGED );
switch( item->Type() )
{
case SCH_COMPONENT_T:
{
SCH_COMPONENT* component = static_cast<SCH_COMPONENT*>( item );
if( clockwise )
component->SetOrientation( CMP_ROTATE_CLOCKWISE );
else
component->SetOrientation( CMP_ROTATE_COUNTERCLOCKWISE );
if( m_frame->GetAutoplaceFields() )
component->AutoAutoplaceFields( m_frame->GetScreen() );
break;
}
case SCH_TEXT_T:
case SCH_LABEL_T:
case SCH_GLOBAL_LABEL_T:
case SCH_HIER_LABEL_T:
{
SCH_TEXT* textItem = static_cast<SCH_TEXT*>( item );
textItem->SetLabelSpinStyle( ( textItem->GetLabelSpinStyle() + 1 ) & 3 );
break;
}
case SCH_BUS_BUS_ENTRY_T:
case SCH_BUS_WIRE_ENTRY_T:
item->Rotate( item->GetPosition() );
break;
case SCH_FIELD_T:
{
SCH_FIELD* field = static_cast<SCH_FIELD*>( item );
if( field->GetTextAngle() == TEXT_ANGLE_HORIZ )
field->SetTextAngle( TEXT_ANGLE_VERT );
else
field->SetTextAngle( TEXT_ANGLE_HORIZ );
// Now that we're moving a field, they're no longer autoplaced.
if( item->GetParent()->Type() == SCH_COMPONENT_T )
{
SCH_COMPONENT *parent = static_cast<SCH_COMPONENT*>( item->GetParent() );
parent->ClearFieldsAutoplaced();
}
break;
}
case SCH_BITMAP_T:
item->Rotate( item->GetPosition() );
// The bitmap is cached in Opengl: clear the cache to redraw
getView()->RecacheAllItems();
break;
case SCH_SHEET_T:
{
SCH_SHEET* sheet = static_cast<SCH_SHEET*>( item );
// Rotate the sheet on itself. Sheets do not have a anchor point.
rotPoint = m_frame->GetNearestGridPosition( sheet->GetBoundingBox().Centre() );
if( clockwise )
{
sheet->Rotate( rotPoint );
}
else
{
sheet->Rotate( rotPoint );
sheet->Rotate( rotPoint );
sheet->Rotate( rotPoint );
}
break;
}
default:
break;
}
connections = item->IsConnectable();
m_frame->RefreshItem( item );
}
else if( selection.GetSize() > 1 )
{
rotPoint = m_frame->GetNearestGridPosition( (wxPoint)selection.GetCenter() );
for( unsigned ii = 0; ii < selection.GetSize(); ii++ )
{
item = static_cast<SCH_ITEM*>( selection.GetItem( ii ) );
if( !moving )
m_frame->SaveCopyInUndoList( item, UR_CHANGED, ii > 0 );
item->Rotate( rotPoint );
connections |= item->IsConnectable();
m_frame->RefreshItem( item );
}
}
if( !item->IsMoving() )
{
if( connections )
m_frame->TestDanglingEnds();
m_frame->OnModify();
}
return 0;
}
int SCH_EDIT_TOOL::Remove( const TOOL_EVENT& aEvent )
{
SCH_SELECTION_TOOL* selTool = m_toolMgr->GetTool<SCH_SELECTION_TOOL>();
std::vector<SCH_ITEM*> lockedItems;
// get a copy instead of reference (as we're going to clear the selection before removing items)
// get a copy instead of reference (we're going to clear the selection before removing items)
SELECTION selectionCopy = selTool->RequestSelection();
if( selectionCopy.Empty() )
@ -113,9 +468,9 @@ int SCH_EDIT_TOOL::Remove( const TOOL_EVENT& aEvent )
// As we are about to remove items, they have to be removed from the selection first
m_toolMgr->RunAction( SCH_ACTIONS::selectionClear, true );
for( EDA_ITEM* it : selectionCopy )
for( unsigned ii = 0; ii < selectionCopy.GetSize(); ii++ )
{
SCH_ITEM* item = static_cast<SCH_ITEM*>( it );
SCH_ITEM* item = static_cast<SCH_ITEM*>( selectionCopy.GetItem( ii ) );
bool itemHasConnections = item->IsConnectable();
m_frame->GetScreen()->SetCurItem( nullptr );
@ -133,7 +488,22 @@ int SCH_EDIT_TOOL::Remove( const TOOL_EVENT& aEvent )
}
void SCH_EDIT_TOOL::updateView( EDA_ITEM* aItem )
{
KICAD_T itemType = aItem->Type();
if( itemType == SCH_PIN_T || itemType == SCH_FIELD_T || itemType == SCH_SHEET_PIN_T )
getView()->Update( aItem->GetParent() );
else
getView()->Update( aItem );
}
void SCH_EDIT_TOOL::setTransitions()
{
Go( &SCH_EDIT_TOOL::Remove, SCH_ACTIONS::remove.MakeEvent() );
Go( &SCH_EDIT_TOOL::Main, SCH_ACTIONS::editActivate.MakeEvent() );
Go( &SCH_EDIT_TOOL::Main, SCH_ACTIONS::move.MakeEvent() );
Go( &SCH_EDIT_TOOL::Rotate, SCH_ACTIONS::rotateCW.MakeEvent() );
Go( &SCH_EDIT_TOOL::Rotate, SCH_ACTIONS::rotateCCW.MakeEvent() );
Go( &SCH_EDIT_TOOL::Remove, SCH_ACTIONS::remove.MakeEvent() );
}

View File

@ -30,6 +30,7 @@
class SCH_EDIT_FRAME;
class SCH_SELECTION_TOOL;
class SCH_EDIT_TOOL : public TOOL_INTERACTIVE
@ -50,19 +51,48 @@ public:
return m_menu;
}
/**
* Function Main()
*
* Main loop in which events are handled.
*/
int Main( const TOOL_EVENT& aEvent );
int Rotate( const TOOL_EVENT& aEvent );
/**
* Function Remove()
*
* Deletes the selected items, or the item under the cursor.
*/
int Remove( const TOOL_EVENT& aEvent );
private:
///> Returns the right modification point (e.g. for rotation), depending on the number of
///> selected items.
bool updateModificationPoint( SELECTION& aSelection );
///> Similar to getView()->Update(), but handles items that are redrawn by their parents.
void updateView( EDA_ITEM* );
///> Sets up handlers for various events.
void setTransitions() override;
private:
KIGFX::SCH_VIEW* m_view;
SCH_SELECTION_TOOL* m_selectionTool;
KIGFX::SCH_VIEW* m_view;
KIGFX::VIEW_CONTROLS* m_controls;
SCH_EDIT_FRAME* m_frame;
SCH_EDIT_FRAME* m_frame;
/// Menu model displayed by the tool.
TOOL_MENU m_menu;
TOOL_MENU m_menu;
///> Flag determining if anything is being dragged right now
bool m_dragging;
///> Last cursor position (needed for getModificationPoint() to avoid changes
///> of edit reference point).
VECTOR2I m_cursor;
};
#endif //KICAD_SCH_EDIT_TOOL_H

View File

@ -33,6 +33,7 @@
#include <view/view.h>
#include <view/view_controls.h>
#include <view/view_group.h>
#include <preview_items/selection_area.h>
#include <tool/tool_event.h>
#include <tool/tool_manager.h>
#include <sch_actions.h>
@ -74,7 +75,6 @@ SCH_SELECTION_TOOL::SCH_SELECTION_TOOL() :
m_subtractive( false ),
m_multiple( false ),
m_skip_heuristics( false ),
m_locked( true ),
m_menu( *this )
{
}
@ -100,7 +100,6 @@ bool SCH_SELECTION_TOOL::Init()
void SCH_SELECTION_TOOL::Reset( RESET_REASON aReason )
{
m_frame = getEditFrame<SCH_BASE_FRAME>();
m_locked = true;
if( aReason == TOOL_BASE::MODEL_RELOAD )
{
@ -182,10 +181,8 @@ int SCH_SELECTION_TOOL::Main( const TOOL_EVENT& aEvent )
{
if( m_additive || m_subtractive || m_selection.Empty() )
{
// JEY TODO: move block selection to SCH_SELECTION_TOOL
//selectMultiple();
selectMultiple();
}
else
{
// Check if dragging has started within any of selected items bounding box
@ -318,6 +315,15 @@ void SCH_SELECTION_TOOL::guessSelectionCandidates( SCH_COLLECTOR& collector,
}
static EDA_RECT getRect( const SCH_ITEM* aItem )
{
if( aItem->Type() == SCH_COMPONENT_T )
return static_cast<const SCH_COMPONENT*>( aItem )->GetBodyBoundingBox();
return aItem->GetBoundingBox();
}
SELECTION& SCH_SELECTION_TOOL::RequestSelection( const KICAD_T aFilterList[] )
{
if( m_selection.Empty() )
@ -366,15 +372,138 @@ bool SCH_SELECTION_TOOL::selectCursor( const KICAD_T aFilterList[], bool aForceS
}
bool SCH_SELECTION_TOOL::selectMultiple()
{
bool cancelled = false; // Was the tool cancelled while it was running?
m_multiple = true; // Multiple selection mode is active
KIGFX::VIEW* view = getView();
KIGFX::PREVIEW::SELECTION_AREA area;
view->Add( &area );
while( OPT_TOOL_EVENT evt = Wait() )
{
if( evt->IsAction( &ACTIONS::cancelInteractive ) || evt->IsActivate() || evt->IsCancel() )
{
cancelled = true;
break;
}
if( evt->IsDrag( BUT_LEFT ) )
{
// Start drawing a selection box
area.SetOrigin( evt->DragOrigin() );
area.SetEnd( evt->Position() );
area.SetAdditive( m_additive );
area.SetSubtractive( m_subtractive );
view->SetVisible( &area, true );
view->Update( &area );
getViewControls()->SetAutoPan( true );
}
if( evt->IsMouseUp( BUT_LEFT ) )
{
getViewControls()->SetAutoPan( false );
// End drawing the selection box
view->SetVisible( &area, false );
// Mark items within the selection box as selected
std::vector<KIGFX::VIEW::LAYER_ITEM_PAIR> selectedItems;
// Filter the view items based on the selection box
BOX2I selectionBox = area.ViewBBox();
view->Query( selectionBox, selectedItems ); // Get the list of selected items
std::vector<KIGFX::VIEW::LAYER_ITEM_PAIR>::iterator it, it_end;
int width = area.GetEnd().x - area.GetOrigin().x;
int height = area.GetEnd().y - area.GetOrigin().y;
/* Selection mode depends on direction of drag-selection:
* Left > Right : Select objects that are fully enclosed by selection
* Right > Left : Select objects that are crossed by selection
*/
bool windowSelection = width >= 0 ? true : false;
if( view->IsMirroredX() )
windowSelection = !windowSelection;
// Construct an EDA_RECT to determine BOARD_ITEM selection
EDA_RECT selectionRect( wxPoint( area.GetOrigin().x, area.GetOrigin().y ),
wxSize( width, height ) );
selectionRect.Normalize();
for( it = selectedItems.begin(), it_end = selectedItems.end(); it != it_end; ++it )
{
SCH_ITEM* item = static_cast<SCH_ITEM*>( it->first );
if( !item || !selectable( item ) )
continue;
if( windowSelection )
{
BOX2I bbox = getRect( item );
if( selectionBox.Contains( bbox ) )
{
if( m_subtractive )
unselect( item );
else
select( item );
}
}
else
{
if( item->HitTest( selectionRect, false ) )
{
if( m_subtractive )
unselect( item );
else
select( item );
}
}
}
if( m_frame )
{
if( m_selection.Size() == 1 )
m_frame->GetScreen()->SetCurItem( static_cast<SCH_ITEM*>( m_selection.Front() ) );
else
m_frame->GetScreen()->SetCurItem( nullptr );
}
// Inform other potentially interested tools
if( !m_selection.Empty() )
m_toolMgr->ProcessEvent( EVENTS::SelectedEvent );
break; // Stop waiting for events
}
}
getViewControls()->SetAutoPan( false );
// Stop drawing the selection box
view->Remove( &area );
m_multiple = false; // Multiple selection mode is inactive
if( !cancelled )
m_selection.ClearReferencePoint();
return cancelled;
}
int SCH_SELECTION_TOOL::SelectItems( const TOOL_EVENT& aEvent )
{
std::vector<SCH_ITEM*>* items = aEvent.Parameter<std::vector<SCH_ITEM*>*>();
PICKED_ITEMS_LIST* pickedItems = aEvent.Parameter<PICKED_ITEMS_LIST*>();
if( items )
if( pickedItems )
{
// Perform individual selection of each item before processing the event.
for( auto item : *items )
select( item );
for( unsigned ii = 0; ii < pickedItems->GetCount(); ii++ )
select( (SCH_ITEM*) pickedItems->GetPickedItem( ii ) );
m_toolMgr->ProcessEvent( EVENTS::SelectedEvent );
}
@ -402,13 +531,12 @@ int SCH_SELECTION_TOOL::SelectItem( const TOOL_EVENT& aEvent )
int SCH_SELECTION_TOOL::UnselectItems( const TOOL_EVENT& aEvent )
{
std::vector<SCH_ITEM*>* items = aEvent.Parameter<std::vector<SCH_ITEM*>*>();
PICKED_ITEMS_LIST* pickedItems = aEvent.Parameter<PICKED_ITEMS_LIST*>();
if( items )
if( pickedItems )
{
// Perform individual unselection of each item before processing the event
for( auto item : *items )
unselect( item );
for( unsigned ii = 0; ii < pickedItems->GetCount(); ii++ )
unselect( (SCH_ITEM*) pickedItems->GetPickedItem( ii ) );
m_toolMgr->ProcessEvent( EVENTS::UnselectedEvent );
}
@ -456,43 +584,6 @@ int SCH_SELECTION_TOOL::SelectionMenu( const TOOL_EVENT& aEvent )
bool SCH_SELECTION_TOOL::doSelectionMenu( SCH_COLLECTOR* aCollector )
{
SCH_ITEM* current = nullptr;
#if 1
// ====================================================================================
// JEY TODO: use wxWidgets event loop for showing menu until we move to modern toolset event loop
wxMenu selectMenu;
AddMenuItem( &selectMenu, wxID_NONE, _( "Clarify Selection" ), KiBitmap( info_xpm ) );
selectMenu.AppendSeparator();
for( int i = 0; i < aCollector->GetCount() && i < MAX_SELECT_ITEM_IDS; i++ )
{
SCH_ITEM* item = ( *aCollector )[i];
wxString text = item->GetSelectMenuText( m_frame->GetUserUnits() );
BITMAP_DEF xpm = item->GetMenuImage();
AddMenuItem( &selectMenu, i, text, KiBitmap( xpm ) );
}
// Set to NULL in case the user aborts the clarification context menu.
m_frame->GetScreen()->SetCurItem( nullptr );
int idx = m_frame->GetPopupMenuSelectionFromUser( selectMenu );
if( idx == wxID_NONE )
{
m_frame->GetScreen()->SetCurItem( nullptr );
return false;
}
m_frame->GetCanvas()->MoveCursorToCrossHair();
current = ( *aCollector )[ idx ];
m_frame->GetScreen()->SetCurItem( current );
aCollector->Empty();
aCollector->Append( current );
return true;
// ====================================================================================
#endif
CONTEXT_MENU menu;
int limit = std::min( MAX_SELECT_ITEM_IDS, aCollector->GetCount() );
@ -549,12 +640,18 @@ bool SCH_SELECTION_TOOL::doSelectionMenu( SCH_COLLECTOR* aCollector )
break;
}
getView()->UpdateItems();
m_frame->GetCanvas()->Refresh();
}
if( current )
{
unhighlight( current, BRIGHTENED );
getView()->UpdateItems();
m_frame->GetCanvas()->Refresh();
aCollector->Empty();
aCollector->Append( current );
return true;
@ -605,8 +702,6 @@ void SCH_SELECTION_TOOL::clearSelection()
if( m_frame )
m_frame->GetScreen()->SetCurItem( nullptr );
m_locked = true;
// Inform other potentially interested tools
m_toolMgr->ProcessEvent( EVENTS::ClearedEvent );
}
@ -643,11 +738,7 @@ void SCH_SELECTION_TOOL::toggleSelection( SCH_ITEM* aItem, bool aForce )
void SCH_SELECTION_TOOL::select( SCH_ITEM* aItem )
{
if( aItem->IsSelected() )
return;
highlight( aItem, SELECTED, &m_selection );
getView()->Update( &m_selection );
if( m_frame )
{
@ -668,13 +759,9 @@ void SCH_SELECTION_TOOL::select( SCH_ITEM* aItem )
void SCH_SELECTION_TOOL::unselect( SCH_ITEM* aItem )
{
unhighlight( aItem, SELECTED, &m_selection );
getView()->Update( &m_selection );
if( m_frame && m_frame->GetScreen()->GetCurItem() == aItem )
m_frame->GetScreen()->SetCurItem( nullptr );
if( m_selection.Empty() )
m_locked = true;
}
@ -689,10 +776,10 @@ void SCH_SELECTION_TOOL::highlight( SCH_ITEM* aItem, int aMode, SELECTION* aGrou
aGroup->Add( aItem );
// Highlight pins and fields. (All the other component children are currently only
// represented in the LIB_PART.)
// represented in the LIB_PART and will inherit the settings of the parent component.)
if( aItem->Type() == SCH_COMPONENT_T )
{
SCH_PINS pins = static_cast<SCH_COMPONENT*>( aItem )->GetPins();
SCH_PINS& pins = static_cast<SCH_COMPONENT*>( aItem )->GetPins();
for( SCH_PIN& pin : pins )
{
@ -705,23 +792,31 @@ void SCH_SELECTION_TOOL::highlight( SCH_ITEM* aItem, int aMode, SELECTION* aGrou
std::vector<SCH_FIELD*> fields;
static_cast<SCH_COMPONENT*>( aItem )->GetFields( fields, false );
for( auto field : fields )
for( SCH_FIELD* field : fields )
{
if( aMode == SELECTED )
field->SetSelected();
else if( aMode == BRIGHTENED )
field->SetBrightened();
}
}
else if( aItem->Type() == SCH_SHEET_T )
{
SCH_SHEET_PINS& pins = static_cast<SCH_SHEET*>( aItem )->GetPins();
// JEY TODO: do these need hiding from view and adding to aGroup?
for( SCH_SHEET_PIN& pin : pins )
{
if( aMode == SELECTED )
pin.SetSelected();
else if( aMode == BRIGHTENED )
pin.SetBrightened();
}
}
// JEY TODO: Sheets and sheet pins?
// Many selections are very temporal and updating the display each time just
// creates noise.
if( aMode == BRIGHTENED )
getView()->MarkTargetDirty( KIGFX::TARGET_OVERLAY );
if( aItem->Type() == SCH_PIN_T || aItem->Type() == SCH_FIELD_T )
getView()->Update( aItem->GetParent() );
else
getView()->Update( aItem );
}
@ -739,7 +834,7 @@ void SCH_SELECTION_TOOL::unhighlight( SCH_ITEM* aItem, int aMode, SELECTION* aGr
// represented in the LIB_PART.)
if( aItem->Type() == SCH_COMPONENT_T )
{
SCH_PINS pins = static_cast<SCH_COMPONENT*>( aItem )->GetPins();
SCH_PINS& pins = static_cast<SCH_COMPONENT*>( aItem )->GetPins();
for( SCH_PIN& pin : pins )
{
@ -752,23 +847,31 @@ void SCH_SELECTION_TOOL::unhighlight( SCH_ITEM* aItem, int aMode, SELECTION* aGr
std::vector<SCH_FIELD*> fields;
static_cast<SCH_COMPONENT*>( aItem )->GetFields( fields, false );
for( auto field : fields )
for( SCH_FIELD* field : fields )
{
if( aMode == SELECTED )
field->ClearSelected();
else if( aMode == BRIGHTENED )
field->ClearBrightened();
}
}
else if( aItem->Type() == SCH_SHEET_T )
{
SCH_SHEET_PINS& pins = static_cast<SCH_SHEET*>( aItem )->GetPins();
// JEY TODO: do these need showing and updating?
for( SCH_SHEET_PIN& pin : pins )
{
if( aMode == SELECTED )
pin.ClearSelected();
else if( aMode == BRIGHTENED )
pin.ClearBrightened();
}
}
// JEY TODO: Sheets and sheet pins?
// Many selections are very temporal and updating the display each time just
// creates noise.
if( aMode == BRIGHTENED )
getView()->MarkTargetDirty( KIGFX::TARGET_OVERLAY );
if( aItem->Type() == SCH_PIN_T || aItem->Type() == SCH_FIELD_T )
getView()->Update( aItem->GetParent() );
else
getView()->Update( aItem );
}

View File

@ -123,6 +123,15 @@ private:
*/
bool selectCursor( const KICAD_T aFilterList[], bool aForceSelect = false );
/**
* Function selectMultiple()
* Handles drawing a selection box that allows one to select many items at
* the same time.
*
* @return true if the function was cancelled (i.e. CancelEvent was received).
*/
bool selectMultiple();
/**
* Apply heuristics to try and determine a single object when multiple are found under the
* cursor.
@ -213,7 +222,6 @@ private:
bool m_subtractive; // Items should be removed from selection
bool m_multiple; // Multiple selection mode is active
bool m_skip_heuristics; // Heuristics are not allowed when choosing item under cursor
bool m_locked; // Other tools are not allowed to modify locked items
TOOL_MENU m_menu;
};

View File

@ -221,11 +221,6 @@ protected:
*/
void RefreshCrossHair( const wxPoint &aOldPos, const wxPoint &aEvtPos, wxDC* aDC );
/**
* @return true if an item edit or a block operation is in progress.
*/
bool isBusy() const;
/**
* Stores the canvas type in the application settings.
*/
@ -744,8 +739,8 @@ public:
void DisplayToolMsg( const wxString& msg );
virtual void RedrawActiveWindow( wxDC* DC, bool EraseBg ) = 0;
virtual void OnLeftClick( wxDC* DC, const wxPoint& MousePos ) = 0;
virtual void OnLeftDClick( wxDC* DC, const wxPoint& MousePos );
virtual void OnLeftClick( wxDC* DC, const wxPoint& MousePos ) {};
virtual void OnLeftDClick( wxDC* DC, const wxPoint& MousePos ) {};
virtual bool OnRightClick( const wxPoint& MousePos, wxMenu* PopMenu ) = 0;
virtual void ToolOnRightClick( wxCommandEvent& event );
void AdjustScrollBars( const wxPoint& aCenterPosition );

View File

@ -75,11 +75,6 @@ protected:
/// Abort mouse capture callback function.
END_MOUSE_CAPTURE_CALLBACK m_endMouseCaptureCallback;
/// useful to avoid false start block in certain cases
/// (like switch from a sheet to another sheet
/// >= 0 (or >= n) if a block can start
int m_canStartBlock;
int m_doubleClickInterval;
public:
@ -100,7 +95,6 @@ public:
m_PrintIsMirrored( false ),
m_mouseCaptureCallback( nullptr ),
m_endMouseCaptureCallback( nullptr ),
m_canStartBlock( true ),
m_doubleClickInterval( 0 )
{};
@ -150,7 +144,7 @@ public:
bool GetPrintMirrored() const { return m_PrintIsMirrored; }
void SetPrintMirrored( bool aMirror ) { m_PrintIsMirrored = aMirror; }
void SetCanStartBlock( int aStartBlock ) { m_canStartBlock = aStartBlock; }
void SetCanStartBlock( int aStartBlock ) { /* JEY TODO: remove */ }
/**
* Function DrawBackGround