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.

475 lines
15 KiB

  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) 2009-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 eeschema/block.cpp
  27. */
  28. #include <fctsys.h>
  29. #include <appl_wxstruct.h>
  30. #include <gr_basic.h>
  31. #include <class_drawpanel.h>
  32. #include <confirm.h>
  33. #include <wxEeschemaStruct.h>
  34. #include <general.h>
  35. #include <class_library.h>
  36. #include <lib_pin.h>
  37. #include <protos.h>
  38. #include <sch_bus_entry.h>
  39. #include <sch_marker.h>
  40. #include <sch_junction.h>
  41. #include <sch_line.h>
  42. #include <sch_no_connect.h>
  43. #include <sch_text.h>
  44. #include <sch_component.h>
  45. #include <sch_sheet.h>
  46. #include <boost/foreach.hpp>
  47. // Imported functions:
  48. extern void SetSchItemParent( SCH_ITEM* Struct, SCH_SCREEN* Screen );
  49. extern void MoveItemsInList( PICKED_ITEMS_LIST& aItemsList, const wxPoint aMoveVector );
  50. extern void RotateListOfItems( PICKED_ITEMS_LIST& aItemsList, wxPoint& Center );
  51. extern void MirrorX( PICKED_ITEMS_LIST& aItemsList, wxPoint& aMirrorPoint );
  52. extern void MirrorY( PICKED_ITEMS_LIST& aItemsList, wxPoint& Center );
  53. extern void DuplicateItemsInList( SCH_SCREEN* screen,
  54. PICKED_ITEMS_LIST& aItemsList,
  55. const wxPoint aMoveVector );
  56. static void DrawMovingBlockOutlines( EDA_DRAW_PANEL* aPanel, wxDC* aDC,
  57. const wxPoint& aPosition, bool aErase );
  58. int SCH_EDIT_FRAME::ReturnBlockCommand( int key )
  59. {
  60. int cmd = BLOCK_IDLE;
  61. switch( key )
  62. {
  63. default:
  64. cmd = key & 0xFF;
  65. break;
  66. case 0:
  67. cmd = BLOCK_MOVE;
  68. break;
  69. case GR_KB_SHIFT:
  70. cmd = BLOCK_COPY;
  71. break;
  72. case GR_KB_ALT:
  73. cmd = BLOCK_ROTATE;
  74. break;
  75. case GR_KB_CTRL:
  76. cmd = BLOCK_DRAG;
  77. break;
  78. case GR_KB_SHIFTCTRL:
  79. cmd = BLOCK_DELETE;
  80. break;
  81. case MOUSE_MIDDLE:
  82. cmd = BLOCK_ZOOM;
  83. break;
  84. }
  85. return cmd;
  86. }
  87. void SCH_EDIT_FRAME::InitBlockPasteInfos()
  88. {
  89. BLOCK_SELECTOR* block = &GetScreen()->m_BlockLocate;
  90. block->GetItems().CopyList( m_blockItems.GetItems() );
  91. m_canvas->SetMouseCaptureCallback( DrawMovingBlockOutlines );
  92. }
  93. void SCH_EDIT_FRAME::HandleBlockPlace( wxDC* DC )
  94. {
  95. BLOCK_SELECTOR* block = &GetScreen()->m_BlockLocate;
  96. if( !m_canvas->IsMouseCaptured() )
  97. {
  98. DisplayError( this, wxT( "HandleBlockPLace() : m_mouseCaptureCallback = NULL" ) );
  99. }
  100. if( block->GetCount() == 0 )
  101. {
  102. wxString msg;
  103. msg.Printf( wxT( "HandleBlockPLace() error : no items to place (cmd %d, state %d)" ),
  104. block->GetCommand(), block->GetState() );
  105. DisplayError( this, msg );
  106. }
  107. block->SetState( STATE_BLOCK_STOP );
  108. switch( block->GetCommand() )
  109. {
  110. case BLOCK_DRAG: /* Drag */
  111. case BLOCK_MOVE: /* Move */
  112. if( m_canvas->IsMouseCaptured() )
  113. m_canvas->CallMouseCapture( DC, wxDefaultPosition, false );
  114. SaveCopyInUndoList( block->GetItems(), UR_MOVED, block->GetMoveVector() );
  115. MoveItemsInList( block->GetItems(), block->GetMoveVector() );
  116. block->ClearItemsList();
  117. break;
  118. case BLOCK_COPY: /* Copy */
  119. case BLOCK_PRESELECT_MOVE: /* Move with preselection list*/
  120. if( m_canvas->IsMouseCaptured() )
  121. m_canvas->CallMouseCapture( DC, wxDefaultPosition, false );
  122. DuplicateItemsInList( GetScreen(), block->GetItems(), block->GetMoveVector() );
  123. SaveCopyInUndoList( block->GetItems(),
  124. ( block->GetCommand() == BLOCK_PRESELECT_MOVE ) ? UR_CHANGED : UR_NEW );
  125. block->ClearItemsList();
  126. break;
  127. case BLOCK_PASTE:
  128. if( m_canvas->IsMouseCaptured() )
  129. m_canvas->CallMouseCapture( DC, wxDefaultPosition, false );
  130. PasteListOfItems( DC );
  131. block->ClearItemsList();
  132. break;
  133. default: // others are handled by HandleBlockEnd()
  134. break;
  135. }
  136. OnModify();
  137. // clear dome flags and pointers
  138. GetScreen()->ClearDrawingState();
  139. GetScreen()->ClearBlockCommand();
  140. GetScreen()->SetCurItem( NULL );
  141. GetScreen()->TestDanglingEnds( m_canvas, DC );
  142. if( block->GetCount() )
  143. {
  144. DisplayError( this, wxT( "HandleBlockPLace() error: some items left in buffer" ) );
  145. block->ClearItemsList();
  146. }
  147. m_canvas->EndMouseCapture( GetToolId(), m_canvas->GetCurrentCursor(), wxEmptyString, false );
  148. m_canvas->Refresh();
  149. }
  150. bool SCH_EDIT_FRAME::HandleBlockEnd( wxDC* aDC )
  151. {
  152. bool nextcmd = false;
  153. bool zoom_command = false;
  154. BLOCK_SELECTOR* block = &GetScreen()->m_BlockLocate;
  155. if( block->GetCount() )
  156. {
  157. BLOCK_STATE_T state = block->GetState();
  158. BLOCK_COMMAND_T command = block->GetCommand();
  159. m_canvas->CallEndMouseCapture( aDC );
  160. block->SetState( state );
  161. block->SetCommand( command );
  162. m_canvas->SetMouseCapture( DrawAndSizingBlockOutlines, AbortBlockCurrentCommand );
  163. SetCrossHairPosition( block->GetEnd() );
  164. if( block->GetCommand() != BLOCK_ABORT )
  165. m_canvas->MoveCursorToCrossHair();
  166. }
  167. if( m_canvas->IsMouseCaptured() )
  168. {
  169. switch( block->GetCommand() )
  170. {
  171. case BLOCK_IDLE:
  172. DisplayError( this, wxT( "Error in HandleBlockPLace()" ) );
  173. break;
  174. case BLOCK_ROTATE:
  175. GetScreen()->UpdatePickList();
  176. DrawAndSizingBlockOutlines( m_canvas, aDC, wxDefaultPosition, false );
  177. if( block->GetCount() )
  178. {
  179. // Compute the rotation center and put it on grid:
  180. wxPoint rotationPoint = block->Centre();
  181. rotationPoint = GetNearestGridPosition( rotationPoint );
  182. SetCrossHairPosition( rotationPoint );
  183. SaveCopyInUndoList( block->GetItems(), UR_ROTATED, rotationPoint );
  184. RotateListOfItems( block->GetItems(), rotationPoint );
  185. OnModify();
  186. }
  187. block->ClearItemsList();
  188. GetScreen()->TestDanglingEnds( m_canvas, aDC );
  189. m_canvas->Refresh();
  190. break;
  191. case BLOCK_DRAG:
  192. GetScreen()->BreakSegmentsOnJunctions();
  193. // fall through
  194. case BLOCK_MOVE:
  195. case BLOCK_COPY:
  196. if( GetScreen()->GetCurItem() != NULL )
  197. {
  198. ITEM_PICKER picker;
  199. picker.SetItem( GetScreen()->GetCurItem() );
  200. block->PushItem( picker );
  201. }
  202. else
  203. {
  204. GetScreen()->UpdatePickList();
  205. }
  206. // fall through
  207. case BLOCK_PRESELECT_MOVE: /* Move with preselection list*/
  208. if( block->GetCount() )
  209. {
  210. nextcmd = true;
  211. GetScreen()->SelectBlockItems();
  212. m_canvas->CallMouseCapture( aDC, wxDefaultPosition, false );
  213. m_canvas->SetMouseCaptureCallback( DrawMovingBlockOutlines );
  214. m_canvas->CallMouseCapture( aDC, wxDefaultPosition, false );
  215. block->SetState( STATE_BLOCK_MOVE );
  216. }
  217. else
  218. {
  219. m_canvas->CallMouseCapture( aDC, wxDefaultPosition, false );
  220. m_canvas->SetMouseCapture( NULL, NULL );
  221. }
  222. break;
  223. case BLOCK_DELETE:
  224. GetScreen()->UpdatePickList();
  225. DrawAndSizingBlockOutlines( m_canvas, aDC, wxDefaultPosition, false );
  226. if( block->GetCount() )
  227. {
  228. DeleteItemsInList( m_canvas, block->GetItems() );
  229. OnModify();
  230. }
  231. block->ClearItemsList();
  232. GetScreen()->TestDanglingEnds( m_canvas, aDC );
  233. m_canvas->Refresh();
  234. break;
  235. case BLOCK_SAVE:
  236. GetScreen()->UpdatePickList();
  237. DrawAndSizingBlockOutlines( m_canvas, aDC, wxDefaultPosition, false );
  238. if( block->GetCount() )
  239. {
  240. wxPoint move_vector = -GetScreen()->m_BlockLocate.GetLastCursorPosition();
  241. copyBlockItems( block->GetItems() );
  242. MoveItemsInList( m_blockItems.GetItems(), move_vector );
  243. }
  244. block->ClearItemsList();
  245. break;
  246. case BLOCK_PASTE:
  247. block->SetState( STATE_BLOCK_MOVE );
  248. break;
  249. case BLOCK_ZOOM:
  250. zoom_command = true;
  251. break;
  252. case BLOCK_MIRROR_X:
  253. GetScreen()->UpdatePickList();
  254. DrawAndSizingBlockOutlines( m_canvas, aDC, wxDefaultPosition, false );
  255. if( block->GetCount() )
  256. {
  257. // Compute the mirror center and put it on grid.
  258. wxPoint mirrorPoint = block->Centre();
  259. mirrorPoint = GetNearestGridPosition( mirrorPoint );
  260. SetCrossHairPosition( mirrorPoint );
  261. SaveCopyInUndoList( block->GetItems(), UR_MIRRORED_X, mirrorPoint );
  262. MirrorX( block->GetItems(), mirrorPoint );
  263. OnModify();
  264. }
  265. GetScreen()->TestDanglingEnds( m_canvas, aDC );
  266. m_canvas->Refresh();
  267. break;
  268. case BLOCK_MIRROR_Y:
  269. GetScreen()->UpdatePickList();
  270. DrawAndSizingBlockOutlines( m_canvas, aDC, wxDefaultPosition, false );
  271. if( block->GetCount() )
  272. {
  273. // Compute the mirror center and put it on grid.
  274. wxPoint mirrorPoint = block->Centre();
  275. mirrorPoint = GetNearestGridPosition( mirrorPoint );
  276. SetCrossHairPosition( mirrorPoint );
  277. SaveCopyInUndoList( block->GetItems(), UR_MIRRORED_Y, mirrorPoint );
  278. MirrorY( block->GetItems(), mirrorPoint );
  279. OnModify();
  280. }
  281. GetScreen()->TestDanglingEnds( m_canvas, aDC );
  282. m_canvas->Refresh();
  283. break;
  284. default:
  285. break;
  286. }
  287. }
  288. if( block->GetCommand() == BLOCK_ABORT )
  289. {
  290. GetScreen()->ClearDrawingState();
  291. m_canvas->Refresh();
  292. }
  293. if( ! nextcmd )
  294. {
  295. block->SetState( STATE_NO_BLOCK );
  296. block->SetCommand( BLOCK_IDLE );
  297. GetScreen()->SetCurItem( NULL );
  298. m_canvas->EndMouseCapture( GetToolId(), m_canvas->GetCurrentCursor(), wxEmptyString,
  299. false );
  300. }
  301. if( zoom_command )
  302. Window_Zoom( GetScreen()->m_BlockLocate );
  303. return nextcmd;
  304. }
  305. /* Traces the outline of the search block structures
  306. * The entire block follows the cursor
  307. */
  308. static void DrawMovingBlockOutlines( EDA_DRAW_PANEL* aPanel, wxDC* aDC, const wxPoint& aPosition,
  309. bool aErase )
  310. {
  311. BASE_SCREEN* screen = aPanel->GetScreen();
  312. BLOCK_SELECTOR* block = &screen->m_BlockLocate;
  313. SCH_ITEM* schitem;
  314. /* Erase old block contents. */
  315. if( aErase )
  316. {
  317. block->Draw( aPanel, aDC, block->GetMoveVector(), g_XorMode, block->GetColor() );
  318. for( unsigned ii = 0; ii < block->GetCount(); ii++ )
  319. {
  320. schitem = (SCH_ITEM*) block->GetItem( ii );
  321. schitem->Draw( aPanel, aDC, block->GetMoveVector(), g_XorMode, g_GhostColor );
  322. }
  323. }
  324. /* Repaint new view. */
  325. block->SetMoveVector( aPanel->GetParent()->GetCrossHairPosition() - block->GetLastCursorPosition() );
  326. block->Draw( aPanel, aDC, block->GetMoveVector(), g_XorMode, block->GetColor() );
  327. for( unsigned ii = 0; ii < block->GetCount(); ii++ )
  328. {
  329. schitem = (SCH_ITEM*) block->GetItem( ii );
  330. schitem->Draw( aPanel, aDC, block->GetMoveVector(), g_XorMode, g_GhostColor );
  331. }
  332. }
  333. void SCH_EDIT_FRAME::copyBlockItems( PICKED_ITEMS_LIST& aItemsList )
  334. {
  335. m_blockItems.ClearListAndDeleteItems(); // delete previous saved list, if exists
  336. for( unsigned ii = 0; ii < aItemsList.GetCount(); ii++ )
  337. {
  338. // Clear m_Flag member of selected items:
  339. aItemsList.GetPickedItem( ii )->ClearFlags();
  340. /* Make a copy of the original picked item. */
  341. SCH_ITEM* copy = DuplicateStruct( (SCH_ITEM*) aItemsList.GetPickedItem( ii ) );
  342. copy->SetParent( NULL );
  343. // In list the wrapper is owner of the schematic item, we can use the UR_DELETED
  344. // status for the picker because pickers with this status are owner of the picked item
  345. // (or TODO ?: create a new status like UR_DUPLICATE)
  346. ITEM_PICKER item( copy, UR_DELETED );
  347. m_blockItems.PushItem( item );
  348. }
  349. }
  350. void SCH_EDIT_FRAME::PasteListOfItems( wxDC* DC )
  351. {
  352. SCH_ITEM* Struct;
  353. if( m_blockItems.GetCount() == 0 )
  354. {
  355. DisplayError( this, wxT( "No struct to paste" ) );
  356. return;
  357. }
  358. PICKED_ITEMS_LIST picklist;
  359. for( unsigned ii = 0; ii < m_blockItems.GetCount(); ii++ )
  360. {
  361. Struct = DuplicateStruct( (SCH_ITEM*) m_blockItems.GetItem( ii ) );
  362. // Creates data, and push it as new data in undo item list buffer
  363. ITEM_PICKER picker( Struct, UR_NEW );
  364. picklist.PushItem( picker );
  365. // Clear annotation and init new time stamp for the new components:
  366. if( Struct->Type() == SCH_COMPONENT_T )
  367. {
  368. ( (SCH_COMPONENT*) Struct )->SetTimeStamp( GetNewTimeStamp() );
  369. ( (SCH_COMPONENT*) Struct )->ClearAnnotation( NULL );
  370. }
  371. SetSchItemParent( Struct, GetScreen() );
  372. Struct->Draw( m_canvas, DC, wxPoint( 0, 0 ), GR_DEFAULT_DRAWMODE );
  373. GetScreen()->Append( Struct );
  374. }
  375. SaveCopyInUndoList( picklist, UR_NEW );
  376. MoveItemsInList( picklist, GetScreen()->m_BlockLocate.GetMoveVector() );
  377. // Clear flags for all items.
  378. GetScreen()->ClearDrawingState();
  379. OnModify();
  380. return;
  381. }