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.

1014 lines
29 KiB

17 years ago
16 years ago
17 years ago
17 years ago
  1. /*
  2. * This program source code file is part of KiCad, a free EDA CAD application.
  3. *
  4. * Copyright (C) 2004 Jean-Pierre Charras, jaen-pierre.charras@gipsa-lab.inpg.com
  5. * Copyright (C) 2008-2011 Wayne Stambaugh <stambaughw@verizon.net>
  6. * Copyright (C) 2004-2011 KiCad Developers, see change_log.txt for contributors.
  7. *
  8. * This program is free software; you can redistribute it and/or
  9. * modify it under the terms of the GNU General Public License
  10. * as published by the Free Software Foundation; either version 2
  11. * of the License, or (at your option) any later version.
  12. *
  13. * This program is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License
  19. * along with this program; if not, you may find one here:
  20. * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
  21. * or you may search the http://www.gnu.org website for the version 2 license,
  22. * or you may write to the Free Software Foundation, Inc.,
  23. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
  24. */
  25. /**
  26. * @file schedit.cpp
  27. */
  28. #include <fctsys.h>
  29. #include <gr_basic.h>
  30. #include <appl_wxstruct.h>
  31. #include <class_drawpanel.h>
  32. #include <confirm.h>
  33. #include <eda_doc.h>
  34. #include <wxEeschemaStruct.h>
  35. #include <kicad_device_context.h>
  36. #include <hotkeys_basic.h>
  37. #include <general.h>
  38. #include <eeschema_id.h>
  39. #include <protos.h>
  40. #include <class_library.h>
  41. #include <sch_bus_entry.h>
  42. #include <sch_marker.h>
  43. #include <sch_component.h>
  44. #include <sch_junction.h>
  45. #include <sch_line.h>
  46. #include <sch_sheet.h>
  47. void SCH_EDIT_FRAME::Process_Special_Functions( wxCommandEvent& event )
  48. {
  49. int id = event.GetId();
  50. wxPoint pos;
  51. SCH_SCREEN* screen = GetScreen();
  52. SCH_ITEM* item = screen->GetCurItem();
  53. pos = wxGetMousePosition();
  54. pos.y += 20;
  55. // If needed, stop the current command and deselect current tool
  56. switch( id )
  57. {
  58. case wxID_CUT:
  59. case wxID_COPY:
  60. case ID_POPUP_CANCEL_CURRENT_COMMAND:
  61. case ID_POPUP_SCH_ENTRY_SELECT_SLASH:
  62. case ID_POPUP_SCH_ENTRY_SELECT_ANTISLASH:
  63. case ID_POPUP_SCH_BEGIN_WIRE:
  64. case ID_POPUP_SCH_BEGIN_BUS:
  65. case ID_POPUP_END_LINE:
  66. case ID_POPUP_SCH_SET_SHAPE_TEXT:
  67. case ID_POPUP_SCH_CLEANUP_SHEET:
  68. case ID_POPUP_SCH_END_SHEET:
  69. case ID_POPUP_SCH_RESIZE_SHEET:
  70. case ID_POPUP_IMPORT_GLABEL:
  71. case ID_POPUP_SCH_INIT_CMP:
  72. case ID_POPUP_SCH_DISPLAYDOC_CMP:
  73. case ID_POPUP_SCH_EDIT_CONVERT_CMP:
  74. case ID_POPUP_DELETE_BLOCK:
  75. case ID_POPUP_PLACE_BLOCK:
  76. case ID_POPUP_ZOOM_BLOCK:
  77. case ID_POPUP_DRAG_BLOCK:
  78. case ID_POPUP_COPY_BLOCK:
  79. case ID_POPUP_SCH_DELETE_NODE:
  80. case ID_POPUP_SCH_DELETE_CONNECTION:
  81. case ID_POPUP_SCH_ENTER_SHEET:
  82. case ID_POPUP_SCH_LEAVE_SHEET:
  83. case ID_POPUP_SCH_ADD_JUNCTION:
  84. case ID_POPUP_SCH_ADD_LABEL:
  85. case ID_POPUP_SCH_GETINFO_MARKER:
  86. /* At this point: Do nothing. these commands do not need to stop the
  87. * current command (mainly a block command) or reset the current state
  88. * They will be executed later, in next switch structure.
  89. */
  90. break;
  91. case ID_POPUP_SCH_DELETE_CMP:
  92. case ID_POPUP_SCH_DELETE:
  93. // Stop the current command (if any) but keep the current tool
  94. m_canvas->EndMouseCapture();
  95. break;
  96. default:
  97. // Stop the current command and deselect the current tool
  98. m_canvas->EndMouseCapture( ID_NO_TOOL_SELECTED, m_canvas->GetDefaultCursor() );
  99. break;
  100. }
  101. INSTALL_UNBUFFERED_DC( dc, m_canvas );
  102. item = screen->GetCurItem(); // Can be modified by previous calls.
  103. switch( id )
  104. {
  105. case ID_HIERARCHY:
  106. InstallHierarchyFrame( &dc, pos );
  107. m_itemToRepeat = NULL;
  108. break;
  109. case wxID_CUT:
  110. if( screen->m_BlockLocate.GetCommand() != BLOCK_MOVE )
  111. break;
  112. HandleBlockEndByPopUp( BLOCK_DELETE, &dc );
  113. m_itemToRepeat = NULL;
  114. SetSheetNumberAndCount();
  115. break;
  116. case wxID_PASTE:
  117. HandleBlockBegin( &dc, BLOCK_PASTE, screen->GetCrossHairPosition() );
  118. break;
  119. case ID_POPUP_SCH_ENTRY_SELECT_SLASH:
  120. m_canvas->MoveCursorToCrossHair();
  121. SetBusEntryShape( &dc, (SCH_BUS_ENTRY*) item, '/' );
  122. break;
  123. case ID_POPUP_SCH_ENTRY_SELECT_ANTISLASH:
  124. m_canvas->MoveCursorToCrossHair();
  125. SetBusEntryShape( &dc, (SCH_BUS_ENTRY*) item, '\\' );
  126. break;
  127. case ID_POPUP_CANCEL_CURRENT_COMMAND:
  128. if( m_canvas->IsMouseCaptured() )
  129. {
  130. m_canvas->EndMouseCapture();
  131. SetToolID( GetToolId(), m_canvas->GetCurrentCursor(), wxEmptyString );
  132. }
  133. else
  134. {
  135. SetToolID( ID_NO_TOOL_SELECTED, m_canvas->GetDefaultCursor(), wxEmptyString );
  136. }
  137. break;
  138. case ID_POPUP_END_LINE:
  139. m_canvas->MoveCursorToCrossHair();
  140. EndSegment( &dc );
  141. break;
  142. case ID_POPUP_SCH_BEGIN_WIRE:
  143. m_canvas->MoveCursorToCrossHair();
  144. OnLeftClick( &dc, screen->GetCrossHairPosition() );
  145. break;
  146. case ID_POPUP_SCH_BEGIN_BUS:
  147. m_canvas->MoveCursorToCrossHair();
  148. OnLeftClick( &dc, screen->GetCrossHairPosition() );
  149. break;
  150. case ID_POPUP_SCH_SET_SHAPE_TEXT:
  151. // Not used
  152. break;
  153. case ID_POPUP_SCH_DELETE_NODE:
  154. case ID_POPUP_SCH_DELETE_CONNECTION:
  155. m_canvas->MoveCursorToCrossHair();
  156. DeleteConnection( id == ID_POPUP_SCH_DELETE_CONNECTION );
  157. screen->SetCurItem( NULL );
  158. m_itemToRepeat = NULL;
  159. screen->TestDanglingEnds( m_canvas, &dc );
  160. m_canvas->Refresh();
  161. break;
  162. case ID_POPUP_SCH_BREAK_WIRE:
  163. {
  164. DLIST< SCH_ITEM > oldWires;
  165. oldWires.SetOwnership( false ); // Prevent DLIST for deleting items in destructor.
  166. m_canvas->MoveCursorToCrossHair();
  167. screen->ExtractWires( oldWires, true );
  168. screen->BreakSegment( screen->GetCrossHairPosition() );
  169. if( oldWires.GetCount() != 0 )
  170. {
  171. PICKED_ITEMS_LIST oldItems;
  172. oldItems.m_Status = UR_WIRE_IMAGE;
  173. while( oldWires.GetCount() != 0 )
  174. {
  175. ITEM_PICKER picker = ITEM_PICKER( oldWires.PopFront(), UR_WIRE_IMAGE );
  176. oldItems.PushItem( picker );
  177. }
  178. SaveCopyInUndoList( oldItems, UR_WIRE_IMAGE );
  179. }
  180. screen->TestDanglingEnds( m_canvas, &dc );
  181. }
  182. break;
  183. case ID_POPUP_SCH_DELETE_CMP:
  184. case ID_POPUP_SCH_DELETE:
  185. if( item == NULL )
  186. break;
  187. DeleteItem( item );
  188. screen->SetCurItem( NULL );
  189. m_itemToRepeat = NULL;
  190. screen->TestDanglingEnds( m_canvas, &dc );
  191. SetSheetNumberAndCount();
  192. OnModify();
  193. break;
  194. case ID_POPUP_SCH_END_SHEET:
  195. m_canvas->MoveCursorToCrossHair();
  196. addCurrentItemToList( &dc );
  197. break;
  198. case ID_POPUP_SCH_RESIZE_SHEET:
  199. ReSizeSheet( (SCH_SHEET*) item, &dc );
  200. screen->TestDanglingEnds( m_canvas, &dc );
  201. break;
  202. case ID_POPUP_IMPORT_GLABEL:
  203. if( item != NULL && item->Type() == SCH_SHEET_T )
  204. screen->SetCurItem( ImportSheetPin( (SCH_SHEET*) item, &dc ) );
  205. break;
  206. case ID_POPUP_SCH_CLEANUP_SHEET:
  207. if( item != NULL && item->Type() == SCH_SHEET_T )
  208. {
  209. SCH_SHEET* sheet = (SCH_SHEET*) item;
  210. if( !sheet->HasUndefinedPins() )
  211. {
  212. DisplayInfoMessage( this,
  213. _( "There are no undefined labels in this sheet to clean up." ) );
  214. return;
  215. }
  216. if( !IsOK( this, _( "Do you wish to cleanup this sheet?" ) ) )
  217. return;
  218. /* Save sheet in undo list before cleaning up unreferenced hierarchical labels. */
  219. SaveCopyInUndoList( sheet, UR_CHANGED );
  220. sheet->CleanupSheet();
  221. OnModify();
  222. m_canvas->RefreshDrawingRect( sheet->GetBoundingBox() );
  223. }
  224. break;
  225. case ID_POPUP_SCH_INIT_CMP:
  226. m_canvas->MoveCursorToCrossHair();
  227. break;
  228. case ID_POPUP_SCH_EDIT_CONVERT_CMP:
  229. // Ensure the struct is a component (could be a struct of a component, like Field, text..)
  230. if( item && item->Type() == SCH_COMPONENT_T )
  231. {
  232. m_canvas->MoveCursorToCrossHair();
  233. ConvertPart( (SCH_COMPONENT*) item, &dc );
  234. }
  235. break;
  236. case ID_POPUP_SCH_DISPLAYDOC_CMP:
  237. // Ensure the struct is a component (could be a piece of a component, like Field, text..)
  238. if( item && item->Type() == SCH_COMPONENT_T )
  239. {
  240. LIB_ALIAS* LibEntry;
  241. LibEntry = CMP_LIBRARY::FindLibraryEntry( ( (SCH_COMPONENT*) item )->GetLibName() );
  242. if( LibEntry && LibEntry->GetDocFileName() != wxEmptyString )
  243. {
  244. GetAssociatedDocument( this, LibEntry->GetDocFileName(),
  245. &wxGetApp().GetLibraryPathList() );
  246. }
  247. }
  248. break;
  249. case ID_POPUP_SCH_ENTER_SHEET:
  250. if( item && (item->Type() == SCH_SHEET_T) )
  251. {
  252. m_CurrentSheet->Push( (SCH_SHEET*) item );
  253. DisplayCurrentSheet();
  254. }
  255. break;
  256. case ID_POPUP_SCH_LEAVE_SHEET:
  257. m_CurrentSheet->Pop();
  258. DisplayCurrentSheet();
  259. break;
  260. case wxID_COPY: // really this is a Save block for paste
  261. HandleBlockEndByPopUp( BLOCK_SAVE, &dc );
  262. break;
  263. case ID_POPUP_PLACE_BLOCK:
  264. m_canvas->SetAutoPanRequest( false );
  265. m_canvas->MoveCursorToCrossHair();
  266. HandleBlockPlace( &dc );
  267. break;
  268. case ID_POPUP_ZOOM_BLOCK:
  269. HandleBlockEndByPopUp( BLOCK_ZOOM, &dc );
  270. break;
  271. case ID_POPUP_DELETE_BLOCK:
  272. m_canvas->MoveCursorToCrossHair();
  273. HandleBlockEndByPopUp( BLOCK_DELETE, &dc );
  274. SetSheetNumberAndCount();
  275. break;
  276. case ID_POPUP_COPY_BLOCK:
  277. m_canvas->MoveCursorToCrossHair();
  278. HandleBlockEndByPopUp( BLOCK_COPY, &dc );
  279. break;
  280. case ID_POPUP_DRAG_BLOCK:
  281. m_canvas->MoveCursorToCrossHair();
  282. HandleBlockEndByPopUp( BLOCK_DRAG, &dc );
  283. break;
  284. case ID_POPUP_SCH_ADD_JUNCTION:
  285. m_canvas->MoveCursorToCrossHair();
  286. screen->SetCurItem( AddJunction( &dc, screen->GetCrossHairPosition(), true ) );
  287. screen->TestDanglingEnds( m_canvas, &dc );
  288. screen->SetCurItem( NULL );
  289. break;
  290. case ID_POPUP_SCH_ADD_LABEL:
  291. case ID_POPUP_SCH_ADD_GLABEL:
  292. screen->SetCurItem( CreateNewText( &dc, id == ID_POPUP_SCH_ADD_LABEL ?
  293. LAYER_LOCLABEL : LAYER_GLOBLABEL ) );
  294. item = screen->GetCurItem();
  295. if( item )
  296. addCurrentItemToList( &dc );
  297. break;
  298. case ID_POPUP_SCH_GETINFO_MARKER:
  299. if( item && item->Type() == SCH_MARKER_T )
  300. ( (SCH_MARKER*) item )->DisplayMarkerInfo( this );
  301. break;
  302. default: // Log error:
  303. wxFAIL_MSG( wxString::Format( wxT( "Cannot process command event ID %d" ),
  304. event.GetId() ) );
  305. break;
  306. }
  307. // End switch ( id ) (Command execution)
  308. if( GetToolId() == ID_NO_TOOL_SELECTED )
  309. m_itemToRepeat = NULL;
  310. }
  311. void SCH_EDIT_FRAME::OnMoveItem( wxCommandEvent& aEvent )
  312. {
  313. SCH_SCREEN* screen = GetScreen();
  314. SCH_ITEM* item = screen->GetCurItem();
  315. if( item == NULL )
  316. {
  317. // If we didn't get here by a hot key, then something has gone wrong.
  318. if( aEvent.GetInt() == 0 )
  319. return;
  320. EDA_HOTKEY_CLIENT_DATA* data = (EDA_HOTKEY_CLIENT_DATA*) aEvent.GetClientObject();
  321. wxCHECK_RET( data != NULL, wxT( "Invalid hot key client object." ) );
  322. item = LocateAndShowItem( data->GetPosition(), SCH_COLLECTOR::MovableItems,
  323. aEvent.GetInt() );
  324. // Exit if no item found at the current location or the item is already being edited.
  325. if( (item == NULL) || (item->GetFlags() != 0) )
  326. return;
  327. }
  328. INSTALL_UNBUFFERED_DC( dc, m_canvas );
  329. switch( item->Type() )
  330. {
  331. case SCH_LINE_T:
  332. break;
  333. case SCH_JUNCTION_T:
  334. case SCH_NO_CONNECT_T:
  335. case SCH_BUS_ENTRY_T:
  336. case SCH_LABEL_T:
  337. case SCH_GLOBAL_LABEL_T:
  338. case SCH_HIERARCHICAL_LABEL_T:
  339. case SCH_TEXT_T:
  340. case SCH_COMPONENT_T:
  341. case SCH_SHEET_PIN_T:
  342. case SCH_FIELD_T:
  343. MoveItem( item, &dc );
  344. break;
  345. case SCH_BITMAP_T:
  346. MoveImage( (SCH_BITMAP*) item, &dc );
  347. break;
  348. case SCH_SHEET_T:
  349. StartMoveSheet( (SCH_SHEET*) item, &dc );
  350. break;
  351. case SCH_MARKER_T:
  352. default:
  353. wxFAIL_MSG( wxString::Format( wxT( "Cannot move item type %s" ),
  354. GetChars( item->GetClass() ) ) );
  355. break;
  356. }
  357. if( GetToolId() == ID_NO_TOOL_SELECTED )
  358. m_itemToRepeat = NULL;
  359. }
  360. void SCH_EDIT_FRAME::OnCancelCurrentCommand( wxCommandEvent& aEvent )
  361. {
  362. SCH_SCREEN* screen = GetScreen();
  363. if( screen->IsBlockActive() )
  364. {
  365. m_canvas->SetCursor( (wxStockCursor) m_canvas->GetDefaultCursor() );
  366. screen->ClearBlockCommand();
  367. // Stop the current command (if any) but keep the current tool
  368. m_canvas->EndMouseCapture();
  369. }
  370. else
  371. {
  372. if( m_canvas->IsMouseCaptured() ) // Stop the current command but keep the current tool
  373. m_canvas->EndMouseCapture();
  374. else // Deselect current tool
  375. m_canvas->EndMouseCapture( ID_NO_TOOL_SELECTED, m_canvas->GetDefaultCursor() );
  376. }
  377. }
  378. void SCH_EDIT_FRAME::OnSelectTool( wxCommandEvent& aEvent )
  379. {
  380. int id = aEvent.GetId();
  381. // Stop the current command and deselect the current tool.
  382. m_canvas->EndMouseCapture( ID_NO_TOOL_SELECTED, m_canvas->GetDefaultCursor() );
  383. switch( id )
  384. {
  385. case ID_NO_TOOL_SELECTED:
  386. SetToolID( id, m_canvas->GetDefaultCursor(), _( "No tool selected" ) );
  387. break;
  388. case ID_HIERARCHY_PUSH_POP_BUTT:
  389. SetToolID( id, wxCURSOR_HAND, _( "Descend or ascend hierarchy" ) );
  390. break;
  391. case ID_NOCONN_BUTT:
  392. SetToolID( id, wxCURSOR_PENCIL, _( "Add no connect" ) );
  393. break;
  394. case ID_WIRE_BUTT:
  395. SetToolID( id, wxCURSOR_PENCIL, _( "Add wire" ) );
  396. break;
  397. case ID_BUS_BUTT:
  398. SetToolID( id, wxCURSOR_PENCIL, _( "Add bus" ) );
  399. break;
  400. case ID_LINE_COMMENT_BUTT:
  401. SetToolID( id, wxCURSOR_PENCIL, _( "Add lines" ) );
  402. break;
  403. case ID_JUNCTION_BUTT:
  404. SetToolID( id, wxCURSOR_PENCIL, _( "Add junction" ) );
  405. break;
  406. case ID_LABEL_BUTT:
  407. SetToolID( id, wxCURSOR_PENCIL, _( "Add label" ) );
  408. break;
  409. case ID_GLABEL_BUTT:
  410. SetToolID( id, wxCURSOR_PENCIL, _( "Add global label" ) );
  411. break;
  412. case ID_HIERLABEL_BUTT:
  413. SetToolID( id, wxCURSOR_PENCIL, _( "Add hierarchical label" ) );
  414. break;
  415. case ID_TEXT_COMMENT_BUTT:
  416. SetToolID( id, wxCURSOR_PENCIL, _( "Add text" ) );
  417. break;
  418. case ID_ADD_IMAGE_BUTT:
  419. SetToolID( id, wxCURSOR_PENCIL, _( "Add image" ) );
  420. break;
  421. case ID_WIRETOBUS_ENTRY_BUTT:
  422. SetToolID( id, wxCURSOR_PENCIL, _( "Add wire to bus entry" ) );
  423. break;
  424. case ID_BUSTOBUS_ENTRY_BUTT:
  425. SetToolID( id, wxCURSOR_PENCIL, _( "Add bus to bus entry" ) );
  426. break;
  427. case ID_SHEET_SYMBOL_BUTT:
  428. SetToolID( id, wxCURSOR_PENCIL, _( "Add sheet" ) );
  429. break;
  430. case ID_SHEET_PIN_BUTT:
  431. SetToolID( id, wxCURSOR_PENCIL, _( "Add sheet pins" ) );
  432. break;
  433. case ID_IMPORT_HLABEL_BUTT:
  434. SetToolID( id, wxCURSOR_PENCIL, _( "Import sheet pins" ) );
  435. break;
  436. case ID_SCH_PLACE_COMPONENT:
  437. SetToolID( id, wxCURSOR_PENCIL, _( "Add component" ) );
  438. break;
  439. case ID_PLACE_POWER_BUTT:
  440. SetToolID( id, wxCURSOR_PENCIL, _( "Add power" ) );
  441. break;
  442. case ID_SCHEMATIC_DELETE_ITEM_BUTT:
  443. SetToolID( id, wxCURSOR_BULLSEYE, _( "Delete item" ) );
  444. break;
  445. default:
  446. m_itemToRepeat = NULL;
  447. }
  448. // Simulate left click event if we got here from a hot key.
  449. if( aEvent.GetClientObject() != NULL )
  450. {
  451. EDA_HOTKEY_CLIENT_DATA* data = (EDA_HOTKEY_CLIENT_DATA*) aEvent.GetClientObject();
  452. wxPoint pos = data->GetPosition();
  453. INSTALL_UNBUFFERED_DC( dc, m_canvas );
  454. OnLeftClick( &dc, pos );
  455. }
  456. }
  457. void SCH_EDIT_FRAME::OnUpdateSelectTool( wxUpdateUIEvent& aEvent )
  458. {
  459. if( aEvent.GetEventObject() == m_drawToolBar )
  460. aEvent.Check( GetToolId() == aEvent.GetId() );
  461. }
  462. void SCH_EDIT_FRAME::DeleteConnection( bool aFullConnection )
  463. {
  464. PICKED_ITEMS_LIST pickList;
  465. SCH_SCREEN* screen = GetScreen();
  466. wxPoint pos = screen->GetCrossHairPosition();
  467. if( screen->GetConnection( pos, pickList, aFullConnection ) != 0 )
  468. {
  469. DeleteItemsInList( m_canvas, pickList );
  470. OnModify();
  471. }
  472. }
  473. bool SCH_EDIT_FRAME::DeleteItemAtCrossHair( wxDC* DC )
  474. {
  475. SCH_ITEM* item;
  476. SCH_SCREEN* screen = GetScreen();
  477. item = LocateItem( screen->GetCrossHairPosition(), SCH_COLLECTOR::ParentItems );
  478. if( item )
  479. {
  480. bool itemHasConnections = item->IsConnectable();
  481. screen->SetCurItem( NULL );
  482. SetRepeatItem( NULL );
  483. DeleteItem( item );
  484. if( itemHasConnections )
  485. screen->TestDanglingEnds( m_canvas, DC );
  486. OnModify();
  487. return true;
  488. }
  489. return false;
  490. }
  491. static void moveItem( EDA_DRAW_PANEL* aPanel, wxDC* aDC, const wxPoint& aPosition, bool aErase )
  492. {
  493. SCH_SCREEN* screen = (SCH_SCREEN*) aPanel->GetScreen();
  494. SCH_ITEM* item = screen->GetCurItem();
  495. wxCHECK_RET( (item != NULL), wxT( "Cannot move invalid schematic item." ) );
  496. #ifndef USE_WX_OVERLAY
  497. // Erase the current item at its current position.
  498. if( aErase )
  499. item->Draw( aPanel, aDC, wxPoint( 0, 0 ), g_XorMode );
  500. #endif
  501. item->SetPosition( screen->GetCrossHairPosition() );
  502. // Draw the item item at it's new position.
  503. item->Draw( aPanel, aDC, wxPoint( 0, 0 ), g_XorMode );
  504. }
  505. static void abortMoveItem( EDA_DRAW_PANEL* aPanel, wxDC* aDC )
  506. {
  507. SCH_SCREEN* screen = (SCH_SCREEN*) aPanel->GetScreen();
  508. SCH_ITEM* item = screen->GetCurItem();
  509. SCH_EDIT_FRAME* parent = ( SCH_EDIT_FRAME* ) aPanel->GetParent();
  510. parent->SetRepeatItem( NULL );
  511. screen->SetCurItem( NULL );
  512. if( item == NULL ) /* no current item */
  513. return;
  514. if( item->IsNew() )
  515. {
  516. delete item;
  517. item = NULL;
  518. }
  519. else
  520. {
  521. SCH_ITEM* oldItem = parent->GetUndoItem();
  522. SCH_ITEM* currentItem;
  523. // Items that are children of other objects are undone by swapping the contents
  524. // of the parent items.
  525. if( (item->Type() == SCH_SHEET_PIN_T) || (item->Type() == SCH_FIELD_T) )
  526. {
  527. currentItem = (SCH_ITEM*) item->GetParent();
  528. }
  529. else
  530. {
  531. currentItem = item;
  532. }
  533. wxCHECK_RET( oldItem != NULL && currentItem->Type() == oldItem->Type(),
  534. wxT( "Cannot restore undefined or bad last schematic item." ) );
  535. // Never delete existing item, because it can be referenced by an undo/redo command
  536. // Just restore its data
  537. currentItem->SwapData( oldItem );
  538. item->ClearFlags();
  539. }
  540. aPanel->Refresh();
  541. }
  542. void SCH_EDIT_FRAME::MoveItem( SCH_ITEM* aItem, wxDC* aDC )
  543. {
  544. wxCHECK_RET( aItem != NULL, wxT( "Cannot move invalid schematic item" ) );
  545. m_itemToRepeat = NULL;
  546. if( !aItem->IsNew() )
  547. {
  548. if( (aItem->Type() == SCH_SHEET_PIN_T) || (aItem->Type() == SCH_FIELD_T) )
  549. SetUndoItem( (SCH_ITEM*) aItem->GetParent() );
  550. else
  551. SetUndoItem( aItem );
  552. }
  553. aItem->SetFlags( IS_MOVED );
  554. #ifdef USE_WX_OVERLAY
  555. this->Refresh();
  556. this->Update();
  557. #endif
  558. m_canvas->CrossHairOff( aDC );
  559. if( aItem->Type() != SCH_SHEET_PIN_T )
  560. GetScreen()->SetCrossHairPosition( aItem->GetPosition() );
  561. m_canvas->MoveCursorToCrossHair();
  562. OnModify();
  563. m_canvas->SetMouseCapture( moveItem, abortMoveItem );
  564. GetScreen()->SetCurItem( aItem );
  565. moveItem( m_canvas, aDC, wxDefaultPosition, true );
  566. m_canvas->CrossHairOn( aDC );
  567. }
  568. void SCH_EDIT_FRAME::OnRotate( wxCommandEvent& aEvent )
  569. {
  570. SCH_SCREEN* screen = GetScreen();
  571. SCH_ITEM* item = screen->GetCurItem();
  572. INSTALL_UNBUFFERED_DC( dc, m_canvas );
  573. if( item == NULL )
  574. {
  575. // Allows block rotate operation on hot key.
  576. if( screen->m_BlockLocate.GetState() != STATE_NO_BLOCK )
  577. {
  578. HandleBlockEndByPopUp( BLOCK_ROTATE, &dc );
  579. return;
  580. }
  581. // If we didn't get here by a hot key, then something has gone wrong.
  582. if( aEvent.GetInt() == 0 )
  583. return;
  584. EDA_HOTKEY_CLIENT_DATA* data = (EDA_HOTKEY_CLIENT_DATA*) aEvent.GetClientObject();
  585. wxCHECK_RET( data != NULL, wxT( "Invalid hot key client object." ) );
  586. item = LocateAndShowItem( data->GetPosition(), SCH_COLLECTOR::RotatableItems,
  587. aEvent.GetInt() );
  588. // Exit if no item found at the current location or the item is already being edited.
  589. if( (item == NULL) || (item->GetFlags() != 0) )
  590. return;
  591. }
  592. switch( item->Type() )
  593. {
  594. case SCH_COMPONENT_T:
  595. if( aEvent.GetId() == ID_SCH_ROTATE_CLOCKWISE )
  596. OrientComponent( CMP_ROTATE_CLOCKWISE );
  597. else if( aEvent.GetId() == ID_SCH_ROTATE_COUNTERCLOCKWISE )
  598. OrientComponent( CMP_ROTATE_COUNTERCLOCKWISE );
  599. else
  600. wxFAIL_MSG( wxT( "Unknown rotate item command ID." ) );
  601. break;
  602. case SCH_TEXT_T:
  603. case SCH_LABEL_T:
  604. case SCH_GLOBAL_LABEL_T:
  605. case SCH_HIERARCHICAL_LABEL_T:
  606. m_canvas->MoveCursorToCrossHair();
  607. ChangeTextOrient( (SCH_TEXT*) item, &dc );
  608. break;
  609. case SCH_FIELD_T:
  610. m_canvas->MoveCursorToCrossHair();
  611. RotateField( (SCH_FIELD*) item, &dc );
  612. break;
  613. case SCH_BITMAP_T:
  614. RotateImage( (SCH_BITMAP*) item );
  615. break;
  616. case SCH_SHEET_T: /// @todo allow sheet rotate on hotkey
  617. default:
  618. wxFAIL_MSG( wxString::Format( wxT( "Cannot rotate schematic item type %s." ),
  619. GetChars( item->GetClass() ) ) );
  620. }
  621. if( item->GetFlags() == 0 )
  622. screen->SetCurItem( NULL );
  623. }
  624. void SCH_EDIT_FRAME::OnEditItem( wxCommandEvent& aEvent )
  625. {
  626. SCH_SCREEN* screen = GetScreen();
  627. SCH_ITEM* item = screen->GetCurItem();
  628. INSTALL_UNBUFFERED_DC( dc, m_canvas );
  629. if( item == NULL )
  630. {
  631. // If we didn't get here by a hot key, then something has gone wrong.
  632. if( aEvent.GetInt() == 0 )
  633. return;
  634. EDA_HOTKEY_CLIENT_DATA* data = (EDA_HOTKEY_CLIENT_DATA*) aEvent.GetClientObject();
  635. wxCHECK_RET( data != NULL, wxT( "Invalid hot key client object." ) );
  636. item = LocateAndShowItem( data->GetPosition(), SCH_COLLECTOR::EditableItems,
  637. aEvent.GetInt() );
  638. // Exit if no item found at the current location or the item is already being edited.
  639. if( (item == NULL) || (item->GetFlags() != 0) )
  640. return;
  641. }
  642. switch( item->Type() )
  643. {
  644. case SCH_COMPONENT_T:
  645. {
  646. switch( aEvent.GetId() )
  647. {
  648. case ID_SCH_EDIT_COMPONENT_REFERENCE:
  649. EditComponentFieldText( ( (SCH_COMPONENT*) item )->GetField( REFERENCE ) );
  650. break;
  651. case ID_SCH_EDIT_COMPONENT_VALUE:
  652. EditComponentFieldText( ( (SCH_COMPONENT*) item )->GetField( VALUE ) );
  653. break;
  654. case ID_SCH_EDIT_COMPONENT_FOOTPRINT:
  655. EditComponentFieldText( ( (SCH_COMPONENT*) item )->GetField( FOOTPRINT ) );
  656. break;
  657. case ID_SCH_EDIT_ITEM:
  658. EditComponent( (SCH_COMPONENT*) item );
  659. break;
  660. default:
  661. wxFAIL_MSG( wxString::Format( wxT( "Invalid schematic component edit command ID %d" ),
  662. aEvent.GetId() ) );
  663. }
  664. break;
  665. }
  666. case SCH_SHEET_T:
  667. EditSheet( (SCH_SHEET*) item, &dc );
  668. break;
  669. case SCH_SHEET_PIN_T:
  670. EditSheetPin( (SCH_SHEET_PIN*) item, &dc );
  671. break;
  672. case SCH_TEXT_T:
  673. case SCH_LABEL_T:
  674. case SCH_GLOBAL_LABEL_T:
  675. case SCH_HIERARCHICAL_LABEL_T:
  676. EditSchematicText( (SCH_TEXT*) item );
  677. break;
  678. case SCH_FIELD_T:
  679. EditComponentFieldText( (SCH_FIELD*) item );
  680. break;
  681. case SCH_BITMAP_T:
  682. EditImage( (SCH_BITMAP*) item );
  683. break;
  684. default:
  685. wxFAIL_MSG( wxString::Format( wxT( "Cannot edit schematic item type %s." ),
  686. GetChars( item->GetClass() ) ) );
  687. }
  688. if( item->GetFlags() == 0 )
  689. screen->SetCurItem( NULL );
  690. }
  691. void SCH_EDIT_FRAME::OnDragItem( wxCommandEvent& aEvent )
  692. {
  693. SCH_SCREEN* screen = GetScreen();
  694. SCH_ITEM* item = screen->GetCurItem();
  695. INSTALL_UNBUFFERED_DC( dc, m_canvas );
  696. if( item == NULL )
  697. {
  698. // If we didn't get here by a hot key, then something has gone wrong.
  699. if( aEvent.GetInt() == 0 )
  700. return;
  701. EDA_HOTKEY_CLIENT_DATA* data = (EDA_HOTKEY_CLIENT_DATA*) aEvent.GetClientObject();
  702. wxCHECK_RET( data != NULL, wxT( "Invalid hot key client object." ) );
  703. item = LocateAndShowItem( data->GetPosition(), SCH_COLLECTOR::DraggableItems,
  704. aEvent.GetInt() );
  705. // Exit if no item found at the current location or the item is already being edited.
  706. if( (item == NULL) || (item->GetFlags() != 0) )
  707. return;
  708. }
  709. switch( item->Type() )
  710. {
  711. case SCH_BUS_ENTRY_T:
  712. case SCH_LINE_T:
  713. case SCH_JUNCTION_T:
  714. if( item->GetLayer() == LAYER_BUS )
  715. break;
  716. // Fall thru if item is not on bus layer.
  717. case SCH_COMPONENT_T:
  718. case SCH_LABEL_T:
  719. case SCH_GLOBAL_LABEL_T:
  720. case SCH_HIERARCHICAL_LABEL_T:
  721. case SCH_SHEET_T:
  722. m_canvas->MoveCursorToCrossHair();
  723. // The easiest way to handle a drag component or sheet command
  724. // is to simulate a block drag command
  725. if( screen->m_BlockLocate.GetState() == STATE_NO_BLOCK )
  726. {
  727. if( !HandleBlockBegin( &dc, BLOCK_DRAG, screen->GetCrossHairPosition() ) )
  728. break;
  729. // Give a non null size to the search block:
  730. screen->m_BlockLocate.Inflate( 1 );
  731. HandleBlockEnd( &dc );
  732. }
  733. break;
  734. default:
  735. wxFAIL_MSG( wxString::Format( wxT( "Cannot drag schematic item type %s." ),
  736. GetChars( item->GetClass() ) ) );
  737. }
  738. // Since the drag is actually a block command, clear the current item.
  739. screen->SetCurItem( NULL );
  740. }
  741. void SCH_EDIT_FRAME::OnOrient( wxCommandEvent& aEvent )
  742. {
  743. SCH_SCREEN* screen = GetScreen();
  744. SCH_ITEM* item = screen->GetCurItem();
  745. INSTALL_UNBUFFERED_DC( dc, m_canvas );
  746. if( item == NULL )
  747. {
  748. // Allows block rotate operation on hot key.
  749. if( screen->m_BlockLocate.GetState() != STATE_NO_BLOCK )
  750. {
  751. if( aEvent.GetId() == ID_SCH_MIRROR_X )
  752. HandleBlockEndByPopUp( BLOCK_MIRROR_X, &dc );
  753. else if( aEvent.GetId() == ID_SCH_MIRROR_Y )
  754. HandleBlockEndByPopUp( BLOCK_MIRROR_Y, &dc );
  755. else
  756. wxFAIL_MSG( wxT( "Unknown block oriention command ID." ) );
  757. return;
  758. }
  759. // If we didn't get here by a hot key, then something has gone wrong.
  760. if( aEvent.GetInt() == 0 )
  761. return;
  762. EDA_HOTKEY_CLIENT_DATA* data = (EDA_HOTKEY_CLIENT_DATA*) aEvent.GetClientObject();
  763. wxCHECK_RET( data != NULL, wxT( "Invalid hot key client object." ) );
  764. item = LocateAndShowItem( data->GetPosition(), SCH_COLLECTOR::OrientableItems,
  765. aEvent.GetInt() );
  766. // Exit if no item found at the current location or the item is already being edited.
  767. if( (item == NULL) || (item->GetFlags() != 0) )
  768. return;
  769. }
  770. switch( item->Type() )
  771. {
  772. case SCH_COMPONENT_T:
  773. if( aEvent.GetId() == ID_SCH_MIRROR_X )
  774. OrientComponent( CMP_MIRROR_X );
  775. else if( aEvent.GetId() == ID_SCH_MIRROR_Y )
  776. OrientComponent( CMP_MIRROR_Y );
  777. else if( aEvent.GetId() == ID_SCH_ORIENT_NORMAL )
  778. OrientComponent( CMP_NORMAL );
  779. else
  780. wxFAIL_MSG( wxT( "Invalid orient schematic component command ID." ) );
  781. break;
  782. case SCH_BITMAP_T:
  783. if( aEvent.GetId() == ID_SCH_MIRROR_X )
  784. MirrorImage( (SCH_BITMAP*) item, true );
  785. else if( aEvent.GetId() == ID_SCH_MIRROR_Y )
  786. MirrorImage( (SCH_BITMAP*) item, false );
  787. break;
  788. default:
  789. wxFAIL_MSG( wxString::Format( wxT( "Schematic object type %s cannot be oriented." ),
  790. GetChars( item->GetClass() ) ) );
  791. }
  792. if( item->GetFlags() == 0 )
  793. screen->SetCurItem( NULL );
  794. }