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.

373 lines
11 KiB

14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
  1. /*
  2. * This program source code file is part of KiCad, a free EDA CAD application.
  3. *
  4. * Copyright (C) 2012 Jean-Pierre Charras, jean-pierre.charras@ujf-grenoble.fr
  5. * Copyright (C) 2012 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
  6. * Copyright (C) 1992-2012 KiCad Developers, see AUTHORS.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 editedge.cpp
  27. * @brief Edit segments and edges of PCB.
  28. */
  29. #include <fctsys.h>
  30. #include <class_drawpanel.h>
  31. #include <confirm.h>
  32. #include <pcb_edit_frame.h>
  33. #include <gr_basic.h>
  34. #include <pcbnew.h>
  35. #include <protos.h>
  36. #include <macros.h>
  37. #include <class_board.h>
  38. #include <class_drawsegment.h>
  39. static void Abort_EditEdge( EDA_DRAW_PANEL* aPanel, wxDC* DC );
  40. static void DrawSegment( EDA_DRAW_PANEL* aPanel, wxDC* aDC, const wxPoint& aPosition, bool aErase );
  41. static void Move_Segment( EDA_DRAW_PANEL* aPanel, wxDC* aDC, const wxPoint& aPosition,
  42. bool aErase );
  43. static wxPoint s_InitialPosition; // Initial cursor position.
  44. static wxPoint s_LastPosition; // Current cursor position.
  45. // Start move of a graphic element type DRAWSEGMENT
  46. void PCB_EDIT_FRAME::Start_Move_DrawItem( DRAWSEGMENT* drawitem, wxDC* DC )
  47. {
  48. if( drawitem == NULL )
  49. return;
  50. drawitem->Draw( m_canvas, DC, GR_XOR );
  51. drawitem->SetFlags( IS_MOVED );
  52. s_InitialPosition = s_LastPosition = GetCrossHairPosition();
  53. SetMsgPanel( drawitem );
  54. m_canvas->SetMouseCapture( Move_Segment, Abort_EditEdge );
  55. SetCurItem( drawitem );
  56. m_canvas->CallMouseCapture( DC, wxDefaultPosition, false );
  57. }
  58. /*
  59. * Place graphic element of type DRAWSEGMENT.
  60. */
  61. void PCB_EDIT_FRAME::Place_DrawItem( DRAWSEGMENT* drawitem, wxDC* DC )
  62. {
  63. if( drawitem == NULL )
  64. return;
  65. drawitem->ClearFlags();
  66. SaveCopyInUndoList(drawitem, UR_MOVED, s_LastPosition - s_InitialPosition);
  67. drawitem->Draw( m_canvas, DC, GR_OR );
  68. m_canvas->SetMouseCapture( NULL, NULL );
  69. SetCurItem( NULL );
  70. OnModify();
  71. }
  72. /*
  73. * Redraw segment during cursor movement.
  74. */
  75. static void Move_Segment( EDA_DRAW_PANEL* aPanel, wxDC* aDC, const wxPoint& aPosition,
  76. bool aErase )
  77. {
  78. DRAWSEGMENT* segment = (DRAWSEGMENT*) aPanel->GetScreen()->GetCurItem();
  79. if( segment == NULL )
  80. return;
  81. if( aErase )
  82. segment->Draw( aPanel, aDC, GR_XOR );
  83. wxPoint delta;
  84. delta = aPanel->GetParent()->GetCrossHairPosition() - s_LastPosition;
  85. segment->SetStart( segment->GetStart() + delta );
  86. segment->SetEnd( segment->GetEnd() + delta );
  87. s_LastPosition = aPanel->GetParent()->GetCrossHairPosition();
  88. segment->Draw( aPanel, aDC, GR_XOR );
  89. }
  90. void PCB_EDIT_FRAME::Delete_Segment_Edge( DRAWSEGMENT* Segment, wxDC* DC )
  91. {
  92. EDA_ITEM* PtStruct;
  93. auto displ_opts = (PCB_DISPLAY_OPTIONS*)GetDisplayOptions();
  94. bool tmp = displ_opts->m_DisplayDrawItemsFill;
  95. if( Segment == NULL )
  96. return;
  97. if( Segment->IsNew() ) // Trace in progress.
  98. {
  99. // Delete current segment.
  100. displ_opts->m_DisplayDrawItemsFill = SKETCH;
  101. Segment->Draw( m_canvas, DC, GR_XOR );
  102. PtStruct = Segment->Back();
  103. Segment ->DeleteStructure();
  104. if( PtStruct && (PtStruct->Type() == PCB_LINE_T ) )
  105. Segment = (DRAWSEGMENT*) PtStruct;
  106. displ_opts->m_DisplayDrawItemsFill = tmp;
  107. SetCurItem( NULL );
  108. }
  109. else if( Segment->GetFlags() == 0 )
  110. {
  111. Segment->Draw( m_canvas, DC, GR_XOR );
  112. Segment->ClearFlags();
  113. SaveCopyInUndoList(Segment, UR_DELETED);
  114. Segment->UnLink();
  115. SetCurItem( NULL );
  116. OnModify();
  117. }
  118. }
  119. void PCB_EDIT_FRAME::Delete_Drawings_All_Layer( PCB_LAYER_ID aLayer )
  120. {
  121. if( IsCopperLayer( aLayer ) )
  122. {
  123. DisplayError( this, _( "Copper layer global delete not allowed!" ) );
  124. return;
  125. }
  126. wxString msg;
  127. msg.Printf( _( "Delete everything on layer %s?" ),
  128. GetChars( GetBoard()->GetLayerName( aLayer ) ) );
  129. if( !IsOK( this, msg ) )
  130. return;
  131. // Step 1: build the list of items to remove.
  132. // because we are using iterators, we cannot modify the drawing list during iterate
  133. // so we are using a 2 steps calculation:
  134. // First, collect items.
  135. // Second, remove items.
  136. std::vector<BOARD_ITEM*> list;
  137. for( auto item : GetBoard()->Drawings() )
  138. {
  139. switch( item->Type() )
  140. {
  141. case PCB_LINE_T:
  142. case PCB_TEXT_T:
  143. case PCB_DIMENSION_T:
  144. case PCB_TARGET_T:
  145. if( item->GetLayer() == aLayer )
  146. list.push_back( item );
  147. break;
  148. default:
  149. {
  150. msg.Printf( wxT("Delete_Drawings_All_Layer() error: unknown type %d"),
  151. item->Type() );
  152. wxMessageBox( msg );
  153. break;
  154. }
  155. }
  156. }
  157. if( list.size() == 0 ) // No item found
  158. return;
  159. // Step 2: remove items from main list, and move them to the undo list
  160. PICKED_ITEMS_LIST pickList;
  161. ITEM_PICKER picker( NULL, UR_DELETED );
  162. for( auto item : list )
  163. {
  164. item->UnLink();
  165. picker.SetItem( item );
  166. pickList.PushItem( picker );
  167. }
  168. OnModify();
  169. SaveCopyInUndoList(pickList, UR_DELETED);
  170. }
  171. static void Abort_EditEdge( EDA_DRAW_PANEL* aPanel, wxDC* DC )
  172. {
  173. DRAWSEGMENT* Segment = (DRAWSEGMENT*) aPanel->GetScreen()->GetCurItem();
  174. if( Segment == NULL )
  175. {
  176. aPanel->SetMouseCapture( NULL, NULL );
  177. return;
  178. }
  179. if( Segment->IsNew() )
  180. {
  181. aPanel->CallMouseCapture( DC, wxDefaultPosition, false );
  182. Segment ->DeleteStructure();
  183. Segment = NULL;
  184. }
  185. else
  186. {
  187. wxPoint pos = aPanel->GetParent()->GetCrossHairPosition();
  188. aPanel->GetParent()->SetCrossHairPosition( s_InitialPosition );
  189. aPanel->CallMouseCapture( DC, wxDefaultPosition, true );
  190. aPanel->GetParent()->SetCrossHairPosition( pos );
  191. Segment->ClearFlags();
  192. Segment->Draw( aPanel, DC, GR_OR );
  193. }
  194. #ifdef USE_WX_OVERLAY
  195. aPanel->Refresh();
  196. #endif
  197. aPanel->SetMouseCapture( NULL, NULL );
  198. ( (PCB_EDIT_FRAME*) aPanel->GetParent() )->SetCurItem( NULL );
  199. }
  200. /* Initialize the drawing of a segment of type other than trace.
  201. */
  202. DRAWSEGMENT* PCB_EDIT_FRAME::Begin_DrawSegment( DRAWSEGMENT* Segment, STROKE_T shape, wxDC* DC )
  203. {
  204. int s_large;
  205. DRAWSEGMENT* DrawItem;
  206. s_large = GetDesignSettings().m_DrawSegmentWidth;
  207. if( GetActiveLayer() == Edge_Cuts )
  208. {
  209. s_large = GetDesignSettings().m_EdgeSegmentWidth;
  210. }
  211. if( Segment == NULL ) // Create new trace.
  212. {
  213. SetCurItem( Segment = new DRAWSEGMENT( GetBoard() ) );
  214. Segment->SetFlags( IS_NEW );
  215. Segment->SetLayer( GetActiveLayer() );
  216. Segment->SetWidth( s_large );
  217. Segment->SetShape( shape );
  218. Segment->SetAngle( 900 );
  219. Segment->SetStart( GetCrossHairPosition() );
  220. Segment->SetEnd( GetCrossHairPosition() );
  221. m_canvas->SetMouseCapture( DrawSegment, Abort_EditEdge );
  222. }
  223. else /* The ending point ccordinate Segment->m_End was updated by he function
  224. * DrawSegment() called on a move mouse event
  225. * during the segment creation
  226. */
  227. {
  228. if( Segment->GetStart() != Segment->GetEnd() )
  229. {
  230. if( Segment->GetShape() == S_SEGMENT )
  231. {
  232. SaveCopyInUndoList( Segment, UR_NEW );
  233. GetBoard()->Add( Segment );
  234. OnModify();
  235. Segment->ClearFlags();
  236. Segment->Draw( m_canvas, DC, GR_OR );
  237. DrawItem = Segment;
  238. SetCurItem( Segment = new DRAWSEGMENT( GetBoard() ) );
  239. Segment->SetFlags( IS_NEW );
  240. Segment->SetLayer( DrawItem->GetLayer() );
  241. Segment->SetWidth( s_large );
  242. Segment->SetShape( DrawItem->GetShape() );
  243. Segment->SetType( DrawItem->GetType() );
  244. Segment->SetAngle( DrawItem->GetAngle() );
  245. Segment->SetStart( DrawItem->GetEnd() );
  246. Segment->SetEnd( DrawItem->GetEnd() );
  247. DrawSegment( m_canvas, DC, wxDefaultPosition, false );
  248. }
  249. else
  250. {
  251. End_Edge( Segment, DC );
  252. Segment = NULL;
  253. }
  254. }
  255. }
  256. return Segment;
  257. }
  258. void PCB_EDIT_FRAME::End_Edge( DRAWSEGMENT* Segment, wxDC* DC )
  259. {
  260. if( Segment == NULL )
  261. return;
  262. Segment->Draw( m_canvas, DC, GR_OR );
  263. // Delete if segment length is zero.
  264. if( Segment->GetStart() == Segment->GetEnd() )
  265. {
  266. Segment->DeleteStructure();
  267. }
  268. else
  269. {
  270. Segment->ClearFlags();
  271. GetBoard()->Add( Segment );
  272. OnModify();
  273. SaveCopyInUndoList( Segment, UR_NEW );
  274. }
  275. m_canvas->SetMouseCapture( NULL, NULL );
  276. SetCurItem( NULL );
  277. }
  278. /* Redraw segment during cursor movement
  279. */
  280. static void DrawSegment( EDA_DRAW_PANEL* aPanel, wxDC* aDC, const wxPoint& aPosition, bool aErase )
  281. {
  282. DRAWSEGMENT* Segment = (DRAWSEGMENT*) aPanel->GetScreen()->GetCurItem();
  283. auto frame = (PCB_EDIT_FRAME*) ( aPanel->GetParent() );
  284. if( Segment == NULL )
  285. return;
  286. auto displ_opts = (PCB_DISPLAY_OPTIONS*) ( aPanel->GetDisplayOptions() );
  287. bool tmp = displ_opts->m_DisplayDrawItemsFill;
  288. displ_opts->m_DisplayDrawItemsFill = SKETCH;
  289. if( aErase )
  290. Segment->Draw( aPanel, aDC, GR_XOR );
  291. if( frame->Settings().m_use45DegreeGraphicSegments && Segment->GetShape() == S_SEGMENT )
  292. {
  293. wxPoint pt;
  294. pt = CalculateSegmentEndPoint( aPanel->GetParent()->GetCrossHairPosition(),
  295. Segment->GetStart() );
  296. Segment->SetEnd( pt );
  297. }
  298. else // here the angle is arbitrary
  299. {
  300. Segment->SetEnd( aPanel->GetParent()->GetCrossHairPosition() );
  301. }
  302. Segment->Draw( aPanel, aDC, GR_XOR );
  303. displ_opts->m_DisplayDrawItemsFill = tmp;
  304. }