88 changed files with 2677 additions and 3736 deletions
-
21Documentation/development/tool-framework.md
-
2common/CMakeLists.txt
-
8common/eda_text.cpp
-
116common/legacy_gal/block.cpp
-
1common/legacy_gal/eda_draw_frame.cpp
-
1common/legacy_wx/eda_draw_frame.cpp
-
2common/tool/actions.cpp
-
2common/tool/edit_constraints.cpp
-
0common/tool/edit_constraints.h
-
8common/tool/edit_points.cpp
-
28common/tool/edit_points.h
-
11eeschema/CMakeLists.txt
-
103eeschema/block.cpp
-
2eeschema/class_libentry.cpp
-
3eeschema/dialogs/dialog_lib_edit_text.cpp
-
13eeschema/eeschema_id.h
-
173eeschema/hotkeys.cpp
-
131eeschema/lib_arc.cpp
-
40eeschema/lib_circle.cpp
-
9eeschema/lib_circle.h
-
43eeschema/lib_field.cpp
-
1eeschema/lib_field.h
-
8eeschema/lib_pin.cpp
-
11eeschema/lib_pin.h
-
30eeschema/lib_polyline.cpp
-
5eeschema/lib_polyline.h
-
41eeschema/lib_rectangle.cpp
-
4eeschema/lib_rectangle.h
-
3eeschema/lib_text.cpp
-
588eeschema/libedit/block_libedit.cpp
-
594eeschema/libedit/lib_edit_frame.cpp
-
155eeschema/libedit/lib_edit_frame.h
-
3eeschema/libedit/lib_export.cpp
-
37eeschema/libedit/libedit.cpp
-
167eeschema/libedit/libedit_onleftclick.cpp
-
366eeschema/libedit/libedit_onrightclick.cpp
-
22eeschema/libedit/libedit_undo_redo.cpp
-
63eeschema/libedit/libfield.cpp
-
180eeschema/libedit/symbdraw.cpp
-
7eeschema/libedit/symbedit.cpp
-
5eeschema/sch_base_frame.h
-
58eeschema/sch_collectors.cpp
-
2eeschema/sch_collectors.h
-
34eeschema/sch_component.cpp
-
348eeschema/sch_draw_panel.cpp
-
8eeschema/sch_draw_panel.h
-
10eeschema/sch_edit_frame.cpp
-
30eeschema/sch_edit_frame.h
-
2eeschema/sch_line.h
-
17eeschema/sch_screen.h
-
5eeschema/sch_sheet.cpp
-
26eeschema/tools/inspection_tool.cpp
-
6eeschema/tools/inspection_tool.h
-
67eeschema/tools/lib_drawing_tools.cpp
-
2eeschema/tools/lib_drawing_tools.h
-
609eeschema/tools/lib_edit_tool.cpp
-
88eeschema/tools/lib_edit_tool.h
-
346eeschema/tools/lib_move_tool.cpp
-
87eeschema/tools/lib_move_tool.h
-
402eeschema/tools/lib_pin_tool.cpp
-
9eeschema/tools/lib_pin_tool.h
-
20eeschema/tools/picker_tool.cpp
-
6eeschema/tools/picker_tool.h
-
782eeschema/tools/point_editor.cpp
-
108eeschema/tools/point_editor.h
-
3eeschema/tools/sch_actions.cpp
-
28eeschema/tools/sch_actions.h
-
118eeschema/tools/sch_drawing_tools.cpp
-
2eeschema/tools/sch_drawing_tools.h
-
36eeschema/tools/sch_edit_tool.cpp
-
10eeschema/tools/sch_editor_control.cpp
-
6eeschema/tools/sch_move_tool.cpp
-
41eeschema/tools/sch_selection_tool.cpp
-
4eeschema/tools/sch_wire_bus_tool.cpp
-
1include/core/typeinfo.h
-
8include/draw_frame.h
-
3include/eda_text.h
-
11include/id.h
-
2include/tool/actions.h
-
2pcbnew/CMakeLists.txt
-
18pcbnew/tools/edit_tool.cpp
-
4pcbnew/tools/pad_tool.cpp
-
3pcbnew/tools/pcb_actions.h
-
18pcbnew/tools/point_editor.cpp
-
8pcbnew/tools/point_editor.h
-
2pcbnew/tools/position_relative_tool.cpp
-
2pcbnew/tools/selection_tool.cpp
-
4qa/qa_utils/mocks.cpp
@ -1,103 +0,0 @@ |
|||
/*
|
|||
* This program source code file is part of KiCad, a free EDA CAD application. |
|||
* |
|||
* Copyright (C) 2015 Jean-Pierre Charras, jp.charras at wanadoo.fr |
|||
* Copyright (C) 2009 Wayne Stambaugh <stambaughw@gmail.com> |
|||
* Copyright (C) 2004-2019 KiCad Developers, see change_log.txt for contributors. |
|||
* |
|||
* This program is free software; you can redistribute it and/or |
|||
* modify it under the terms of the GNU General Public License |
|||
* as published by the Free Software Foundation; either version 2 |
|||
* of the License, or (at your option) any later version. |
|||
* |
|||
* This program is distributed in the hope that it will be useful, |
|||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
* GNU General Public License for more details. |
|||
* |
|||
* You should have received a copy of the GNU General Public License |
|||
* along with this program; if not, you may find one here: |
|||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
|||
* or you may search the http://www.gnu.org website for the version 2 license,
|
|||
* or you may write to the Free Software Foundation, Inc., |
|||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA |
|||
*/ |
|||
|
|||
#include <fctsys.h>
|
|||
#include <pgm_base.h>
|
|||
#include <gr_basic.h>
|
|||
#include <sch_draw_panel.h>
|
|||
#include <confirm.h>
|
|||
#include <sch_edit_frame.h>
|
|||
#include <tool/tool_manager.h>
|
|||
#include <general.h>
|
|||
#include <class_library.h>
|
|||
#include <lib_pin.h>
|
|||
#include <sch_bus_entry.h>
|
|||
#include <sch_marker.h>
|
|||
#include <sch_junction.h>
|
|||
#include <sch_line.h>
|
|||
#include <sch_no_connect.h>
|
|||
#include <sch_text.h>
|
|||
#include <sch_component.h>
|
|||
#include <sch_sheet.h>
|
|||
#include <sch_sheet_path.h>
|
|||
|
|||
#include <preview_items/selection_area.h>
|
|||
#include <sch_view.h>
|
|||
#include <view/view_group.h>
|
|||
|
|||
|
|||
void SCH_EDIT_FRAME::InitBlockPasteInfos() |
|||
{ |
|||
wxFAIL_MSG( "How did we get here? Should have gone through modern toolset..." ); |
|||
return; |
|||
} |
|||
|
|||
|
|||
void SCH_EDIT_FRAME::HandleBlockPlace( wxDC* DC ) |
|||
{ |
|||
wxFAIL_MSG( "How did we get here? Should have gone through modern toolset..." ); |
|||
return; |
|||
} |
|||
|
|||
|
|||
bool SCH_EDIT_FRAME::HandleBlockEnd( wxDC* aDC ) |
|||
{ |
|||
wxFAIL_MSG( "How did we get here? Should have gone through modern toolset..." ); |
|||
return false; |
|||
} |
|||
|
|||
|
|||
void DrawAndSizingBlockOutlines( EDA_DRAW_PANEL* aPanel, wxDC* aDC, const wxPoint& aPosition, |
|||
bool aErase ) |
|||
{ |
|||
auto panel =static_cast<SCH_DRAW_PANEL*>(aPanel); |
|||
auto area = panel->GetView()->GetSelectionArea(); |
|||
auto frame = static_cast<EDA_BASE_FRAME*>(aPanel->GetParent()); |
|||
|
|||
BLOCK_SELECTOR* block; |
|||
bool isLibEdit = frame->IsType( FRAME_SCH_LIB_EDITOR ); |
|||
|
|||
block = &aPanel->GetScreen()->m_BlockLocate; |
|||
block->SetMoveVector( wxPoint( 0, 0 ) ); |
|||
block->SetLastCursorPosition( aPanel->GetParent()->GetCrossHairPosition( isLibEdit ) ); |
|||
block->SetEnd( aPanel->GetParent()->GetCrossHairPosition() ); |
|||
|
|||
panel->GetView()->ClearPreview(); |
|||
panel->GetView()->ClearHiddenFlags(); |
|||
|
|||
area->SetOrigin( block->GetOrigin() );; |
|||
area->SetEnd( block->GetEnd() ); |
|||
|
|||
panel->GetView()->SetVisible( area ); |
|||
panel->GetView()->Hide( area, false ); |
|||
panel->GetView()->Update( area ); |
|||
|
|||
if( block->GetState() == STATE_BLOCK_INIT ) |
|||
{ |
|||
if( block->GetWidth() || block->GetHeight() ) |
|||
// 2nd point exists: the rectangle is not surface anywhere
|
|||
block->SetState( STATE_BLOCK_END ); |
|||
} |
|||
} |
|||
@ -1,588 +0,0 @@ |
|||
/*
|
|||
* This program source code file is part of KiCad, a free EDA CAD application. |
|||
* |
|||
* Copyright (C) 2004 Jean-Pierre Charras, jaen-pierre.charras@gipsa-lab.inpg.com |
|||
* Copyright (C) 2008-2011 Wayne Stambaugh <stambaughw@verizon.net> |
|||
* Copyright (C) 2004-2017 KiCad Developers, see AUTHORS.txt for contributors. |
|||
* |
|||
* This program is free software; you can redistribute it and/or |
|||
* modify it under the terms of the GNU General Public License |
|||
* as published by the Free Software Foundation; either version 2 |
|||
* of the License, or (at your option) any later version. |
|||
* |
|||
* This program is distributed in the hope that it will be useful, |
|||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
* GNU General Public License for more details. |
|||
* |
|||
* You should have received a copy of the GNU General Public License |
|||
* along with this program; if not, you may find one here: |
|||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
|||
* or you may search the http://www.gnu.org website for the version 2 license,
|
|||
* or you may write to the Free Software Foundation, Inc., |
|||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA |
|||
*/ |
|||
|
|||
/**
|
|||
* @file block_libedit.cpp |
|||
*/ |
|||
|
|||
#include <fctsys.h>
|
|||
#include <gr_basic.h>
|
|||
#include <sch_draw_panel.h>
|
|||
#include <confirm.h>
|
|||
|
|||
#include <general.h>
|
|||
#include <class_library.h>
|
|||
#include <lib_edit_frame.h>
|
|||
|
|||
#include <preview_items/selection_area.h>
|
|||
#include <sch_view.h>
|
|||
#include <view/view_group.h>
|
|||
|
|||
static void DrawMovingBlockOutlines( EDA_DRAW_PANEL* aPanel, wxDC* aDC, const wxPoint& aPosition, |
|||
bool aErase ); |
|||
|
|||
|
|||
int LIB_EDIT_FRAME::BlockSelectItems( LIB_PART* aPart, BLOCK_SELECTOR* aBlock, int aUnit, int aConvert, bool aSyncPinEdit ) |
|||
{ |
|||
int itemCount = 0; |
|||
|
|||
for( LIB_ITEM& item : aPart->GetDrawItems() ) |
|||
{ |
|||
item.ClearFlags( SELECTED ); |
|||
|
|||
if( ( item.GetUnit() && item.GetUnit() != aUnit ) |
|||
|| ( item.GetConvert() && item.GetConvert() != aConvert ) ) |
|||
{ |
|||
if( item.Type() != LIB_PIN_T ) |
|||
continue; |
|||
|
|||
// Specific rules for pins:
|
|||
// - do not select pins in other units when synchronized pin edit mode is disabled
|
|||
// - do not select pins in other units when units are not interchangeable
|
|||
// - in other cases verify if the pin belongs to the requested unit
|
|||
if( !aSyncPinEdit || aPart->UnitsLocked() |
|||
|| ( item.GetConvert() && item.GetConvert() != aConvert ) ) |
|||
continue; |
|||
} |
|||
|
|||
if( item.Inside( *aBlock ) ) |
|||
{ |
|||
auto picker = ITEM_PICKER( &item ); |
|||
aBlock->PushItem( picker ); |
|||
item.SetFlags( SELECTED ); |
|||
itemCount++; |
|||
} |
|||
} |
|||
|
|||
return itemCount; |
|||
} |
|||
|
|||
|
|||
void LIB_EDIT_FRAME::BlockClearSelectedItems( LIB_PART* aPart, BLOCK_SELECTOR* aBlock ) |
|||
{ |
|||
for( LIB_ITEM& item : aPart->GetDrawItems() ) |
|||
{ |
|||
item.ClearFlags(); |
|||
} |
|||
aBlock->ClearItemsList(); |
|||
} |
|||
|
|||
|
|||
void LIB_EDIT_FRAME::BlockMoveSelectedItems( const wxPoint& aOffset, LIB_PART* aPart, BLOCK_SELECTOR* aBlock ) |
|||
{ |
|||
for( LIB_ITEM& item : aPart->GetDrawItems() ) |
|||
{ |
|||
if( !item.IsSelected() ) |
|||
continue; |
|||
|
|||
item.SetOffset( aOffset ); |
|||
item.ClearFlags(); |
|||
} |
|||
|
|||
// view update
|
|||
} |
|||
|
|||
|
|||
void LIB_EDIT_FRAME::BlockDeleteSelectedItems( LIB_PART* aPart, BLOCK_SELECTOR* aBlock ) |
|||
{ |
|||
LIB_ITEMS_CONTAINER::ITERATOR item = aPart->GetDrawItems().begin(); |
|||
|
|||
// We *do not* remove the 2 mandatory fields: reference and value
|
|||
// so skip them (do not remove) if they are flagged selected.
|
|||
// Skip also not visible items.
|
|||
// But I think fields must not be deleted by a block delete command or other global command
|
|||
// because they are not really graphic items
|
|||
while( item != aPart->GetDrawItems().end() ) |
|||
{ |
|||
if( item->Type() == LIB_FIELD_T ) |
|||
{ |
|||
item->ClearFlags( SELECTED ); |
|||
} |
|||
|
|||
if( !item->IsSelected() ) |
|||
++item; |
|||
else |
|||
item = aPart->GetDrawItems().erase( item ); |
|||
} |
|||
|
|||
// view update
|
|||
|
|||
} |
|||
|
|||
|
|||
void LIB_EDIT_FRAME::BlockCopySelectedItems( const wxPoint& aOffset, LIB_PART* aPart, BLOCK_SELECTOR* aBlock ) |
|||
{ |
|||
PICKED_ITEMS_LIST& aItemsList = aBlock->GetItems(); |
|||
LIB_ITEM* oldItem; |
|||
LIB_ITEM* newItem; |
|||
|
|||
for( unsigned ii = 0; ii < aItemsList.GetCount(); ii++ ) |
|||
{ |
|||
oldItem = static_cast<LIB_ITEM*>( aItemsList.GetPickedItem( ii ) ); |
|||
|
|||
// We *do not* copy fields because they are unique for the whole component
|
|||
// so skip them (do not duplicate) if they are flagged selected.
|
|||
if( oldItem->Type() == LIB_FIELD_T ) |
|||
oldItem->ClearFlags( SELECTED ); |
|||
|
|||
if( !oldItem->IsSelected() ) |
|||
continue; |
|||
|
|||
newItem = (LIB_ITEM*) oldItem->Clone(); |
|||
newItem->SetFlags( SELECTED ); |
|||
oldItem->ClearFlags( SELECTED ); |
|||
|
|||
newItem->SetOffset( aBlock->GetMoveVector() ); |
|||
|
|||
aItemsList.SetPickedItem( newItem, ii ); |
|||
aItemsList.SetPickedItemStatus( UR_NEW, ii ); |
|||
|
|||
aPart->GetDrawItems().push_back( newItem ); |
|||
} |
|||
} |
|||
|
|||
|
|||
int LIB_EDIT_FRAME::BlockCommand( EDA_KEY key ) |
|||
{ |
|||
int cmd = BLOCK_IDLE; |
|||
|
|||
switch( key ) |
|||
{ |
|||
default: |
|||
cmd = key & 0xFF; |
|||
break; |
|||
|
|||
case EDA_KEY_C( 0xffffffff ): // -1
|
|||
// Historically, -1 has been used as a key, which can cause bit flag
|
|||
// clashes with unaware code. On debug builds, catch any old code that
|
|||
// might still be doing this. TODO: remove if sure all this old code is gone.
|
|||
wxFAIL_MSG( "negative EDA_KEY value should be converted to GR_KEY_INVALID" ); |
|||
// fall through on release builds
|
|||
|
|||
case GR_KEY_INVALID: |
|||
cmd = BLOCK_PRESELECT_MOVE; |
|||
break; |
|||
|
|||
case GR_KEY_NONE: |
|||
cmd = BLOCK_MOVE; |
|||
break; |
|||
|
|||
case GR_KB_SHIFT: |
|||
cmd = BLOCK_DUPLICATE; |
|||
break; |
|||
|
|||
case GR_KB_ALT: |
|||
cmd = BLOCK_ROTATE; |
|||
break; |
|||
|
|||
case GR_KB_SHIFTCTRL: |
|||
cmd = BLOCK_DELETE; |
|||
break; |
|||
|
|||
case GR_KB_CTRL: |
|||
cmd = BLOCK_MIRROR_Y; |
|||
break; |
|||
|
|||
case MOUSE_MIDDLE: |
|||
cmd = BLOCK_ZOOM; |
|||
break; |
|||
} |
|||
|
|||
return cmd; |
|||
} |
|||
|
|||
|
|||
bool LIB_EDIT_FRAME::HandleBlockEnd( wxDC* aDC ) |
|||
{ |
|||
int ItemCount = 0; |
|||
bool nextCmd = false; |
|||
BLOCK_SELECTOR* block = &GetScreen()->m_BlockLocate; |
|||
wxPoint pt; |
|||
|
|||
auto panel =static_cast<SCH_DRAW_PANEL*>(m_canvas); |
|||
auto view = panel->GetView(); |
|||
auto area = view->GetSelectionArea(); |
|||
|
|||
auto start = area->GetOrigin(); |
|||
auto end = area->GetEnd(); |
|||
|
|||
block->SetOrigin( wxPoint( start.x, start.y ) ); |
|||
block->SetEnd( wxPoint( end.x, end.y ) ); |
|||
|
|||
view->ShowSelectionArea( false ); |
|||
view->ClearHiddenFlags(); |
|||
|
|||
if( block->GetCount() ) |
|||
{ |
|||
BLOCK_STATE_T state = block->GetState(); |
|||
BLOCK_COMMAND_T command = block->GetCommand(); |
|||
|
|||
m_canvas->CallEndMouseCapture( aDC ); |
|||
|
|||
block->SetState( state ); |
|||
block->SetCommand( command ); |
|||
m_canvas->SetMouseCapture( DrawAndSizingBlockOutlines, AbortBlockCurrentCommand ); |
|||
|
|||
if( block->GetCommand() != BLOCK_ABORT |
|||
&& block->GetCommand() != BLOCK_DUPLICATE |
|||
&& block->GetCommand() != BLOCK_COPY |
|||
&& block->GetCommand() != BLOCK_CUT |
|||
&& block->GetCommand() != BLOCK_DELETE ) |
|||
{ |
|||
SetCrossHairPosition( block->GetEnd() ); |
|||
m_canvas->MoveCursorToCrossHair(); |
|||
} |
|||
} |
|||
|
|||
if( m_canvas->IsMouseCaptured() ) |
|||
{ |
|||
switch( block->GetCommand() ) |
|||
{ |
|||
case BLOCK_IDLE: |
|||
DisplayError( this, wxT( "Error in HandleBlockPLace" ) ); |
|||
break; |
|||
|
|||
case BLOCK_DRAG: // Drag
|
|||
case BLOCK_DRAG_ITEM: |
|||
case BLOCK_MOVE: // Move
|
|||
case BLOCK_DUPLICATE: // Duplicate
|
|||
if( GetCurPart() ) |
|||
ItemCount = BlockSelectItems( GetCurPart(), block, m_unit, m_convert, m_syncPinEdit ); |
|||
|
|||
if( ItemCount ) |
|||
{ |
|||
nextCmd = true; |
|||
block->SetState( STATE_BLOCK_MOVE ); |
|||
|
|||
if( block->GetCommand() == BLOCK_DUPLICATE ) |
|||
{ |
|||
if( block->AppendUndo() ) |
|||
; // UR_LIBEDIT saves entire state, so no need to append anything more
|
|||
else |
|||
{ |
|||
SaveCopyInUndoList( GetCurPart(), UR_LIBEDIT ); |
|||
block->SetAppendUndo(); |
|||
} |
|||
|
|||
BlockCopySelectedItems( pt, GetCurPart(), block ); |
|||
block->SetLastCursorPosition( GetCrossHairPosition( true ) ); |
|||
} |
|||
|
|||
m_canvas->SetMouseCaptureCallback( DrawMovingBlockOutlines ); |
|||
m_canvas->CallMouseCapture( aDC, wxDefaultPosition, false ); |
|||
} |
|||
else |
|||
{ |
|||
m_canvas->CallMouseCapture( aDC, wxDefaultPosition, false ); |
|||
m_canvas->SetMouseCapture( NULL, NULL ); |
|||
} |
|||
break; |
|||
|
|||
case BLOCK_COPY: // Save a copy of items in the clipboard buffer
|
|||
case BLOCK_CUT: |
|||
if( GetCurPart() ) |
|||
ItemCount = BlockSelectItems( GetCurPart(), block, m_unit, m_convert, m_syncPinEdit ); |
|||
|
|||
if( ItemCount ) |
|||
{ |
|||
copySelectedItems(); |
|||
auto cmd = block->GetCommand(); |
|||
|
|||
if( cmd == BLOCK_COPY ) |
|||
{ |
|||
BlockClearSelectedItems( GetCurPart(), block ); |
|||
block->ClearItemsList(); |
|||
} |
|||
else if( cmd == BLOCK_CUT ) |
|||
{ |
|||
if( block->AppendUndo() ) |
|||
; // UR_LIBEDIT saves entire state, so no need to append anything more
|
|||
else |
|||
{ |
|||
SaveCopyInUndoList( GetCurPart(), UR_LIBEDIT ); |
|||
block->SetAppendUndo(); |
|||
} |
|||
|
|||
BlockDeleteSelectedItems( GetCurPart(), block ); |
|||
RebuildView(); |
|||
GetCanvas()->Refresh(); |
|||
OnModify(); |
|||
} |
|||
} |
|||
break; |
|||
|
|||
case BLOCK_DELETE: // Delete
|
|||
if( GetCurPart() ) |
|||
ItemCount = BlockSelectItems( GetCurPart(), block, m_unit, m_convert, m_syncPinEdit ); |
|||
|
|||
if( block->AppendUndo() ) |
|||
; // UR_LIBEDIT saves entire state, so no need to append anything more
|
|||
else if( ItemCount ) |
|||
{ |
|||
SaveCopyInUndoList( GetCurPart(), UR_LIBEDIT ); |
|||
block->SetAppendUndo(); |
|||
} |
|||
|
|||
if( GetCurPart() ) |
|||
{ |
|||
BlockDeleteSelectedItems( GetCurPart(), block ); |
|||
RebuildView(); |
|||
GetCanvas()->Refresh(); |
|||
OnModify(); |
|||
} |
|||
break; |
|||
|
|||
case BLOCK_PASTE: |
|||
case BLOCK_ROTATE: |
|||
case BLOCK_MIRROR_X: |
|||
case BLOCK_MIRROR_Y: |
|||
case BLOCK_FLIP: |
|||
wxFAIL; // should not happen
|
|||
break; |
|||
|
|||
case BLOCK_ZOOM: // Window Zoom
|
|||
Window_Zoom( *block ); |
|||
break; |
|||
|
|||
case BLOCK_ABORT: |
|||
break; |
|||
|
|||
case BLOCK_SELECT_ITEMS_ONLY: |
|||
break; |
|||
|
|||
case BLOCK_PRESELECT_MOVE: // not used in LibEdit
|
|||
case BLOCK_DUPLICATE_AND_INCREMENT: // not used in Eeschema
|
|||
case BLOCK_MOVE_EXACT: // not used in Eeschema
|
|||
break; |
|||
} |
|||
} |
|||
|
|||
if( block->GetCommand() == BLOCK_ABORT ) |
|||
{ |
|||
GetScreen()->ClearDrawingState(); |
|||
} |
|||
|
|||
if( !nextCmd ) |
|||
{ |
|||
if( block->GetCommand() != BLOCK_SELECT_ITEMS_ONLY && GetCurPart() ) |
|||
BlockClearSelectedItems( GetCurPart(), block ); |
|||
|
|||
GetScreen()->ClearBlockCommand(); |
|||
GetScreen()->SetCurItem( NULL ); |
|||
m_canvas->EndMouseCapture( GetToolId(), GetGalCanvas()->GetCurrentCursor(), wxEmptyString, |
|||
false ); |
|||
} |
|||
|
|||
view->ShowSelectionArea( false ); |
|||
view->ShowPreview( nextCmd ); |
|||
|
|||
return nextCmd; |
|||
} |
|||
|
|||
|
|||
void LIB_EDIT_FRAME::HandleBlockPlace( wxDC* DC ) |
|||
{ |
|||
BLOCK_SELECTOR* block = &GetScreen()->m_BlockLocate; |
|||
wxPoint pt; |
|||
|
|||
if( !m_canvas->IsMouseCaptured() ) |
|||
{ |
|||
DisplayError( this, wxT( "HandleBlockPLace : m_mouseCaptureCallback = NULL" ) ); |
|||
} |
|||
|
|||
block->SetState( STATE_BLOCK_STOP ); |
|||
|
|||
switch( block->GetCommand() ) |
|||
{ |
|||
case BLOCK_IDLE: |
|||
break; |
|||
|
|||
case BLOCK_DRAG: // Drag
|
|||
case BLOCK_DRAG_ITEM: |
|||
case BLOCK_MOVE: // Move
|
|||
case BLOCK_DUPLICATE: // Duplicate
|
|||
if( GetCurPart() && !block->AppendUndo() ) |
|||
SaveCopyInUndoList( GetCurPart() ); |
|||
|
|||
pt = block->GetMoveVector(); |
|||
|
|||
if( GetCurPart() ) |
|||
BlockMoveSelectedItems( pt, GetCurPart(), block ); |
|||
|
|||
block->ClearItemsList(); |
|||
break; |
|||
|
|||
case BLOCK_PASTE: // Paste (recopy the last block saved)
|
|||
if( GetCurPart() ) |
|||
SaveCopyInUndoList( GetCurPart() ); |
|||
|
|||
pt = block->GetMoveVector(); |
|||
|
|||
pasteClipboard( pt ); |
|||
|
|||
block->ClearItemsList(); |
|||
break; |
|||
|
|||
case BLOCK_ZOOM: // Handled by HandleBlockEnd
|
|||
case BLOCK_DELETE: |
|||
case BLOCK_COPY: |
|||
case BLOCK_ABORT: |
|||
default: |
|||
break; |
|||
} |
|||
|
|||
RebuildView(); |
|||
GetCanvas()->Refresh(); |
|||
OnModify(); |
|||
|
|||
block->SetState( STATE_NO_BLOCK ); |
|||
block->SetCommand( BLOCK_IDLE ); |
|||
GetScreen()->SetCurItem( NULL ); |
|||
m_canvas->EndMouseCapture( GetToolId(), GetGalCanvas()->GetCurrentCursor(), wxEmptyString, false ); |
|||
|
|||
GetCanvas()->GetView()->ClearPreview(); |
|||
GetCanvas()->GetView()->ClearHiddenFlags(); |
|||
} |
|||
|
|||
|
|||
void LIB_EDIT_FRAME::InitBlockPasteInfos() |
|||
{ |
|||
BLOCK_SELECTOR& block = GetScreen()->m_BlockLocate; |
|||
|
|||
// Copy the clipboard contents to the screen block selector
|
|||
// (only the copy, the new instances will be appended to the part once the items are placed)
|
|||
block.GetItems().CopyList( m_clipboard.GetItems() ); |
|||
|
|||
// Reparent block items and set their current unit & DeMorgan variant
|
|||
for( size_t i = 0; i < m_clipboard.GetItems().GetCount(); ++i ) |
|||
{ |
|||
LIB_ITEM* item = dynamic_cast<LIB_ITEM*>( m_clipboard.GetItem( i ) ); |
|||
|
|||
if( item ) |
|||
{ |
|||
item->SetParent( GetCurPart() ); |
|||
|
|||
item->SetUnit( m_unit ); |
|||
item->SetConvert( m_convert ); |
|||
} |
|||
} |
|||
|
|||
// Set the paste reference point
|
|||
block.SetLastCursorPosition( m_clipboard.GetLastCursorPosition() ); |
|||
m_canvas->SetMouseCaptureCallback( DrawMovingBlockOutlines ); |
|||
} |
|||
|
|||
|
|||
void LIB_EDIT_FRAME::copySelectedItems() |
|||
{ |
|||
LIB_PART* part = GetCurPart(); |
|||
|
|||
if( !part ) |
|||
return; |
|||
|
|||
m_clipboard.ClearListAndDeleteItems(); // delete previous saved list, if exists
|
|||
m_clipboard.SetLastCursorPosition( GetScreen()->m_BlockLocate.GetEnd() ); // store the reference point
|
|||
|
|||
for( LIB_ITEM& item : part->GetDrawItems() ) |
|||
{ |
|||
// We *do not* copy fields because they are unique for the whole component
|
|||
// so skip them (do not duplicate) if they are flagged selected.
|
|||
if( item.Type() == LIB_FIELD_T ) |
|||
item.ClearFlags( SELECTED ); |
|||
|
|||
if( !item.IsSelected() ) |
|||
continue; |
|||
|
|||
// Do not clear the 'selected' flag. It is required to have items drawn when they are pasted.
|
|||
LIB_ITEM* copy = (LIB_ITEM*) item.Clone(); |
|||
copy->SetFlags( UR_TRANSIENT ); |
|||
ITEM_PICKER picker( copy, UR_NEW ); |
|||
m_clipboard.PushItem( picker ); |
|||
} |
|||
} |
|||
|
|||
|
|||
void LIB_EDIT_FRAME::pasteClipboard( const wxPoint& aOffset ) |
|||
{ |
|||
LIB_PART* part = GetCurPart(); |
|||
|
|||
if( !part || m_clipboard.GetCount() == 0 ) |
|||
return; |
|||
|
|||
for( unsigned int i = 0; i < m_clipboard.GetCount(); i++ ) |
|||
{ |
|||
// Append a copy to the current part, so the clipboard buffer might be pasted multiple times
|
|||
LIB_ITEM* item = (LIB_ITEM*) m_clipboard.GetItem( i )->Clone(); |
|||
item->SetParent( part ); |
|||
item->SetSelected(); |
|||
item->SetUnit( GetUnit() ); |
|||
part->AddDrawItem( item ); |
|||
} |
|||
|
|||
BlockMoveSelectedItems( aOffset, GetCurPart(), &GetScreen()->m_BlockLocate ); |
|||
RebuildView(); |
|||
GetCanvas()->Refresh(); |
|||
OnModify(); |
|||
} |
|||
|
|||
|
|||
/*
|
|||
* Traces the outline of the search block structures |
|||
* The entire block follows the cursor |
|||
*/ |
|||
void DrawMovingBlockOutlines( EDA_DRAW_PANEL* aPanel, wxDC* aDC, const wxPoint& aPosition, |
|||
bool aErase ) |
|||
{ |
|||
SCH_DRAW_PANEL* panel =static_cast<SCH_DRAW_PANEL*>( aPanel ); |
|||
LIB_EDIT_FRAME* frame = (LIB_EDIT_FRAME*) aPanel->GetParent(); |
|||
KIGFX::SCH_VIEW* view = panel->GetView(); |
|||
KIGFX::VIEW_GROUP* preview = view->GetPreview(); |
|||
|
|||
BASE_SCREEN* screen = aPanel->GetScreen(); |
|||
BLOCK_SELECTOR* block = &screen->m_BlockLocate; |
|||
LIB_PART* component = frame->GetCurPart(); |
|||
|
|||
if( component == NULL ) |
|||
return; |
|||
|
|||
block->SetMoveVector( frame->GetCrossHairPosition( true ) - block->GetLastCursorPosition() ); |
|||
|
|||
preview->Clear(); |
|||
view->SetVisible( preview, true ); |
|||
|
|||
for( unsigned ii = 0; ii < block->GetCount(); ii++ ) |
|||
{ |
|||
LIB_ITEM* libItem = (LIB_ITEM*) block->GetItem( ii ); |
|||
LIB_ITEM* copy = static_cast<LIB_ITEM*>( libItem->Clone() ); |
|||
|
|||
copy->Move( copy->GetPosition() + block->GetMoveVector() ); |
|||
copy->SetFlags( IS_MOVED ); |
|||
preview->Add( copy ); |
|||
|
|||
view->Hide( libItem ); |
|||
} |
|||
|
|||
view->Update( preview ); |
|||
} |
|||
@ -1,167 +0,0 @@ |
|||
/*
|
|||
* This program source code file is part of KiCad, a free EDA CAD application. |
|||
* |
|||
* Copyright (C) 2013 Jean-Pierre Charras, jp.charras at wanadoo.fr |
|||
* Copyright (C) 2013 Wayne Stambaugh <stambaughw@verizon.net> |
|||
* Copyright (C) 1992-2013 KiCad Developers, see AUTHORS.txt for contributors. |
|||
* |
|||
* This program is free software; you can redistribute it and/or |
|||
* modify it under the terms of the GNU General Public License |
|||
* as published by the Free Software Foundation; either version 2 |
|||
* of the License, or (at your option) any later version. |
|||
* |
|||
* This program is distributed in the hope that it will be useful, |
|||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
* GNU General Public License for more details. |
|||
* |
|||
* You should have received a copy of the GNU General Public License |
|||
* along with this program; if not, you may find one here: |
|||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
|||
* or you may search the http://www.gnu.org website for the version 2 license,
|
|||
* or you may write to the Free Software Foundation, Inc., |
|||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA |
|||
*/ |
|||
|
|||
/**
|
|||
* @file libedit_onleftclick.cpp |
|||
* @brief Eeschema library editor event handler for a mouse left button single or double click. |
|||
*/ |
|||
|
|||
#include <fctsys.h>
|
|||
#include <sch_draw_panel.h>
|
|||
#include <eeschema_id.h>
|
|||
#include <msgpanel.h>
|
|||
|
|||
#include <general.h>
|
|||
#include <lib_edit_frame.h>
|
|||
#include <class_libentry.h>
|
|||
|
|||
|
|||
void LIB_EDIT_FRAME::OnLeftClick( wxDC* DC, const wxPoint& aPosition ) |
|||
{ |
|||
LIB_ITEM* item = GetDrawItem(); |
|||
bool item_in_edit = item && item->InEditMode(); |
|||
bool no_item_edited = !item_in_edit; |
|||
|
|||
LIB_PART* part = GetCurPart(); |
|||
|
|||
if( !part ) // No component loaded !
|
|||
return; |
|||
|
|||
if( ( GetToolId() == ID_NO_TOOL_SELECTED ) && no_item_edited ) |
|||
item = LocateItemUsingCursor( aPosition ); |
|||
|
|||
switch( GetToolId() ) |
|||
{ |
|||
case ID_ZOOM_SELECTION: |
|||
break; |
|||
|
|||
case ID_NO_TOOL_SELECTED: |
|||
break; |
|||
|
|||
case ID_LIBEDIT_DELETE_ITEM_BUTT: |
|||
item = LocateItemUsingCursor( aPosition ); |
|||
|
|||
if( item ) |
|||
deleteItem( DC, item ); |
|||
break; |
|||
|
|||
case ID_LIBEDIT_BODY_TEXT_BUTT: |
|||
case ID_LIBEDIT_ANCHOR_ITEM_BUTT: |
|||
case ID_LIBEDIT_PIN_BUTT: |
|||
case ID_LIBEDIT_BODY_LINE_BUTT: |
|||
case ID_LIBEDIT_BODY_ARC_BUTT: |
|||
case ID_LIBEDIT_BODY_CIRCLE_BUTT: |
|||
case ID_LIBEDIT_BODY_RECT_BUTT: |
|||
// Moved to modern toolset
|
|||
break; |
|||
|
|||
default: |
|||
wxFAIL_MSG( wxString::Format( wxT( "Unhandled command ID %d" ), GetToolId() ) ); |
|||
SetNoToolSelected(); |
|||
break; |
|||
} |
|||
} |
|||
|
|||
|
|||
/*
|
|||
* Called on a double click: |
|||
* If an editable item (field, pin, graphic): |
|||
* Call the suitable dialog editor. |
|||
*/ |
|||
void LIB_EDIT_FRAME::OnLeftDClick( wxDC* DC, const wxPoint& aPosition ) |
|||
{ |
|||
LIB_PART* part = GetCurPart(); |
|||
LIB_ITEM* item = GetDrawItem(); |
|||
|
|||
if( !part ) |
|||
return; |
|||
|
|||
if( !item || !item->InEditMode() ) |
|||
{ // We can locate an item
|
|||
item = LocateItemUsingCursor( aPosition, SCH_COLLECTOR::LibItems ); |
|||
|
|||
if( item == NULL ) |
|||
{ |
|||
// The user canceled the disambiguation menu
|
|||
if( m_canvas->GetAbortRequest() ) |
|||
m_canvas->SetAbortRequest( false ); |
|||
else |
|||
{ |
|||
// If there is only a random double-click, we allow the use to edit the part
|
|||
wxCommandEvent cmd( wxEVT_COMMAND_MENU_SELECTED ); |
|||
|
|||
cmd.SetId( ID_LIBEDIT_GET_FRAME_EDIT_PART ); |
|||
GetEventHandler()->ProcessEvent( cmd ); |
|||
} |
|||
} |
|||
} |
|||
|
|||
if( item ) |
|||
SetMsgPanel( item ); |
|||
else |
|||
return; |
|||
|
|||
m_canvas->SetIgnoreMouseEvents( true ); |
|||
bool not_edited = !item->InEditMode(); |
|||
|
|||
switch( item->Type() ) |
|||
{ |
|||
case LIB_PIN_T: |
|||
if( not_edited ) |
|||
{ |
|||
SetDrawItem( item ); |
|||
wxCommandEvent cmd( wxEVT_COMMAND_MENU_SELECTED ); |
|||
|
|||
cmd.SetId( ID_LIBEDIT_EDIT_PIN ); |
|||
GetEventHandler()->ProcessEvent( cmd ); |
|||
} |
|||
break; |
|||
|
|||
case LIB_ARC_T: |
|||
case LIB_CIRCLE_T: |
|||
case LIB_RECTANGLE_T: |
|||
case LIB_POLYLINE_T: |
|||
if( not_edited ) |
|||
EditGraphicSymbol( DC, item ); |
|||
break; |
|||
|
|||
case LIB_TEXT_T: |
|||
if( not_edited ) |
|||
EditSymbolText( DC, item ); |
|||
break; |
|||
|
|||
case LIB_FIELD_T: |
|||
if( not_edited ) |
|||
EditField( (LIB_FIELD*) item ); |
|||
break; |
|||
|
|||
default: |
|||
wxFAIL_MSG( wxT( "Unhandled item <" ) + item->GetClass() + wxT( ">" ) ); |
|||
break; |
|||
} |
|||
|
|||
m_canvas->MoveCursorToCrossHair(); |
|||
m_canvas->SetIgnoreMouseEvents( false ); |
|||
} |
|||
@ -1,180 +0,0 @@ |
|||
/*
|
|||
* This program source code file is part of KiCad, a free EDA CAD application. |
|||
* |
|||
* Copyright (C) 2006 Jean-Pierre Charras, jaen-pierre.charras@gipsa-lab.inpg.com |
|||
* Copyright (C) 2009-2017 Wayne Stambaugh <stambaughw@verizon.net> |
|||
* Copyright (C) 2004-2017 KiCad Developers, see change_log.txt for contributors. |
|||
* |
|||
* This program is free software; you can redistribute it and/or |
|||
* modify it under the terms of the GNU General Public License |
|||
* as published by the Free Software Foundation; either version 2 |
|||
* of the License, or (at your option) any later version. |
|||
* |
|||
* This program is distributed in the hope that it will be useful, |
|||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
* GNU General Public License for more details. |
|||
* |
|||
* You should have received a copy of the GNU General Public License |
|||
* along with this program; if not, you may find one here: |
|||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
|||
* or you may search the http://www.gnu.org website for the version 2 license,
|
|||
* or you may write to the Free Software Foundation, Inc., |
|||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA |
|||
*/ |
|||
|
|||
/**
|
|||
* @file symbdraw.cpp |
|||
* @brief Create, move .. graphic shapes used to build and draw a symbol (lines, arcs ..) |
|||
*/ |
|||
|
|||
#include <fctsys.h>
|
|||
#include <sch_draw_panel.h>
|
|||
#include <confirm.h>
|
|||
#include <base_units.h>
|
|||
#include <msgpanel.h>
|
|||
|
|||
#include <eeschema_id.h>
|
|||
#include <lib_edit_frame.h>
|
|||
#include <class_libentry.h>
|
|||
#include <lib_arc.h>
|
|||
#include <lib_circle.h>
|
|||
#include <lib_polyline.h>
|
|||
#include <lib_rectangle.h>
|
|||
#include <lib_text.h>
|
|||
|
|||
#include <sch_view.h>
|
|||
#include <dialogs/dialog_lib_edit_draw_item.h>
|
|||
|
|||
|
|||
static void RedrawWhileMovingCursor( EDA_DRAW_PANEL* aPanel, wxDC* aDC, const wxPoint& aPosition, |
|||
bool aErase ); |
|||
|
|||
|
|||
void LIB_EDIT_FRAME::EditGraphicSymbol( wxDC* DC, LIB_ITEM* DrawItem ) |
|||
{ |
|||
if( DrawItem == NULL ) |
|||
return; |
|||
|
|||
DIALOG_LIB_EDIT_DRAW_ITEM dialog( this, DrawItem ); |
|||
|
|||
if( dialog.ShowModal() == wxID_CANCEL ) |
|||
return; |
|||
|
|||
// Init default values (used to create a new draw item)
|
|||
g_LastLineWidth = dialog.GetWidth(); |
|||
m_DrawSpecificConvert = !dialog.GetApplyToAllConversions(); |
|||
m_DrawSpecificUnit = !dialog.GetApplyToAllUnits(); |
|||
|
|||
// Save copy for undo if not in edit (edit command already handle the save copy)
|
|||
if( !DrawItem->InEditMode() ) |
|||
SaveCopyInUndoList( DrawItem->GetParent() ); |
|||
|
|||
if( m_DrawSpecificUnit ) |
|||
DrawItem->SetUnit( GetUnit() ); |
|||
else |
|||
DrawItem->SetUnit( 0 ); |
|||
|
|||
if( m_DrawSpecificConvert ) |
|||
DrawItem->SetConvert( GetConvert() ); |
|||
else |
|||
DrawItem->SetConvert( 0 ); |
|||
|
|||
if( DrawItem->IsFillable() ) |
|||
DrawItem->SetFillMode( (FILL_T) dialog.GetFillStyle() ); |
|||
|
|||
DrawItem->SetWidth( g_LastLineWidth ); |
|||
|
|||
GetCanvas()->GetView()->Update( DrawItem ); |
|||
GetCanvas()->Refresh(); |
|||
OnModify( ); |
|||
|
|||
MSG_PANEL_ITEMS items; |
|||
DrawItem->GetMsgPanelInfo( m_UserUnits, items ); |
|||
SetMsgPanel( items ); |
|||
} |
|||
|
|||
|
|||
static void AbortSymbolTraceOn( EDA_DRAW_PANEL* aPanel, wxDC* DC ) |
|||
{ |
|||
LIB_EDIT_FRAME* parent = (LIB_EDIT_FRAME*) aPanel->GetParent(); |
|||
LIB_ITEM* item = parent->GetDrawItem(); |
|||
|
|||
if( item == NULL ) |
|||
return; |
|||
|
|||
bool newItem = item->IsNew(); |
|||
item->EndEdit( parent->GetCrossHairPosition( true ) ); |
|||
|
|||
if( newItem ) |
|||
delete item; |
|||
else |
|||
parent->RestoreComponent(); |
|||
|
|||
parent->SetDrawItem( NULL ); |
|||
|
|||
auto view = static_cast<SCH_DRAW_PANEL*>(aPanel)->GetView(); |
|||
view->ClearPreview(); |
|||
view->ShowPreview( false ); |
|||
view->ClearHiddenFlags(); |
|||
parent->RebuildView(); |
|||
} |
|||
|
|||
|
|||
/*
|
|||
* Redraw the graphic shape while moving |
|||
*/ |
|||
static void RedrawWhileMovingCursor( EDA_DRAW_PANEL* aPanel, wxDC* aDC, const wxPoint& aPosition, |
|||
bool aErase ) |
|||
{ |
|||
LIB_ITEM* item = ( (LIB_EDIT_FRAME*) aPanel->GetParent() )->GetDrawItem(); |
|||
|
|||
if( item == NULL ) |
|||
return; |
|||
|
|||
auto view = static_cast<SCH_DRAW_PANEL*>(aPanel)->GetView(); |
|||
auto p = aPanel->GetParent()->GetCrossHairPosition( true ); |
|||
|
|||
item->CalcEdit( p ); |
|||
|
|||
view->Hide( item ); |
|||
view->ClearPreview(); |
|||
view->AddToPreview( item->Clone() ); |
|||
} |
|||
|
|||
|
|||
void LIB_EDIT_FRAME::StartMoveDrawSymbol( wxDC* DC, LIB_ITEM* aItem ) |
|||
{ |
|||
if( aItem == NULL ) |
|||
return; |
|||
|
|||
SetCursor( wxCURSOR_HAND ); |
|||
|
|||
GetGalCanvas()->GetView()->Hide ( aItem ); |
|||
|
|||
TempCopyComponent(); |
|||
|
|||
// For fields only, move the anchor point of the field
|
|||
// to the cursor position to allow user to see the text justification
|
|||
if( aItem->Type() == LIB_FIELD_T ) |
|||
aItem->BeginEdit( IS_MOVED, aItem->GetPosition() ); |
|||
else |
|||
aItem->BeginEdit( IS_MOVED, GetCrossHairPosition( true ) ); |
|||
|
|||
m_canvas->SetMouseCapture( RedrawWhileMovingCursor, AbortSymbolTraceOn ); |
|||
m_canvas->CallMouseCapture( DC, wxDefaultPosition, true ); |
|||
} |
|||
|
|||
|
|||
void LIB_EDIT_FRAME::StartModifyDrawSymbol( wxDC* DC, LIB_ITEM* aItem ) |
|||
{ |
|||
if( aItem == NULL ) |
|||
return; |
|||
|
|||
DBG(printf("startmdifyraw\n");) |
|||
|
|||
TempCopyComponent(); |
|||
aItem->BeginEdit( IS_RESIZED, GetCrossHairPosition( true ) ); |
|||
m_canvas->SetMouseCapture( RedrawWhileMovingCursor, AbortSymbolTraceOn ); |
|||
m_canvas->CallMouseCapture( DC, wxDefaultPosition, true ); |
|||
} |
|||
@ -0,0 +1,609 @@ |
|||
/*
|
|||
* This program source code file is part of KiCad, a free EDA CAD application. |
|||
* |
|||
* Copyright (C) 2019 KiCad Developers, see AUTHORS.txt for contributors. |
|||
* |
|||
* This program is free software; you can redistribute it and/or |
|||
* modify it under the terms of the GNU General Public License |
|||
* as published by the Free Software Foundation; either version 2 |
|||
* of the License, or (at your option) any later version. |
|||
* |
|||
* This program is distributed in the hope that it will be useful, |
|||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
* GNU General Public License for more details. |
|||
* |
|||
* You should have received a copy of the GNU General Public License |
|||
* along with this program; if not, you may find one here: |
|||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
|||
* or you may search the http://www.gnu.org website for the version 2 license,
|
|||
* or you may write to the Free Software Foundation, Inc., |
|||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA |
|||
*/ |
|||
|
|||
#include <tool/tool_manager.h>
|
|||
#include <tools/sch_selection_tool.h>
|
|||
#include <tools/picker_tool.h>
|
|||
#include <tools/lib_pin_tool.h>
|
|||
#include <tools/lib_drawing_tools.h>
|
|||
#include <tools/lib_move_tool.h>
|
|||
#include <sch_actions.h>
|
|||
#include <hotkeys.h>
|
|||
#include <bitmaps.h>
|
|||
#include <confirm.h>
|
|||
#include <base_struct.h>
|
|||
#include <sch_view.h>
|
|||
#include <lib_edit_frame.h>
|
|||
#include <eeschema_id.h>
|
|||
#include <dialogs/dialog_lib_edit_draw_item.h>
|
|||
#include <dialogs/dialog_lib_edit_text.h>
|
|||
#include <dialogs/dialog_edit_one_field.h>
|
|||
#include <sch_legacy_plugin.h>
|
|||
#include "lib_edit_tool.h"
|
|||
|
|||
LIB_EDIT_TOOL::LIB_EDIT_TOOL() : |
|||
TOOL_INTERACTIVE( "libedit.InteractiveEdit" ), |
|||
m_selectionTool( nullptr ), |
|||
m_frame( nullptr ), |
|||
m_menu( *this ) |
|||
{ |
|||
} |
|||
|
|||
|
|||
LIB_EDIT_TOOL::~LIB_EDIT_TOOL() |
|||
{ |
|||
} |
|||
|
|||
|
|||
bool LIB_EDIT_TOOL::Init() |
|||
{ |
|||
m_frame = getEditFrame<LIB_EDIT_FRAME>(); |
|||
m_selectionTool = m_toolMgr->GetTool<SCH_SELECTION_TOOL>(); |
|||
LIB_DRAWING_TOOLS* drawingTools = m_toolMgr->GetTool<LIB_DRAWING_TOOLS>(); |
|||
LIB_MOVE_TOOL* moveTool = m_toolMgr->GetTool<LIB_MOVE_TOOL>(); |
|||
|
|||
wxASSERT_MSG( m_selectionTool, "eeshema.InteractiveSelection tool is not available" ); |
|||
wxASSERT_MSG( drawingTools, "libedit.InteractiveDrawing tool is not available" ); |
|||
|
|||
//
|
|||
// Add edit actions to the move tool menu
|
|||
//
|
|||
if( moveTool ) |
|||
{ |
|||
CONDITIONAL_MENU& moveMenu = moveTool->GetToolMenu().GetMenu(); |
|||
|
|||
moveMenu.AddSeparator( SELECTION_CONDITIONS::NotEmpty ); |
|||
moveMenu.AddItem( SCH_ACTIONS::rotateCCW, SCH_CONDITIONS::NotEmpty ); |
|||
moveMenu.AddItem( SCH_ACTIONS::rotateCW, SCH_CONDITIONS::NotEmpty ); |
|||
moveMenu.AddItem( SCH_ACTIONS::mirrorX, SCH_CONDITIONS::NotEmpty ); |
|||
moveMenu.AddItem( SCH_ACTIONS::mirrorY, SCH_CONDITIONS::NotEmpty ); |
|||
moveMenu.AddItem( SCH_ACTIONS::duplicate, SCH_CONDITIONS::NotEmpty ); |
|||
moveMenu.AddItem( SCH_ACTIONS::doDelete, SCH_CONDITIONS::NotEmpty ); |
|||
|
|||
moveMenu.AddItem( SCH_ACTIONS::properties, SCH_CONDITIONS::Count( 1 ) ); |
|||
|
|||
moveMenu.AddSeparator( SCH_CONDITIONS::IdleSelection ); |
|||
moveMenu.AddItem( SCH_ACTIONS::cut, SCH_CONDITIONS::IdleSelection ); |
|||
moveMenu.AddItem( SCH_ACTIONS::copy, SCH_CONDITIONS::IdleSelection ); |
|||
} |
|||
|
|||
//
|
|||
// Add editing actions to the drawing tool menu
|
|||
//
|
|||
CONDITIONAL_MENU& drawMenu = drawingTools->GetToolMenu().GetMenu(); |
|||
|
|||
drawMenu.AddSeparator( SCH_CONDITIONS::NotEmpty, 200 ); |
|||
drawMenu.AddItem( SCH_ACTIONS::rotateCCW, SCH_CONDITIONS::IdleSelection, 200 ); |
|||
drawMenu.AddItem( SCH_ACTIONS::rotateCW, SCH_CONDITIONS::IdleSelection, 200 ); |
|||
drawMenu.AddItem( SCH_ACTIONS::mirrorX, SCH_CONDITIONS::IdleSelection, 200 ); |
|||
drawMenu.AddItem( SCH_ACTIONS::mirrorY, SCH_CONDITIONS::IdleSelection, 200 ); |
|||
|
|||
drawMenu.AddItem( SCH_ACTIONS::properties, SCH_CONDITIONS::Count( 1 ), 200 ); |
|||
|
|||
//
|
|||
// Add editing actions to the selection tool menu
|
|||
//
|
|||
CONDITIONAL_MENU& selToolMenu = m_selectionTool->GetToolMenu().GetMenu(); |
|||
|
|||
selToolMenu.AddItem( SCH_ACTIONS::rotateCCW, SCH_CONDITIONS::NotEmpty, 200 ); |
|||
selToolMenu.AddItem( SCH_ACTIONS::rotateCW, SCH_CONDITIONS::NotEmpty, 200 ); |
|||
selToolMenu.AddItem( SCH_ACTIONS::mirrorX, SCH_CONDITIONS::NotEmpty, 200 ); |
|||
selToolMenu.AddItem( SCH_ACTIONS::mirrorY, SCH_CONDITIONS::NotEmpty, 200 ); |
|||
selToolMenu.AddItem( SCH_ACTIONS::duplicate, SCH_CONDITIONS::NotEmpty, 200 ); |
|||
selToolMenu.AddItem( SCH_ACTIONS::doDelete, SCH_CONDITIONS::NotEmpty, 200 ); |
|||
|
|||
selToolMenu.AddItem( SCH_ACTIONS::properties, SCH_CONDITIONS::Count( 1 ), 200 ); |
|||
|
|||
selToolMenu.AddSeparator( SCH_CONDITIONS::Idle, 200 ); |
|||
selToolMenu.AddItem( SCH_ACTIONS::cut, SCH_CONDITIONS::IdleSelection, 200 ); |
|||
selToolMenu.AddItem( SCH_ACTIONS::copy, SCH_CONDITIONS::IdleSelection, 200 ); |
|||
selToolMenu.AddItem( SCH_ACTIONS::paste, SCH_CONDITIONS::Idle, 200 ); |
|||
|
|||
return true; |
|||
} |
|||
|
|||
|
|||
void LIB_EDIT_TOOL::Reset( RESET_REASON aReason ) |
|||
{ |
|||
if( aReason == MODEL_RELOAD ) |
|||
{ |
|||
// Init variables used by every drawing tool
|
|||
m_frame = getEditFrame<LIB_EDIT_FRAME>(); |
|||
} |
|||
} |
|||
|
|||
|
|||
int LIB_EDIT_TOOL::Rotate( const TOOL_EVENT& aEvent ) |
|||
{ |
|||
SELECTION& selection = m_selectionTool->RequestSelection(); |
|||
|
|||
if( selection.GetSize() == 0 ) |
|||
return 0; |
|||
|
|||
wxPoint rotPoint; |
|||
bool ccw = ( aEvent.Matches( SCH_ACTIONS::rotateCCW.MakeEvent() ) ); |
|||
LIB_ITEM* item = static_cast<LIB_ITEM*>( selection.Front() ); |
|||
|
|||
if( !item->IsMoving() ) |
|||
m_frame->SaveCopyInUndoList( m_frame->GetCurPart() ); |
|||
|
|||
if( selection.GetSize() == 1 ) |
|||
rotPoint = item->GetPosition(); |
|||
else |
|||
rotPoint = m_frame->GetNearestGridPosition( mapCoords( selection.GetCenter() ) ); |
|||
|
|||
for( unsigned ii = 0; ii < selection.GetSize(); ii++ ) |
|||
{ |
|||
item = static_cast<LIB_ITEM*>( selection.GetItem( ii ) ); |
|||
item->Rotate( rotPoint, ccw ); |
|||
m_frame->RefreshItem( item ); |
|||
} |
|||
|
|||
m_toolMgr->PostEvent( EVENTS::SelectedItemsModified ); |
|||
|
|||
if( !item->IsMoving() ) |
|||
{ |
|||
if( selection.IsHover() ) |
|||
m_toolMgr->RunAction( SCH_ACTIONS::clearSelection, true ); |
|||
|
|||
m_frame->OnModify(); |
|||
} |
|||
|
|||
return 0; |
|||
} |
|||
|
|||
|
|||
int LIB_EDIT_TOOL::Mirror( const TOOL_EVENT& aEvent ) |
|||
{ |
|||
SELECTION& selection = m_selectionTool->RequestSelection(); |
|||
|
|||
if( selection.GetSize() == 0 ) |
|||
return 0; |
|||
|
|||
wxPoint mirrorPoint; |
|||
bool xAxis = ( aEvent.Matches( SCH_ACTIONS::mirrorX.MakeEvent() ) ); |
|||
LIB_ITEM* item = static_cast<LIB_ITEM*>( selection.Front() ); |
|||
|
|||
if( !item->IsMoving() ) |
|||
m_frame->SaveCopyInUndoList( m_frame->GetCurPart() ); |
|||
|
|||
if( selection.GetSize() == 1 ) |
|||
mirrorPoint = item->GetPosition(); |
|||
else |
|||
mirrorPoint = m_frame->GetNearestGridPosition( mapCoords( selection.GetCenter() ) ); |
|||
|
|||
for( unsigned ii = 0; ii < selection.GetSize(); ii++ ) |
|||
{ |
|||
item = static_cast<LIB_ITEM*>( selection.GetItem( ii ) ); |
|||
|
|||
if( xAxis ) |
|||
item->MirrorVertical( mirrorPoint ); |
|||
else |
|||
item->MirrorHorizontal( mirrorPoint ); |
|||
|
|||
m_frame->RefreshItem( item ); |
|||
} |
|||
|
|||
m_toolMgr->PostEvent( EVENTS::SelectedItemsModified ); |
|||
|
|||
if( !item->IsMoving() ) |
|||
{ |
|||
if( selection.IsHover() ) |
|||
m_toolMgr->RunAction( SCH_ACTIONS::clearSelection, true ); |
|||
|
|||
m_frame->OnModify(); |
|||
} |
|||
|
|||
return 0; |
|||
} |
|||
|
|||
|
|||
static KICAD_T nonFields[] = |
|||
{ |
|||
LIB_PART_T, |
|||
LIB_ALIAS_T, |
|||
LIB_ARC_T, |
|||
LIB_CIRCLE_T, |
|||
LIB_TEXT_T, |
|||
LIB_RECTANGLE_T, |
|||
LIB_POLYLINE_T, |
|||
LIB_BEZIER_T, |
|||
LIB_PIN_T, |
|||
EOT |
|||
}; |
|||
|
|||
|
|||
int LIB_EDIT_TOOL::Duplicate( const TOOL_EVENT& aEvent ) |
|||
{ |
|||
LIB_PART* part = m_frame->GetCurPart(); |
|||
SELECTION& selection = m_selectionTool->RequestSelection( nonFields ); |
|||
|
|||
if( selection.GetSize() == 0 ) |
|||
return 0; |
|||
|
|||
// Doing a duplicate of a new object doesn't really make any sense; we'd just end
|
|||
// up dragging around a stack of objects...
|
|||
if( selection.Front()->IsNew() ) |
|||
return 0; |
|||
|
|||
if( !selection.Front()->IsMoving() ) |
|||
m_frame->SaveCopyInUndoList( m_frame->GetCurPart() ); |
|||
|
|||
EDA_ITEMS newItems; |
|||
|
|||
for( unsigned ii = 0; ii < selection.GetSize(); ++ii ) |
|||
{ |
|||
LIB_ITEM* oldItem = static_cast<LIB_ITEM*>( selection.GetItem( ii ) ); |
|||
LIB_ITEM* newItem = (LIB_ITEM*) oldItem->Clone(); |
|||
newItem->SetFlags( IS_NEW ); |
|||
newItems.push_back( newItem ); |
|||
|
|||
part->GetDrawItems().push_back( newItem ); |
|||
getView()->Add( newItem ); |
|||
} |
|||
|
|||
m_toolMgr->RunAction( SCH_ACTIONS::clearSelection, true ); |
|||
m_toolMgr->RunAction( SCH_ACTIONS::addItemsToSel, true, &newItems ); |
|||
m_toolMgr->RunAction( SCH_ACTIONS::move, true ); |
|||
|
|||
return 0; |
|||
} |
|||
|
|||
|
|||
int LIB_EDIT_TOOL::DoDelete( const TOOL_EVENT& aEvent ) |
|||
{ |
|||
LIB_PART* part = m_frame->GetCurPart(); |
|||
auto items = m_selectionTool->RequestSelection( nonFields ).GetItems(); |
|||
|
|||
if( items.empty() ) |
|||
return 0; |
|||
|
|||
// Don't leave a freed pointer in the selection
|
|||
m_toolMgr->RunAction( SCH_ACTIONS::clearSelection, true ); |
|||
|
|||
m_frame->SaveCopyInUndoList( part ); |
|||
|
|||
for( EDA_ITEM* item : items ) |
|||
{ |
|||
if( item->Type() == LIB_PIN_T ) |
|||
{ |
|||
LIB_PIN* pin = static_cast<LIB_PIN*>( item ); |
|||
wxPoint pos = pin->GetPosition(); |
|||
|
|||
part->RemoveDrawItem( pin ); |
|||
|
|||
// when pin editing is synchronized, all pins of the same body style are removed:
|
|||
if( m_frame->SynchronizePins() ) |
|||
{ |
|||
int curr_convert = pin->GetConvert(); |
|||
LIB_PIN* next_pin = part->GetNextPin(); |
|||
|
|||
while( next_pin != NULL ) |
|||
{ |
|||
pin = next_pin; |
|||
next_pin = part->GetNextPin( pin ); |
|||
|
|||
if( pin->GetPosition() != pos ) |
|||
continue; |
|||
|
|||
if( pin->GetConvert() != curr_convert ) |
|||
continue; |
|||
|
|||
part->RemoveDrawItem( pin ); |
|||
} |
|||
} |
|||
} |
|||
else |
|||
{ |
|||
part->RemoveDrawItem( (LIB_ITEM*) item ); |
|||
} |
|||
} |
|||
|
|||
m_frame->RebuildView(); |
|||
m_frame->OnModify(); |
|||
|
|||
return 0; |
|||
} |
|||
|
|||
|
|||
static bool deleteItem( SCH_BASE_FRAME* aFrame, const VECTOR2D& aPosition ) |
|||
{ |
|||
SCH_SELECTION_TOOL* selectionTool = aFrame->GetToolManager()->GetTool<SCH_SELECTION_TOOL>(); |
|||
wxCHECK( selectionTool, false ); |
|||
|
|||
aFrame->GetToolManager()->RunAction( SCH_ACTIONS::clearSelection, true ); |
|||
|
|||
EDA_ITEM* item = selectionTool->SelectPoint( aPosition ); |
|||
|
|||
if( item ) |
|||
aFrame->GetToolManager()->RunAction( SCH_ACTIONS::doDelete, true ); |
|||
|
|||
return true; |
|||
} |
|||
|
|||
|
|||
int LIB_EDIT_TOOL::DeleteItemCursor( const TOOL_EVENT& aEvent ) |
|||
{ |
|||
Activate(); |
|||
|
|||
PICKER_TOOL* picker = m_toolMgr->GetTool<PICKER_TOOL>(); |
|||
wxCHECK( picker, 0 ); |
|||
|
|||
m_frame->SetToolID( ID_LIBEDIT_DELETE_ITEM_BUTT, wxCURSOR_BULLSEYE, _( "Delete item" ) ); |
|||
picker->SetClickHandler( std::bind( deleteItem, m_frame, std::placeholders::_1 ) ); |
|||
picker->Activate(); |
|||
Wait(); |
|||
|
|||
return 0; |
|||
} |
|||
|
|||
|
|||
int LIB_EDIT_TOOL::Properties( const TOOL_EVENT& aEvent ) |
|||
{ |
|||
SELECTION& selection = m_selectionTool->RequestSelection(); |
|||
|
|||
if( selection.Empty() ) |
|||
{ |
|||
wxCommandEvent cmd( wxEVT_COMMAND_MENU_SELECTED ); |
|||
|
|||
cmd.SetId( ID_LIBEDIT_GET_FRAME_EDIT_PART ); |
|||
m_frame->GetEventHandler()->ProcessEvent( cmd ); |
|||
} |
|||
else if( selection.Size() == 1 ) |
|||
{ |
|||
LIB_ITEM* item = (LIB_ITEM*) selection.Front(); |
|||
|
|||
// Save copy for undo if not in edit (edit command already handle the save copy)
|
|||
if( !item->InEditMode() ) |
|||
m_frame->SaveCopyInUndoList( item->GetParent() ); |
|||
|
|||
switch( item->Type() ) |
|||
{ |
|||
case LIB_PIN_T: |
|||
{ |
|||
LIB_PIN_TOOL* pinTool = m_toolMgr->GetTool<LIB_PIN_TOOL>(); |
|||
|
|||
if( pinTool ) |
|||
pinTool->EditPinProperties( (LIB_PIN*) item ); |
|||
|
|||
break; |
|||
} |
|||
case LIB_ARC_T: |
|||
case LIB_CIRCLE_T: |
|||
case LIB_RECTANGLE_T: |
|||
case LIB_POLYLINE_T: |
|||
editGraphicProperties( item ); |
|||
break; |
|||
|
|||
case LIB_TEXT_T: |
|||
editTextProperties( item ); |
|||
break; |
|||
|
|||
case LIB_FIELD_T: |
|||
editFieldProperties( (LIB_FIELD*) item ); |
|||
break; |
|||
|
|||
default: |
|||
wxFAIL_MSG( wxT( "Unhandled item <" ) + item->GetClass() + wxT( ">" ) ); |
|||
break; |
|||
} |
|||
} |
|||
|
|||
m_toolMgr->PostEvent( EVENTS::SelectedItemsModified ); |
|||
|
|||
return 0; |
|||
} |
|||
|
|||
|
|||
void LIB_EDIT_TOOL::editGraphicProperties( LIB_ITEM* aItem ) |
|||
{ |
|||
if( aItem == NULL ) |
|||
return; |
|||
|
|||
DIALOG_LIB_EDIT_DRAW_ITEM dialog( m_frame, aItem ); |
|||
|
|||
if( dialog.ShowModal() != wxID_OK ) |
|||
return; |
|||
|
|||
if( aItem->IsFillable() ) |
|||
aItem->SetFillMode( (FILL_T) dialog.GetFillStyle() ); |
|||
|
|||
aItem->SetWidth( dialog.GetWidth() ); |
|||
|
|||
m_frame->GetCanvas()->GetView()->Update( aItem ); |
|||
m_frame->GetCanvas()->Refresh(); |
|||
m_frame->OnModify( ); |
|||
|
|||
m_frame->g_LastLineWidth = dialog.GetWidth(); |
|||
m_frame->m_DrawSpecificConvert = !dialog.GetApplyToAllConversions(); |
|||
m_frame->m_DrawSpecificUnit = !dialog.GetApplyToAllUnits(); |
|||
|
|||
MSG_PANEL_ITEMS items; |
|||
aItem->GetMsgPanelInfo( m_frame->GetUserUnits(), items ); |
|||
m_frame->SetMsgPanel( items ); |
|||
} |
|||
|
|||
|
|||
void LIB_EDIT_TOOL::editTextProperties( LIB_ITEM* aItem ) |
|||
{ |
|||
if ( ( aItem == NULL ) || ( aItem->Type() != LIB_TEXT_T ) ) |
|||
return; |
|||
|
|||
DIALOG_LIB_EDIT_TEXT dlg( m_frame, (LIB_TEXT*) aItem ); |
|||
|
|||
if( dlg.ShowModal() != wxID_OK ) |
|||
return; |
|||
|
|||
m_frame->GetCanvas()->GetView()->Update( aItem ); |
|||
m_frame->GetCanvas()->Refresh(); |
|||
m_frame->OnModify( ); |
|||
} |
|||
|
|||
|
|||
void LIB_EDIT_TOOL::editFieldProperties( LIB_FIELD* aField ) |
|||
{ |
|||
if( aField == NULL ) |
|||
return; |
|||
|
|||
wxString caption; |
|||
LIB_PART* parent = aField->GetParent(); |
|||
wxCHECK( parent, /* void */ ); |
|||
|
|||
// Editing the component value field is equivalent to creating a new component based
|
|||
// on the current component. Set the dialog message to inform the user.
|
|||
if( aField->GetId() == VALUE ) |
|||
caption = _( "Edit Component Name" ); |
|||
else |
|||
caption.Printf( _( "Edit %s Field" ), GetChars( aField->GetName() ) ); |
|||
|
|||
DIALOG_LIB_EDIT_ONE_FIELD dlg( m_frame, caption, aField ); |
|||
|
|||
// The dialog may invoke a kiway player for footprint fields
|
|||
// so we must use a quasimodal dialog.
|
|||
if( dlg.ShowQuasiModal() != wxID_OK ) |
|||
return; |
|||
|
|||
wxString newFieldValue = LIB_ID::FixIllegalChars( dlg.GetText(), LIB_ID::ID_SCH ); |
|||
wxString oldFieldValue = aField->GetFullText( m_frame->GetUnit() ); |
|||
bool renamed = aField->GetId() == VALUE && newFieldValue != oldFieldValue; |
|||
|
|||
if( renamed ) |
|||
m_frame->UpdateAfterRename( parent, oldFieldValue, newFieldValue ); |
|||
|
|||
dlg.UpdateField( aField ); |
|||
|
|||
m_frame->GetCanvas()->GetView()->Update( aField ); |
|||
m_frame->GetCanvas()->Refresh(); |
|||
m_frame->OnModify( ); |
|||
} |
|||
|
|||
|
|||
int LIB_EDIT_TOOL::Cut( const TOOL_EVENT& aEvent ) |
|||
{ |
|||
int retVal = Copy( aEvent ); |
|||
|
|||
if( retVal == 0 ) |
|||
retVal = DoDelete( aEvent ); |
|||
|
|||
return retVal; |
|||
} |
|||
|
|||
|
|||
int LIB_EDIT_TOOL::Copy( const TOOL_EVENT& aEvent ) |
|||
{ |
|||
LIB_PART* part = m_frame->GetCurPart(); |
|||
SELECTION& selection = m_selectionTool->RequestSelection( nonFields ); |
|||
|
|||
if( !part || !selection.GetSize() ) |
|||
return 0; |
|||
|
|||
for( LIB_ITEM& item : part->GetDrawItems() ) |
|||
{ |
|||
if( item.Type() == LIB_FIELD_T ) |
|||
continue; |
|||
|
|||
wxASSERT( ( item.GetFlags() & STRUCT_DELETED ) == 0 ); |
|||
|
|||
if( !item.IsSelected() ) |
|||
item.SetFlags( STRUCT_DELETED ); |
|||
} |
|||
|
|||
LIB_PART* partCopy = new LIB_PART( *part ); |
|||
|
|||
STRING_FORMATTER formatter; |
|||
SCH_LEGACY_PLUGIN::FormatPart( partCopy, formatter ); |
|||
|
|||
delete partCopy; |
|||
|
|||
for( LIB_ITEM& item : part->GetDrawItems() ) |
|||
item.ClearFlags( STRUCT_DELETED ); |
|||
|
|||
if( m_toolMgr->SaveClipboard( formatter.GetString() ) ) |
|||
return 0; |
|||
else |
|||
return -1; |
|||
} |
|||
|
|||
|
|||
int LIB_EDIT_TOOL::Paste( const TOOL_EVENT& aEvent ) |
|||
{ |
|||
LIB_PART* part = m_frame->GetCurPart(); |
|||
|
|||
if( !part ) |
|||
return 0; |
|||
|
|||
std::string text = m_toolMgr->GetClipboard(); |
|||
STRING_LINE_READER reader( text, "Clipboard" ); |
|||
LIB_PART* newPart; |
|||
EDA_ITEMS newItems; |
|||
|
|||
try |
|||
{ |
|||
reader.ReadLine(); |
|||
newPart = SCH_LEGACY_PLUGIN::ParsePart( reader ); |
|||
} |
|||
catch( IO_ERROR& e ) |
|||
{ |
|||
wxLogError( wxString::Format( "Malformed clipboard: %s" ), GetChars( e.What() ) ); |
|||
return -1; |
|||
} |
|||
|
|||
for( LIB_ITEM& item : newPart->GetDrawItems() ) |
|||
{ |
|||
if( item.Type() == LIB_FIELD_T ) |
|||
continue; |
|||
|
|||
LIB_ITEM* newItem = (LIB_ITEM*) item.Clone(); |
|||
newItem->SetFlags( IS_NEW ); |
|||
newItems.push_back( newItem ); |
|||
|
|||
part->GetDrawItems().push_back( newItem ); |
|||
getView()->Add( newItem ); |
|||
} |
|||
|
|||
delete newPart; |
|||
|
|||
m_toolMgr->RunAction( SCH_ACTIONS::clearSelection, true ); |
|||
m_toolMgr->RunAction( SCH_ACTIONS::addItemsToSel, true, &newItems ); |
|||
m_toolMgr->RunAction( SCH_ACTIONS::move, true ); |
|||
|
|||
return 0; |
|||
} |
|||
|
|||
|
|||
void LIB_EDIT_TOOL::setTransitions() |
|||
{ |
|||
Go( &LIB_EDIT_TOOL::Duplicate, SCH_ACTIONS::duplicate.MakeEvent() ); |
|||
Go( &LIB_EDIT_TOOL::Rotate, SCH_ACTIONS::rotateCW.MakeEvent() ); |
|||
Go( &LIB_EDIT_TOOL::Rotate, SCH_ACTIONS::rotateCCW.MakeEvent() ); |
|||
Go( &LIB_EDIT_TOOL::Mirror, SCH_ACTIONS::mirrorX.MakeEvent() ); |
|||
Go( &LIB_EDIT_TOOL::Mirror, SCH_ACTIONS::mirrorY.MakeEvent() ); |
|||
Go( &LIB_EDIT_TOOL::DoDelete, SCH_ACTIONS::doDelete.MakeEvent() ); |
|||
Go( &LIB_EDIT_TOOL::DeleteItemCursor, SCH_ACTIONS::deleteItemCursor.MakeEvent() ); |
|||
|
|||
Go( &LIB_EDIT_TOOL::Properties, SCH_ACTIONS::properties.MakeEvent() ); |
|||
|
|||
Go( &LIB_EDIT_TOOL::Cut, SCH_ACTIONS::cut.MakeEvent() ); |
|||
Go( &LIB_EDIT_TOOL::Copy, SCH_ACTIONS::copy.MakeEvent() ); |
|||
Go( &LIB_EDIT_TOOL::Paste, SCH_ACTIONS::paste.MakeEvent() ); |
|||
} |
|||
@ -0,0 +1,88 @@ |
|||
/* |
|||
* This program source code file is part of KiCad, a free EDA CAD application. |
|||
* |
|||
* Copyright (C) 2019 KiCad Developers, see AUTHORS.txt for contributors. |
|||
* |
|||
* This program is free software; you can redistribute it and/or |
|||
* modify it under the terms of the GNU General Public License |
|||
* as published by the Free Software Foundation; either version 2 |
|||
* of the License, or (at your option) any later version. |
|||
* |
|||
* This program is distributed in the hope that it will be useful, |
|||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
* GNU General Public License for more details. |
|||
* |
|||
* You should have received a copy of the GNU General Public License |
|||
* along with this program; if not, you may find one here: |
|||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html |
|||
* or you may search the http://www.gnu.org website for the version 2 license, |
|||
* or you may write to the Free Software Foundation, Inc., |
|||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA |
|||
*/ |
|||
|
|||
#ifndef KICAD_LIB_EDIT_TOOL_H |
|||
#define KICAD_LIB_EDIT_TOOL_H |
|||
|
|||
#include <tool/tool_interactive.h> |
|||
#include <tool/tool_menu.h> |
|||
#include <sch_base_frame.h> |
|||
|
|||
|
|||
class LIB_EDIT_FRAME; |
|||
class SCH_SELECTION_TOOL; |
|||
|
|||
|
|||
class LIB_EDIT_TOOL : public TOOL_INTERACTIVE |
|||
{ |
|||
public: |
|||
LIB_EDIT_TOOL(); |
|||
~LIB_EDIT_TOOL(); |
|||
|
|||
/// @copydoc TOOL_INTERACTIVE::Init() |
|||
bool Init() override; |
|||
|
|||
/// @copydoc TOOL_INTERACTIVE::Reset() |
|||
void Reset( RESET_REASON aReason ) override; |
|||
|
|||
///> Get the SCH_DRAWING_TOOL top-level context menu |
|||
inline TOOL_MENU& GetToolMenu() { return m_menu; } |
|||
|
|||
int Rotate( const TOOL_EVENT& aEvent ); |
|||
int Mirror( const TOOL_EVENT& aEvent ); |
|||
|
|||
int Duplicate( const TOOL_EVENT& aEvent ); |
|||
|
|||
int Properties( const TOOL_EVENT& aEvent ); |
|||
|
|||
int Cut( const TOOL_EVENT& aEvent ); |
|||
int Copy( const TOOL_EVENT& aEvent ); |
|||
int Paste( const TOOL_EVENT& aEvent ); |
|||
|
|||
/** |
|||
* Function DoDelete() |
|||
* |
|||
* Deletes the selected items, or the item under the cursor. |
|||
*/ |
|||
int DoDelete( const TOOL_EVENT& aEvent ); |
|||
|
|||
///> Runs the deletion tool. |
|||
int DeleteItemCursor( const TOOL_EVENT& aEvent ); |
|||
|
|||
private: |
|||
void editGraphicProperties( LIB_ITEM* aItem ); |
|||
void editTextProperties( LIB_ITEM* aItem ); |
|||
void editFieldProperties( LIB_FIELD* aField ); |
|||
|
|||
///> Sets up handlers for various events. |
|||
void setTransitions() override; |
|||
|
|||
private: |
|||
SCH_SELECTION_TOOL* m_selectionTool; |
|||
LIB_EDIT_FRAME* m_frame; |
|||
|
|||
/// Menu model displayed by the tool. |
|||
TOOL_MENU m_menu; |
|||
}; |
|||
|
|||
#endif //KICAD_LIB_EDIT_TOOL_H |
|||
@ -0,0 +1,346 @@ |
|||
/*
|
|||
* This program source code file is part of KiCad, a free EDA CAD application. |
|||
* |
|||
* Copyright (C) 2019 KiCad Developers, see AUTHORS.txt for contributors. |
|||
* |
|||
* This program is free software; you can redistribute it and/or |
|||
* modify it under the terms of the GNU General Public License |
|||
* as published by the Free Software Foundation; either version 2 |
|||
* of the License, or (at your option) any later version. |
|||
* |
|||
* This program is distributed in the hope that it will be useful, |
|||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
* GNU General Public License for more details. |
|||
* |
|||
* You should have received a copy of the GNU General Public License |
|||
* along with this program; if not, you may find one here: |
|||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
|||
* or you may search the http://www.gnu.org website for the version 2 license,
|
|||
* or you may write to the Free Software Foundation, Inc., |
|||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA |
|||
*/ |
|||
|
|||
#include <tool/tool_manager.h>
|
|||
#include <tools/sch_selection_tool.h>
|
|||
#include <sch_actions.h>
|
|||
#include <hotkeys.h>
|
|||
#include <view/view.h>
|
|||
#include <bitmaps.h>
|
|||
#include <base_struct.h>
|
|||
#include <lib_edit_frame.h>
|
|||
#include <eeschema_id.h>
|
|||
#include "lib_move_tool.h"
|
|||
#include "lib_pin_tool.h"
|
|||
|
|||
|
|||
LIB_MOVE_TOOL::LIB_MOVE_TOOL() : |
|||
TOOL_INTERACTIVE( "libedit.InteractiveMove" ), |
|||
m_selectionTool( nullptr ), |
|||
m_controls( nullptr ), |
|||
m_frame( nullptr ), |
|||
m_menu( *this ), |
|||
m_moveInProgress( false ), |
|||
m_moveOffset( 0, 0 ) |
|||
{ |
|||
} |
|||
|
|||
|
|||
LIB_MOVE_TOOL::~LIB_MOVE_TOOL() |
|||
{ |
|||
} |
|||
|
|||
|
|||
bool LIB_MOVE_TOOL::Init() |
|||
{ |
|||
m_frame = getEditFrame<LIB_EDIT_FRAME>(); |
|||
m_selectionTool = m_toolMgr->GetTool<SCH_SELECTION_TOOL>(); |
|||
|
|||
wxASSERT_MSG( m_selectionTool, "eeshema.InteractiveSelection tool is not available" ); |
|||
|
|||
//
|
|||
// Build the tool menu
|
|||
//
|
|||
CONDITIONAL_MENU& ctxMenu = m_menu.GetMenu(); |
|||
|
|||
ctxMenu.AddItem( ACTIONS::cancelInteractive, SCH_CONDITIONS::ShowAlways, 1 ); |
|||
|
|||
ctxMenu.AddSeparator( SCH_CONDITIONS::ShowAlways, 1000 ); |
|||
m_menu.AddStandardSubMenus( m_frame ); |
|||
|
|||
//
|
|||
// Add move actions to the selection tool menu
|
|||
//
|
|||
CONDITIONAL_MENU& selToolMenu = m_selectionTool->GetToolMenu().GetMenu(); |
|||
|
|||
selToolMenu.AddItem( SCH_ACTIONS::move, SCH_CONDITIONS::Idle, 150 ); |
|||
|
|||
return true; |
|||
} |
|||
|
|||
|
|||
void LIB_MOVE_TOOL::Reset( RESET_REASON aReason ) |
|||
{ |
|||
if( aReason == MODEL_RELOAD ) |
|||
{ |
|||
m_moveInProgress = false; |
|||
m_moveOffset = { 0, 0 }; |
|||
|
|||
// Init variables used by every drawing tool
|
|||
m_controls = getViewControls(); |
|||
m_frame = getEditFrame<LIB_EDIT_FRAME>(); |
|||
} |
|||
} |
|||
|
|||
|
|||
int LIB_MOVE_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 move. If there's no selection try
|
|||
// looking for the stuff under mouse cursor (i.e. Kicad old-style hover selection).
|
|||
SELECTION& selection = m_selectionTool->RequestSelection(); |
|||
bool unselect = selection.IsHover(); |
|||
|
|||
if( selection.Empty() ) |
|||
return 0; |
|||
|
|||
m_frame->SetToolID( ID_SCH_MOVE, wxCURSOR_DEFAULT, _( "Move Items" ) ); |
|||
|
|||
Activate(); |
|||
controls->ShowCursor( true ); |
|||
controls->SetAutoPan( true ); |
|||
|
|||
bool restore_state = false; |
|||
bool chain_commands = false; |
|||
OPT_TOOL_EVENT evt = aEvent; |
|||
VECTOR2I prevPos; |
|||
|
|||
if( !selection.Front()->IsNew() ) |
|||
m_frame->SaveCopyInUndoList( m_frame->GetCurPart() ); |
|||
|
|||
// Main loop: keep receiving events
|
|||
do |
|||
{ |
|||
controls->SetSnapping( !evt->Modifier( MD_ALT ) ); |
|||
|
|||
if( evt->IsAction( &SCH_ACTIONS::move ) || evt->IsMotion() || evt->IsDrag( BUT_LEFT ) |
|||
|| evt->IsAction( &SCH_ACTIONS::refreshPreview ) ) |
|||
{ |
|||
if( !m_moveInProgress ) // Prepare to start moving/dragging
|
|||
{ |
|||
// Pick up any synchronized pins
|
|||
//
|
|||
if( selection.GetSize() == 1 && selection.Front()->Type() == LIB_PIN_T |
|||
&& m_frame->SynchronizePins() ) |
|||
{ |
|||
LIB_PIN* cur_pin = (LIB_PIN*) selection.Front(); |
|||
LIB_PART* part = m_frame->GetCurPart(); |
|||
|
|||
for( LIB_PIN* pin = part->GetNextPin(); pin; pin = part->GetNextPin( pin ) ) |
|||
{ |
|||
if( pin->GetPosition() == cur_pin->GetPosition() |
|||
&& pin->GetOrientation() == cur_pin->GetOrientation() |
|||
&& pin->GetConvert() == cur_pin->GetConvert() ) |
|||
{ |
|||
m_selectionTool->AddItemToSel( pin, true ); |
|||
} |
|||
} |
|||
} |
|||
|
|||
// Apply any initial offset in case we're coming from a previous command.
|
|||
//
|
|||
for( EDA_ITEM* item : selection ) |
|||
moveItem( item, m_moveOffset ); |
|||
|
|||
// Set up the starting position and move/drag offset
|
|||
//
|
|||
m_cursor = controls->GetCursorPosition(); |
|||
|
|||
if( selection.HasReferencePoint() ) |
|||
{ |
|||
VECTOR2I delta = m_cursor - selection.GetReferencePoint(); |
|||
|
|||
// Drag items to the current cursor position
|
|||
for( EDA_ITEM* item : selection ) |
|||
{ |
|||
// Don't double move pins, fields, etc.
|
|||
if( item->GetParent() && item->GetParent()->IsSelected() ) |
|||
continue; |
|||
|
|||
moveItem( item, delta ); |
|||
getView()->Update( item ); |
|||
} |
|||
|
|||
selection.SetReferencePoint( m_cursor ); |
|||
} |
|||
else if( selection.Size() == 1 ) |
|||
{ |
|||
// Set the current cursor position to the first dragged item origin,
|
|||
// so the movement vector can be computed later
|
|||
updateModificationPoint( selection ); |
|||
m_cursor = originalCursorPos; |
|||
} |
|||
else |
|||
{ |
|||
updateModificationPoint( selection ); |
|||
} |
|||
|
|||
controls->SetCursorPosition( m_cursor, false ); |
|||
|
|||
prevPos = m_cursor; |
|||
controls->SetAutoPan( true ); |
|||
m_moveInProgress = true; |
|||
} |
|||
|
|||
//------------------------------------------------------------------------
|
|||
// Follow the mouse
|
|||
//
|
|||
m_cursor = controls->GetCursorPosition(); |
|||
VECTOR2I delta( m_cursor - prevPos ); |
|||
selection.SetReferencePoint( m_cursor ); |
|||
|
|||
m_moveOffset += delta; |
|||
prevPos = m_cursor; |
|||
|
|||
for( EDA_ITEM* item : selection ) |
|||
{ |
|||
moveItem( item, delta ); |
|||
getView()->Update( item ); |
|||
} |
|||
|
|||
m_toolMgr->PostEvent( EVENTS::SelectedItemsModified ); |
|||
m_frame->UpdateMsgPanel(); |
|||
} |
|||
//------------------------------------------------------------------------
|
|||
// Handle cancel
|
|||
//
|
|||
else if( TOOL_EVT_UTILS::IsCancelInteractive( evt.get() ) ) |
|||
{ |
|||
m_toolMgr->RunAction( SCH_ACTIONS::clearSelection, true ); |
|||
|
|||
if( m_moveInProgress ) |
|||
restore_state = true; |
|||
|
|||
break; |
|||
} |
|||
//------------------------------------------------------------------------
|
|||
// Handle TOOL_ACTION special cases
|
|||
//
|
|||
else if( evt->Action() == TA_UNDO_REDO_PRE ) |
|||
{ |
|||
unselect = true; |
|||
break; |
|||
} |
|||
else if( evt->Category() == TC_COMMAND ) |
|||
{ |
|||
if( evt->IsAction( &SCH_ACTIONS::doDelete ) ) |
|||
{ |
|||
// Exit on a remove operation; there is no further processing for removed items.
|
|||
break; |
|||
} |
|||
else if( evt->IsAction( &SCH_ACTIONS::duplicate ) ) |
|||
{ |
|||
if( selection.Front()->IsNew() ) |
|||
{ |
|||
// This doesn't really make sense; we'll just end up dragging a stack of
|
|||
// objects so Duplicate() is going to ignore this and we'll just carry on.
|
|||
continue; |
|||
} |
|||
|
|||
// Move original back and exit. The duplicate will run in its own loop.
|
|||
restore_state = true; |
|||
unselect = false; |
|||
chain_commands = true; |
|||
break; |
|||
} |
|||
} |
|||
//------------------------------------------------------------------------
|
|||
// Handle context menu
|
|||
//
|
|||
else if( evt->IsClick( BUT_RIGHT ) ) |
|||
{ |
|||
m_menu.ShowContextMenu( selection ); |
|||
} |
|||
//------------------------------------------------------------------------
|
|||
// Handle drop
|
|||
//
|
|||
else if( evt->IsMouseUp( BUT_LEFT ) || evt->IsClick( BUT_LEFT ) ) |
|||
{ |
|||
if( selection.GetSize() == 1 && selection.Front()->Type() == LIB_PIN_T ) |
|||
{ |
|||
LIB_PIN_TOOL* pinTool = m_toolMgr->GetTool<LIB_PIN_TOOL>(); |
|||
|
|||
if( !pinTool->PlacePin( (LIB_PIN*) selection.Front() ) ) |
|||
restore_state = true; |
|||
} |
|||
|
|||
break; // Finish
|
|||
} |
|||
|
|||
} while( ( evt = Wait() ) ); //Should be assignment not equality test
|
|||
|
|||
controls->ForceCursorPosition( false ); |
|||
controls->ShowCursor( false ); |
|||
controls->SetSnapping( false ); |
|||
controls->SetAutoPan( false ); |
|||
|
|||
if( !chain_commands ) |
|||
m_moveOffset = { 0, 0 }; |
|||
|
|||
m_moveInProgress = false; |
|||
m_frame->SetNoToolSelected(); |
|||
|
|||
selection.ClearReferencePoint(); |
|||
|
|||
for( auto item : selection ) |
|||
item->ClearFlags( item->GetEditFlags() ); |
|||
|
|||
if( unselect ) |
|||
m_toolMgr->RunAction( SCH_ACTIONS::clearSelection, true ); |
|||
|
|||
if( restore_state ) |
|||
m_frame->RollbackPartFromUndo(); |
|||
else |
|||
m_frame->OnModify(); |
|||
|
|||
return 0; |
|||
} |
|||
|
|||
|
|||
void LIB_MOVE_TOOL::moveItem( EDA_ITEM* aItem, VECTOR2I aDelta ) |
|||
{ |
|||
static_cast<LIB_ITEM*>( aItem )->Move( mapCoords( aDelta ) ); |
|||
aItem->SetFlags( IS_MOVED ); |
|||
} |
|||
|
|||
|
|||
bool LIB_MOVE_TOOL::updateModificationPoint( SELECTION& aSelection ) |
|||
{ |
|||
if( m_moveInProgress && aSelection.HasReferencePoint() ) |
|||
return false; |
|||
|
|||
// When there is only one item selected, the reference point is its position...
|
|||
if( aSelection.Size() == 1 ) |
|||
{ |
|||
LIB_ITEM* item = static_cast<LIB_ITEM*>( aSelection.Front() ); |
|||
aSelection.SetReferencePoint( item->GetPosition() ); |
|||
} |
|||
// ...otherwise modify items with regard to the grid-snapped cursor position
|
|||
else |
|||
{ |
|||
m_cursor = getViewControls()->GetCursorPosition( true ); |
|||
aSelection.SetReferencePoint( m_cursor ); |
|||
} |
|||
|
|||
return true; |
|||
} |
|||
|
|||
|
|||
void LIB_MOVE_TOOL::setTransitions() |
|||
{ |
|||
Go( &LIB_MOVE_TOOL::Main, SCH_ACTIONS::move.MakeEvent() ); |
|||
} |
|||
@ -0,0 +1,87 @@ |
|||
/* |
|||
* This program source code file is part of KiCad, a free EDA CAD application. |
|||
* |
|||
* Copyright (C) 2019 KiCad Developers, see AUTHORS.txt for contributors. |
|||
* |
|||
* This program is free software; you can redistribute it and/or |
|||
* modify it under the terms of the GNU General Public License |
|||
* as published by the Free Software Foundation; either version 2 |
|||
* of the License, or (at your option) any later version. |
|||
* |
|||
* This program is distributed in the hope that it will be useful, |
|||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
* GNU General Public License for more details. |
|||
* |
|||
* You should have received a copy of the GNU General Public License |
|||
* along with this program; if not, you may find one here: |
|||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html |
|||
* or you may search the http://www.gnu.org website for the version 2 license, |
|||
* or you may write to the Free Software Foundation, Inc., |
|||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA |
|||
*/ |
|||
|
|||
#ifndef KICAD_LIB_MOVE_TOOL_H |
|||
#define KICAD_LIB_MOVE_TOOL_H |
|||
|
|||
#include <tool/tool_interactive.h> |
|||
#include <tool/tool_menu.h> |
|||
#include <sch_base_frame.h> |
|||
|
|||
|
|||
class LIB_EDIT_FRAME; |
|||
class SCH_SELECTION_TOOL; |
|||
|
|||
|
|||
class LIB_MOVE_TOOL : public TOOL_INTERACTIVE |
|||
{ |
|||
public: |
|||
LIB_MOVE_TOOL(); |
|||
~LIB_MOVE_TOOL(); |
|||
|
|||
/// @copydoc TOOL_INTERACTIVE::Init() |
|||
bool Init() override; |
|||
|
|||
/// @copydoc TOOL_INTERACTIVE::Reset() |
|||
void Reset( RESET_REASON aReason ) override; |
|||
|
|||
///> Get the SCH_DRAWING_TOOL top-level context menu |
|||
inline TOOL_MENU& GetToolMenu() { return m_menu; } |
|||
|
|||
/** |
|||
* Function Main() |
|||
* |
|||
* Runs an interactive move of the selected items, or the item under the cursor. |
|||
*/ |
|||
int Main( const TOOL_EVENT& aEvent ); |
|||
|
|||
private: |
|||
void moveItem( EDA_ITEM* aItem, VECTOR2I aDelta ); |
|||
|
|||
///> Returns the right modification point (e.g. for rotation), depending on the number of |
|||
///> selected items. |
|||
bool updateModificationPoint( SELECTION& aSelection ); |
|||
|
|||
///> Sets up handlers for various events. |
|||
void setTransitions() override; |
|||
|
|||
private: |
|||
SCH_SELECTION_TOOL* m_selectionTool; |
|||
KIGFX::VIEW_CONTROLS* m_controls; |
|||
LIB_EDIT_FRAME* m_frame; |
|||
|
|||
/// Menu model displayed by the tool. |
|||
TOOL_MENU m_menu; |
|||
|
|||
///> Flag determining if anything is being dragged right now |
|||
bool m_moveInProgress; |
|||
|
|||
///> Used for chaining commands |
|||
VECTOR2I m_moveOffset; |
|||
|
|||
///> Last cursor position (needed for getModificationPoint() to avoid changes |
|||
///> of edit reference point). |
|||
VECTOR2I m_cursor; |
|||
}; |
|||
|
|||
#endif //KICAD_LIB_MOVE_TOOL_H |
|||
@ -0,0 +1,782 @@ |
|||
/*
|
|||
* This program source code file is part of KiCad, a free EDA CAD application. |
|||
* |
|||
* Copyright (C) 2019 KiCad Developers, see AUTHORS.txt for contributors. |
|||
* |
|||
* This program is free software; you can redistribute it and/or |
|||
* modify it under the terms of the GNU General Public License |
|||
* as published by the Free Software Foundation; either version 2 |
|||
* of the License, or (at your option) any later version. |
|||
* |
|||
* This program is distributed in the hope that it will be useful, |
|||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
* GNU General Public License for more details. |
|||
* |
|||
* You should have received a copy of the GNU General Public License |
|||
* along with this program; if not, you may find one here: |
|||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
|||
* or you may search the http://www.gnu.org website for the version 2 license,
|
|||
* or you may write to the Free Software Foundation, Inc., |
|||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA |
|||
*/ |
|||
|
|||
#include <functional>
|
|||
using namespace std::placeholders; |
|||
|
|||
#include "point_editor.h"
|
|||
#include <tool/tool_manager.h>
|
|||
#include <view/view_controls.h>
|
|||
#include <gal/graphics_abstraction_layer.h>
|
|||
#include <geometry/seg.h>
|
|||
#include <confirm.h>
|
|||
|
|||
#include <tools/sch_actions.h>
|
|||
#include <tools/sch_selection_tool.h>
|
|||
#include <bitmaps.h>
|
|||
#include <status_popup.h>
|
|||
#include <sch_edit_frame.h>
|
|||
#include <sch_line.h>
|
|||
#include <sch_sheet.h>
|
|||
#include <lib_edit_frame.h>
|
|||
#include <lib_arc.h>
|
|||
#include <lib_circle.h>
|
|||
#include <lib_rectangle.h>
|
|||
#include <lib_polyline.h>
|
|||
#include <widgets/progress_reporter.h>
|
|||
|
|||
|
|||
// Point editor
|
|||
TOOL_ACTION SCH_ACTIONS::pointEditorAddCorner( "eeschema.PointEditor.addCorner", |
|||
AS_GLOBAL, 0, |
|||
_( "Create Corner" ), _( "Create a corner" ), add_corner_xpm ); |
|||
|
|||
TOOL_ACTION SCH_ACTIONS::pointEditorRemoveCorner( "eeschema.PointEditor.removeCorner", |
|||
AS_GLOBAL, 0, |
|||
_( "Remove Corner" ), _( "Remove corner" ), delete_xpm ); |
|||
|
|||
|
|||
// Few constants to avoid using bare numbers for point indices
|
|||
enum ARC_POINTS |
|||
{ |
|||
ARC_CENTER, ARC_START, ARC_END |
|||
}; |
|||
|
|||
enum CIRCLE_POINTS |
|||
{ |
|||
CIRC_CENTER, CIRC_END |
|||
}; |
|||
|
|||
enum RECTANGLE_POINTS |
|||
{ |
|||
RECT_TOPLEFT, RECT_TOPRIGHT, RECT_BOTLEFT, RECT_BOTRIGHT |
|||
}; |
|||
|
|||
enum LINE_POINTS |
|||
{ |
|||
LINE_START, LINE_END |
|||
}; |
|||
|
|||
class EDIT_POINTS_FACTORY |
|||
{ |
|||
public: |
|||
static std::shared_ptr<EDIT_POINTS> Make( EDA_ITEM* aItem, SCH_BASE_FRAME* frame ) |
|||
{ |
|||
std::shared_ptr<EDIT_POINTS> points = std::make_shared<EDIT_POINTS>( aItem ); |
|||
|
|||
if( !aItem ) |
|||
return points; |
|||
|
|||
// Generate list of edit points based on the item type
|
|||
switch( aItem->Type() ) |
|||
{ |
|||
case LIB_ARC_T: |
|||
{ |
|||
LIB_ARC* arc = (LIB_ARC*) aItem; |
|||
|
|||
points->AddPoint( mapCoords( arc->GetPosition() ) ); |
|||
points->AddPoint( mapCoords( arc->GetStart() ) ); |
|||
points->AddPoint( mapCoords( arc->GetEnd() ) ); |
|||
break; |
|||
} |
|||
case LIB_CIRCLE_T: |
|||
{ |
|||
LIB_CIRCLE* circle = (LIB_CIRCLE*) aItem; |
|||
|
|||
points->AddPoint( mapCoords( circle->GetPosition() ) ); |
|||
points->AddPoint( mapCoords( circle->GetEnd() ) ); |
|||
break; |
|||
} |
|||
case LIB_POLYLINE_T: |
|||
{ |
|||
LIB_POLYLINE* lines = (LIB_POLYLINE*) aItem; |
|||
const std::vector<wxPoint>& pts = lines->GetPolyPoints(); |
|||
|
|||
for( wxPoint pt : pts ) |
|||
points->AddPoint( mapCoords( pt ) ); |
|||
|
|||
break; |
|||
} |
|||
case LIB_RECTANGLE_T: |
|||
{ |
|||
LIB_RECTANGLE* rect = (LIB_RECTANGLE*) aItem; |
|||
wxPoint topLeft = rect->GetPosition(); |
|||
wxPoint botRight = rect->GetEnd(); |
|||
|
|||
points->AddPoint( mapCoords( topLeft ) ); |
|||
points->AddPoint( mapCoords( botRight.x, topLeft.y ) ); |
|||
points->AddPoint( mapCoords( topLeft.x, botRight.y ) ); |
|||
points->AddPoint( mapCoords( botRight ) ); |
|||
break; |
|||
} |
|||
case SCH_SHEET_T: |
|||
{ |
|||
SCH_SHEET* sheet = (SCH_SHEET*) aItem; |
|||
wxPoint topLeft = sheet->GetPosition(); |
|||
wxPoint botRight = sheet->GetPosition() + sheet->GetSize(); |
|||
|
|||
points->AddPoint( (wxPoint) topLeft ); |
|||
points->AddPoint( wxPoint( botRight.x, topLeft.y ) ); |
|||
points->AddPoint( wxPoint( topLeft.x, botRight.y ) ); |
|||
points->AddPoint( (wxPoint) botRight ); |
|||
break; |
|||
} |
|||
case SCH_LINE_T: |
|||
{ |
|||
SCH_LINE* line = (SCH_LINE*) aItem; |
|||
SCH_LINE* connectedStart = nullptr; |
|||
SCH_LINE* connectedEnd = nullptr; |
|||
|
|||
for( SCH_ITEM* test = frame->GetScreen()->GetDrawItems(); test; test = test->Next() ) |
|||
{ |
|||
if( test->Type() != SCH_LINE_T || test->GetLayer() != LAYER_NOTES ) |
|||
continue; |
|||
|
|||
if( test == aItem ) |
|||
continue; |
|||
|
|||
SCH_LINE* testLine = (SCH_LINE*) test; |
|||
testLine->ClearFlags( STARTPOINT | ENDPOINT ); |
|||
|
|||
if( testLine->GetStartPoint() == line->GetStartPoint() ) |
|||
{ |
|||
connectedStart = testLine; |
|||
testLine->SetFlags( STARTPOINT ); |
|||
} |
|||
else if( testLine->GetEndPoint() == line->GetStartPoint() ) |
|||
{ |
|||
connectedStart = testLine; |
|||
testLine->SetFlags( ENDPOINT ); |
|||
} |
|||
else if( testLine->GetStartPoint() == line->GetEndPoint() ) |
|||
{ |
|||
connectedEnd = testLine; |
|||
testLine->SetFlags( STARTPOINT ); |
|||
} |
|||
else if( testLine->GetEndPoint() == line->GetEndPoint() ) |
|||
{ |
|||
connectedEnd = testLine; |
|||
testLine->SetFlags( ENDPOINT ); |
|||
} |
|||
} |
|||
|
|||
points->AddPoint( line->GetStartPoint(), connectedStart ); |
|||
points->AddPoint( line->GetEndPoint(), connectedEnd ); |
|||
break; |
|||
} |
|||
default: |
|||
points.reset(); |
|||
break; |
|||
} |
|||
|
|||
return points; |
|||
} |
|||
|
|||
private: |
|||
EDIT_POINTS_FACTORY() {}; |
|||
}; |
|||
|
|||
|
|||
POINT_EDITOR::POINT_EDITOR() : |
|||
TOOL_INTERACTIVE( "eeschema.PointEditor" ), |
|||
m_frame( nullptr ), |
|||
m_selectionTool( nullptr ), |
|||
m_editedPoint( nullptr ) |
|||
{ |
|||
} |
|||
|
|||
|
|||
void POINT_EDITOR::Reset( RESET_REASON aReason ) |
|||
{ |
|||
m_editPoints.reset(); |
|||
getViewControls()->SetAutoPan( false ); |
|||
m_frame = getEditFrame<SCH_BASE_FRAME>(); |
|||
m_isLibEdit = dynamic_cast<LIB_EDIT_FRAME*>( m_frame ) != nullptr; |
|||
} |
|||
|
|||
|
|||
bool POINT_EDITOR::Init() |
|||
{ |
|||
m_frame = getEditFrame<SCH_BASE_FRAME>(); |
|||
m_isLibEdit = dynamic_cast<LIB_EDIT_FRAME*>( m_frame ) != nullptr; |
|||
m_selectionTool = m_toolMgr->GetTool<SCH_SELECTION_TOOL>(); |
|||
|
|||
wxASSERT_MSG( m_selectionTool, "eeshema.InteractiveSelection tool is not available" ); |
|||
|
|||
auto& menu = m_selectionTool->GetToolMenu().GetMenu(); |
|||
menu.AddItem( SCH_ACTIONS::pointEditorAddCorner, |
|||
std::bind( &POINT_EDITOR::addCornerCondition, this, _1 ) ); |
|||
menu.AddItem( SCH_ACTIONS::pointEditorRemoveCorner, |
|||
std::bind( &POINT_EDITOR::removeCornerCondition, this, _1 ) ); |
|||
|
|||
return true; |
|||
} |
|||
|
|||
|
|||
void POINT_EDITOR::updateEditedPoint( const TOOL_EVENT& aEvent ) |
|||
{ |
|||
EDIT_POINT* point = m_editedPoint; |
|||
|
|||
if( aEvent.IsMotion() ) |
|||
{ |
|||
point = m_editPoints->FindPoint( aEvent.Position(), getView() ); |
|||
} |
|||
else if( aEvent.IsDrag( BUT_LEFT ) ) |
|||
{ |
|||
point = m_editPoints->FindPoint( aEvent.DragOrigin(), getView() ); |
|||
} |
|||
|
|||
if( m_editedPoint != point ) |
|||
setEditedPoint( point ); |
|||
} |
|||
|
|||
|
|||
int POINT_EDITOR::Main( const TOOL_EVENT& aEvent ) |
|||
{ |
|||
static KICAD_T pointTypes[] = { LIB_ARC_T, LIB_CIRCLE_T, LIB_POLYLINE_T, LIB_RECTANGLE_T, |
|||
SCH_SHEET_T, SCH_LINE_LOCATE_GRAPHIC_LINE_T, EOT }; |
|||
|
|||
if( !m_selectionTool ) |
|||
return 0; |
|||
|
|||
const SELECTION& selection = m_selectionTool->GetSelection(); |
|||
|
|||
if( selection.Size() != 1 || !selection.Front()->IsType( pointTypes ) ) |
|||
return 0; |
|||
|
|||
Activate(); |
|||
|
|||
KIGFX::VIEW_CONTROLS* controls = getViewControls(); |
|||
KIGFX::VIEW* view = getView(); |
|||
int savedToolID = m_frame->GetToolId(); |
|||
wxString savedToolMsg = m_frame->GetToolMsg(); |
|||
EDA_ITEM* item = (EDA_ITEM*) selection.Front(); |
|||
|
|||
controls->ShowCursor( true ); |
|||
|
|||
m_editPoints = EDIT_POINTS_FACTORY::Make( item, m_frame ); |
|||
|
|||
if( !m_editPoints ) |
|||
return 0; |
|||
|
|||
view->Add( m_editPoints.get() ); |
|||
setEditedPoint( nullptr ); |
|||
bool inDrag = false; |
|||
bool modified = false; |
|||
|
|||
// Main loop: keep receiving events
|
|||
while( OPT_TOOL_EVENT evt = Wait() ) |
|||
{ |
|||
if( !m_editPoints |
|||
|| evt->Matches( EVENTS::ClearedEvent ) |
|||
|| evt->Matches( EVENTS::UnselectedEvent ) |
|||
|| evt->Matches( EVENTS::SelectedEvent ) ) |
|||
{ |
|||
break; |
|||
} |
|||
|
|||
if ( !inDrag ) |
|||
updateEditedPoint( *evt ); |
|||
|
|||
if( evt->IsDrag( BUT_LEFT ) && m_editedPoint ) |
|||
{ |
|||
m_frame->SetToolID( ID_DRAG_POINT, -1, _( "Drag Point" ) ); |
|||
|
|||
if( !inDrag ) |
|||
{ |
|||
saveItemsToUndo(); |
|||
controls->ForceCursorPosition( false ); |
|||
inDrag = true; |
|||
modified = true; |
|||
} |
|||
|
|||
m_editedPoint->SetPosition( controls->GetCursorPosition( !evt->Modifier( MD_ALT ) ) ); |
|||
|
|||
updateItem(); |
|||
updatePoints(); |
|||
|
|||
view->Redraw(); |
|||
} |
|||
|
|||
else if( evt->IsMouseUp( BUT_LEFT ) ) |
|||
{ |
|||
controls->SetAutoPan( false ); |
|||
m_frame->SetToolID( savedToolID, -1, savedToolMsg ); |
|||
|
|||
inDrag = false; |
|||
|
|||
m_toolMgr->PassEvent(); |
|||
} |
|||
|
|||
else if( evt->IsCancel() ) |
|||
{ |
|||
if( inDrag ) // Restore the last change
|
|||
{ |
|||
rollbackFromUndo(); |
|||
modified = false; |
|||
} |
|||
|
|||
m_frame->SetToolID( savedToolID, -1, savedToolMsg ); |
|||
break; |
|||
} |
|||
|
|||
else |
|||
{ |
|||
m_toolMgr->PassEvent(); |
|||
} |
|||
|
|||
controls->SetAutoPan( inDrag ); |
|||
controls->CaptureCursor( inDrag ); |
|||
} |
|||
|
|||
controls->SetAutoPan( false ); |
|||
controls->CaptureCursor( false ); |
|||
m_frame->SetToolID( savedToolID, -1, savedToolMsg ); |
|||
|
|||
if( m_editPoints ) |
|||
{ |
|||
view->Remove( m_editPoints.get() ); |
|||
|
|||
if( modified ) |
|||
m_frame->OnModify(); |
|||
|
|||
m_editPoints.reset(); |
|||
m_frame->GetCanvas()->Refresh(); |
|||
} |
|||
|
|||
return 0; |
|||
} |
|||
|
|||
|
|||
void pinEditedCorner( int editedPointIndex, int minWidth, int minHeight, VECTOR2I& topLeft, |
|||
VECTOR2I& topRight, VECTOR2I& botLeft, VECTOR2I& botRight ) |
|||
{ |
|||
switch( editedPointIndex ) |
|||
{ |
|||
case RECT_TOPLEFT: |
|||
// pin edited point within opposite corner
|
|||
topLeft.x = std::min( topLeft.x, botRight.x - minWidth ); |
|||
topLeft.y = std::min( topLeft.y, botRight.y - minHeight ); |
|||
|
|||
// push edited point edges to adjacent corners
|
|||
topRight.y = topLeft.y; |
|||
botLeft.x = topLeft.x; |
|||
|
|||
break; |
|||
|
|||
case RECT_TOPRIGHT: |
|||
// pin edited point within opposite corner
|
|||
topRight.x = std::max( topRight.x, botLeft.x + minWidth ); |
|||
topRight.y = std::min( topRight.y, botLeft.y - minHeight ); |
|||
|
|||
// push edited point edges to adjacent corners
|
|||
topLeft.y = topRight.y; |
|||
botRight.x = topRight.x; |
|||
|
|||
break; |
|||
|
|||
case RECT_BOTLEFT: |
|||
// pin edited point within opposite corner
|
|||
botLeft.x = std::min( botLeft.x, topRight.x - minWidth ); |
|||
botLeft.y = std::max( botLeft.y, topRight.y + minHeight ); |
|||
|
|||
// push edited point edges to adjacent corners
|
|||
botRight.y = botLeft.y; |
|||
topLeft.x = botLeft.x; |
|||
|
|||
break; |
|||
|
|||
case RECT_BOTRIGHT: |
|||
// pin edited point within opposite corner
|
|||
botRight.x = std::max( botRight.x, topLeft.x + minWidth ); |
|||
botRight.y = std::max( botRight.y, topLeft.y + minHeight ); |
|||
|
|||
// push edited point edges to adjacent corners
|
|||
botLeft.y = botRight.y; |
|||
topRight.x = botRight.x; |
|||
|
|||
break; |
|||
} |
|||
} |
|||
|
|||
|
|||
void POINT_EDITOR::updateItem() const |
|||
{ |
|||
EDA_ITEM* item = m_editPoints->GetParent(); |
|||
|
|||
if( !item ) |
|||
return; |
|||
|
|||
switch( item->Type() ) |
|||
{ |
|||
case LIB_ARC_T: |
|||
{ |
|||
LIB_ARC* arc = (LIB_ARC*) item; |
|||
|
|||
arc->SetPosition( mapCoords( m_editPoints->Point( ARC_CENTER ).GetPosition() ) ); |
|||
arc->SetStart( mapCoords( m_editPoints->Point( ARC_START ).GetPosition() ) ); |
|||
arc->SetEnd( mapCoords( m_editPoints->Point( ARC_END ).GetPosition() ) ); |
|||
break; |
|||
} |
|||
|
|||
case LIB_CIRCLE_T: |
|||
{ |
|||
LIB_CIRCLE* circle = (LIB_CIRCLE*) item; |
|||
|
|||
circle->SetPosition( mapCoords( m_editPoints->Point( CIRC_CENTER ).GetPosition() ) ); |
|||
circle->SetEnd( mapCoords( m_editPoints->Point( CIRC_END ).GetPosition() ) ); |
|||
break; |
|||
} |
|||
|
|||
case LIB_POLYLINE_T: |
|||
{ |
|||
LIB_POLYLINE* lines = (LIB_POLYLINE*) item; |
|||
|
|||
lines->ClearPoints(); |
|||
|
|||
for( int i = 0; i < m_editPoints->PointsSize(); ++i ) |
|||
lines->AddPoint( mapCoords( m_editPoints->Point( i ).GetPosition() ) ); |
|||
|
|||
break; |
|||
} |
|||
|
|||
case LIB_RECTANGLE_T: |
|||
{ |
|||
LIB_RECTANGLE* rect = (LIB_RECTANGLE*) item; |
|||
VECTOR2I topLeft = m_editPoints->Point( RECT_TOPLEFT ).GetPosition(); |
|||
VECTOR2I topRight = m_editPoints->Point( RECT_TOPRIGHT ).GetPosition(); |
|||
VECTOR2I botLeft = m_editPoints->Point( RECT_BOTLEFT ).GetPosition(); |
|||
VECTOR2I botRight = m_editPoints->Point( RECT_BOTRIGHT ).GetPosition(); |
|||
|
|||
pinEditedCorner( getEditedPointIndex(), Mils2iu( 1 ), Mils2iu( 1 ), |
|||
topLeft, topRight, botLeft, botRight ); |
|||
|
|||
rect->SetPosition( (wxPoint) topLeft ); |
|||
rect->SetEnd( (wxPoint) botRight ); |
|||
break; |
|||
} |
|||
|
|||
case SCH_SHEET_T: |
|||
{ |
|||
SCH_SHEET* sheet = (SCH_SHEET*) item; |
|||
VECTOR2I topLeft = m_editPoints->Point( RECT_TOPLEFT ).GetPosition(); |
|||
VECTOR2I topRight = m_editPoints->Point( RECT_TOPRIGHT ).GetPosition(); |
|||
VECTOR2I botLeft = m_editPoints->Point( RECT_BOTLEFT ).GetPosition(); |
|||
VECTOR2I botRight = m_editPoints->Point( RECT_BOTRIGHT ).GetPosition(); |
|||
|
|||
pinEditedCorner( getEditedPointIndex(), sheet->GetMinWidth(), sheet->GetMinHeight(), |
|||
topLeft, topRight, botLeft, botRight ); |
|||
|
|||
sheet->SetPosition( (wxPoint) topLeft ); |
|||
sheet->SetSize( wxSize( botRight.x - topLeft.x, botRight.y - topLeft.y ) ); |
|||
break; |
|||
} |
|||
|
|||
case SCH_LINE_T: |
|||
{ |
|||
SCH_LINE* line = (SCH_LINE*) item; |
|||
|
|||
line->SetStartPoint( (wxPoint) m_editPoints->Point( LINE_START ).GetPosition() ); |
|||
line->SetEndPoint( (wxPoint) m_editPoints->Point( LINE_END ).GetPosition() ); |
|||
|
|||
SCH_LINE* connection = (SCH_LINE*) ( m_editPoints->Point( LINE_START ).GetConnection() ); |
|||
|
|||
if( connection ) |
|||
{ |
|||
if( ( connection->GetFlags() & STARTPOINT ) != 0 ) |
|||
connection->SetStartPoint( line->GetPosition() ); |
|||
else if( ( connection->GetFlags() & ENDPOINT ) != 0 ) |
|||
connection->SetEndPoint( line->GetPosition() ); |
|||
|
|||
getView()->Update( connection, KIGFX::GEOMETRY ); |
|||
} |
|||
|
|||
connection = (SCH_LINE*) ( m_editPoints->Point( LINE_END ).GetConnection() ); |
|||
|
|||
if( connection ) |
|||
{ |
|||
if( ( connection->GetFlags() & STARTPOINT ) != 0 ) |
|||
connection->SetStartPoint( line->GetEndPoint() ); |
|||
else if( ( connection->GetFlags() & ENDPOINT ) != 0 ) |
|||
connection->SetEndPoint( line->GetEndPoint() ); |
|||
|
|||
getView()->Update( connection, KIGFX::GEOMETRY ); |
|||
} |
|||
|
|||
break; |
|||
} |
|||
|
|||
default: |
|||
break; |
|||
} |
|||
|
|||
getView()->Update( item, KIGFX::GEOMETRY ); |
|||
m_frame->SetMsgPanel( item ); |
|||
} |
|||
|
|||
|
|||
void POINT_EDITOR::updatePoints() |
|||
{ |
|||
if( !m_editPoints ) |
|||
return; |
|||
|
|||
EDA_ITEM* item = m_editPoints->GetParent(); |
|||
|
|||
if( !item ) |
|||
return; |
|||
|
|||
switch( item->Type() ) |
|||
{ |
|||
case LIB_ARC_T: |
|||
{ |
|||
LIB_ARC* arc = (LIB_ARC*) item; |
|||
|
|||
m_editPoints->Point( ARC_CENTER ).SetPosition( mapCoords( arc->GetPosition() ) ); |
|||
m_editPoints->Point( ARC_START ).SetPosition( mapCoords( arc->GetStart() ) ); |
|||
m_editPoints->Point( ARC_END ).SetPosition( mapCoords( arc->GetEnd() ) ); |
|||
break; |
|||
} |
|||
|
|||
case LIB_CIRCLE_T: |
|||
{ |
|||
LIB_CIRCLE* circle = (LIB_CIRCLE*) item; |
|||
|
|||
m_editPoints->Point( CIRC_CENTER ).SetPosition( mapCoords( circle->GetPosition() ) ); |
|||
m_editPoints->Point( CIRC_END ).SetPosition( mapCoords( circle->GetEnd() ) ); |
|||
break; |
|||
} |
|||
|
|||
case LIB_POLYLINE_T: |
|||
{ |
|||
LIB_POLYLINE* lines = (LIB_POLYLINE*) item; |
|||
const std::vector<wxPoint>& pts = lines->GetPolyPoints(); |
|||
|
|||
if( m_editPoints->PointsSize() != (unsigned) pts.size() ) |
|||
{ |
|||
getView()->Remove( m_editPoints.get() ); |
|||
m_editedPoint = nullptr; |
|||
m_editPoints = EDIT_POINTS_FACTORY::Make( item, m_frame ); |
|||
getView()->Add(m_editPoints.get() ); |
|||
} |
|||
else |
|||
{ |
|||
for( unsigned i = 0; i < pts.size(); i++ ) |
|||
m_editPoints->Point( i ).SetPosition( mapCoords( pts[i] ) ); |
|||
} |
|||
|
|||
break; |
|||
} |
|||
|
|||
case LIB_RECTANGLE_T: |
|||
{ |
|||
LIB_RECTANGLE* rect = (LIB_RECTANGLE*) item; |
|||
wxPoint topLeft = rect->GetPosition(); |
|||
wxPoint botRight = rect->GetEnd(); |
|||
|
|||
m_editPoints->Point( RECT_TOPLEFT ).SetPosition( mapCoords( topLeft ) ); |
|||
m_editPoints->Point( RECT_TOPRIGHT ).SetPosition( mapCoords( botRight.x, topLeft.y ) ); |
|||
m_editPoints->Point( RECT_BOTLEFT ).SetPosition( mapCoords( topLeft.x, botRight.y ) ); |
|||
m_editPoints->Point( RECT_BOTRIGHT ).SetPosition( mapCoords( botRight ) ); |
|||
break; |
|||
} |
|||
|
|||
case SCH_SHEET_T: |
|||
{ |
|||
SCH_SHEET* sheet = (SCH_SHEET*) item; |
|||
wxPoint topLeft = sheet->GetPosition(); |
|||
wxPoint botRight = sheet->GetPosition() + sheet->GetSize(); |
|||
|
|||
m_editPoints->Point( RECT_TOPLEFT ).SetPosition( topLeft ); |
|||
m_editPoints->Point( RECT_TOPRIGHT ).SetPosition( botRight.x, topLeft.y ); |
|||
m_editPoints->Point( RECT_BOTLEFT ).SetPosition( topLeft.x, botRight.y ); |
|||
m_editPoints->Point( RECT_BOTRIGHT ).SetPosition( botRight ); |
|||
break; |
|||
} |
|||
|
|||
case SCH_LINE_T: |
|||
{ |
|||
SCH_LINE* line = (SCH_LINE*) item; |
|||
|
|||
m_editPoints->Point( LINE_START ).SetPosition( line->GetStartPoint() ); |
|||
m_editPoints->Point( LINE_END ).SetPosition( line->GetEndPoint() ); |
|||
break; |
|||
} |
|||
|
|||
default: |
|||
break; |
|||
} |
|||
|
|||
getView()->Update( m_editPoints.get() ); |
|||
} |
|||
|
|||
|
|||
void POINT_EDITOR::setEditedPoint( EDIT_POINT* aPoint ) |
|||
{ |
|||
KIGFX::VIEW_CONTROLS* controls = getViewControls(); |
|||
|
|||
if( aPoint ) |
|||
{ |
|||
controls->ForceCursorPosition( true, aPoint->GetPosition() ); |
|||
controls->ShowCursor( true ); |
|||
} |
|||
else |
|||
{ |
|||
controls->ShowCursor( false ); |
|||
controls->ForceCursorPosition( false ); |
|||
} |
|||
|
|||
m_editedPoint = aPoint; |
|||
} |
|||
|
|||
|
|||
bool POINT_EDITOR::removeCornerCondition( const SELECTION& ) |
|||
{ |
|||
if( !m_editPoints || !m_editedPoint ) |
|||
return false; |
|||
|
|||
LIB_POLYLINE* polyLine = dynamic_cast<LIB_POLYLINE*>( m_editPoints->GetParent() ); |
|||
|
|||
if( !polyLine || polyLine->GetCornerCount() < 3 ) |
|||
return false; |
|||
|
|||
const std::vector<wxPoint>& pts = polyLine->GetPolyPoints(); |
|||
|
|||
for( int i = 0; i < polyLine->GetCornerCount(); ++i ) |
|||
{ |
|||
if( pts[i] == mapCoords( m_editedPoint->GetPosition() ) ) |
|||
return true; |
|||
} |
|||
|
|||
return false; |
|||
} |
|||
|
|||
|
|||
bool POINT_EDITOR::addCornerCondition( const SELECTION& ) |
|||
{ |
|||
if( !m_editPoints || !m_editedPoint ) |
|||
return false; |
|||
|
|||
LIB_POLYLINE* polyLine = dynamic_cast<LIB_POLYLINE*>( m_editPoints->GetParent() ); |
|||
|
|||
if( !polyLine ) |
|||
return false; |
|||
|
|||
VECTOR2I cursorPos = getViewControls()->GetCursorPosition(); |
|||
double threshold = getView()->ToWorld( EDIT_POINT::POINT_SIZE ); |
|||
|
|||
return polyLine->HitTest( mapCoords( cursorPos ), (int) threshold ); |
|||
} |
|||
|
|||
|
|||
int POINT_EDITOR::addCorner( const TOOL_EVENT& aEvent ) |
|||
{ |
|||
if( !m_editPoints ) |
|||
return 0; |
|||
|
|||
LIB_POLYLINE* polyLine = dynamic_cast<LIB_POLYLINE*>( m_editPoints->GetParent() ); |
|||
|
|||
if( !polyLine ) |
|||
return false; |
|||
|
|||
VECTOR2I cursorPos = getViewControls()->GetCursorPosition( !aEvent.Modifier( MD_ALT ) ); |
|||
polyLine->AddCorner( mapCoords( cursorPos ) ); |
|||
|
|||
m_frame->RefreshItem( polyLine ); |
|||
updatePoints(); |
|||
|
|||
return 0; |
|||
} |
|||
|
|||
|
|||
int POINT_EDITOR::removeCorner( const TOOL_EVENT& aEvent ) |
|||
{ |
|||
if( !m_editPoints || !m_editedPoint ) |
|||
return 0; |
|||
|
|||
LIB_POLYLINE* polyLine = dynamic_cast<LIB_POLYLINE*>( m_editPoints->GetParent() ); |
|||
|
|||
if( !polyLine || polyLine->GetCornerCount() < 3 ) |
|||
return 0; |
|||
|
|||
polyLine->RemoveCorner( getEditedPointIndex() ); |
|||
|
|||
m_frame->RefreshItem( polyLine ); |
|||
updatePoints(); |
|||
|
|||
return 0; |
|||
} |
|||
|
|||
|
|||
int POINT_EDITOR::modifiedSelection( const TOOL_EVENT& aEvent ) |
|||
{ |
|||
updatePoints(); |
|||
return 0; |
|||
} |
|||
|
|||
|
|||
void POINT_EDITOR::saveItemsToUndo() |
|||
{ |
|||
if( m_isLibEdit ) |
|||
{ |
|||
LIB_EDIT_FRAME* editFrame = static_cast<LIB_EDIT_FRAME*>( m_frame ); |
|||
editFrame->SaveCopyInUndoList( m_editPoints->GetParent()->GetParent() ); |
|||
} |
|||
else |
|||
{ |
|||
SCH_EDIT_FRAME* editFrame = static_cast<SCH_EDIT_FRAME*>( m_frame ); |
|||
editFrame->SaveCopyInUndoList( (SCH_ITEM*) m_editPoints->GetParent(), UR_CHANGED ); |
|||
|
|||
if( m_editPoints->GetParent()->Type() == SCH_LINE_T ) |
|||
{ |
|||
EDA_ITEM* connection = m_editPoints->Point( LINE_START ).GetConnection(); |
|||
|
|||
if( connection ) |
|||
editFrame->SaveCopyInUndoList( (SCH_ITEM*) connection, UR_CHANGED, true ); |
|||
|
|||
connection = m_editPoints->Point( LINE_END ).GetConnection(); |
|||
|
|||
if( connection ) |
|||
editFrame->SaveCopyInUndoList( (SCH_ITEM*) connection, UR_CHANGED, true ); |
|||
} |
|||
} |
|||
} |
|||
|
|||
|
|||
void POINT_EDITOR::rollbackFromUndo() |
|||
{ |
|||
if( m_isLibEdit ) |
|||
static_cast<LIB_EDIT_FRAME*>( m_frame )->RollbackPartFromUndo(); |
|||
else |
|||
static_cast<SCH_EDIT_FRAME*>( m_frame )->RollbackSchematicFromUndo(); |
|||
} |
|||
|
|||
|
|||
void POINT_EDITOR::setTransitions() |
|||
{ |
|||
Go( &POINT_EDITOR::addCorner, SCH_ACTIONS::pointEditorAddCorner.MakeEvent() ); |
|||
Go( &POINT_EDITOR::removeCorner, SCH_ACTIONS::pointEditorRemoveCorner.MakeEvent() ); |
|||
Go( &POINT_EDITOR::modifiedSelection, EVENTS::SelectedItemsModified ); |
|||
Go( &POINT_EDITOR::Main, EVENTS::SelectedEvent ); |
|||
} |
|||
|
|||
|
|||
@ -0,0 +1,108 @@ |
|||
/* |
|||
* This program source code file is part of KiCad, a free EDA CAD application. |
|||
* |
|||
* Copyright (C) 2019 KiCad Developers, see AUTHORS.txt for contributors. |
|||
* |
|||
* This program is free software; you can redistribute it and/or |
|||
* modify it under the terms of the GNU General Public License |
|||
* as published by the Free Software Foundation; either version 2 |
|||
* of the License, or (at your option) any later version. |
|||
* |
|||
* This program is distributed in the hope that it will be useful, |
|||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
* GNU General Public License for more details. |
|||
* |
|||
* You should have received a copy of the GNU General Public License |
|||
* along with this program; if not, you may find one here: |
|||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html |
|||
* or you may search the http://www.gnu.org website for the version 2 license, |
|||
* or you may write to the Free Software Foundation, Inc., |
|||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA |
|||
*/ |
|||
|
|||
#ifndef SCH_POINT_EDITOR_H |
|||
#define SCH_POINT_EDITOR_H |
|||
|
|||
#include <tool/tool_interactive.h> |
|||
#include <tool/edit_points.h> |
|||
#include <tool/selection.h> |
|||
|
|||
class SCH_SELECTION_TOOL; |
|||
class SCH_BASE_FRAME; |
|||
|
|||
/** |
|||
* Class SCH_POINT_EDITOR |
|||
* |
|||
* Tool that displays edit points allowing to modify items by dragging the points. |
|||
*/ |
|||
class POINT_EDITOR : public TOOL_INTERACTIVE |
|||
{ |
|||
public: |
|||
POINT_EDITOR(); |
|||
|
|||
/// @copydoc TOOL_INTERACTIVE::Reset() |
|||
void Reset( RESET_REASON aReason ) override; |
|||
|
|||
/// @copydoc TOOL_INTERACTIVE::Init() |
|||
bool Init() override; |
|||
|
|||
int Main( const TOOL_EVENT& aEvent ); |
|||
|
|||
///> Sets up handlers for various events. |
|||
void setTransitions() override; |
|||
|
|||
private: |
|||
///> Updates item's points with edit points. |
|||
void updateItem() const; |
|||
|
|||
///> Updates edit points with item's points. |
|||
void updatePoints(); |
|||
|
|||
///> Updates which point is being edited. |
|||
void updateEditedPoint( const TOOL_EVENT& aEvent ); |
|||
|
|||
///> Sets the current point being edited. NULL means none. |
|||
void setEditedPoint( EDIT_POINT* aPoint ); |
|||
|
|||
///> Returns true if aPoint is the currently modified point. |
|||
inline bool isModified( const EDIT_POINT& aPoint ) const |
|||
{ |
|||
return m_editedPoint == &aPoint; |
|||
} |
|||
|
|||
inline int getEditedPointIndex() const |
|||
{ |
|||
for( int i = 0; i < m_editPoints->PointsSize(); ++i ) |
|||
{ |
|||
if( m_editedPoint == &m_editPoints->Point( i ) ) |
|||
return i; |
|||
} |
|||
|
|||
return wxNOT_FOUND; |
|||
} |
|||
|
|||
bool addCornerCondition( const SELECTION& aSelection ); |
|||
bool removeCornerCondition( const SELECTION& aSelection ); |
|||
|
|||
/// TOOL_ACTION handlers |
|||
int addCorner( const TOOL_EVENT& aEvent ); |
|||
int removeCorner( const TOOL_EVENT& aEvent ); |
|||
int modifiedSelection( const TOOL_EVENT& aEvent ); |
|||
|
|||
void saveItemsToUndo(); |
|||
void rollbackFromUndo(); |
|||
|
|||
private: |
|||
SCH_BASE_FRAME* m_frame; |
|||
SCH_SELECTION_TOOL* m_selectionTool; |
|||
bool m_isLibEdit; |
|||
|
|||
///> Currently edited point, NULL if there is none. |
|||
EDIT_POINT* m_editedPoint; |
|||
|
|||
///> Currently available edit points. |
|||
std::shared_ptr<EDIT_POINTS> m_editPoints; |
|||
}; |
|||
|
|||
#endif // SCH_POINT_EDITOR_H |
|||
Write
Preview
Loading…
Cancel
Save
Reference in new issue