You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

850 lines
26 KiB

6 years ago
  1. /*
  2. * This program source code file is part of KiCad, a free EDA CAD application.
  3. *
  4. * Copyright (C) 2019 CERN
  5. * Copyright (C) 2019-2021 KiCad Developers, see AUTHORS.txt for contributors.
  6. *
  7. * This program is free software; you can redistribute it and/or
  8. * modify it under the terms of the GNU General Public License
  9. * as published by the Free Software Foundation; either version 2
  10. * of the License, or (at your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License
  18. * along with this program; if not, you may find one here:
  19. * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
  20. * or you may search the http://www.gnu.org website for the version 2 license,
  21. * or you may write to the Free Software Foundation, Inc.,
  22. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
  23. */
  24. #include <tool/picker_tool.h>
  25. #include <tools/ee_selection_tool.h>
  26. #include <tools/symbol_editor_pin_tool.h>
  27. #include <tools/symbol_editor_drawing_tools.h>
  28. #include <tools/symbol_editor_move_tool.h>
  29. #include <ee_actions.h>
  30. #include <bitmaps.h>
  31. #include <string_utils.h>
  32. #include <symbol_edit_frame.h>
  33. #include <dialogs/dialog_lib_shape_properties.h>
  34. #include <dialogs/dialog_lib_text_properties.h>
  35. #include <dialogs/dialog_field_properties.h>
  36. #include <dialogs/dialog_lib_symbol_properties.h>
  37. #include <dialogs/dialog_lib_edit_pin_table.h>
  38. #include <dialogs/dialog_update_symbol_fields.h>
  39. #include <sch_plugins/kicad/sch_sexpr_plugin.h>
  40. #include <lib_text.h>
  41. #include "symbol_editor_edit_tool.h"
  42. #include "dialog_lib_textbox_properties.h"
  43. #include "lib_textbox.h"
  44. #include <math/util.h> // for KiROUND
  45. SYMBOL_EDITOR_EDIT_TOOL::SYMBOL_EDITOR_EDIT_TOOL() :
  46. EE_TOOL_BASE( "eeschema.SymbolEditTool" ),
  47. m_pickerItem( nullptr )
  48. {
  49. }
  50. bool SYMBOL_EDITOR_EDIT_TOOL::Init()
  51. {
  52. EE_TOOL_BASE::Init();
  53. SYMBOL_EDITOR_DRAWING_TOOLS* drawingTools = m_toolMgr->GetTool<SYMBOL_EDITOR_DRAWING_TOOLS>();
  54. SYMBOL_EDITOR_MOVE_TOOL* moveTool = m_toolMgr->GetTool<SYMBOL_EDITOR_MOVE_TOOL>();
  55. wxASSERT_MSG( drawingTools, "eeschema.SymbolDrawing tool is not available" );
  56. auto haveSymbolCondition =
  57. [&]( const SELECTION& sel )
  58. {
  59. return m_isSymbolEditor &&
  60. static_cast<SYMBOL_EDIT_FRAME*>( m_frame )->GetCurSymbol();
  61. };
  62. auto canEdit =
  63. [&]( const SELECTION& sel )
  64. {
  65. SYMBOL_EDIT_FRAME* editor = static_cast<SYMBOL_EDIT_FRAME*>( m_frame );
  66. wxCHECK( editor, false );
  67. if( !editor->IsSymbolEditable() )
  68. return false;
  69. if( editor->IsSymbolAlias() )
  70. {
  71. for( EDA_ITEM* item : sel )
  72. {
  73. if( item->Type() != LIB_FIELD_T )
  74. return false;
  75. }
  76. }
  77. return true;
  78. };
  79. // Add edit actions to the move tool menu
  80. if( moveTool )
  81. {
  82. CONDITIONAL_MENU& moveMenu = moveTool->GetToolMenu().GetMenu();
  83. moveMenu.AddSeparator( 200 );
  84. moveMenu.AddItem( EE_ACTIONS::rotateCCW, canEdit && EE_CONDITIONS::NotEmpty, 200 );
  85. moveMenu.AddItem( EE_ACTIONS::rotateCW, canEdit && EE_CONDITIONS::NotEmpty, 200 );
  86. moveMenu.AddItem( EE_ACTIONS::mirrorV, canEdit && EE_CONDITIONS::NotEmpty, 200 );
  87. moveMenu.AddItem( EE_ACTIONS::mirrorH, canEdit && EE_CONDITIONS::NotEmpty, 200 );
  88. moveMenu.AddItem( EE_ACTIONS::properties, canEdit && EE_CONDITIONS::Count( 1 ), 200 );
  89. moveMenu.AddSeparator( 300 );
  90. moveMenu.AddItem( ACTIONS::cut, EE_CONDITIONS::IdleSelection, 300 );
  91. moveMenu.AddItem( ACTIONS::copy, EE_CONDITIONS::IdleSelection, 300 );
  92. moveMenu.AddItem( ACTIONS::duplicate, canEdit && EE_CONDITIONS::NotEmpty, 300 );
  93. moveMenu.AddItem( ACTIONS::doDelete, canEdit && EE_CONDITIONS::NotEmpty, 200 );
  94. moveMenu.AddSeparator( 400 );
  95. moveMenu.AddItem( ACTIONS::selectAll, haveSymbolCondition, 400 );
  96. }
  97. // Add editing actions to the drawing tool menu
  98. CONDITIONAL_MENU& drawMenu = drawingTools->GetToolMenu().GetMenu();
  99. drawMenu.AddSeparator( 200 );
  100. drawMenu.AddItem( EE_ACTIONS::rotateCCW, canEdit && EE_CONDITIONS::IdleSelection, 200 );
  101. drawMenu.AddItem( EE_ACTIONS::rotateCW, canEdit && EE_CONDITIONS::IdleSelection, 200 );
  102. drawMenu.AddItem( EE_ACTIONS::mirrorV, canEdit && EE_CONDITIONS::IdleSelection, 200 );
  103. drawMenu.AddItem( EE_ACTIONS::mirrorH, canEdit && EE_CONDITIONS::IdleSelection, 200 );
  104. drawMenu.AddItem( EE_ACTIONS::properties, canEdit && EE_CONDITIONS::Count( 1 ), 200 );
  105. // Add editing actions to the selection tool menu
  106. CONDITIONAL_MENU& selToolMenu = m_selectionTool->GetToolMenu().GetMenu();
  107. selToolMenu.AddItem( EE_ACTIONS::rotateCCW, canEdit && EE_CONDITIONS::NotEmpty, 200 );
  108. selToolMenu.AddItem( EE_ACTIONS::rotateCW, canEdit && EE_CONDITIONS::NotEmpty, 200 );
  109. selToolMenu.AddItem( EE_ACTIONS::mirrorV, canEdit && EE_CONDITIONS::NotEmpty, 200 );
  110. selToolMenu.AddItem( EE_ACTIONS::mirrorH, canEdit && EE_CONDITIONS::NotEmpty, 200 );
  111. selToolMenu.AddItem( EE_ACTIONS::properties, canEdit && EE_CONDITIONS::Count( 1 ), 200 );
  112. selToolMenu.AddSeparator( 300 );
  113. selToolMenu.AddItem( ACTIONS::cut, EE_CONDITIONS::IdleSelection, 300 );
  114. selToolMenu.AddItem( ACTIONS::copy, EE_CONDITIONS::IdleSelection, 300 );
  115. selToolMenu.AddItem( ACTIONS::paste, canEdit && EE_CONDITIONS::Idle, 300 );
  116. selToolMenu.AddItem( ACTIONS::duplicate, canEdit && EE_CONDITIONS::NotEmpty, 300 );
  117. selToolMenu.AddItem( ACTIONS::doDelete, canEdit && EE_CONDITIONS::NotEmpty, 300 );
  118. selToolMenu.AddSeparator( 400 );
  119. selToolMenu.AddItem( ACTIONS::selectAll, haveSymbolCondition, 400 );
  120. return true;
  121. }
  122. int SYMBOL_EDITOR_EDIT_TOOL::Rotate( const TOOL_EVENT& aEvent )
  123. {
  124. EE_SELECTION& selection = m_selectionTool->RequestSelection();
  125. if( selection.GetSize() == 0 )
  126. return 0;
  127. VECTOR2I rotPoint;
  128. bool ccw = ( aEvent.Matches( EE_ACTIONS::rotateCCW.MakeEvent() ) );
  129. LIB_ITEM* item = static_cast<LIB_ITEM*>( selection.Front() );
  130. if( !item->IsMoving() )
  131. saveCopyInUndoList( m_frame->GetCurSymbol(), UNDO_REDO::LIBEDIT );
  132. if( selection.GetSize() == 1 )
  133. rotPoint = item->GetPosition();
  134. else
  135. rotPoint = m_frame->GetNearestHalfGridPosition( mapCoords( selection.GetCenter() ) );
  136. for( unsigned ii = 0; ii < selection.GetSize(); ii++ )
  137. {
  138. item = static_cast<LIB_ITEM*>( selection.GetItem( ii ) );
  139. item->Rotate( rotPoint, ccw );
  140. m_frame->UpdateItem( item, false, true );
  141. }
  142. if( item->IsMoving() )
  143. {
  144. m_toolMgr->RunAction( ACTIONS::refreshPreview, true );
  145. }
  146. else
  147. {
  148. m_toolMgr->PostEvent( EVENTS::SelectedItemsModified );
  149. if( selection.IsHover() )
  150. m_toolMgr->RunAction( EE_ACTIONS::clearSelection, true );
  151. m_frame->OnModify();
  152. }
  153. return 0;
  154. }
  155. int SYMBOL_EDITOR_EDIT_TOOL::Mirror( const TOOL_EVENT& aEvent )
  156. {
  157. EE_SELECTION& selection = m_selectionTool->RequestSelection();
  158. if( selection.GetSize() == 0 )
  159. return 0;
  160. VECTOR2I mirrorPoint;
  161. bool xAxis = ( aEvent.Matches( EE_ACTIONS::mirrorV.MakeEvent() ) );
  162. LIB_ITEM* item = static_cast<LIB_ITEM*>( selection.Front() );
  163. if( !item->IsMoving() )
  164. saveCopyInUndoList( m_frame->GetCurSymbol(), UNDO_REDO::LIBEDIT );
  165. if( selection.GetSize() == 1 )
  166. mirrorPoint = item->GetPosition();
  167. else
  168. mirrorPoint = m_frame->GetNearestHalfGridPosition( mapCoords( selection.GetCenter() ) );
  169. for( unsigned ii = 0; ii < selection.GetSize(); ii++ )
  170. {
  171. item = static_cast<LIB_ITEM*>( selection.GetItem( ii ) );
  172. if( xAxis )
  173. item->MirrorVertical( mirrorPoint );
  174. else
  175. item->MirrorHorizontal( mirrorPoint );
  176. m_frame->UpdateItem( item, false, true );
  177. }
  178. m_toolMgr->PostEvent( EVENTS::SelectedItemsModified );
  179. if( item->IsMoving() )
  180. {
  181. m_toolMgr->RunAction( ACTIONS::refreshPreview, true );
  182. }
  183. else
  184. {
  185. if( selection.IsHover() )
  186. m_toolMgr->RunAction( EE_ACTIONS::clearSelection, true );
  187. m_frame->OnModify();
  188. }
  189. return 0;
  190. }
  191. static KICAD_T nonFields[] =
  192. {
  193. LIB_SYMBOL_T,
  194. LIB_SHAPE_T,
  195. LIB_TEXT_T,
  196. LIB_TEXTBOX_T,
  197. LIB_PIN_T,
  198. EOT
  199. };
  200. int SYMBOL_EDITOR_EDIT_TOOL::DoDelete( const TOOL_EVENT& aEvent )
  201. {
  202. LIB_SYMBOL *symbol = m_frame->GetCurSymbol();
  203. std::deque<EDA_ITEM*> items = m_selectionTool->RequestSelection( nonFields ).GetItems();
  204. if( items.empty() )
  205. return 0;
  206. // Don't leave a freed pointer in the selection
  207. m_toolMgr->RunAction( EE_ACTIONS::clearSelection, true );
  208. saveCopyInUndoList( symbol, UNDO_REDO::LIBEDIT );
  209. std::set<LIB_ITEM *> toDelete;
  210. for( EDA_ITEM* item : items )
  211. {
  212. if( item->Type() == LIB_PIN_T )
  213. {
  214. LIB_PIN* pin = static_cast<LIB_PIN*>( item );
  215. VECTOR2I pos = pin->GetPosition();
  216. toDelete.insert( pin );
  217. // when pin editing is synchronized, pins in the same position, with the same name
  218. // in different units are also removed. But only one pin per unit (matching)
  219. if( m_frame->SynchronizePins() )
  220. {
  221. std::vector<bool> got_unit( symbol->GetUnitCount() + 1 );
  222. got_unit[pin->GetUnit()] = true;
  223. int curr_convert = pin->GetConvert();
  224. ELECTRICAL_PINTYPE etype = pin->GetType();
  225. wxString name = pin->GetName();
  226. LIB_PIN* next_pin = symbol->GetNextPin();
  227. while( next_pin != nullptr )
  228. {
  229. pin = next_pin;
  230. next_pin = symbol->GetNextPin( pin );
  231. if( got_unit[pin->GetUnit()] )
  232. continue;
  233. if( pin->GetPosition() != pos )
  234. continue;
  235. if( pin->GetConvert() != curr_convert )
  236. continue;
  237. if( pin->GetType() != etype )
  238. continue;
  239. if( pin->GetName() != name )
  240. continue;
  241. toDelete.insert( pin );
  242. got_unit[pin->GetUnit()] = true;
  243. }
  244. }
  245. }
  246. else
  247. {
  248. toDelete.insert( (LIB_ITEM*) item );
  249. }
  250. }
  251. for( LIB_ITEM* item : toDelete )
  252. symbol->RemoveDrawItem( item );
  253. m_frame->RebuildView();
  254. m_frame->OnModify();
  255. return 0;
  256. }
  257. #define HITTEST_THRESHOLD_PIXELS 5
  258. int SYMBOL_EDITOR_EDIT_TOOL::DeleteItemCursor( const TOOL_EVENT& aEvent )
  259. {
  260. std::string tool = aEvent.GetCommandStr().get();
  261. PICKER_TOOL* picker = m_toolMgr->GetTool<PICKER_TOOL>();
  262. m_toolMgr->RunAction( EE_ACTIONS::clearSelection, true );
  263. m_pickerItem = nullptr;
  264. // Deactivate other tools; particularly important if another PICKER is currently running
  265. Activate();
  266. picker->SetCursor( KICURSOR::REMOVE );
  267. picker->SetClickHandler(
  268. [this]( const VECTOR2D& aPosition ) -> bool
  269. {
  270. if( m_pickerItem )
  271. {
  272. EE_SELECTION_TOOL* selectionTool = m_toolMgr->GetTool<EE_SELECTION_TOOL>();
  273. selectionTool->UnbrightenItem( m_pickerItem );
  274. selectionTool->AddItemToSel( m_pickerItem, true /*quiet mode*/ );
  275. m_toolMgr->RunAction( ACTIONS::doDelete, true );
  276. m_pickerItem = nullptr;
  277. }
  278. return true;
  279. } );
  280. picker->SetMotionHandler(
  281. [this]( const VECTOR2D& aPos )
  282. {
  283. EE_SELECTION_TOOL* selectionTool = m_toolMgr->GetTool<EE_SELECTION_TOOL>();
  284. EE_COLLECTOR collector;
  285. selectionTool->CollectHits( collector, aPos, nonFields );
  286. // Remove unselectable items
  287. for( int i = collector.GetCount() - 1; i >= 0; --i )
  288. {
  289. if( !selectionTool->Selectable( collector[ i ] ) )
  290. collector.Remove( i );
  291. }
  292. if( collector.GetCount() > 1 )
  293. selectionTool->GuessSelectionCandidates( collector, aPos );
  294. EDA_ITEM* item = collector.GetCount() == 1 ? collector[ 0 ] : nullptr;
  295. if( m_pickerItem != item )
  296. {
  297. if( m_pickerItem )
  298. selectionTool->UnbrightenItem( m_pickerItem );
  299. m_pickerItem = item;
  300. if( m_pickerItem )
  301. selectionTool->BrightenItem( m_pickerItem );
  302. }
  303. } );
  304. picker->SetFinalizeHandler(
  305. [this]( const int& aFinalState )
  306. {
  307. if( m_pickerItem )
  308. m_toolMgr->GetTool<EE_SELECTION_TOOL>()->UnbrightenItem( m_pickerItem );
  309. // Wake the selection tool after exiting to ensure the cursor gets updated
  310. m_toolMgr->RunAction( EE_ACTIONS::selectionActivate, false );
  311. } );
  312. m_toolMgr->RunAction( ACTIONS::pickerTool, true, &tool );
  313. return 0;
  314. }
  315. int SYMBOL_EDITOR_EDIT_TOOL::Properties( const TOOL_EVENT& aEvent )
  316. {
  317. EE_SELECTION& selection = m_selectionTool->RequestSelection();
  318. if( selection.Empty() || aEvent.IsAction( &EE_ACTIONS::symbolProperties ) )
  319. {
  320. if( m_frame->GetCurSymbol() )
  321. editSymbolProperties();
  322. }
  323. else if( selection.Size() == 1 )
  324. {
  325. LIB_ITEM* item = (LIB_ITEM*) selection.Front();
  326. // Save copy for undo if not in edit (edit command already handle the save copy)
  327. if( item->GetEditFlags() == 0 )
  328. saveCopyInUndoList( item->GetParent(), UNDO_REDO::LIBEDIT );
  329. switch( item->Type() )
  330. {
  331. case LIB_PIN_T:
  332. {
  333. SYMBOL_EDITOR_PIN_TOOL* pinTool = m_toolMgr->GetTool<SYMBOL_EDITOR_PIN_TOOL>();
  334. if( pinTool )
  335. pinTool->EditPinProperties( (LIB_PIN*) item );
  336. }
  337. break;
  338. case LIB_SHAPE_T:
  339. editShapeProperties( item );
  340. break;
  341. case LIB_TEXT_T:
  342. editTextProperties( item );
  343. break;
  344. case LIB_TEXTBOX_T:
  345. editTextBoxProperties( item );
  346. break;
  347. case LIB_FIELD_T:
  348. editFieldProperties( (LIB_FIELD*) item );
  349. break;
  350. default:
  351. wxFAIL_MSG( wxT( "Unhandled item <" ) + item->GetClass() + wxT( ">" ) );
  352. break;
  353. }
  354. }
  355. if( selection.IsHover() )
  356. m_toolMgr->RunAction( EE_ACTIONS::clearSelection, true );
  357. else
  358. m_toolMgr->PostEvent( EVENTS::SelectedItemsModified );
  359. return 0;
  360. }
  361. void SYMBOL_EDITOR_EDIT_TOOL::editShapeProperties( LIB_ITEM* aItem )
  362. {
  363. DIALOG_LIB_SHAPE_PROPERTIES dlg( m_frame, aItem );
  364. if( dlg.ShowModal() != wxID_OK )
  365. return;
  366. updateItem( aItem, true );
  367. m_frame->GetCanvas()->Refresh();
  368. m_frame->OnModify();
  369. SYMBOL_EDITOR_DRAWING_TOOLS* drawingTools = m_toolMgr->GetTool<SYMBOL_EDITOR_DRAWING_TOOLS>();
  370. drawingTools->SetDrawSpecificConvert( !dlg.GetApplyToAllConversions() );
  371. drawingTools->SetDrawSpecificUnit( !dlg.GetApplyToAllUnits() );
  372. std::vector<MSG_PANEL_ITEM> items;
  373. aItem->GetMsgPanelInfo( m_frame, items );
  374. m_frame->SetMsgPanel( items );
  375. }
  376. void SYMBOL_EDITOR_EDIT_TOOL::editTextProperties( LIB_ITEM* aItem )
  377. {
  378. if ( aItem->Type() != LIB_TEXT_T )
  379. return;
  380. DIALOG_LIB_TEXT_PROPERTIES dlg( m_frame, static_cast<LIB_TEXT*>( aItem ) );
  381. if( dlg.ShowModal() != wxID_OK )
  382. return;
  383. updateItem( aItem, true );
  384. m_frame->GetCanvas()->Refresh();
  385. m_frame->OnModify( );
  386. }
  387. void SYMBOL_EDITOR_EDIT_TOOL::editTextBoxProperties( LIB_ITEM* aItem )
  388. {
  389. if ( aItem->Type() != LIB_TEXTBOX_T )
  390. return;
  391. DIALOG_LIB_TEXTBOX_PROPERTIES dlg( m_frame, static_cast<LIB_TEXTBOX*>( aItem ) );
  392. if( dlg.ShowModal() != wxID_OK )
  393. return;
  394. updateItem( aItem, true );
  395. m_frame->GetCanvas()->Refresh();
  396. m_frame->OnModify( );
  397. }
  398. void SYMBOL_EDITOR_EDIT_TOOL::editFieldProperties( LIB_FIELD* aField )
  399. {
  400. if( aField == nullptr )
  401. return;
  402. wxString caption;
  403. LIB_SYMBOL* parent = aField->GetParent();
  404. wxCHECK( parent, /* void */ );
  405. // Editing the symbol value field is equivalent to creating a new symbol based on the
  406. // current symbol. Set the dialog message to inform the user.
  407. if( aField->GetId() == VALUE_FIELD )
  408. caption = _( "Edit Symbol Name" );
  409. else if( aField->GetId() < MANDATORY_FIELDS )
  410. caption.Printf( _( "Edit %s Field" ), TitleCaps( aField->GetName() ) );
  411. else
  412. caption.Printf( _( "Edit '%s' Field" ), aField->GetName() );
  413. DIALOG_LIB_FIELD_PROPERTIES dlg( m_frame, caption, aField );
  414. // The dialog may invoke a kiway player for footprint fields
  415. // so we must use a quasimodal dialog.
  416. if( dlg.ShowQuasiModal() != wxID_OK )
  417. return;
  418. wxString newFieldValue = EscapeString( dlg.GetText(), CTX_LIBID );
  419. wxString oldFieldValue = aField->GetFullText( m_frame->GetUnit() );
  420. bool renamed = aField->GetId() == VALUE_FIELD && newFieldValue != oldFieldValue;
  421. if( renamed )
  422. saveCopyInUndoList( parent, UNDO_REDO::LIB_RENAME );
  423. else
  424. saveCopyInUndoList( parent, UNDO_REDO::LIBEDIT );
  425. dlg.UpdateField( aField );
  426. if( renamed )
  427. {
  428. parent->SetName( newFieldValue );
  429. m_frame->UpdateAfterSymbolProperties( &oldFieldValue );
  430. }
  431. else
  432. {
  433. updateItem( aField, true );
  434. m_frame->GetCanvas()->Refresh();
  435. m_frame->OnModify();
  436. m_frame->UpdateSymbolMsgPanelInfo();
  437. }
  438. }
  439. void SYMBOL_EDITOR_EDIT_TOOL::editSymbolProperties()
  440. {
  441. LIB_SYMBOL* symbol = m_frame->GetCurSymbol();
  442. bool partLocked = symbol->UnitsLocked();
  443. m_toolMgr->RunAction( ACTIONS::cancelInteractive, true );
  444. m_toolMgr->RunAction( EE_ACTIONS::clearSelection, true );
  445. DIALOG_LIB_SYMBOL_PROPERTIES dlg( m_frame, symbol );
  446. // This dialog itself subsequently can invoke a KIWAY_PLAYER as a quasimodal
  447. // frame. Therefore this dialog as a modal frame parent, MUST be run under
  448. // quasimodal mode for the quasimodal frame support to work. So don't use
  449. // the QUASIMODAL macros here.
  450. if( dlg.ShowQuasiModal() != wxID_OK )
  451. return;
  452. m_frame->OnModify();
  453. // if m_UnitSelectionLocked has changed, set some edit options or defaults
  454. // to the best value
  455. if( partLocked != symbol->UnitsLocked() )
  456. {
  457. SYMBOL_EDITOR_DRAWING_TOOLS* tools = m_toolMgr->GetTool<SYMBOL_EDITOR_DRAWING_TOOLS>();
  458. // Enable synchronized pin edit mode for symbols with interchangeable units
  459. m_frame->m_SyncPinEdit = !symbol->UnitsLocked();
  460. // also set default edit options to the better value
  461. // Usually if units are locked, graphic items are specific to each unit
  462. // and if units are interchangeable, graphic items are common to units
  463. tools->SetDrawSpecificUnit( symbol->UnitsLocked() );
  464. }
  465. }
  466. int SYMBOL_EDITOR_EDIT_TOOL::PinTable( const TOOL_EVENT& aEvent )
  467. {
  468. LIB_SYMBOL* symbol = m_frame->GetCurSymbol();
  469. if( !symbol )
  470. return 0;
  471. m_toolMgr->RunAction( EE_ACTIONS::clearSelection, true );
  472. saveCopyInUndoList( symbol, UNDO_REDO::LIBEDIT );
  473. DIALOG_LIB_EDIT_PIN_TABLE dlg( m_frame, symbol );
  474. if( dlg.ShowModal() == wxID_CANCEL )
  475. return -1;
  476. m_frame->RebuildView();
  477. m_frame->OnModify();
  478. return 0;
  479. }
  480. int SYMBOL_EDITOR_EDIT_TOOL::UpdateSymbolFields( const TOOL_EVENT& aEvent )
  481. {
  482. LIB_SYMBOL* symbol = m_frame->GetCurSymbol();
  483. if( !symbol )
  484. return 0;
  485. if( !symbol->IsAlias() )
  486. {
  487. m_frame->ShowInfoBarError( _( "Symbol is not derived from another symbol." ) );
  488. }
  489. else
  490. {
  491. DIALOG_UPDATE_SYMBOL_FIELDS dlg( m_frame, symbol );
  492. if( dlg.ShowModal() == wxID_CANCEL )
  493. return -1;
  494. }
  495. return 0;
  496. }
  497. int SYMBOL_EDITOR_EDIT_TOOL::Undo( const TOOL_EVENT& aEvent )
  498. {
  499. m_frame->GetSymbolFromUndoList();
  500. EE_SELECTION_TOOL* selTool = m_toolMgr->GetTool<EE_SELECTION_TOOL>();
  501. selTool->RebuildSelection();
  502. return 0;
  503. }
  504. int SYMBOL_EDITOR_EDIT_TOOL::Redo( const TOOL_EVENT& aEvent )
  505. {
  506. m_frame->GetSymbolFromRedoList();
  507. EE_SELECTION_TOOL* selTool = m_toolMgr->GetTool<EE_SELECTION_TOOL>();
  508. selTool->RebuildSelection();
  509. return 0;
  510. }
  511. int SYMBOL_EDITOR_EDIT_TOOL::Cut( const TOOL_EVENT& aEvent )
  512. {
  513. int retVal = Copy( aEvent );
  514. if( retVal == 0 )
  515. retVal = DoDelete( aEvent );
  516. return retVal;
  517. }
  518. int SYMBOL_EDITOR_EDIT_TOOL::Copy( const TOOL_EVENT& aEvent )
  519. {
  520. LIB_SYMBOL* symbol = m_frame->GetCurSymbol();
  521. EE_SELECTION& selection = m_selectionTool->RequestSelection( nonFields );
  522. if( !symbol || !selection.GetSize() )
  523. return 0;
  524. for( LIB_ITEM& item : symbol->GetDrawItems() )
  525. {
  526. if( item.Type() == LIB_FIELD_T )
  527. continue;
  528. wxASSERT( !item.HasFlag( STRUCT_DELETED ) );
  529. if( !item.IsSelected() )
  530. item.SetFlags( STRUCT_DELETED );
  531. }
  532. LIB_SYMBOL* partCopy = new LIB_SYMBOL( *symbol );
  533. STRING_FORMATTER formatter;
  534. SCH_SEXPR_PLUGIN::FormatLibSymbol( partCopy, formatter );
  535. delete partCopy;
  536. for( LIB_ITEM& item : symbol->GetDrawItems() )
  537. item.ClearFlags( STRUCT_DELETED );
  538. if( m_toolMgr->SaveClipboard( formatter.GetString() ) )
  539. return 0;
  540. else
  541. return -1;
  542. }
  543. int SYMBOL_EDITOR_EDIT_TOOL::Paste( const TOOL_EVENT& aEvent )
  544. {
  545. LIB_SYMBOL* symbol = m_frame->GetCurSymbol();
  546. if( !symbol || symbol->IsAlias() )
  547. return 0;
  548. std::string text_utf8 = m_toolMgr->GetClipboardUTF8();
  549. STRING_LINE_READER reader( text_utf8, "Clipboard" );
  550. LIB_SYMBOL* newPart;
  551. try
  552. {
  553. newPart = SCH_SEXPR_PLUGIN::ParseLibSymbol( reader );
  554. }
  555. catch( IO_ERROR& )
  556. {
  557. // If it's not a symbol then paste as text
  558. newPart = new LIB_SYMBOL( "dummy_part" );
  559. LIB_TEXT* newText = new LIB_TEXT( newPart );
  560. newText->SetText( wxString::FromUTF8( text_utf8.c_str() ) );
  561. newPart->AddDrawItem( newText );
  562. }
  563. if( !newPart )
  564. return -1;
  565. m_frame->SaveCopyInUndoList( symbol );
  566. m_selectionTool->ClearSelection();
  567. for( LIB_ITEM& item : symbol->GetDrawItems() )
  568. item.ClearFlags( IS_NEW | IS_PASTED | SELECTED );
  569. for( LIB_ITEM& item : newPart->GetDrawItems() )
  570. {
  571. if( item.Type() == LIB_FIELD_T )
  572. continue;
  573. LIB_ITEM* newItem = (LIB_ITEM*) item.Clone();
  574. newItem->SetParent( symbol );
  575. newItem->SetFlags( IS_NEW | IS_PASTED | SELECTED );
  576. newItem->SetUnit( newItem->GetUnit() ? m_frame->GetUnit() : 0 );
  577. newItem->SetConvert( newItem->GetConvert() ? m_frame->GetConvert() : 0 );
  578. symbol->AddDrawItem( newItem );
  579. getView()->Add( newItem );
  580. }
  581. delete newPart;
  582. m_selectionTool->RebuildSelection();
  583. EE_SELECTION& selection = m_selectionTool->GetSelection();
  584. if( !selection.Empty() )
  585. {
  586. selection.SetReferencePoint( getViewControls()->GetCursorPosition( true ) );
  587. m_toolMgr->RunAction( EE_ACTIONS::move, false );
  588. }
  589. return 0;
  590. }
  591. int SYMBOL_EDITOR_EDIT_TOOL::Duplicate( const TOOL_EVENT& aEvent )
  592. {
  593. LIB_SYMBOL* symbol = m_frame->GetCurSymbol();
  594. EE_SELECTION& selection = m_selectionTool->RequestSelection( nonFields );
  595. if( selection.GetSize() == 0 )
  596. return 0;
  597. // Doing a duplicate of a new object doesn't really make any sense; we'd just end
  598. // up dragging around a stack of objects...
  599. if( selection.Front()->IsNew() )
  600. return 0;
  601. if( !selection.Front()->IsMoving() )
  602. saveCopyInUndoList( m_frame->GetCurSymbol(), UNDO_REDO::LIBEDIT );
  603. EDA_ITEMS newItems;
  604. for( unsigned ii = 0; ii < selection.GetSize(); ++ii )
  605. {
  606. LIB_ITEM* oldItem = static_cast<LIB_ITEM*>( selection.GetItem( ii ) );
  607. LIB_ITEM* newItem = (LIB_ITEM*) oldItem->Clone();
  608. oldItem->ClearFlags( IS_NEW | IS_PASTED | SELECTED );
  609. newItem->SetFlags( IS_NEW | IS_PASTED | SELECTED );
  610. newItem->SetParent( symbol );
  611. newItems.push_back( newItem );
  612. symbol->AddDrawItem( newItem );
  613. getView()->Add( newItem );
  614. }
  615. m_toolMgr->RunAction( EE_ACTIONS::clearSelection, true );
  616. m_toolMgr->RunAction( EE_ACTIONS::addItemsToSel, true, &newItems );
  617. selection.SetReferencePoint( mapCoords( getViewControls()->GetCursorPosition( true ) ) );
  618. m_toolMgr->RunAction( EE_ACTIONS::move, false );
  619. return 0;
  620. }
  621. void SYMBOL_EDITOR_EDIT_TOOL::setTransitions()
  622. {
  623. Go( &SYMBOL_EDITOR_EDIT_TOOL::Undo, ACTIONS::undo.MakeEvent() );
  624. Go( &SYMBOL_EDITOR_EDIT_TOOL::Redo, ACTIONS::redo.MakeEvent() );
  625. Go( &SYMBOL_EDITOR_EDIT_TOOL::Cut, ACTIONS::cut.MakeEvent() );
  626. Go( &SYMBOL_EDITOR_EDIT_TOOL::Copy, ACTIONS::copy.MakeEvent() );
  627. Go( &SYMBOL_EDITOR_EDIT_TOOL::Paste, ACTIONS::paste.MakeEvent() );
  628. Go( &SYMBOL_EDITOR_EDIT_TOOL::Duplicate, ACTIONS::duplicate.MakeEvent() );
  629. Go( &SYMBOL_EDITOR_EDIT_TOOL::Rotate, EE_ACTIONS::rotateCW.MakeEvent() );
  630. Go( &SYMBOL_EDITOR_EDIT_TOOL::Rotate, EE_ACTIONS::rotateCCW.MakeEvent() );
  631. Go( &SYMBOL_EDITOR_EDIT_TOOL::Mirror, EE_ACTIONS::mirrorV.MakeEvent() );
  632. Go( &SYMBOL_EDITOR_EDIT_TOOL::Mirror, EE_ACTIONS::mirrorH.MakeEvent() );
  633. Go( &SYMBOL_EDITOR_EDIT_TOOL::DoDelete, ACTIONS::doDelete.MakeEvent() );
  634. Go( &SYMBOL_EDITOR_EDIT_TOOL::DeleteItemCursor, ACTIONS::deleteTool.MakeEvent() );
  635. Go( &SYMBOL_EDITOR_EDIT_TOOL::Properties, EE_ACTIONS::properties.MakeEvent() );
  636. Go( &SYMBOL_EDITOR_EDIT_TOOL::Properties, EE_ACTIONS::symbolProperties.MakeEvent() );
  637. Go( &SYMBOL_EDITOR_EDIT_TOOL::PinTable, EE_ACTIONS::pinTable.MakeEvent() );
  638. Go( &SYMBOL_EDITOR_EDIT_TOOL::UpdateSymbolFields, EE_ACTIONS::updateSymbolFields.MakeEvent() );
  639. }