KiCad PCB EDA Suite
edgemod.cpp
Go to the documentation of this file.
1 /*
2  * This program source code file is part of KiCad, a free EDA CAD application.
3  *
4  * Copyright (C) 2013 Jean-Pierre Charras, jp.charras at wanadoo.fr
5  * Copyright (C) 2013 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
6  * Copyright (C) 2013 Wayne Stambaugh <stambaughw@verizon.net>
7  * Copyright (C) 1992-2013 KiCad Developers, see AUTHORS.txt for contributors.
8  *
9  * This program is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU General Public License
11  * as published by the Free Software Foundation; either version 2
12  * of the License, or (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, you may find one here:
21  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
22  * or you may search the http://www.gnu.org website for the version 2 license,
23  * or you may write to the Free Software Foundation, Inc.,
24  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
25  */
26 
34 #include <fctsys.h>
35 #include <trigo.h>
36 #include <gr_basic.h>
37 #include <class_drawpanel.h>
38 #include <confirm.h>
39 #include <pcb_edit_frame.h>
40 #include <base_units.h>
41 #include <dialog_text_entry.h>
42 
43 #include <footprint_edit_frame.h>
44 #include <class_board.h>
45 #include <class_module.h>
46 #include <class_edge_mod.h>
47 
48 #include <pcbnew.h>
49 
50 
51 static void ShowNewEdgeModule( EDA_DRAW_PANEL* aPanel, wxDC* aDC, const wxPoint& aPosition,
52  bool erase );
53 static void Abort_Move_ModuleOutline( EDA_DRAW_PANEL* Panel, wxDC* DC );
54 static void ShowCurrentOutlineWhileMoving( EDA_DRAW_PANEL* aPanel, wxDC* aDC,
55  const wxPoint& aPosition, bool aErase );
56 
57 static double ArcValue = 900;
58 static wxPoint MoveVector; // Move vector for move edge
59 static wxPoint CursorInitialPosition; // Mouse cursor initial position for move command
60 
61 
63 {
64  if( aEdge == NULL )
65  return;
66 
67  aEdge->Draw( m_canvas, DC, GR_XOR );
68  aEdge->SetFlags( IS_MOVED );
69  MoveVector.x = MoveVector.y = 0;
70  CursorInitialPosition = GetCrossHairPosition();
72  SetCurItem( aEdge );
73  m_canvas->CallMouseCapture( DC, wxDefaultPosition, false );
74 }
75 
76 
78 {
79  if( aEdge == NULL )
80  return;
81 
82  aEdge->Move( -MoveVector );
83 
84  aEdge->ClearFlags();
85  m_canvas->SetMouseCapture( NULL, NULL );
86  SetCurItem( NULL );
87  OnModify();
88 
89  MODULE* module = (MODULE*) aEdge->GetParent();
90  module->CalculateBoundingBox();
91 
92  m_canvas->Refresh( );
93 }
94 
95 
96 /* Redraw the current moved graphic item when mouse is moving
97  * Use this function to show an existing outline, in move command
98 */
99 static void ShowCurrentOutlineWhileMoving( EDA_DRAW_PANEL* aPanel, wxDC* aDC,
100  const wxPoint& aPosition, bool aErase )
101 {
102  BASE_SCREEN* screen = aPanel->GetScreen();
103  EDGE_MODULE* edge = (EDGE_MODULE*) screen->GetCurItem();
104 
105  if( edge == NULL )
106  return;
107 
108  MODULE* module = (MODULE*) edge->GetParent();
109 
110  if( aErase )
111  {
112  edge->Draw( aPanel, aDC, GR_XOR, MoveVector );
113  }
114 
115  MoveVector = -(aPanel->GetParent()->GetCrossHairPosition() - CursorInitialPosition);
116 
117  edge->Draw( aPanel, aDC, GR_XOR, MoveVector );
118 
119  module->CalculateBoundingBox();
120 }
121 
122 
123 /* Redraw the current graphic item during its creation
124  * Use this function to show a new outline, in begin command
125  */
126 static void ShowNewEdgeModule( EDA_DRAW_PANEL* aPanel, wxDC* aDC, const wxPoint& aPosition,
127  bool aErase )
128 {
129  BASE_SCREEN* screen = aPanel->GetScreen();
130  EDGE_MODULE* edge = (EDGE_MODULE*) screen->GetCurItem();
131 
132  if( edge == NULL )
133  return;
134 
135  MODULE* module = (MODULE*) edge->GetParent();
136 
137  // if( erase )
138  {
139  edge->Draw( aPanel, aDC, GR_XOR );
140  }
141 
142  edge->SetEnd( aPanel->GetParent()->GetCrossHairPosition() );
143 
144  // Update relative coordinate.
145  edge->SetEnd0( edge->GetEnd() - module->GetPosition() );
146 
147  wxPoint pt( edge->GetEnd0() );
148 
149  RotatePoint( &pt, -module->GetOrientation() );
150 
151  edge->SetEnd0( pt );
152 
153  edge->Draw( aPanel, aDC, GR_XOR );
154 
155  module->CalculateBoundingBox();
156 }
157 
158 
160 {
161  MODULE* module = GetBoard()->m_Modules;
162 
163  SaveCopyInUndoList( module, UR_CHANGED );
164 
165  if( aEdge == NULL )
166  {
167  for( BOARD_ITEM *item = module->GraphicalItemsList(); item; item = item->Next() )
168  {
169  aEdge = dyn_cast<EDGE_MODULE*>( item );
170 
171  if( aEdge )
172  aEdge->SetWidth( GetDesignSettings().GetLineThickness( aEdge->GetLayer() ) );
173  }
174  }
175  else
176  {
177  aEdge->SetWidth( GetDesignSettings().GetLineThickness( aEdge->GetLayer() ) );
178  }
179 
180  OnModify();
181  module->CalculateBoundingBox();
182  module->SetLastEditTime();
183 }
184 
185 
187 {
188  // note: if aEdge == NULL, all outline segments will be modified
189 
190  MODULE* module = GetBoard()->m_Modules;
191  PCB_LAYER_ID layer = F_SilkS;
192  bool modified = false;
193 
194  if( aEdge )
195  layer = aEdge->GetLayer();
196 
197  // Ask for the new layer
198  PCB_LAYER_ID new_layer = SelectLayer( layer, Edge_Cuts );
199 
200  if( layer < 0 )
201  return;
202 
203  if( IsCopperLayer( new_layer ) )
204  {
205  // an edge is put on a copper layer, and it is very dangerous.
206  // A confirmation is requested
207  if( !IsOK( this,
208  _( "The graphic item will be on a copper layer.\n"
209  "This is very dangerous. Are you sure?" ) ) )
210  return;
211  }
212 
213  if( !aEdge )
214  {
215  for( BOARD_ITEM *item = module->GraphicalItemsList() ; item != NULL;
216  item = item->Next() )
217  {
218  aEdge = dyn_cast<EDGE_MODULE*>( item );
219 
220  if( aEdge && (aEdge->GetLayer() != new_layer) )
221  {
222  if( ! modified ) // save only once
223  SaveCopyInUndoList( module, UR_CHANGED );
224  aEdge->SetLayer( new_layer );
225  modified = true;
226  }
227  }
228  }
229  else if( aEdge->GetLayer() != new_layer )
230  {
231  SaveCopyInUndoList( module, UR_CHANGED );
232  aEdge->SetLayer( new_layer );
233  modified = true;
234  }
235 
236  if( modified )
237  {
238  module->CalculateBoundingBox();
239  module->SetLastEditTime();
240  }
241 }
242 
243 
245 {
246  if( aEdge == NULL )
247  return;
248 
249  if( aEdge->Type() != PCB_MODULE_EDGE_T )
250  {
251  DisplayError( this, wxT( "StructType error: PCB_MODULE_EDGE_T expected" ) );
252  return;
253  }
254 
255  MODULE* module = (MODULE*) aEdge->GetParent();
256 
257  // Delete segment.
258  aEdge->DeleteStructure();
259  module->SetLastEditTime();
260  module->CalculateBoundingBox();
261  OnModify();
262 }
263 
264 
265 /* abort function in moving outline.
266  */
267 static void Abort_Move_ModuleOutline( EDA_DRAW_PANEL* Panel, wxDC* DC )
268 {
269  EDGE_MODULE* edge = (EDGE_MODULE*) Panel->GetScreen()->GetCurItem();
270 
271  Panel->SetMouseCapture( NULL, NULL );
272 
273  if( edge && ( edge->Type() == PCB_MODULE_EDGE_T ) )
274  {
275  if( edge->IsNew() ) // On aborting, delete new outline.
276  {
277  MODULE* module = (MODULE*) edge->GetParent();
278  edge->Draw( Panel, DC, GR_XOR, MoveVector );
279  edge->DeleteStructure();
280  module->CalculateBoundingBox();
281  }
282  else // On aborting, move existing outline to its initial position.
283  {
284  edge->Draw( Panel, DC, GR_XOR, MoveVector );
285  edge->ClearFlags();
286  edge->Draw( Panel, DC, GR_OR );
287  }
288  }
289 
290  Panel->GetScreen()->SetCurItem( NULL );
291 }
292 
293 
295  wxDC* DC,
296  STROKE_T type_edge )
297 {
298  MODULE* module = GetBoard()->m_Modules;
299 
300  if( module == NULL )
301  return NULL;
302 
303  if( aEdge == NULL ) // Start a new edge item
304  {
305  SaveCopyInUndoList( module, UR_CHANGED );
306 
307  aEdge = new EDGE_MODULE( module );
308  MoveVector.x = MoveVector.y = 0;
309 
310  // Add the new item to the Drawings list head
311  module->GraphicalItemsList().PushFront( aEdge );
312 
313  // Update characteristics of the segment or arc.
314  aEdge->SetFlags( IS_NEW );
315  aEdge->SetAngle( 0 );
316  aEdge->SetShape( type_edge );
317 
318  if( aEdge->GetShape() == S_ARC )
319  aEdge->SetAngle( ArcValue );
320 
321  aEdge->SetWidth( GetDesignSettings().GetLineThickness( GetActiveLayer() ) );
322  aEdge->SetLayer( GetActiveLayer() );
323 
324  // Initialize the starting point of the new segment or arc
325  aEdge->SetStart( GetCrossHairPosition() );
326 
327  // Initialize the ending point of the new segment or arc
328  aEdge->SetEnd( aEdge->GetStart() );
329 
330  // Initialize the relative coordinates
331  aEdge->SetStart0( aEdge->GetStart() - module->GetPosition() );
332 
333  RotatePoint( &aEdge->m_Start0, -module->GetOrientation() );
334 
335  aEdge->m_End0 = aEdge->m_Start0;
336  module->CalculateBoundingBox();
338  }
339  /* Segment creation in progress.
340  * The ending coordinate is updated by the function
341  * ShowNewEdgeModule() called on move mouse event
342  * during the segment creation
343  */
344  else
345  {
346  if( type_edge == S_SEGMENT )
347  {
348  if( aEdge->m_Start0 != aEdge->m_End0 )
349  {
350  aEdge->Draw( m_canvas, DC, GR_OR );
351 
352  EDGE_MODULE* newedge = new EDGE_MODULE( *aEdge );
353 
354  // insert _after_ aEdge, which is the same as inserting before aEdge->Next()
355  module->GraphicalItemsList().Insert( newedge, aEdge->Next() );
356  aEdge->ClearFlags();
357 
358  aEdge = newedge; // point now new item
359 
360  aEdge->SetFlags( IS_NEW );
361  aEdge->SetWidth( GetDesignSettings().GetLineThickness( aEdge->GetLayer() ) );
362  aEdge->SetStart( GetCrossHairPosition() );
363  aEdge->SetEnd( aEdge->GetStart() );
364 
365  // Update relative coordinate.
366  aEdge->SetStart0( aEdge->GetStart() - module->GetPosition() );
367 
368  wxPoint pt( aEdge->GetStart0() );
369 
370  RotatePoint( &pt, -module->GetOrientation() );
371 
372  aEdge->SetStart0( pt );
373 
374  aEdge->SetEnd0( aEdge->GetStart0() );
375 
376  module->CalculateBoundingBox();
377  module->SetLastEditTime();
378  OnModify();
379  }
380  }
381  else
382  {
383  wxMessageBox( wxT( "Begin_Edge() error" ) );
384  }
385  }
386 
387  return aEdge;
388 }
389 
390 
392 {
393  MODULE* module = GetBoard()->m_Modules;
394 
395  if( aEdge )
396  {
397  aEdge->ClearFlags();
398 
399  // If last segment length is 0: remove it
400  if( aEdge->GetStart() == aEdge->GetEnd() )
401  aEdge->DeleteStructure();
402  }
403 
404  module->CalculateBoundingBox();
405  module->SetLastEditTime();
406  OnModify();
407  m_canvas->SetMouseCapture( NULL, NULL );
408 }
virtual BASE_SCREEN * GetScreen()=0
KICAD_T Type() const
Function Type()
Definition: base_struct.h:201
void SetEnd0(const wxPoint &aPoint)
BOARD_ITEM_CONTAINER * GetParent() const
void SetCurItem(EDA_ITEM *aItem)
Function SetCurItem sets the currently selected object, m_CurrentItem.
Definition: base_screen.h:231
void SetShape(STROKE_T aShape)
static void Abort_Move_ModuleOutline(EDA_DRAW_PANEL *Panel, wxDC *DC)
Definition: edgemod.cpp:267
BOARD_DESIGN_SETTINGS & GetDesignSettings() const override
Function GetDesignSettings returns the BOARD_DESIGN_SETTINGS for the BOARD owned by this frame...
EDA_ITEM * GetCurItem() const
Definition: base_screen.h:233
void PushFront(T *aNewElement)
Function PushFront puts aNewElement at front of list sequence.
Definition: dlist.h:240
static wxPoint MoveVector
Definition: edgemod.cpp:58
virtual void SetLayer(PCB_LAYER_ID aLayer)
Function SetLayer sets the layer this item is on.
Implementation of conversion functions that require both schematic and board internal units...
This file is part of the common library.
bool IsNew() const
Definition: base_struct.h:219
Class BOARD_ITEM is a base class for any item which can be embedded within the BOARD container class...
virtual PCB_LAYER_ID GetLayer() const
Function GetLayer returns the primary layer this item is on.
void CalculateBoundingBox()
Function CalculateBoundingBox calculates the bounding box in board coordinates.
Class BOARD to handle a board.
const wxPoint & GetEnd0() const
void SetCurItem(BOARD_ITEM *aItem, bool aDisplayInfo=true)
Function SetCurItem sets the currently selected item and displays it in the MsgPanel.
void DeleteStructure()
Function DeleteStructure deletes this object after UnLink()ing it from its owner if it has one...
static void ShowCurrentOutlineWhileMoving(EDA_DRAW_PANEL *aPanel, wxDC *aDC, const wxPoint &aPosition, bool aErase)
Definition: edgemod.cpp:99
BOARD * GetBoard() const
usual segment : line with rounded ends
void RotatePoint(int *pX, int *pY, double angle)
Definition: trigo.cpp:216
static double ArcValue
Definition: edgemod.cpp:57
Definition of class FOOTPRINT_EDIT_FRAME.
class EDGE_MODULE, a footprint edge
Definition: typeinfo.h:94
Casted dyn_cast(From aObject)
Function dyn_cast()
Definition: typeinfo.h:61
wxPoint m_End0
End point, relative to module origin, orient 0.
#define IS_NEW
New item, just created.
Definition: base_struct.h:114
BOARD_ITEM * Next() const
void Edit_Edge_Width(EDGE_MODULE *aEdge)
Change the width of module perimeter lines, EDGE_MODULEs.
Definition: edgemod.cpp:159
virtual EDA_DRAW_FRAME * GetParent() const =0
static wxPoint CursorInitialPosition
Definition: edgemod.cpp:59
PCB_LAYER_ID
A quick note on layer IDs:
STROKE_T GetShape() const
const wxPoint & GetEnd() const
Function GetEnd returns the ending point of the graphic.
void SetFlags(STATUS_FLAGS aMask)
Definition: base_struct.h:256
virtual void OnModify() override
Must be called after a footprint change in order to set the "modify" flag of the current screen and p...
double GetOrientation() const
Definition: class_module.h:189
Class BASE_SCREEN handles how to draw a screen (a board, a schematic ...)
Definition: base_screen.h:76
virtual void SetMouseCapture(MOUSE_CAPTURE_CALLBACK aMouseCaptureCallback, END_MOUSE_CAPTURE_CALLBACK aEndMouseCaptureCallback)
Function SetMouseCapture sets the mouse capture and end mouse capture callbacks to aMouseCaptureCallb...
Arcs (with rounded ends)
void SetLastEditTime(timestamp_t aTime)
Definition: class_module.h:314
virtual void CallMouseCapture(wxDC *aDC, const wxPoint &aPosition, bool aErase)
Function CallMouseCapture calls the mouse capture callback.
STROKE_T
Enum STROKE_T is the set of shapes for segments (graphic segments and tracks) which are often in the ...
EDGE_MODULE * Begin_Edge_Module(EDGE_MODULE *Edge, wxDC *DC, STROKE_T type_edge)
Creates a new edge item (line, arc ..).
Definition: edgemod.cpp:294
void Draw(EDA_DRAW_PANEL *panel, wxDC *DC, GR_DRAWMODE aDrawMode, const wxPoint &offset=ZeroOffset) override
Function Draw BOARD_ITEMs have their own color information.
void SaveCopyInUndoList(BOARD_ITEM *aItemToCopy, UNDO_REDO_T aTypeCommand, const wxPoint &aTransformPoint=wxPoint(0, 0)) override
Function SaveCopyInUndoList Creates a new entry in undo list of commands.
Definition: undo_redo.cpp:202
static void ShowNewEdgeModule(EDA_DRAW_PANEL *aPanel, wxDC *aDC, const wxPoint &aPosition, bool erase)
Definition: edgemod.cpp:126
void SetStart(const wxPoint &aStart)
Definition: gr_basic.h:38
EDA_DRAW_PANEL * m_canvas
The area to draw on.
Definition: draw_frame.h:123
const wxPoint & GetStart0() const
void Place_EdgeMod(EDGE_MODULE *drawitem)
Function to place a graphic item type EDGE_MODULE currently moved.
Definition: edgemod.cpp:77
DLIST< MODULE > m_Modules
Definition: class_board.h:248
void Move(const wxPoint &aMoveVector) override
Move an edge of the footprint.
void SetStart0(const wxPoint &aPoint)
void Delete_Edge_Module(EDGE_MODULE *Edge)
Delete EDGE_MODULE ddge.
Definition: edgemod.cpp:244
void End_Edge_Module(EDGE_MODULE *Edge)
Terminate a move or create edge function.
Definition: edgemod.cpp:391
void SetEnd(const wxPoint &aEnd)
void SetAngle(double aAngle)
Function SetAngle sets the angle for arcs, and normalizes it within the range 0 - 360 degrees...
bool IsCopperLayer(LAYER_NUM aLayerId)
Function IsCopperLayer tests whether a layer is a copper layer.
void ClearFlags(STATUS_FLAGS aMask=EDA_ITEM_ALL_FLAGS)
Definition: base_struct.h:257
DLIST< BOARD_ITEM > & GraphicalItemsList()
Definition: class_module.h:166
Module description (excepted pads)
wxPoint m_Start0
Start point or center, relative to module origin, orient 0.
virtual void Refresh(bool eraseBackground=true, const wxRect *rect=NULL)
void Start_Move_EdgeMod(EDGE_MODULE *drawitem, wxDC *DC)
Function to initialize the move function params of a graphic item type DRAWSEGMENT.
Definition: edgemod.cpp:62
EDGE_MODULE class definition.
const wxPoint & GetStart() const
Function GetStart returns the starting point of the graphic.
void DisplayError(wxWindow *parent, const wxString &text, int displaytime)
Function DisplayError displays an error or warning message box with aMessage.
Definition: confirm.cpp:245
wxPoint GetCrossHairPosition(bool aInvertY=false) const
Return the current cross hair position in logical (drawing) coordinates.
bool IsOK(wxWindow *aParent, const wxString &aMessage)
Function IsOK displays a yes/no dialog with aMessage and returns the user response.
Definition: confirm.cpp:295
PCB_LAYER_ID SelectLayer(PCB_LAYER_ID aDefaultLayer, LSET aNotAllowedLayersMask=LSET(), wxPoint aDlgPosition=wxDefaultPosition)
Install the dialog box for layer selection.
Definition: sel_layer.cpp:205
const wxPoint GetPosition() const override
Definition: class_module.h:184
void Edit_Edge_Layer(EDGE_MODULE *Edge)
Change the EDGE_MODULE Edge layer, (The new layer will be asked) if Edge == NULL change the layer of ...
Definition: edgemod.cpp:186
virtual PCB_LAYER_ID GetActiveLayer() const
Function GetActiveLayer returns the active layer.
void Insert(T *aNewElement, T *aElementAfterMe)
Function Insert puts aNewElement just in front of aElementAfterMe in the list sequence.
Definition: dlist.h:200
#define IS_MOVED
Item being moved.
Definition: base_struct.h:113
void SetWidth(int aWidth)