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.

1408 lines
47 KiB

7 years ago
7 years ago
  1. /*
  2. * This program source code file is part of KiCad, a free EDA CAD application.
  3. *
  4. * Copyright (C) 2019 KiCad Developers, see AUTHORS.txt for contributors.
  5. *
  6. * This program is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU General Public License
  8. * as published by the Free Software Foundation; either version 2
  9. * of the License, or (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this program; if not, you may find one here:
  18. * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
  19. * or you may search the http://www.gnu.org website for the version 2 license,
  20. * or you may write to the Free Software Foundation, Inc.,
  21. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
  22. */
  23. #include <tool/tool_manager.h>
  24. #include <tools/sch_edit_tool.h>
  25. #include <tools/ee_selection_tool.h>
  26. #include <tools/sch_wire_bus_tool.h>
  27. #include <tools/ee_picker_tool.h>
  28. #include <tools/sch_move_tool.h>
  29. #include <ee_actions.h>
  30. #include <ee_hotkeys.h>
  31. #include <bitmaps.h>
  32. #include <confirm.h>
  33. #include <eda_doc.h>
  34. #include <base_struct.h>
  35. #include <sch_item.h>
  36. #include <sch_component.h>
  37. #include <sch_sheet.h>
  38. #include <sch_text.h>
  39. #include <sch_bitmap.h>
  40. #include <sch_view.h>
  41. #include <sch_line.h>
  42. #include <sch_item.h>
  43. #include <sch_bus_entry.h>
  44. #include <sch_edit_frame.h>
  45. #include <eeschema_id.h>
  46. #include <status_popup.h>
  47. #include <wx/gdicmn.h>
  48. #include <invoke_sch_dialog.h>
  49. #include "sch_drawing_tools.h"
  50. TOOL_ACTION EE_ACTIONS::repeatDrawItem( "eeschema.InteractiveEdit.repeatDrawItem",
  51. AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_REPEAT_LAST ),
  52. _( "Repeat Last Item" ), _( "Duplicates the last drawn item" ),
  53. nullptr );
  54. TOOL_ACTION EE_ACTIONS::rotateCW( "eeschema.InteractiveEdit.rotateCW",
  55. AS_GLOBAL, 0,
  56. _( "Rotate Clockwise" ), _( "Rotates selected item(s) clockwise" ),
  57. rotate_cw_xpm );
  58. TOOL_ACTION EE_ACTIONS::rotateCCW( "eeschema.InteractiveEdit.rotateCCW",
  59. AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_ROTATE ),
  60. _( "Rotate" ), _( "Rotates selected item(s) counter-clockwise" ),
  61. rotate_ccw_xpm );
  62. TOOL_ACTION EE_ACTIONS::mirrorX( "eeschema.InteractiveEdit.mirrorX",
  63. AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_MIRROR_X ),
  64. _( "Mirror Around Horizontal Axis" ), _( "Flips selected item(s) from top to bottom" ),
  65. mirror_v_xpm );
  66. TOOL_ACTION EE_ACTIONS::mirrorY( "eeschema.InteractiveEdit.mirrorY",
  67. AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_MIRROR_Y ),
  68. _( "Mirror Around Vertical Axis" ), _( "Flips selected item(s) from left to right" ),
  69. mirror_h_xpm );
  70. TOOL_ACTION EE_ACTIONS::properties( "eeschema.InteractiveEdit.properties",
  71. AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_EDIT ),
  72. _( "Properties..." ), _( "Displays item properties dialog" ),
  73. edit_xpm );
  74. TOOL_ACTION EE_ACTIONS::editReference( "eeschema.InteractiveEdit.editReference",
  75. AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_EDIT_COMPONENT_REFERENCE ),
  76. _( "Edit Reference..." ), _( "Displays reference field dialog" ),
  77. edit_comp_ref_xpm );
  78. TOOL_ACTION EE_ACTIONS::editValue( "eeschema.InteractiveEdit.editValue",
  79. AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_EDIT_COMPONENT_VALUE ),
  80. _( "Edit Value..." ), _( "Displays value field dialog" ),
  81. edit_comp_value_xpm );
  82. TOOL_ACTION EE_ACTIONS::editFootprint( "eeschema.InteractiveEdit.editFootprint",
  83. AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_EDIT_COMPONENT_FOOTPRINT ),
  84. _( "Edit Footprint..." ), _( "Displays footprint field dialog" ),
  85. edit_comp_footprint_xpm );
  86. TOOL_ACTION EE_ACTIONS::autoplaceFields( "eeschema.InteractiveEdit.autoplaceFields",
  87. AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_AUTOPLACE_FIELDS ),
  88. _( "Autoplace Fields" ), _( "Runs the automatic placement algorithm on the symbol's fields" ),
  89. autoplace_fields_xpm );
  90. TOOL_ACTION EE_ACTIONS::updateFieldsFromLibrary( "eeschema.InteractiveEdit.updateFieldsFromLibrary",
  91. AS_GLOBAL, 0,
  92. _( "Update Fields from Library..." ), _( "Sets symbol fields to original library values" ),
  93. update_fields_xpm );
  94. TOOL_ACTION EE_ACTIONS::toggleDeMorgan( "eeschema.InteractiveEdit.toggleDeMorgan",
  95. AS_GLOBAL, 0,
  96. _( "DeMorgan Conversion" ), _( "Switch between DeMorgan representations" ),
  97. morgan2_xpm );
  98. TOOL_ACTION EE_ACTIONS::showDeMorganStandard( "eeschema.InteractiveEdit.showDeMorganStandard",
  99. AS_GLOBAL, 0,
  100. _( "DeMorgan Standard" ), _( "Switch to standard DeMorgan representation" ),
  101. morgan1_xpm );
  102. TOOL_ACTION EE_ACTIONS::showDeMorganAlternate( "eeschema.InteractiveEdit.showDeMorganAlternate",
  103. AS_GLOBAL, 0,
  104. _( "DeMorgan Alternate" ), _( "Switch to alternate DeMorgan representation" ),
  105. morgan2_xpm );
  106. TOOL_ACTION EE_ACTIONS::toShapeSlash( "eeschema.InteractiveEdit.toShapeSlash",
  107. AS_GLOBAL, 0,
  108. _( "Set Bus Entry Shape /" ), _( "Change the bus entry shape to /" ),
  109. change_entry_orient_xpm );
  110. TOOL_ACTION EE_ACTIONS::toShapeBackslash( "eeschema.InteractiveEdit.toShapeBackslash",
  111. AS_GLOBAL, 0,
  112. _( "Set Bus Entry Shape \\" ), _( "Change the bus entry shape to \\" ),
  113. change_entry_orient_xpm );
  114. TOOL_ACTION EE_ACTIONS::toLabel( "eeschema.InteractiveEdit.toLabel",
  115. AS_GLOBAL, 0,
  116. _( "Change to Label" ), _( "Change existing item to a label" ),
  117. add_line_label_xpm );
  118. TOOL_ACTION EE_ACTIONS::toHLabel( "eeschema.InteractiveEdit.toHLabel",
  119. AS_GLOBAL, 0,
  120. _( "Change to Hierarchical Label" ), _( "Change existing item to a hierarchical label" ),
  121. add_hierarchical_label_xpm );
  122. TOOL_ACTION EE_ACTIONS::toGLabel( "eeschema.InteractiveEdit.toGLabel",
  123. AS_GLOBAL, 0,
  124. _( "Change to Global Label" ), _( "Change existing item to a global label" ),
  125. add_glabel_xpm );
  126. TOOL_ACTION EE_ACTIONS::toText( "eeschema.InteractiveEdit.toText",
  127. AS_GLOBAL, 0,
  128. _( "Change to Text" ), _( "Change existing item to a text comment" ),
  129. text_xpm );
  130. TOOL_ACTION EE_ACTIONS::cleanupSheetPins( "eeschema.InteractiveEdit.cleanupSheetPins",
  131. AS_GLOBAL, 0,
  132. _( "Cleanup Sheet Pins" ), _( "Delete unreferenced sheet pins" ),
  133. nullptr );
  134. TOOL_ACTION EE_ACTIONS::symbolProperties( "eeschema.InteractiveEdit.symbolProperties",
  135. AS_GLOBAL, 0,
  136. _( "Symbol Properties..." ), _( "Displays symbol properties dialog" ),
  137. part_properties_xpm );
  138. TOOL_ACTION EE_ACTIONS::pinTable( "eeschema.InteractiveEdit.pinTable",
  139. AS_GLOBAL, 0,
  140. _( "Pin Table..." ), _( "Displays pin table for bulk editing of pins" ),
  141. pin_table_xpm );
  142. TOOL_ACTION EE_ACTIONS::deleteItemCursor( "eeschema.InteractiveEdit.deleteTool",
  143. AS_GLOBAL, 0,
  144. _( "Delete Items" ), _( "Delete clicked items" ),
  145. delete_xpm, AF_ACTIVATE );
  146. TOOL_ACTION EE_ACTIONS::breakWire( "eeschema.InteractiveEdit.breakWire",
  147. AS_GLOBAL, 0,
  148. _( "Break Wire" ), _( "Divide a wire into segments which can be dragged independently" ),
  149. break_line_xpm );
  150. TOOL_ACTION EE_ACTIONS::breakBus( "eeschema.InteractiveEdit.breakBus",
  151. AS_GLOBAL, 0,
  152. _( "Break Bus" ), _( "Divide a bus into segments which can be dragged independently" ),
  153. break_line_xpm );
  154. char g_lastBusEntryShape = '/';
  155. class SYMBOL_UNIT_MENU : public ACTION_MENU
  156. {
  157. public:
  158. SYMBOL_UNIT_MENU()
  159. {
  160. SetIcon( component_select_unit_xpm );
  161. SetTitle( _( "Symbol Unit" ) );
  162. }
  163. protected:
  164. ACTION_MENU* create() const override
  165. {
  166. return new SYMBOL_UNIT_MENU();
  167. }
  168. private:
  169. void update() override
  170. {
  171. EE_SELECTION_TOOL* selTool = getToolManager()->GetTool<EE_SELECTION_TOOL>();
  172. SELECTION& selection = selTool->GetSelection();
  173. SCH_COMPONENT* component = dynamic_cast<SCH_COMPONENT*>( selection.Front() );
  174. if( !component )
  175. {
  176. Append( ID_POPUP_SCH_UNFOLD_BUS, _( "no symbol selected" ), wxEmptyString );
  177. Enable( ID_POPUP_SCH_UNFOLD_BUS, false );
  178. return;
  179. }
  180. int unit = component->GetUnit();
  181. auto partRef = component->GetPartRef().lock();
  182. if( !partRef || partRef->GetUnitCount() < 2 )
  183. {
  184. Append( ID_POPUP_SCH_UNFOLD_BUS, _( "symbol is not multi-unit" ), wxEmptyString );
  185. Enable( ID_POPUP_SCH_UNFOLD_BUS, false );
  186. return;
  187. }
  188. for( int ii = 0; ii < partRef->GetUnitCount(); ii++ )
  189. {
  190. wxString num_unit;
  191. num_unit.Printf( _( "Unit %s" ), LIB_PART::SubReference( ii + 1, false ) );
  192. wxMenuItem * item = Append( ID_POPUP_SCH_SELECT_UNIT1 + ii, num_unit, wxEmptyString,
  193. wxITEM_CHECK );
  194. if( unit == ii + 1 )
  195. item->Check(true);
  196. // The ID max for these submenus is ID_POPUP_SCH_SELECT_UNIT_CMP_MAX
  197. // See eeschema_id to modify this value.
  198. if( ii >= (ID_POPUP_SCH_SELECT_UNIT_CMP_MAX - ID_POPUP_SCH_SELECT_UNIT1) )
  199. break; // We have used all IDs for these submenus
  200. }
  201. }
  202. };
  203. SCH_EDIT_TOOL::SCH_EDIT_TOOL() :
  204. EE_TOOL_BASE<SCH_EDIT_FRAME>( "eeschema.InteractiveEdit" )
  205. {
  206. }
  207. using E_C = EE_CONDITIONS;
  208. bool SCH_EDIT_TOOL::Init()
  209. {
  210. EE_TOOL_BASE::Init();
  211. SCH_DRAWING_TOOLS* drawingTools = m_toolMgr->GetTool<SCH_DRAWING_TOOLS>();
  212. SCH_MOVE_TOOL* moveTool = m_toolMgr->GetTool<SCH_MOVE_TOOL>();
  213. wxASSERT_MSG( drawingTools, "eeshema.InteractiveDrawing tool is not available" );
  214. auto sheetTool = [ this ] ( const SELECTION& aSel ) {
  215. return ( m_frame->GetToolId() == ID_SHEET_TOOL );
  216. };
  217. auto anyTextTool = [ this ] ( const SELECTION& aSel ) {
  218. return ( m_frame->GetToolId() == ID_LABEL_TOOL
  219. || m_frame->GetToolId() == ID_GLOBALLABEL_TOOL
  220. || m_frame->GetToolId() == ID_HIERLABEL_TOOL
  221. || m_frame->GetToolId() == ID_SCHEMATIC_TEXT_TOOL );
  222. };
  223. auto duplicateCondition = [] ( const SELECTION& aSel ) {
  224. if( SCH_WIRE_BUS_TOOL::IsDrawingLineWireOrBus( aSel ) )
  225. return false;
  226. return true;
  227. };
  228. auto orientCondition = [] ( const SELECTION& aSel ) {
  229. if( aSel.Empty() )
  230. return false;
  231. if( SCH_WIRE_BUS_TOOL::IsDrawingLineWireOrBus( aSel ) )
  232. return false;
  233. SCH_ITEM* item = (SCH_ITEM*) aSel.Front();
  234. if( aSel.GetSize() > 1 )
  235. return true;
  236. switch( item->Type() )
  237. {
  238. case SCH_MARKER_T:
  239. case SCH_JUNCTION_T:
  240. case SCH_NO_CONNECT_T:
  241. case SCH_LINE_T:
  242. case SCH_PIN_T:
  243. return false;
  244. default:
  245. return true;
  246. }
  247. };
  248. auto propertiesCondition = [] ( const SELECTION& aSel ) {
  249. if( aSel.GetSize() != 1 )
  250. return false;
  251. switch( static_cast<EDA_ITEM*>( aSel.Front() )->Type() )
  252. {
  253. case SCH_MARKER_T:
  254. case SCH_JUNCTION_T:
  255. case SCH_NO_CONNECT_T:
  256. case SCH_BUS_WIRE_ENTRY_T:
  257. case SCH_BUS_BUS_ENTRY_T:
  258. case SCH_LINE_T:
  259. case SCH_SHEET_PIN_T:
  260. case SCH_PIN_T:
  261. return false;
  262. default:
  263. return true;
  264. }
  265. };
  266. static KICAD_T toLabelTypes[] = { SCH_GLOBAL_LABEL_T, SCH_HIER_LABEL_T, SCH_TEXT_T, EOT };
  267. auto toLabelCondition = E_C::Count( 1 ) && E_C::OnlyTypes( toLabelTypes );
  268. static KICAD_T toHLableTypes[] = { SCH_LABEL_T, SCH_GLOBAL_LABEL_T, SCH_TEXT_T, EOT };
  269. auto toHLabelCondition = E_C::Count( 1 ) && E_C::OnlyTypes( toHLableTypes );
  270. static KICAD_T toGLableTypes[] = { SCH_LABEL_T, SCH_HIER_LABEL_T, SCH_TEXT_T, EOT };
  271. auto toGLabelCondition = E_C::Count( 1 ) && E_C::OnlyTypes( toGLableTypes );
  272. static KICAD_T toTextTypes[] = { SCH_LABEL_T, SCH_GLOBAL_LABEL_T, SCH_HIER_LABEL_T, EOT };
  273. auto toTextlCondition = E_C::Count( 1 ) && E_C::OnlyTypes( toTextTypes );
  274. static KICAD_T entryTypes[] = { SCH_BUS_WIRE_ENTRY_T, SCH_BUS_BUS_ENTRY_T, EOT };
  275. auto entryCondition = E_C::MoreThan( 0 ) && E_C::OnlyTypes( entryTypes );
  276. auto singleComponentCondition = E_C::Count( 1 ) && E_C::OnlyType( SCH_COMPONENT_T );
  277. auto wireSelectionCondition = E_C::MoreThan( 0 ) && E_C::OnlyType( SCH_LINE_LOCATE_WIRE_T );
  278. auto busSelectionCondition = E_C::MoreThan( 0 ) && E_C::OnlyType( SCH_LINE_LOCATE_BUS_T );
  279. auto singleSheetCondition = E_C::Count( 1 ) && E_C::OnlyType( SCH_SHEET_T );
  280. //
  281. // Add edit actions to the move tool menu
  282. //
  283. if( moveTool )
  284. {
  285. CONDITIONAL_MENU& moveMenu = moveTool->GetToolMenu().GetMenu();
  286. moveMenu.AddSeparator( SELECTION_CONDITIONS::NotEmpty );
  287. moveMenu.AddItem( EE_ACTIONS::rotateCCW, orientCondition );
  288. moveMenu.AddItem( EE_ACTIONS::rotateCW, orientCondition );
  289. moveMenu.AddItem( EE_ACTIONS::mirrorX, orientCondition );
  290. moveMenu.AddItem( EE_ACTIONS::mirrorY, orientCondition );
  291. moveMenu.AddItem( EE_ACTIONS::doDelete, E_C::NotEmpty );
  292. moveMenu.AddItem( EE_ACTIONS::properties, propertiesCondition );
  293. moveMenu.AddItem( EE_ACTIONS::editReference, singleComponentCondition );
  294. moveMenu.AddItem( EE_ACTIONS::editValue, singleComponentCondition );
  295. moveMenu.AddItem( EE_ACTIONS::editFootprint, singleComponentCondition );
  296. moveMenu.AddItem( EE_ACTIONS::toggleDeMorgan, E_C::SingleDeMorganSymbol );
  297. std::shared_ptr<SYMBOL_UNIT_MENU> symUnitMenu = std::make_shared<SYMBOL_UNIT_MENU>();
  298. symUnitMenu->SetTool( this );
  299. m_menu.AddSubMenu( symUnitMenu );
  300. moveMenu.AddMenu( symUnitMenu.get(), E_C::SingleMultiUnitSymbol, 1 );
  301. moveMenu.AddSeparator( E_C::IdleSelection );
  302. moveMenu.AddItem( ACTIONS::cut, E_C::IdleSelection );
  303. moveMenu.AddItem( ACTIONS::copy, E_C::IdleSelection );
  304. moveMenu.AddItem( ACTIONS::duplicate, duplicateCondition );
  305. }
  306. //
  307. // Add editing actions to the drawing tool menu
  308. //
  309. CONDITIONAL_MENU& drawMenu = drawingTools->GetToolMenu().GetMenu();
  310. drawMenu.AddItem( EE_ACTIONS::rotateCCW, orientCondition, 200 );
  311. drawMenu.AddItem( EE_ACTIONS::rotateCW, orientCondition, 200 );
  312. drawMenu.AddItem( EE_ACTIONS::mirrorX, orientCondition, 200 );
  313. drawMenu.AddItem( EE_ACTIONS::mirrorY, orientCondition, 200 );
  314. drawMenu.AddItem( EE_ACTIONS::properties, propertiesCondition, 200 );
  315. drawMenu.AddItem( EE_ACTIONS::editReference, singleComponentCondition, 200 );
  316. drawMenu.AddItem( EE_ACTIONS::editValue, singleComponentCondition, 200 );
  317. drawMenu.AddItem( EE_ACTIONS::editFootprint, singleComponentCondition, 200 );
  318. drawMenu.AddItem( EE_ACTIONS::autoplaceFields, singleComponentCondition, 200 );
  319. drawMenu.AddItem( EE_ACTIONS::toggleDeMorgan, E_C::SingleDeMorganSymbol, 200 );
  320. std::shared_ptr<SYMBOL_UNIT_MENU> symUnitMenu2 = std::make_shared<SYMBOL_UNIT_MENU>();
  321. symUnitMenu2->SetTool( drawingTools );
  322. drawingTools->GetToolMenu().AddSubMenu( symUnitMenu2 );
  323. drawMenu.AddMenu( symUnitMenu2.get(), E_C::SingleMultiUnitSymbol, 1 );
  324. drawMenu.AddItem( EE_ACTIONS::editWithLibEdit, singleComponentCondition && E_C::Idle, 200 );
  325. drawMenu.AddItem( EE_ACTIONS::toShapeSlash, entryCondition, 200 );
  326. drawMenu.AddItem( EE_ACTIONS::toShapeBackslash, entryCondition, 200 );
  327. drawMenu.AddItem( EE_ACTIONS::toLabel, anyTextTool && E_C::Idle, 200 );
  328. drawMenu.AddItem( EE_ACTIONS::toHLabel, anyTextTool && E_C::Idle, 200 );
  329. drawMenu.AddItem( EE_ACTIONS::toGLabel, anyTextTool && E_C::Idle, 200 );
  330. drawMenu.AddItem( EE_ACTIONS::toText, anyTextTool && E_C::Idle, 200 );
  331. drawMenu.AddItem( EE_ACTIONS::cleanupSheetPins, sheetTool && E_C::Idle, 250 );
  332. //
  333. // Add editing actions to the selection tool menu
  334. //
  335. CONDITIONAL_MENU& selToolMenu = m_selectionTool->GetToolMenu().GetMenu();
  336. selToolMenu.AddItem( EE_ACTIONS::rotateCCW, orientCondition, 200 );
  337. selToolMenu.AddItem( EE_ACTIONS::rotateCW, orientCondition, 200 );
  338. selToolMenu.AddItem( EE_ACTIONS::mirrorX, orientCondition, 200 );
  339. selToolMenu.AddItem( EE_ACTIONS::mirrorY, orientCondition, 200 );
  340. selToolMenu.AddItem( EE_ACTIONS::doDelete, E_C::NotEmpty, 200 );
  341. selToolMenu.AddItem( EE_ACTIONS::properties, propertiesCondition, 200 );
  342. selToolMenu.AddItem( EE_ACTIONS::editReference, E_C::SingleSymbol, 200 );
  343. selToolMenu.AddItem( EE_ACTIONS::editValue, E_C::SingleSymbol, 200 );
  344. selToolMenu.AddItem( EE_ACTIONS::editFootprint, E_C::SingleSymbol, 200 );
  345. selToolMenu.AddItem( EE_ACTIONS::autoplaceFields, singleComponentCondition, 200 );
  346. selToolMenu.AddItem( EE_ACTIONS::toggleDeMorgan, E_C::SingleSymbol, 200 );
  347. std::shared_ptr<SYMBOL_UNIT_MENU> symUnitMenu3 = std::make_shared<SYMBOL_UNIT_MENU>();
  348. symUnitMenu3->SetTool( m_selectionTool );
  349. m_selectionTool->GetToolMenu().AddSubMenu( symUnitMenu3 );
  350. selToolMenu.AddMenu( symUnitMenu3.get(), E_C::SingleMultiUnitSymbol, 1 );
  351. selToolMenu.AddItem( EE_ACTIONS::editWithLibEdit, singleComponentCondition && E_C::Idle, 200 );
  352. selToolMenu.AddItem( EE_ACTIONS::toShapeSlash, entryCondition, 200 );
  353. selToolMenu.AddItem( EE_ACTIONS::toShapeBackslash, entryCondition, 200 );
  354. selToolMenu.AddItem( EE_ACTIONS::toLabel, toLabelCondition, 200 );
  355. selToolMenu.AddItem( EE_ACTIONS::toHLabel, toHLabelCondition, 200 );
  356. selToolMenu.AddItem( EE_ACTIONS::toGLabel, toGLabelCondition, 200 );
  357. selToolMenu.AddItem( EE_ACTIONS::toText, toTextlCondition, 200 );
  358. selToolMenu.AddItem( EE_ACTIONS::cleanupSheetPins, singleSheetCondition, 250 );
  359. selToolMenu.AddSeparator( E_C::Idle, 300 );
  360. selToolMenu.AddItem( ACTIONS::cut, E_C::IdleSelection, 300 );
  361. selToolMenu.AddItem( ACTIONS::copy, E_C::IdleSelection, 300 );
  362. selToolMenu.AddItem( ACTIONS::paste, E_C::Idle, 300 );
  363. selToolMenu.AddItem( ACTIONS::duplicate, duplicateCondition, 300 );
  364. return true;
  365. }
  366. int SCH_EDIT_TOOL::Rotate( const TOOL_EVENT& aEvent )
  367. {
  368. SELECTION& selection = m_selectionTool->RequestSelection( EE_COLLECTOR::RotatableItems );
  369. if( selection.GetSize() == 0 )
  370. return 0;
  371. wxPoint rotPoint;
  372. bool clockwise = ( aEvent.Matches( EE_ACTIONS::rotateCW.MakeEvent() ) );
  373. SCH_ITEM* item = static_cast<SCH_ITEM*>( selection.Front() );
  374. bool connections = false;
  375. bool moving = item->IsMoving();
  376. if( selection.GetSize() == 1 )
  377. {
  378. if( !moving )
  379. saveCopyInUndoList( item, UR_CHANGED );
  380. for( int i = 0; clockwise ? i < 1 : i < 3; ++i )
  381. {
  382. switch( item->Type() )
  383. {
  384. case SCH_COMPONENT_T:
  385. {
  386. SCH_COMPONENT* component = static_cast<SCH_COMPONENT*>( item );
  387. if( clockwise )
  388. component->SetOrientation( CMP_ROTATE_CLOCKWISE );
  389. else
  390. component->SetOrientation( CMP_ROTATE_COUNTERCLOCKWISE );
  391. if( m_frame->GetAutoplaceFields() )
  392. component->AutoAutoplaceFields( m_frame->GetScreen() );
  393. break;
  394. }
  395. case SCH_TEXT_T:
  396. case SCH_LABEL_T:
  397. case SCH_GLOBAL_LABEL_T:
  398. case SCH_HIER_LABEL_T:
  399. {
  400. SCH_TEXT* textItem = static_cast<SCH_TEXT*>( item );
  401. textItem->SetLabelSpinStyle( ( textItem->GetLabelSpinStyle() + 1 ) & 3 );
  402. break;
  403. }
  404. case SCH_SHEET_PIN_T:
  405. {
  406. // Rotate pin within parent sheet
  407. SCH_SHEET_PIN* pin = static_cast<SCH_SHEET_PIN*>( item );
  408. SCH_SHEET* sheet = pin->GetParent();
  409. pin->Rotate( sheet->GetBoundingBox().GetCenter() );
  410. break;
  411. }
  412. case SCH_BUS_BUS_ENTRY_T:
  413. case SCH_BUS_WIRE_ENTRY_T:
  414. item->Rotate( item->GetPosition() );
  415. break;
  416. case SCH_FIELD_T:
  417. {
  418. SCH_FIELD* field = static_cast<SCH_FIELD*>( item );
  419. if( field->GetTextAngle() == TEXT_ANGLE_HORIZ )
  420. field->SetTextAngle( TEXT_ANGLE_VERT );
  421. else
  422. field->SetTextAngle( TEXT_ANGLE_HORIZ );
  423. // Now that we're moving a field, they're no longer autoplaced.
  424. if( item->GetParent()->Type() == SCH_COMPONENT_T )
  425. {
  426. SCH_COMPONENT *parent = static_cast<SCH_COMPONENT*>( item->GetParent() );
  427. parent->ClearFieldsAutoplaced();
  428. }
  429. break;
  430. }
  431. case SCH_BITMAP_T:
  432. item->Rotate( item->GetPosition() );
  433. // The bitmap is cached in Opengl: clear the cache to redraw
  434. getView()->RecacheAllItems();
  435. break;
  436. case SCH_SHEET_T:
  437. // Rotate the sheet on itself. Sheets do not have an anchor point.
  438. rotPoint = m_frame->GetNearestGridPosition( item->GetBoundingBox().Centre() );
  439. item->Rotate( rotPoint );
  440. break;
  441. default:
  442. break;
  443. }
  444. }
  445. connections = item->IsConnectable();
  446. m_frame->RefreshItem( item );
  447. }
  448. else if( selection.GetSize() > 1 )
  449. {
  450. rotPoint = (wxPoint)selection.GetReferencePoint();
  451. for( unsigned ii = 0; ii < selection.GetSize(); ii++ )
  452. {
  453. item = static_cast<SCH_ITEM*>( selection.GetItem( ii ) );
  454. if( !moving )
  455. saveCopyInUndoList( item, UR_CHANGED, ii > 0 );
  456. for( int i = 0; clockwise ? i < 1 : i < 3; ++i )
  457. {
  458. if( item->Type() == SCH_LINE_T )
  459. {
  460. SCH_LINE* line = (SCH_LINE*) item;
  461. if( item->GetFlags() & STARTPOINT )
  462. line->RotateStart( rotPoint );
  463. if( item->GetFlags() & ENDPOINT )
  464. line->RotateEnd( rotPoint );
  465. }
  466. else if( item->Type() == SCH_SHEET_PIN_T )
  467. {
  468. if( item->GetParent()->IsSelected() )
  469. {
  470. // parent will rotate us
  471. }
  472. else
  473. {
  474. // rotate within parent
  475. SCH_SHEET_PIN* pin = static_cast<SCH_SHEET_PIN*>( item );
  476. SCH_SHEET* sheet = pin->GetParent();
  477. pin->Rotate( sheet->GetBoundingBox().GetCenter() );
  478. }
  479. }
  480. else
  481. {
  482. item->Rotate( rotPoint );
  483. }
  484. }
  485. connections |= item->IsConnectable();
  486. m_frame->RefreshItem( item );
  487. }
  488. }
  489. m_toolMgr->PostEvent( EVENTS::SelectedItemsModified );
  490. if( item->IsMoving() )
  491. {
  492. m_toolMgr->RunAction( EE_ACTIONS::refreshPreview );
  493. }
  494. else
  495. {
  496. if( selection.IsHover() )
  497. m_toolMgr->RunAction( EE_ACTIONS::clearSelection, true );
  498. if( connections )
  499. m_frame->TestDanglingEnds();
  500. m_frame->OnModify();
  501. }
  502. return 0;
  503. }
  504. int SCH_EDIT_TOOL::Mirror( const TOOL_EVENT& aEvent )
  505. {
  506. SELECTION& selection = m_selectionTool->RequestSelection( EE_COLLECTOR::RotatableItems );
  507. if( selection.GetSize() == 0 )
  508. return 0;
  509. wxPoint mirrorPoint;
  510. bool xAxis = ( aEvent.Matches( EE_ACTIONS::mirrorX.MakeEvent() ) );
  511. SCH_ITEM* item = static_cast<SCH_ITEM*>( selection.Front() );
  512. bool connections = false;
  513. bool moving = item->IsMoving();
  514. if( selection.GetSize() == 1 )
  515. {
  516. if( !moving )
  517. saveCopyInUndoList( item, UR_CHANGED );
  518. switch( item->Type() )
  519. {
  520. case SCH_COMPONENT_T:
  521. {
  522. SCH_COMPONENT* component = static_cast<SCH_COMPONENT*>( item );
  523. if( xAxis )
  524. component->SetOrientation( CMP_MIRROR_X );
  525. else
  526. component->SetOrientation( CMP_MIRROR_Y );
  527. if( m_frame->GetAutoplaceFields() )
  528. component->AutoAutoplaceFields( m_frame->GetScreen() );
  529. break;
  530. }
  531. case SCH_TEXT_T:
  532. case SCH_LABEL_T:
  533. case SCH_GLOBAL_LABEL_T:
  534. case SCH_HIER_LABEL_T:
  535. {
  536. SCH_TEXT* textItem = static_cast<SCH_TEXT*>( item );
  537. int spin = textItem->GetLabelSpinStyle();
  538. if( xAxis && spin % 2 )
  539. textItem->SetLabelSpinStyle( ( spin + 2 ) % 4 );
  540. else if ( !xAxis && !( spin % 2 ) )
  541. textItem->SetLabelSpinStyle( ( spin + 2 ) % 4 );
  542. break;
  543. }
  544. case SCH_SHEET_PIN_T:
  545. {
  546. // mirror within parent sheet
  547. SCH_SHEET_PIN* pin = static_cast<SCH_SHEET_PIN*>( item );
  548. SCH_SHEET* sheet = pin->GetParent();
  549. if( xAxis )
  550. pin->MirrorX( sheet->GetBoundingBox().GetCenter().y );
  551. else
  552. pin->MirrorY( sheet->GetBoundingBox().GetCenter().x );
  553. break;
  554. }
  555. case SCH_BUS_BUS_ENTRY_T:
  556. case SCH_BUS_WIRE_ENTRY_T:
  557. if( xAxis )
  558. item->MirrorX( item->GetPosition().y );
  559. else
  560. item->MirrorY( item->GetPosition().x );
  561. break;
  562. case SCH_FIELD_T:
  563. {
  564. SCH_FIELD* field = static_cast<SCH_FIELD*>( item );
  565. if( xAxis )
  566. field->SetVertJustify( (EDA_TEXT_VJUSTIFY_T)-field->GetVertJustify() );
  567. else
  568. field->SetHorizJustify( (EDA_TEXT_HJUSTIFY_T)-field->GetHorizJustify() );
  569. // Now that we're re-justifying a field, they're no longer autoplaced.
  570. if( item->GetParent()->Type() == SCH_COMPONENT_T )
  571. {
  572. SCH_COMPONENT *parent = static_cast<SCH_COMPONENT*>( item->GetParent() );
  573. parent->ClearFieldsAutoplaced();
  574. }
  575. break;
  576. }
  577. case SCH_BITMAP_T:
  578. if( xAxis )
  579. item->MirrorX( item->GetPosition().y );
  580. else
  581. item->MirrorY( item->GetPosition().x );
  582. // The bitmap is cached in Opengl: clear the cache to redraw
  583. getView()->RecacheAllItems();
  584. break;
  585. case SCH_SHEET_T:
  586. // Mirror the sheet on itself. Sheets do not have a anchor point.
  587. mirrorPoint = m_frame->GetNearestGridPosition( item->GetBoundingBox().Centre() );
  588. if( xAxis )
  589. item->MirrorX( mirrorPoint.y );
  590. else
  591. item->MirrorY( mirrorPoint.x );
  592. break;
  593. default:
  594. break;
  595. }
  596. connections = item->IsConnectable();
  597. m_frame->RefreshItem( item );
  598. }
  599. else if( selection.GetSize() > 1 )
  600. {
  601. mirrorPoint = (wxPoint)selection.GetReferencePoint();
  602. for( unsigned ii = 0; ii < selection.GetSize(); ii++ )
  603. {
  604. item = static_cast<SCH_ITEM*>( selection.GetItem( ii ) );
  605. if( !moving )
  606. saveCopyInUndoList( item, UR_CHANGED, ii > 0 );
  607. if( item->Type() == SCH_SHEET_PIN_T )
  608. {
  609. if( item->GetParent()->IsSelected() )
  610. {
  611. // parent will mirror us
  612. }
  613. else
  614. {
  615. // mirror within parent sheet
  616. SCH_SHEET_PIN* pin = static_cast<SCH_SHEET_PIN*>( item );
  617. SCH_SHEET* sheet = pin->GetParent();
  618. if( xAxis )
  619. pin->MirrorX( sheet->GetBoundingBox().GetCenter().y );
  620. else
  621. pin->MirrorY( sheet->GetBoundingBox().GetCenter().x );
  622. }
  623. }
  624. else
  625. {
  626. if( xAxis )
  627. item->MirrorX( mirrorPoint.y );
  628. else
  629. item->MirrorY( mirrorPoint.x );
  630. }
  631. connections |= item->IsConnectable();
  632. m_frame->RefreshItem( item );
  633. }
  634. }
  635. m_toolMgr->PostEvent( EVENTS::SelectedItemsModified );
  636. if( item->IsMoving() )
  637. {
  638. m_toolMgr->RunAction( EE_ACTIONS::refreshPreview );
  639. }
  640. else
  641. {
  642. if( selection.IsHover() )
  643. m_toolMgr->RunAction( EE_ACTIONS::clearSelection, true );
  644. if( connections )
  645. m_frame->TestDanglingEnds();
  646. m_frame->OnModify();
  647. }
  648. return 0;
  649. }
  650. int SCH_EDIT_TOOL::Duplicate( const TOOL_EVENT& aEvent )
  651. {
  652. static KICAD_T duplicatableItems[] =
  653. {
  654. SCH_JUNCTION_T,
  655. SCH_LINE_T,
  656. SCH_BUS_BUS_ENTRY_T,
  657. SCH_BUS_WIRE_ENTRY_T,
  658. SCH_TEXT_T,
  659. SCH_LABEL_T,
  660. SCH_GLOBAL_LABEL_T,
  661. SCH_HIER_LABEL_T,
  662. SCH_NO_CONNECT_T,
  663. SCH_SHEET_T,
  664. SCH_COMPONENT_T,
  665. EOT
  666. };
  667. SELECTION& selection = m_selectionTool->RequestSelection( duplicatableItems );
  668. if( selection.GetSize() == 0 )
  669. return 0;
  670. // Doing a duplicate of a new object doesn't really make any sense; we'd just end
  671. // up dragging around a stack of objects...
  672. if( selection.Front()->IsNew() )
  673. return 0;
  674. EDA_ITEMS newItems;
  675. // Keep track of existing sheet paths. Duplicating a selection can modify this list
  676. bool copiedSheets = false;
  677. SCH_SHEET_LIST initial_sheetpathList( g_RootSheet );
  678. for( unsigned ii = 0; ii < selection.GetSize(); ++ii )
  679. {
  680. SCH_ITEM* oldItem = static_cast<SCH_ITEM*>( selection.GetItem( ii ) );
  681. SCH_ITEM* newItem = oldItem->Duplicate();
  682. newItem->SetFlags( IS_NEW );
  683. newItems.push_back( newItem );
  684. saveCopyInUndoList( newItem, UR_NEW, ii > 0 );
  685. switch( newItem->Type() )
  686. {
  687. case SCH_JUNCTION_T:
  688. case SCH_LINE_T:
  689. case SCH_BUS_BUS_ENTRY_T:
  690. case SCH_BUS_WIRE_ENTRY_T:
  691. case SCH_TEXT_T:
  692. case SCH_LABEL_T:
  693. case SCH_GLOBAL_LABEL_T:
  694. case SCH_HIER_LABEL_T:
  695. case SCH_NO_CONNECT_T:
  696. newItem->SetParent( m_frame->GetScreen() );
  697. m_frame->AddToScreen( newItem );
  698. break;
  699. case SCH_SHEET_T:
  700. {
  701. SCH_SHEET* sheet = (SCH_SHEET*) newItem;
  702. // Duplicate sheet names and sheet time stamps are not valid. Use a time stamp
  703. // based sheet name and update the time stamp for each sheet in the block.
  704. timestamp_t timeStamp = GetNewTimeStamp();
  705. sheet->SetName( wxString::Format( wxT( "sheet%8.8lX" ), (unsigned long)timeStamp ) );
  706. sheet->SetTimeStamp( timeStamp );
  707. sheet->SetParent( m_frame->GetScreen() );
  708. m_frame->AddToScreen( sheet );
  709. copiedSheets = true;
  710. break;
  711. }
  712. case SCH_COMPONENT_T:
  713. {
  714. SCH_COMPONENT* component = (SCH_COMPONENT*) newItem;
  715. component->SetTimeStamp( GetNewTimeStamp() );
  716. component->ClearAnnotation( NULL );
  717. component->SetParent( m_frame->GetScreen() );
  718. m_frame->AddToScreen( component );
  719. break;
  720. }
  721. default:
  722. break;
  723. }
  724. }
  725. if( copiedSheets )
  726. {
  727. // We clear annotation of new sheet paths.
  728. // Annotation of new components added in current sheet is already cleared.
  729. SCH_SCREENS screensList( g_RootSheet );
  730. screensList.ClearAnnotationOfNewSheetPaths( initial_sheetpathList );
  731. m_frame->SetSheetNumberAndCount();
  732. }
  733. m_toolMgr->RunAction( EE_ACTIONS::clearSelection, true );
  734. m_toolMgr->RunAction( EE_ACTIONS::addItemsToSel, true, &newItems );
  735. m_toolMgr->RunAction( EE_ACTIONS::move, false );
  736. return 0;
  737. }
  738. int SCH_EDIT_TOOL::RepeatDrawItem( const TOOL_EVENT& aEvent )
  739. {
  740. SCH_ITEM* sourceItem = m_frame->GetRepeatItem();
  741. if( !sourceItem )
  742. return 0;
  743. m_toolMgr->RunAction( EE_ACTIONS::clearSelection, true );
  744. SCH_ITEM* newItem = (SCH_ITEM*) sourceItem->Clone();
  745. bool performDrag = false;
  746. // If cloning a component then put into 'move' mode.
  747. if( newItem->Type() == SCH_COMPONENT_T )
  748. {
  749. ( (SCH_COMPONENT*) newItem )->SetTimeStamp( GetNewTimeStamp() );
  750. wxPoint cursorPos = (wxPoint) getViewControls()->GetCursorPosition( true );
  751. newItem->Move( cursorPos - newItem->GetPosition() );
  752. performDrag = true;
  753. }
  754. else
  755. {
  756. if( newItem->CanIncrementLabel() )
  757. ( (SCH_TEXT*) newItem )->IncrementLabel( m_frame->GetRepeatDeltaLabel() );
  758. newItem->Move( m_frame->GetRepeatStep() );
  759. }
  760. newItem->SetFlags( IS_NEW );
  761. m_frame->AddToScreen( newItem );
  762. m_frame->SaveCopyInUndoList( newItem, UR_NEW );
  763. m_selectionTool->AddItemToSel( newItem );
  764. if( performDrag )
  765. m_toolMgr->RunAction( EE_ACTIONS::move, true );
  766. newItem->ClearFlags();
  767. if( newItem->IsConnectable() )
  768. m_frame->TestDanglingEnds();
  769. // newItem newItem, now that it has been moved, thus saving new position.
  770. m_frame->SaveCopyForRepeatItem( newItem );
  771. return 0;
  772. }
  773. int SCH_EDIT_TOOL::DoDelete( const TOOL_EVENT& aEvent )
  774. {
  775. SCH_SCREEN* screen = m_frame->GetScreen();
  776. auto items = m_selectionTool->RequestSelection().GetItems();
  777. bool appendToUndo = false;
  778. if( items.empty() )
  779. return 0;
  780. // Don't leave a freed pointer in the selection
  781. m_toolMgr->RunAction( EE_ACTIONS::clearSelection, true );
  782. for( EDA_ITEM* item : items )
  783. {
  784. // Junctions, in particular, may have already been deleted if deleting wires made
  785. // them redundant
  786. if( item->GetEditFlags() & STRUCT_DELETED )
  787. continue;
  788. if( item->Type() == SCH_JUNCTION_T )
  789. {
  790. m_frame->DeleteJunction( (SCH_ITEM*) item, appendToUndo );
  791. appendToUndo = true;
  792. }
  793. else
  794. {
  795. item->SetFlags( STRUCT_DELETED );
  796. saveCopyInUndoList( item, UR_DELETED, appendToUndo );
  797. appendToUndo = true;
  798. updateView( item );
  799. SCH_ITEM* sch_item = dynamic_cast<SCH_ITEM*>( item );
  800. if( sch_item && sch_item->IsConnectable() )
  801. {
  802. std::vector< wxPoint > pts;
  803. sch_item->GetConnectionPoints( pts );
  804. for( auto point : pts )
  805. {
  806. SCH_ITEM* junction = screen->GetItem( point, 0, SCH_JUNCTION_T );
  807. if( junction && !screen->IsJunctionNeeded( point ) )
  808. m_frame->DeleteJunction( junction, appendToUndo );
  809. }
  810. }
  811. if( item->Type() == SCH_SHEET_PIN_T )
  812. static_cast<SCH_SHEET*>( item->GetParent() )->RemovePin( (SCH_SHEET_PIN*) item );
  813. else
  814. m_frame->RemoveFromScreen( item );
  815. }
  816. }
  817. m_frame->TestDanglingEnds();
  818. m_frame->GetCanvas()->Refresh();
  819. m_frame->OnModify();
  820. return 0;
  821. }
  822. static bool deleteItem( SCH_BASE_FRAME* aFrame, const VECTOR2D& aPosition )
  823. {
  824. EE_SELECTION_TOOL* selectionTool = aFrame->GetToolManager()->GetTool<EE_SELECTION_TOOL>();
  825. wxCHECK( selectionTool, false );
  826. aFrame->GetToolManager()->RunAction( EE_ACTIONS::clearSelection, true );
  827. EDA_ITEM* item = selectionTool->SelectPoint( aPosition );
  828. SCH_ITEM* sch_item = dynamic_cast<SCH_ITEM*>( item );
  829. if( sch_item && sch_item->IsLocked() )
  830. {
  831. STATUS_TEXT_POPUP statusPopup( aFrame );
  832. statusPopup.SetText( _( "Item locked." ) );
  833. statusPopup.PopupFor( 2000 );
  834. statusPopup.Move( wxGetMousePosition() + wxPoint( 20, 20 ) );
  835. return true;
  836. }
  837. if( item )
  838. aFrame->GetToolManager()->RunAction( EE_ACTIONS::doDelete, true );
  839. return true;
  840. }
  841. int SCH_EDIT_TOOL::DeleteItemCursor( const TOOL_EVENT& aEvent )
  842. {
  843. Activate();
  844. EE_PICKER_TOOL* picker = m_toolMgr->GetTool<EE_PICKER_TOOL>();
  845. wxCHECK( picker, 0 );
  846. m_frame->SetToolID( ID_DELETE_TOOL, wxCURSOR_BULLSEYE, _( "Delete item" ) );
  847. picker->SetClickHandler( std::bind( deleteItem, m_frame, std::placeholders::_1 ) );
  848. picker->Activate();
  849. Wait();
  850. return 0;
  851. }
  852. int SCH_EDIT_TOOL::EditField( const TOOL_EVENT& aEvent )
  853. {
  854. static KICAD_T Nothing[] = { EOT };
  855. static KICAD_T CmpOrReference[] = { SCH_FIELD_LOCATE_REFERENCE_T, SCH_COMPONENT_T, EOT };
  856. static KICAD_T CmpOrValue[] = { SCH_FIELD_LOCATE_VALUE_T, SCH_COMPONENT_T, EOT };
  857. static KICAD_T CmpOrFootprint[] = { SCH_FIELD_LOCATE_FOOTPRINT_T, SCH_COMPONENT_T, EOT };
  858. KICAD_T* filter = Nothing;
  859. if( aEvent.IsAction( &EE_ACTIONS::editReference ) )
  860. filter = CmpOrReference;
  861. else if( aEvent.IsAction( &EE_ACTIONS::editValue ) )
  862. filter = CmpOrValue;
  863. else if( aEvent.IsAction( &EE_ACTIONS::editFootprint ) )
  864. filter = CmpOrFootprint;
  865. SELECTION& selection = m_selectionTool->RequestSelection( filter );
  866. if( selection.Empty() )
  867. return 0;
  868. SCH_ITEM* item = (SCH_ITEM*) selection.Front();
  869. if( item->Type() == SCH_COMPONENT_T )
  870. {
  871. SCH_COMPONENT* component = (SCH_COMPONENT*) item;
  872. if( aEvent.IsAction( &EE_ACTIONS::editReference ) )
  873. m_frame->EditComponentFieldText( component->GetField( REFERENCE ) );
  874. else if( aEvent.IsAction( &EE_ACTIONS::editValue ) )
  875. m_frame->EditComponentFieldText( component->GetField( VALUE ) );
  876. else if( aEvent.IsAction( &EE_ACTIONS::editFootprint ) )
  877. m_frame->EditComponentFieldText( component->GetField( FOOTPRINT ) );
  878. }
  879. else if( item->Type() == SCH_FIELD_T )
  880. {
  881. m_frame->EditComponentFieldText( (SCH_FIELD*) item );
  882. }
  883. return 0;
  884. }
  885. int SCH_EDIT_TOOL::AutoplaceFields( const TOOL_EVENT& aEvent )
  886. {
  887. SELECTION& selection = m_selectionTool->RequestSelection( EE_COLLECTOR::ComponentsOnly );
  888. if( selection.Empty() )
  889. return 0;
  890. SCH_COMPONENT* component = (SCH_COMPONENT*) selection.Front();
  891. if( !component->IsNew() )
  892. m_frame->SaveCopyInUndoList( component, UR_CHANGED );
  893. component->AutoplaceFields( m_frame->GetScreen(), /* aManual */ true );
  894. updateView( component );
  895. m_frame->OnModify();
  896. return 0;
  897. }
  898. int SCH_EDIT_TOOL::UpdateFields( const TOOL_EVENT& aEvent )
  899. {
  900. std::list<SCH_COMPONENT*> components;
  901. for( SCH_ITEM* item = m_frame->GetScreen()->GetDrawItems(); item; item = item->Next() )
  902. {
  903. if( item->Type() == SCH_COMPONENT_T )
  904. components.push_back( static_cast<SCH_COMPONENT*>( item ) );
  905. }
  906. if( InvokeDialogUpdateFields( m_frame, components, true ) == wxID_OK )
  907. m_frame->GetCanvas()->Refresh();
  908. return 0;
  909. }
  910. int SCH_EDIT_TOOL::ConvertDeMorgan( const TOOL_EVENT& aEvent )
  911. {
  912. SELECTION& selection = m_selectionTool->RequestSelection( EE_COLLECTOR::ComponentsOnly );
  913. if( selection.Empty() )
  914. return 0;
  915. SCH_COMPONENT* component = (SCH_COMPONENT*) selection.Front();
  916. if( aEvent.IsAction( &EE_ACTIONS::showDeMorganStandard )
  917. && component->GetConvert() == LIB_ITEM::LIB_CONVERT::BASE )
  918. return 0;
  919. if( aEvent.IsAction( &EE_ACTIONS::showDeMorganAlternate )
  920. && component->GetConvert() != LIB_ITEM::LIB_CONVERT::DEMORGAN )
  921. return 0;
  922. if( !component->IsNew() )
  923. m_frame->SaveCopyInUndoList( component, UR_CHANGED );
  924. m_frame->ConvertPart( component );
  925. if( component->IsNew() )
  926. m_toolMgr->RunAction( EE_ACTIONS::refreshPreview );
  927. return 0;
  928. }
  929. int SCH_EDIT_TOOL::Properties( const TOOL_EVENT& aEvent )
  930. {
  931. SELECTION& selection = m_selectionTool->RequestSelection( EE_COLLECTOR::EditableItems );
  932. if( selection.Empty() )
  933. return 0;
  934. SCH_ITEM* item = (SCH_ITEM*) selection.Front();
  935. switch( item->Type() )
  936. {
  937. case SCH_COMPONENT_T:
  938. m_frame->EditComponent( (SCH_COMPONENT*) item );
  939. break;
  940. case SCH_SHEET_T:
  941. {
  942. bool doClearAnnotation;
  943. bool doRefresh = false;
  944. // Keep track of existing sheet paths. EditSheet() can modify this list
  945. SCH_SHEET_LIST initial_sheetpathList( g_RootSheet );
  946. doRefresh = m_frame->EditSheet( (SCH_SHEET*) item, g_CurrentSheet, &doClearAnnotation );
  947. if( doClearAnnotation ) // happens when the current sheet load a existing file
  948. { // we must clear "new" components annotation
  949. SCH_SCREENS screensList( g_RootSheet );
  950. // We clear annotation of new sheet paths here:
  951. screensList.ClearAnnotationOfNewSheetPaths( initial_sheetpathList );
  952. // Clear annotation of g_CurrentSheet itself, because its sheetpath
  953. // is not a new path, but components managed by its sheet path must have
  954. // their annotation cleared, becuase they are new:
  955. ((SCH_SHEET*) item)->GetScreen()->ClearAnnotation( g_CurrentSheet );
  956. }
  957. if( doRefresh )
  958. {
  959. m_toolMgr->PostEvent( EVENTS::SelectedItemsModified );
  960. m_frame->GetCanvas()->Refresh();
  961. }
  962. break;
  963. }
  964. case SCH_SHEET_PIN_T:
  965. m_frame->EditSheetPin( (SCH_SHEET_PIN*) item, true );
  966. break;
  967. case SCH_TEXT_T:
  968. case SCH_LABEL_T:
  969. case SCH_GLOBAL_LABEL_T:
  970. case SCH_HIER_LABEL_T:
  971. m_frame->EditSchematicText( (SCH_TEXT*) item );
  972. break;
  973. case SCH_FIELD_T:
  974. m_frame->EditComponentFieldText( (SCH_FIELD*) item );
  975. break;
  976. case SCH_BITMAP_T:
  977. if( m_frame->EditImage( (SCH_BITMAP*) item ) )
  978. {
  979. // The bitmap is cached in Opengl: clear the cache in case it has become invalid
  980. getView()->RecacheAllItems();
  981. }
  982. break;
  983. case SCH_LINE_T:
  984. m_frame->EditLine( (SCH_LINE*) item, true );
  985. break;
  986. case SCH_MARKER_T: // These items have no properties to edit
  987. case SCH_JUNCTION_T:
  988. case SCH_NO_CONNECT_T:
  989. break;
  990. default: // Unexpected item
  991. wxFAIL_MSG( wxString( "Cannot edit schematic item type " ) + item->GetClass() );
  992. }
  993. updateView( item );
  994. if( selection.IsHover() )
  995. {
  996. m_toolMgr->RunAction( EE_ACTIONS::clearSelection, true );
  997. }
  998. return 0;
  999. }
  1000. int SCH_EDIT_TOOL::ChangeShape( const TOOL_EVENT& aEvent )
  1001. {
  1002. SELECTION& selection = m_selectionTool->GetSelection();
  1003. char shape;
  1004. if( aEvent.IsAction( &EE_ACTIONS::toShapeSlash ) )
  1005. shape = '/';
  1006. else if( aEvent.IsAction( &EE_ACTIONS::toShapeBackslash ) )
  1007. shape = '\\';
  1008. else
  1009. return 0;
  1010. for( unsigned int i = 0; i < selection.GetSize(); ++i )
  1011. {
  1012. SCH_BUS_ENTRY_BASE* entry = dynamic_cast<SCH_BUS_ENTRY_BASE*>( selection.GetItem( i ) );
  1013. if( entry )
  1014. {
  1015. if( entry->GetEditFlags() == 0 )
  1016. m_frame->SaveCopyInUndoList( entry, UR_CHANGED );
  1017. entry->SetBusEntryShape( shape );
  1018. m_frame->TestDanglingEnds();
  1019. updateView( entry );
  1020. m_frame->OnModify( );
  1021. }
  1022. }
  1023. g_lastBusEntryShape = shape;
  1024. return 0;
  1025. }
  1026. int SCH_EDIT_TOOL::ChangeTextType( const TOOL_EVENT& aEvent )
  1027. {
  1028. KICAD_T allTextTypes[] = { SCH_LABEL_T, SCH_GLOBAL_LABEL_T, SCH_HIER_LABEL_T, SCH_TEXT_T, EOT };
  1029. SELECTION& selection = m_selectionTool->RequestSelection( allTextTypes );
  1030. KICAD_T convertTo;
  1031. if( aEvent.IsAction( &EE_ACTIONS::toLabel ) )
  1032. convertTo = SCH_LABEL_T;
  1033. else if( aEvent.IsAction( &EE_ACTIONS::toHLabel ) )
  1034. convertTo = SCH_HIER_LABEL_T;
  1035. else if( aEvent.IsAction( &EE_ACTIONS::toGLabel ) )
  1036. convertTo = SCH_GLOBAL_LABEL_T;
  1037. else if( aEvent.IsAction( &EE_ACTIONS::toText ) )
  1038. convertTo = SCH_TEXT_T;
  1039. else
  1040. return 0;
  1041. for( unsigned int i = 0; i < selection.GetSize(); ++i )
  1042. {
  1043. SCH_TEXT* text = dynamic_cast<SCH_TEXT*>( selection.GetItem( i ) );
  1044. if( text )
  1045. m_frame->ConvertTextType( text, convertTo );
  1046. }
  1047. return 0;
  1048. }
  1049. int SCH_EDIT_TOOL::BreakWire( const TOOL_EVENT& aEvent )
  1050. {
  1051. VECTOR2I cursorPos = getViewControls()->GetCursorPosition( !aEvent.Modifier( MD_ALT ) );
  1052. if( m_frame->BreakSegments( (wxPoint) cursorPos ) )
  1053. {
  1054. m_frame->TestDanglingEnds();
  1055. m_frame->OnModify();
  1056. m_frame->GetCanvas()->Refresh();
  1057. }
  1058. return 0;
  1059. }
  1060. int SCH_EDIT_TOOL::CleanupSheetPins( const TOOL_EVENT& aEvent )
  1061. {
  1062. SELECTION& selection = m_selectionTool->RequestSelection( EE_COLLECTOR::SheetsOnly );
  1063. SCH_SHEET* sheet = (SCH_SHEET*) selection.Front();
  1064. if( !sheet )
  1065. return 0;
  1066. if( !sheet->HasUndefinedPins() )
  1067. {
  1068. DisplayInfoMessage( m_frame, _( "There are no unreferenced pins in this sheet to remove." ) );
  1069. return 0;
  1070. }
  1071. if( !IsOK( m_frame, _( "Do you wish to delete the unreferenced pins from this sheet?" ) ) )
  1072. return 0;
  1073. m_frame->SaveCopyInUndoList( sheet, UR_CHANGED );
  1074. sheet->CleanupSheet();
  1075. updateView( sheet );
  1076. m_frame->OnModify();
  1077. return 0;
  1078. }
  1079. void SCH_EDIT_TOOL::setTransitions()
  1080. {
  1081. Go( &SCH_EDIT_TOOL::Duplicate, ACTIONS::duplicate.MakeEvent() );
  1082. Go( &SCH_EDIT_TOOL::RepeatDrawItem, EE_ACTIONS::repeatDrawItem.MakeEvent() );
  1083. Go( &SCH_EDIT_TOOL::Rotate, EE_ACTIONS::rotateCW.MakeEvent() );
  1084. Go( &SCH_EDIT_TOOL::Rotate, EE_ACTIONS::rotateCCW.MakeEvent() );
  1085. Go( &SCH_EDIT_TOOL::Mirror, EE_ACTIONS::mirrorX.MakeEvent() );
  1086. Go( &SCH_EDIT_TOOL::Mirror, EE_ACTIONS::mirrorY.MakeEvent() );
  1087. Go( &SCH_EDIT_TOOL::DoDelete, EE_ACTIONS::doDelete.MakeEvent() );
  1088. Go( &SCH_EDIT_TOOL::DeleteItemCursor, EE_ACTIONS::deleteItemCursor.MakeEvent() );
  1089. Go( &SCH_EDIT_TOOL::Properties, EE_ACTIONS::properties.MakeEvent() );
  1090. Go( &SCH_EDIT_TOOL::EditField, EE_ACTIONS::editReference.MakeEvent() );
  1091. Go( &SCH_EDIT_TOOL::EditField, EE_ACTIONS::editValue.MakeEvent() );
  1092. Go( &SCH_EDIT_TOOL::EditField, EE_ACTIONS::editFootprint.MakeEvent() );
  1093. Go( &SCH_EDIT_TOOL::AutoplaceFields, EE_ACTIONS::autoplaceFields.MakeEvent() );
  1094. Go( &SCH_EDIT_TOOL::UpdateFields, EE_ACTIONS::updateFieldsFromLibrary.MakeEvent() );
  1095. Go( &SCH_EDIT_TOOL::ConvertDeMorgan, EE_ACTIONS::toggleDeMorgan.MakeEvent() );
  1096. Go( &SCH_EDIT_TOOL::ConvertDeMorgan, EE_ACTIONS::showDeMorganStandard.MakeEvent() );
  1097. Go( &SCH_EDIT_TOOL::ConvertDeMorgan, EE_ACTIONS::showDeMorganAlternate.MakeEvent() );
  1098. Go( &SCH_EDIT_TOOL::ChangeShape, EE_ACTIONS::toShapeSlash.MakeEvent() );
  1099. Go( &SCH_EDIT_TOOL::ChangeShape, EE_ACTIONS::toShapeBackslash.MakeEvent() );
  1100. Go( &SCH_EDIT_TOOL::ChangeTextType, EE_ACTIONS::toLabel.MakeEvent() );
  1101. Go( &SCH_EDIT_TOOL::ChangeTextType, EE_ACTIONS::toHLabel.MakeEvent() );
  1102. Go( &SCH_EDIT_TOOL::ChangeTextType, EE_ACTIONS::toGLabel.MakeEvent() );
  1103. Go( &SCH_EDIT_TOOL::ChangeTextType, EE_ACTIONS::toText.MakeEvent() );
  1104. Go( &SCH_EDIT_TOOL::BreakWire, EE_ACTIONS::breakWire.MakeEvent() );
  1105. Go( &SCH_EDIT_TOOL::BreakWire, EE_ACTIONS::breakBus.MakeEvent() );
  1106. Go( &SCH_EDIT_TOOL::CleanupSheetPins, EE_ACTIONS::cleanupSheetPins.MakeEvent() );
  1107. }