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.

896 lines
28 KiB

7 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 <wx/textdlg.h> // for wxTextEntryDialog
  45. #include <math/util.h> // for KiROUND
  46. SYMBOL_EDITOR_EDIT_TOOL::SYMBOL_EDITOR_EDIT_TOOL() :
  47. EE_TOOL_BASE( "eeschema.SymbolEditTool" ),
  48. m_pickerItem( nullptr )
  49. {
  50. }
  51. bool SYMBOL_EDITOR_EDIT_TOOL::Init()
  52. {
  53. EE_TOOL_BASE::Init();
  54. SYMBOL_EDITOR_DRAWING_TOOLS* drawingTools = m_toolMgr->GetTool<SYMBOL_EDITOR_DRAWING_TOOLS>();
  55. SYMBOL_EDITOR_MOVE_TOOL* moveTool = m_toolMgr->GetTool<SYMBOL_EDITOR_MOVE_TOOL>();
  56. wxASSERT_MSG( drawingTools, "eeschema.SymbolDrawing tool is not available" );
  57. auto haveSymbolCondition =
  58. [&]( const SELECTION& sel )
  59. {
  60. return m_isSymbolEditor &&
  61. static_cast<SYMBOL_EDIT_FRAME*>( m_frame )->GetCurSymbol();
  62. };
  63. auto canEdit =
  64. [&]( const SELECTION& sel )
  65. {
  66. SYMBOL_EDIT_FRAME* editor = static_cast<SYMBOL_EDIT_FRAME*>( m_frame );
  67. wxCHECK( editor, false );
  68. if( !editor->IsSymbolEditable() )
  69. return false;
  70. if( editor->IsSymbolAlias() )
  71. {
  72. for( EDA_ITEM* item : sel )
  73. {
  74. if( item->Type() != LIB_FIELD_T )
  75. return false;
  76. }
  77. }
  78. return true;
  79. };
  80. // Add edit actions to the move tool menu
  81. if( moveTool )
  82. {
  83. CONDITIONAL_MENU& moveMenu = moveTool->GetToolMenu().GetMenu();
  84. moveMenu.AddSeparator( 200 );
  85. moveMenu.AddItem( EE_ACTIONS::rotateCCW, canEdit && EE_CONDITIONS::NotEmpty, 200 );
  86. moveMenu.AddItem( EE_ACTIONS::rotateCW, canEdit && EE_CONDITIONS::NotEmpty, 200 );
  87. moveMenu.AddItem( EE_ACTIONS::mirrorV, canEdit && EE_CONDITIONS::NotEmpty, 200 );
  88. moveMenu.AddItem( EE_ACTIONS::mirrorH, canEdit && EE_CONDITIONS::NotEmpty, 200 );
  89. moveMenu.AddItem( EE_ACTIONS::properties, canEdit && EE_CONDITIONS::Count( 1 ), 200 );
  90. moveMenu.AddSeparator( 300 );
  91. moveMenu.AddItem( ACTIONS::cut, EE_CONDITIONS::IdleSelection, 300 );
  92. moveMenu.AddItem( ACTIONS::copy, EE_CONDITIONS::IdleSelection, 300 );
  93. moveMenu.AddItem( ACTIONS::duplicate, canEdit && EE_CONDITIONS::NotEmpty, 300 );
  94. moveMenu.AddItem( ACTIONS::doDelete, canEdit && EE_CONDITIONS::NotEmpty, 200 );
  95. moveMenu.AddSeparator( 400 );
  96. moveMenu.AddItem( ACTIONS::selectAll, haveSymbolCondition, 400 );
  97. }
  98. // Add editing actions to the drawing tool menu
  99. CONDITIONAL_MENU& drawMenu = drawingTools->GetToolMenu().GetMenu();
  100. drawMenu.AddSeparator( 200 );
  101. drawMenu.AddItem( EE_ACTIONS::rotateCCW, canEdit && EE_CONDITIONS::IdleSelection, 200 );
  102. drawMenu.AddItem( EE_ACTIONS::rotateCW, canEdit && EE_CONDITIONS::IdleSelection, 200 );
  103. drawMenu.AddItem( EE_ACTIONS::mirrorV, canEdit && EE_CONDITIONS::IdleSelection, 200 );
  104. drawMenu.AddItem( EE_ACTIONS::mirrorH, canEdit && EE_CONDITIONS::IdleSelection, 200 );
  105. drawMenu.AddItem( EE_ACTIONS::properties, canEdit && EE_CONDITIONS::Count( 1 ), 200 );
  106. // Add editing actions to the selection tool menu
  107. CONDITIONAL_MENU& selToolMenu = m_selectionTool->GetToolMenu().GetMenu();
  108. selToolMenu.AddItem( EE_ACTIONS::rotateCCW, canEdit && EE_CONDITIONS::NotEmpty, 200 );
  109. selToolMenu.AddItem( EE_ACTIONS::rotateCW, canEdit && EE_CONDITIONS::NotEmpty, 200 );
  110. selToolMenu.AddItem( EE_ACTIONS::mirrorV, canEdit && EE_CONDITIONS::NotEmpty, 200 );
  111. selToolMenu.AddItem( EE_ACTIONS::mirrorH, canEdit && EE_CONDITIONS::NotEmpty, 200 );
  112. selToolMenu.AddItem( EE_ACTIONS::properties, canEdit && EE_CONDITIONS::Count( 1 ), 200 );
  113. selToolMenu.AddSeparator( 300 );
  114. selToolMenu.AddItem( ACTIONS::cut, EE_CONDITIONS::IdleSelection, 300 );
  115. selToolMenu.AddItem( ACTIONS::copy, EE_CONDITIONS::IdleSelection, 300 );
  116. selToolMenu.AddItem( ACTIONS::paste, canEdit && EE_CONDITIONS::Idle, 300 );
  117. selToolMenu.AddItem( ACTIONS::duplicate, canEdit && EE_CONDITIONS::NotEmpty, 300 );
  118. selToolMenu.AddItem( ACTIONS::doDelete, canEdit && EE_CONDITIONS::NotEmpty, 300 );
  119. selToolMenu.AddSeparator( 400 );
  120. selToolMenu.AddItem( ACTIONS::selectAll, haveSymbolCondition, 400 );
  121. return true;
  122. }
  123. int SYMBOL_EDITOR_EDIT_TOOL::Rotate( const TOOL_EVENT& aEvent )
  124. {
  125. EE_SELECTION& selection = m_selectionTool->RequestSelection();
  126. if( selection.GetSize() == 0 )
  127. return 0;
  128. VECTOR2I rotPoint;
  129. bool ccw = ( aEvent.Matches( EE_ACTIONS::rotateCCW.MakeEvent() ) );
  130. LIB_ITEM* item = static_cast<LIB_ITEM*>( selection.Front() );
  131. if( !item->IsMoving() )
  132. saveCopyInUndoList( m_frame->GetCurSymbol(), UNDO_REDO::LIBEDIT );
  133. if( selection.GetSize() == 1 )
  134. rotPoint = item->GetPosition();
  135. else
  136. rotPoint = m_frame->GetNearestHalfGridPosition( mapCoords( selection.GetCenter() ) );
  137. for( unsigned ii = 0; ii < selection.GetSize(); ii++ )
  138. {
  139. item = static_cast<LIB_ITEM*>( selection.GetItem( ii ) );
  140. item->Rotate( rotPoint, ccw );
  141. m_frame->UpdateItem( item, false, true );
  142. }
  143. if( item->IsMoving() )
  144. {
  145. m_toolMgr->RunAction( ACTIONS::refreshPreview, true );
  146. }
  147. else
  148. {
  149. m_toolMgr->PostEvent( EVENTS::SelectedItemsModified );
  150. if( selection.IsHover() )
  151. m_toolMgr->RunAction( EE_ACTIONS::clearSelection, true );
  152. m_frame->OnModify();
  153. }
  154. return 0;
  155. }
  156. int SYMBOL_EDITOR_EDIT_TOOL::Mirror( const TOOL_EVENT& aEvent )
  157. {
  158. EE_SELECTION& selection = m_selectionTool->RequestSelection();
  159. if( selection.GetSize() == 0 )
  160. return 0;
  161. VECTOR2I mirrorPoint;
  162. bool xAxis = ( aEvent.Matches( EE_ACTIONS::mirrorV.MakeEvent() ) );
  163. LIB_ITEM* item = static_cast<LIB_ITEM*>( selection.Front() );
  164. if( !item->IsMoving() )
  165. saveCopyInUndoList( m_frame->GetCurSymbol(), UNDO_REDO::LIBEDIT );
  166. if( selection.GetSize() == 1 )
  167. mirrorPoint = item->GetPosition();
  168. else
  169. mirrorPoint = m_frame->GetNearestHalfGridPosition( mapCoords( selection.GetCenter() ) );
  170. for( unsigned ii = 0; ii < selection.GetSize(); ii++ )
  171. {
  172. item = static_cast<LIB_ITEM*>( selection.GetItem( ii ) );
  173. if( xAxis )
  174. item->MirrorVertical( mirrorPoint );
  175. else
  176. item->MirrorHorizontal( mirrorPoint );
  177. m_frame->UpdateItem( item, false, true );
  178. }
  179. m_toolMgr->PostEvent( EVENTS::SelectedItemsModified );
  180. if( item->IsMoving() )
  181. {
  182. m_toolMgr->RunAction( ACTIONS::refreshPreview, true );
  183. }
  184. else
  185. {
  186. if( selection.IsHover() )
  187. m_toolMgr->RunAction( EE_ACTIONS::clearSelection, true );
  188. m_frame->OnModify();
  189. }
  190. return 0;
  191. }
  192. static std::vector<KICAD_T> nonFields =
  193. {
  194. LIB_SYMBOL_T,
  195. LIB_SHAPE_T,
  196. LIB_TEXT_T,
  197. LIB_TEXTBOX_T,
  198. LIB_PIN_T
  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* curr_pin = static_cast<LIB_PIN*>( item );
  215. VECTOR2I pos = curr_pin->GetPosition();
  216. toDelete.insert( curr_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[curr_pin->GetUnit()] = true;
  223. int curr_convert = curr_pin->GetConvert();
  224. ELECTRICAL_PINTYPE etype = curr_pin->GetType();
  225. wxString name = curr_pin->GetName();
  226. std::vector<LIB_PIN*> pins = symbol->GetAllLibPins();
  227. for( LIB_PIN* pin : pins )
  228. {
  229. if( got_unit[pin->GetUnit()] )
  230. continue;
  231. if( pin->GetPosition() != pos )
  232. continue;
  233. if( pin->GetConvert() != curr_convert )
  234. continue;
  235. if( pin->GetType() != etype )
  236. continue;
  237. if( pin->GetName() != name )
  238. continue;
  239. toDelete.insert( pin );
  240. got_unit[pin->GetUnit()] = true;
  241. }
  242. }
  243. }
  244. else
  245. {
  246. toDelete.insert( (LIB_ITEM*) item );
  247. }
  248. }
  249. for( LIB_ITEM* item : toDelete )
  250. symbol->RemoveDrawItem( item );
  251. m_frame->RebuildView();
  252. m_frame->OnModify();
  253. return 0;
  254. }
  255. #define HITTEST_THRESHOLD_PIXELS 5
  256. int SYMBOL_EDITOR_EDIT_TOOL::DeleteItemCursor( const TOOL_EVENT& aEvent )
  257. {
  258. PICKER_TOOL* picker = m_toolMgr->GetTool<PICKER_TOOL>();
  259. m_toolMgr->RunAction( EE_ACTIONS::clearSelection, true );
  260. m_pickerItem = nullptr;
  261. // Deactivate other tools; particularly important if another PICKER is currently running
  262. Activate();
  263. picker->SetCursor( KICURSOR::REMOVE );
  264. picker->SetClickHandler(
  265. [this]( const VECTOR2D& aPosition ) -> bool
  266. {
  267. if( m_pickerItem )
  268. {
  269. EE_SELECTION_TOOL* selectionTool = m_toolMgr->GetTool<EE_SELECTION_TOOL>();
  270. selectionTool->UnbrightenItem( m_pickerItem );
  271. selectionTool->AddItemToSel( m_pickerItem, true /*quiet mode*/ );
  272. m_toolMgr->RunAction( ACTIONS::doDelete, true );
  273. m_pickerItem = nullptr;
  274. }
  275. return true;
  276. } );
  277. picker->SetMotionHandler(
  278. [this]( const VECTOR2D& aPos )
  279. {
  280. EE_SELECTION_TOOL* selectionTool = m_toolMgr->GetTool<EE_SELECTION_TOOL>();
  281. EE_COLLECTOR collector;
  282. selectionTool->CollectHits( collector, aPos, nonFields );
  283. // Remove unselectable items
  284. for( int i = collector.GetCount() - 1; i >= 0; --i )
  285. {
  286. if( !selectionTool->Selectable( collector[ i ] ) )
  287. collector.Remove( i );
  288. }
  289. if( collector.GetCount() > 1 )
  290. selectionTool->GuessSelectionCandidates( collector, aPos );
  291. EDA_ITEM* item = collector.GetCount() == 1 ? collector[ 0 ] : nullptr;
  292. if( m_pickerItem != item )
  293. {
  294. if( m_pickerItem )
  295. selectionTool->UnbrightenItem( m_pickerItem );
  296. m_pickerItem = item;
  297. if( m_pickerItem )
  298. selectionTool->BrightenItem( m_pickerItem );
  299. }
  300. } );
  301. picker->SetFinalizeHandler(
  302. [this]( const int& aFinalState )
  303. {
  304. if( m_pickerItem )
  305. m_toolMgr->GetTool<EE_SELECTION_TOOL>()->UnbrightenItem( m_pickerItem );
  306. // Wake the selection tool after exiting to ensure the cursor gets updated
  307. m_toolMgr->RunAction( EE_ACTIONS::selectionActivate, false );
  308. } );
  309. m_toolMgr->RunAction( ACTIONS::pickerTool, true );
  310. return 0;
  311. }
  312. int SYMBOL_EDITOR_EDIT_TOOL::Properties( const TOOL_EVENT& aEvent )
  313. {
  314. EE_SELECTION& selection = m_selectionTool->RequestSelection();
  315. if( selection.Empty() || aEvent.IsAction( &EE_ACTIONS::symbolProperties ) )
  316. {
  317. if( m_frame->GetCurSymbol() )
  318. editSymbolProperties();
  319. }
  320. else if( selection.Size() == 1 )
  321. {
  322. LIB_ITEM* item = (LIB_ITEM*) selection.Front();
  323. // Save copy for undo if not in edit (edit command already handle the save copy)
  324. if( item->GetEditFlags() == 0 )
  325. saveCopyInUndoList( item->GetParent(), UNDO_REDO::LIBEDIT );
  326. switch( item->Type() )
  327. {
  328. case LIB_PIN_T:
  329. {
  330. SYMBOL_EDITOR_PIN_TOOL* pinTool = m_toolMgr->GetTool<SYMBOL_EDITOR_PIN_TOOL>();
  331. if( pinTool )
  332. pinTool->EditPinProperties( (LIB_PIN*) item );
  333. }
  334. break;
  335. case LIB_SHAPE_T:
  336. editShapeProperties( static_cast<LIB_SHAPE*>( item ) );
  337. break;
  338. case LIB_TEXT_T:
  339. editTextProperties( item );
  340. break;
  341. case LIB_TEXTBOX_T:
  342. editTextBoxProperties( item );
  343. break;
  344. case LIB_FIELD_T:
  345. editFieldProperties( (LIB_FIELD*) item );
  346. break;
  347. default:
  348. wxFAIL_MSG( wxT( "Unhandled item <" ) + item->GetClass() + wxT( ">" ) );
  349. break;
  350. }
  351. }
  352. if( selection.IsHover() )
  353. m_toolMgr->RunAction( EE_ACTIONS::clearSelection, true );
  354. else
  355. m_toolMgr->PostEvent( EVENTS::SelectedItemsModified );
  356. return 0;
  357. }
  358. void SYMBOL_EDITOR_EDIT_TOOL::editShapeProperties( LIB_SHAPE* aShape )
  359. {
  360. DIALOG_LIB_SHAPE_PROPERTIES dlg( m_frame, aShape );
  361. if( dlg.ShowModal() != wxID_OK )
  362. return;
  363. updateItem( aShape, true );
  364. m_frame->GetCanvas()->Refresh();
  365. m_frame->OnModify();
  366. SYMBOL_EDITOR_DRAWING_TOOLS* drawingTools = m_toolMgr->GetTool<SYMBOL_EDITOR_DRAWING_TOOLS>();
  367. drawingTools->SetDrawSpecificConvert( !dlg.GetApplyToAllConversions() );
  368. drawingTools->SetDrawSpecificUnit( !dlg.GetApplyToAllUnits() );
  369. std::vector<MSG_PANEL_ITEM> items;
  370. aShape->GetMsgPanelInfo( m_frame, items );
  371. m_frame->SetMsgPanel( items );
  372. }
  373. void SYMBOL_EDITOR_EDIT_TOOL::editTextProperties( LIB_ITEM* aItem )
  374. {
  375. if ( aItem->Type() != LIB_TEXT_T )
  376. return;
  377. DIALOG_LIB_TEXT_PROPERTIES dlg( m_frame, static_cast<LIB_TEXT*>( aItem ) );
  378. if( dlg.ShowModal() != wxID_OK )
  379. return;
  380. updateItem( aItem, true );
  381. m_frame->GetCanvas()->Refresh();
  382. m_frame->OnModify( );
  383. }
  384. void SYMBOL_EDITOR_EDIT_TOOL::editTextBoxProperties( LIB_ITEM* aItem )
  385. {
  386. if ( aItem->Type() != LIB_TEXTBOX_T )
  387. return;
  388. DIALOG_LIB_TEXTBOX_PROPERTIES dlg( m_frame, static_cast<LIB_TEXTBOX*>( aItem ) );
  389. if( dlg.ShowModal() != wxID_OK )
  390. return;
  391. updateItem( aItem, true );
  392. m_frame->GetCanvas()->Refresh();
  393. m_frame->OnModify( );
  394. }
  395. void SYMBOL_EDITOR_EDIT_TOOL::editFieldProperties( LIB_FIELD* aField )
  396. {
  397. if( aField == nullptr )
  398. return;
  399. wxString caption;
  400. LIB_SYMBOL* parent = aField->GetParent();
  401. wxCHECK( parent, /* void */ );
  402. if( aField->GetId() < MANDATORY_FIELDS )
  403. caption.Printf( _( "Edit %s Field" ), TitleCaps( aField->GetName() ) );
  404. else
  405. caption.Printf( _( "Edit '%s' Field" ), aField->GetName() );
  406. DIALOG_LIB_FIELD_PROPERTIES dlg( m_frame, caption, aField );
  407. // The dialog may invoke a kiway player for footprint fields
  408. // so we must use a quasimodal dialog.
  409. if( dlg.ShowQuasiModal() != wxID_OK )
  410. return;
  411. wxString newFieldValue = EscapeString( dlg.GetText(), CTX_LIBID );
  412. wxString oldFieldValue = aField->GetFullText( m_frame->GetUnit() );
  413. saveCopyInUndoList( parent, UNDO_REDO::LIBEDIT );
  414. dlg.UpdateField( aField );
  415. updateItem( aField, true );
  416. m_frame->GetCanvas()->Refresh();
  417. m_frame->OnModify();
  418. m_frame->UpdateSymbolMsgPanelInfo();
  419. }
  420. void SYMBOL_EDITOR_EDIT_TOOL::editSymbolProperties()
  421. {
  422. LIB_SYMBOL* symbol = m_frame->GetCurSymbol();
  423. bool partLocked = symbol->UnitsLocked();
  424. m_toolMgr->RunAction( ACTIONS::cancelInteractive, true );
  425. m_toolMgr->RunAction( EE_ACTIONS::clearSelection, true );
  426. DIALOG_LIB_SYMBOL_PROPERTIES dlg( m_frame, symbol );
  427. // This dialog itself subsequently can invoke a KIWAY_PLAYER as a quasimodal
  428. // frame. Therefore this dialog as a modal frame parent, MUST be run under
  429. // quasimodal mode for the quasimodal frame support to work. So don't use
  430. // the QUASIMODAL macros here.
  431. if( dlg.ShowQuasiModal() != wxID_OK )
  432. return;
  433. m_frame->OnModify();
  434. // if m_UnitSelectionLocked has changed, set some edit options or defaults
  435. // to the best value
  436. if( partLocked != symbol->UnitsLocked() )
  437. {
  438. SYMBOL_EDITOR_DRAWING_TOOLS* tools = m_toolMgr->GetTool<SYMBOL_EDITOR_DRAWING_TOOLS>();
  439. // Enable synchronized pin edit mode for symbols with interchangeable units
  440. m_frame->m_SyncPinEdit = !symbol->UnitsLocked();
  441. // also set default edit options to the better value
  442. // Usually if units are locked, graphic items are specific to each unit
  443. // and if units are interchangeable, graphic items are common to units
  444. tools->SetDrawSpecificUnit( symbol->UnitsLocked() );
  445. }
  446. }
  447. void SYMBOL_EDITOR_EDIT_TOOL::handlePinDuplication( LIB_PIN* aOldPin, LIB_PIN* aNewPin,
  448. int& aSymbolLastPinNumber )
  449. {
  450. if( !aNewPin->GetNumber().IsEmpty() )
  451. {
  452. // when duplicating a pin in symbol editor, assigning identical pin number
  453. // to the old one does not makes any sense, so assign the next unassigned number to it
  454. aSymbolLastPinNumber++;
  455. aNewPin->SetNumber( wxString::Format( wxT( "%i" ), aSymbolLastPinNumber ) );
  456. }
  457. }
  458. int SYMBOL_EDITOR_EDIT_TOOL::PinTable( const TOOL_EVENT& aEvent )
  459. {
  460. LIB_SYMBOL* symbol = m_frame->GetCurSymbol();
  461. if( !symbol )
  462. return 0;
  463. m_toolMgr->RunAction( EE_ACTIONS::clearSelection, true );
  464. saveCopyInUndoList( symbol, UNDO_REDO::LIBEDIT );
  465. DIALOG_LIB_EDIT_PIN_TABLE dlg( m_frame, symbol );
  466. if( dlg.ShowModal() == wxID_CANCEL )
  467. return -1;
  468. m_frame->RebuildView();
  469. m_frame->OnModify();
  470. return 0;
  471. }
  472. int SYMBOL_EDITOR_EDIT_TOOL::UpdateSymbolFields( const TOOL_EVENT& aEvent )
  473. {
  474. LIB_SYMBOL* symbol = m_frame->GetCurSymbol();
  475. if( !symbol )
  476. return 0;
  477. if( !symbol->IsAlias() )
  478. {
  479. m_frame->ShowInfoBarError( _( "Symbol is not derived from another symbol." ) );
  480. }
  481. else
  482. {
  483. DIALOG_UPDATE_SYMBOL_FIELDS dlg( m_frame, symbol );
  484. if( dlg.ShowModal() == wxID_CANCEL )
  485. return -1;
  486. }
  487. return 0;
  488. }
  489. int SYMBOL_EDITOR_EDIT_TOOL::SetUnitDisplayName( const TOOL_EVENT& aEvent )
  490. {
  491. LIB_SYMBOL* symbol = m_frame->GetCurSymbol();
  492. if( !symbol )
  493. return 0;
  494. int unitid = m_frame->GetUnit();
  495. if( unitid == 0 )
  496. {
  497. return -1;
  498. }
  499. wxString promptText = wxString::Format( _( "Enter display name for unit %s" ),
  500. symbol->GetUnitReference( unitid ) );
  501. wxString currentvalue;
  502. if( symbol->HasUnitDisplayName( unitid ) )
  503. {
  504. currentvalue = symbol->GetUnitDisplayName( unitid );
  505. }
  506. wxTextEntryDialog dlg( m_frame, promptText, _( "Set Unit Display Name" ), currentvalue );
  507. if( dlg.ShowModal() == wxID_OK )
  508. {
  509. saveCopyInUndoList( symbol, UNDO_REDO::LIBEDIT );
  510. symbol->SetUnitDisplayName( unitid, dlg.GetValue() );
  511. m_frame->RebuildSymbolUnitsList();
  512. m_frame->OnModify();
  513. }
  514. else
  515. {
  516. return -1;
  517. }
  518. return 0;
  519. }
  520. int SYMBOL_EDITOR_EDIT_TOOL::Undo( const TOOL_EVENT& aEvent )
  521. {
  522. m_frame->GetSymbolFromUndoList();
  523. EE_SELECTION_TOOL* selTool = m_toolMgr->GetTool<EE_SELECTION_TOOL>();
  524. selTool->RebuildSelection();
  525. return 0;
  526. }
  527. int SYMBOL_EDITOR_EDIT_TOOL::Redo( const TOOL_EVENT& aEvent )
  528. {
  529. m_frame->GetSymbolFromRedoList();
  530. EE_SELECTION_TOOL* selTool = m_toolMgr->GetTool<EE_SELECTION_TOOL>();
  531. selTool->RebuildSelection();
  532. return 0;
  533. }
  534. int SYMBOL_EDITOR_EDIT_TOOL::Cut( const TOOL_EVENT& aEvent )
  535. {
  536. int retVal = Copy( aEvent );
  537. if( retVal == 0 )
  538. retVal = DoDelete( aEvent );
  539. return retVal;
  540. }
  541. int SYMBOL_EDITOR_EDIT_TOOL::Copy( const TOOL_EVENT& aEvent )
  542. {
  543. LIB_SYMBOL* symbol = m_frame->GetCurSymbol();
  544. EE_SELECTION& selection = m_selectionTool->RequestSelection( nonFields );
  545. if( !symbol || !selection.GetSize() )
  546. return 0;
  547. for( LIB_ITEM& item : symbol->GetDrawItems() )
  548. {
  549. if( item.Type() == LIB_FIELD_T )
  550. continue;
  551. wxASSERT( !item.HasFlag( STRUCT_DELETED ) );
  552. if( !item.IsSelected() )
  553. item.SetFlags( STRUCT_DELETED );
  554. }
  555. LIB_SYMBOL* partCopy = new LIB_SYMBOL( *symbol );
  556. STRING_FORMATTER formatter;
  557. SCH_SEXPR_PLUGIN::FormatLibSymbol( partCopy, formatter );
  558. delete partCopy;
  559. for( LIB_ITEM& item : symbol->GetDrawItems() )
  560. item.ClearFlags( STRUCT_DELETED );
  561. if( m_toolMgr->SaveClipboard( formatter.GetString() ) )
  562. return 0;
  563. else
  564. return -1;
  565. }
  566. int SYMBOL_EDITOR_EDIT_TOOL::Paste( const TOOL_EVENT& aEvent )
  567. {
  568. LIB_SYMBOL* symbol = m_frame->GetCurSymbol();
  569. if( !symbol || symbol->IsAlias() )
  570. return 0;
  571. std::string text_utf8 = m_toolMgr->GetClipboardUTF8();
  572. STRING_LINE_READER reader( text_utf8, "Clipboard" );
  573. LIB_SYMBOL* newPart;
  574. try
  575. {
  576. newPart = SCH_SEXPR_PLUGIN::ParseLibSymbol( reader );
  577. }
  578. catch( IO_ERROR& )
  579. {
  580. // If it's not a symbol then paste as text
  581. newPart = new LIB_SYMBOL( "dummy_part" );
  582. LIB_TEXT* newText = new LIB_TEXT( newPart );
  583. newText->SetText( wxString::FromUTF8( text_utf8.c_str() ) );
  584. newPart->AddDrawItem( newText );
  585. }
  586. if( !newPart )
  587. return -1;
  588. m_frame->SaveCopyInUndoList( symbol );
  589. m_selectionTool->ClearSelection();
  590. for( LIB_ITEM& item : symbol->GetDrawItems() )
  591. item.ClearFlags( IS_NEW | IS_PASTED | SELECTED );
  592. for( LIB_ITEM& item : newPart->GetDrawItems() )
  593. {
  594. if( item.Type() == LIB_FIELD_T )
  595. continue;
  596. LIB_ITEM* newItem = (LIB_ITEM*) item.Clone();
  597. newItem->SetParent( symbol );
  598. newItem->SetFlags( IS_NEW | IS_PASTED | SELECTED );
  599. newItem->SetUnit( newItem->GetUnit() ? m_frame->GetUnit() : 0 );
  600. newItem->SetConvert( newItem->GetConvert() ? m_frame->GetConvert() : 0 );
  601. symbol->AddDrawItem( newItem );
  602. getView()->Add( newItem );
  603. }
  604. delete newPart;
  605. m_selectionTool->RebuildSelection();
  606. EE_SELECTION& selection = m_selectionTool->GetSelection();
  607. if( !selection.Empty() )
  608. {
  609. selection.SetReferencePoint( getViewControls()->GetCursorPosition( true ) );
  610. m_toolMgr->RunAction( EE_ACTIONS::move, false );
  611. }
  612. return 0;
  613. }
  614. int SYMBOL_EDITOR_EDIT_TOOL::Duplicate( const TOOL_EVENT& aEvent )
  615. {
  616. LIB_SYMBOL* symbol = m_frame->GetCurSymbol();
  617. EE_SELECTION& selection = m_selectionTool->RequestSelection( nonFields );
  618. if( selection.GetSize() == 0 )
  619. return 0;
  620. // Doing a duplicate of a new object doesn't really make any sense; we'd just end
  621. // up dragging around a stack of objects...
  622. if( selection.Front()->IsNew() )
  623. return 0;
  624. if( !selection.Front()->IsMoving() )
  625. saveCopyInUndoList( m_frame->GetCurSymbol(), UNDO_REDO::LIBEDIT );
  626. EDA_ITEMS newItems;
  627. int symbolLastPinNumber = -1;
  628. for( unsigned ii = 0; ii < selection.GetSize(); ++ii )
  629. {
  630. LIB_ITEM* oldItem = static_cast<LIB_ITEM*>( selection.GetItem( ii ) );
  631. LIB_ITEM* newItem = (LIB_ITEM*) oldItem->Clone();
  632. if( oldItem->Type() == LIB_PIN_T )
  633. {
  634. if( symbolLastPinNumber == -1 )
  635. {
  636. symbolLastPinNumber = symbol->GetMaxPinNumber();
  637. }
  638. handlePinDuplication( static_cast<LIB_PIN*>( oldItem ),
  639. static_cast<LIB_PIN*>( newItem ), symbolLastPinNumber );
  640. }
  641. oldItem->ClearFlags( IS_NEW | IS_PASTED | SELECTED );
  642. newItem->SetFlags( IS_NEW | IS_PASTED | SELECTED );
  643. newItem->SetParent( symbol );
  644. newItems.push_back( newItem );
  645. symbol->AddDrawItem( newItem );
  646. getView()->Add( newItem );
  647. }
  648. m_toolMgr->RunAction( EE_ACTIONS::clearSelection, true );
  649. m_toolMgr->RunAction( EE_ACTIONS::addItemsToSel, true, &newItems );
  650. selection.SetReferencePoint( mapCoords( getViewControls()->GetCursorPosition( true ) ) );
  651. m_toolMgr->RunAction( EE_ACTIONS::move, false );
  652. return 0;
  653. }
  654. void SYMBOL_EDITOR_EDIT_TOOL::setTransitions()
  655. {
  656. Go( &SYMBOL_EDITOR_EDIT_TOOL::Undo, ACTIONS::undo.MakeEvent() );
  657. Go( &SYMBOL_EDITOR_EDIT_TOOL::Redo, ACTIONS::redo.MakeEvent() );
  658. Go( &SYMBOL_EDITOR_EDIT_TOOL::Cut, ACTIONS::cut.MakeEvent() );
  659. Go( &SYMBOL_EDITOR_EDIT_TOOL::Copy, ACTIONS::copy.MakeEvent() );
  660. Go( &SYMBOL_EDITOR_EDIT_TOOL::Paste, ACTIONS::paste.MakeEvent() );
  661. Go( &SYMBOL_EDITOR_EDIT_TOOL::Duplicate, ACTIONS::duplicate.MakeEvent() );
  662. Go( &SYMBOL_EDITOR_EDIT_TOOL::Rotate, EE_ACTIONS::rotateCW.MakeEvent() );
  663. Go( &SYMBOL_EDITOR_EDIT_TOOL::Rotate, EE_ACTIONS::rotateCCW.MakeEvent() );
  664. Go( &SYMBOL_EDITOR_EDIT_TOOL::Mirror, EE_ACTIONS::mirrorV.MakeEvent() );
  665. Go( &SYMBOL_EDITOR_EDIT_TOOL::Mirror, EE_ACTIONS::mirrorH.MakeEvent() );
  666. Go( &SYMBOL_EDITOR_EDIT_TOOL::DoDelete, ACTIONS::doDelete.MakeEvent() );
  667. Go( &SYMBOL_EDITOR_EDIT_TOOL::DeleteItemCursor, ACTIONS::deleteTool.MakeEvent() );
  668. Go( &SYMBOL_EDITOR_EDIT_TOOL::Properties, EE_ACTIONS::properties.MakeEvent() );
  669. Go( &SYMBOL_EDITOR_EDIT_TOOL::Properties, EE_ACTIONS::symbolProperties.MakeEvent() );
  670. Go( &SYMBOL_EDITOR_EDIT_TOOL::PinTable, EE_ACTIONS::pinTable.MakeEvent() );
  671. Go( &SYMBOL_EDITOR_EDIT_TOOL::UpdateSymbolFields, EE_ACTIONS::updateSymbolFields.MakeEvent() );
  672. Go( &SYMBOL_EDITOR_EDIT_TOOL::SetUnitDisplayName, EE_ACTIONS::setUnitDisplayName.MakeEvent() );
  673. }