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 <wxPcbStruct.h>
40 #include <base_units.h>
41 
42 #include <module_editor_frame.h>
43 #include <class_board.h>
44 #include <class_module.h>
45 #include <class_edge_mod.h>
46 
47 #include <pcbnew.h>
48 
49 
50 static void ShowNewEdgeModule( EDA_DRAW_PANEL* aPanel, wxDC* aDC, const wxPoint& aPosition,
51  bool erase );
52 static void Abort_Move_ModuleOutline( EDA_DRAW_PANEL* Panel, wxDC* DC );
53 static void ShowCurrentOutlineWhileMoving( EDA_DRAW_PANEL* aPanel, wxDC* aDC,
54  const wxPoint& aPosition, bool aErase );
55 
56 static double ArcValue = 900;
57 static wxPoint MoveVector; // Move vector for move edge
58 static wxPoint CursorInitialPosition; // Mouse cursor initial position for move command
59 
60 
62 {
63  if( aEdge == NULL )
64  return;
65 
66  aEdge->Draw( m_canvas, DC, GR_XOR );
67  aEdge->SetFlags( IS_MOVED );
68  MoveVector.x = MoveVector.y = 0;
69  CursorInitialPosition = GetCrossHairPosition();
71  SetCurItem( aEdge );
72  m_canvas->CallMouseCapture( DC, wxDefaultPosition, false );
73 }
74 
75 
77 {
78  if( aEdge == NULL )
79  return;
80 
81  aEdge->SetStart( aEdge->GetStart() - MoveVector );
82  aEdge->SetEnd( aEdge->GetEnd() - MoveVector );
83 
84  aEdge->SetStart0( aEdge->GetStart0() - MoveVector );
85  aEdge->SetEnd0( aEdge->GetEnd0() - MoveVector );
86 
87  aEdge->ClearFlags();
88  m_canvas->SetMouseCapture( NULL, NULL );
89  SetCurItem( NULL );
90  OnModify();
91 
92  MODULE* module = (MODULE*) aEdge->GetParent();
93  module->CalculateBoundingBox();
94 
95  m_canvas->Refresh( );
96 }
97 
98 
99 /* Redraw the current moved graphic item when mouse is moving
100  * Use this function to show an existing outline, in move command
101 */
102 static void ShowCurrentOutlineWhileMoving( EDA_DRAW_PANEL* aPanel, wxDC* aDC,
103  const wxPoint& aPosition, bool aErase )
104 {
105  BASE_SCREEN* screen = aPanel->GetScreen();
106  EDGE_MODULE* edge = (EDGE_MODULE*) screen->GetCurItem();
107 
108  if( edge == NULL )
109  return;
110 
111  MODULE* module = (MODULE*) edge->GetParent();
112 
113  if( aErase )
114  {
115  edge->Draw( aPanel, aDC, GR_XOR, MoveVector );
116  }
117 
118  MoveVector = -(aPanel->GetParent()->GetCrossHairPosition() - CursorInitialPosition);
119 
120  edge->Draw( aPanel, aDC, GR_XOR, MoveVector );
121 
122  module->CalculateBoundingBox();
123 }
124 
125 
126 /* Redraw the current graphic item during its creation
127  * Use this function to show a new outline, in begin command
128  */
129 static void ShowNewEdgeModule( EDA_DRAW_PANEL* aPanel, wxDC* aDC, const wxPoint& aPosition,
130  bool aErase )
131 {
132  BASE_SCREEN* screen = aPanel->GetScreen();
133  EDGE_MODULE* edge = (EDGE_MODULE*) screen->GetCurItem();
134 
135  if( edge == NULL )
136  return;
137 
138  MODULE* module = (MODULE*) edge->GetParent();
139 
140  // if( erase )
141  {
142  edge->Draw( aPanel, aDC, GR_XOR );
143  }
144 
145  edge->SetEnd( aPanel->GetParent()->GetCrossHairPosition() );
146 
147  // Update relative coordinate.
148  edge->SetEnd0( edge->GetEnd() - module->GetPosition() );
149 
150  wxPoint pt( edge->GetEnd0() );
151 
152  RotatePoint( &pt, -module->GetOrientation() );
153 
154  edge->SetEnd0( pt );
155 
156  edge->Draw( aPanel, aDC, GR_XOR );
157 
158  module->CalculateBoundingBox();
159 }
160 
161 
163 {
164  MODULE* module = GetBoard()->m_Modules;
165 
166  SaveCopyInUndoList( module, UR_CHANGED );
167 
168  if( aEdge == NULL )
169  {
170  aEdge = (EDGE_MODULE*) (BOARD_ITEM*) module->GraphicalItems();
171 
172  for( BOARD_ITEM *item = module->GraphicalItems(); item; item = item->Next() )
173  {
174  aEdge = dyn_cast<EDGE_MODULE*>( item );
175 
176  if( aEdge )
177  aEdge->SetWidth( GetDesignSettings().m_ModuleSegmentWidth );
178  }
179  }
180  else
181  {
182  aEdge->SetWidth( GetDesignSettings().m_ModuleSegmentWidth );
183  }
184 
185  OnModify();
186  module->CalculateBoundingBox();
187  module->SetLastEditTime();
188 }
189 
190 
192 {
193  // note: if aEdge == NULL, all outline segments will be modified
194 
195  MODULE* module = GetBoard()->m_Modules;
196  PCB_LAYER_ID layer = F_SilkS;
197  bool modified = false;
198 
199  if( aEdge )
200  layer = aEdge->GetLayer();
201 
202  // Ask for the new layer
203  PCB_LAYER_ID new_layer = SelectLayer( layer, Edge_Cuts );
204 
205  if( layer < 0 )
206  return;
207 
208  if( IsCopperLayer( new_layer ) )
209  {
210  // an edge is put on a copper layer, and it is very dangerous.
211  // A confirmation is requested
212  if( !IsOK( this,
213  _( "The graphic item will be on a copper layer.\n"
214  "This is very dangerous. Are you sure?" ) ) )
215  return;
216  }
217 
218  if( !aEdge )
219  {
220  for( BOARD_ITEM *item = module->GraphicalItems() ; item != NULL;
221  item = item->Next() )
222  {
223  aEdge = dyn_cast<EDGE_MODULE*>( item );
224 
225  if( aEdge && (aEdge->GetLayer() != new_layer) )
226  {
227  if( ! modified ) // save only once
228  SaveCopyInUndoList( module, UR_CHANGED );
229  aEdge->SetLayer( new_layer );
230  modified = true;
231  }
232  }
233  }
234  else if( aEdge->GetLayer() != new_layer )
235  {
236  SaveCopyInUndoList( module, UR_CHANGED );
237  aEdge->SetLayer( new_layer );
238  modified = true;
239  }
240 
241  if( modified )
242  {
243  module->CalculateBoundingBox();
244  module->SetLastEditTime();
245  }
246 }
247 
248 
250 {
251  wxString buffer;
252 
253  buffer = StringFromValue( g_UserUnit, GetDesignSettings().m_ModuleSegmentWidth );
254  wxTextEntryDialog dlg( this, _( "New Width:" ), _( "Edge Width" ), buffer );
255 
256  if( dlg.ShowModal() != wxID_OK )
257  return; // canceled by user
258 
259  buffer = dlg.GetValue( );
261 
262  if( aEdge )
263  {
264  MODULE* module = GetBoard()->m_Modules;
265  aEdge->SetWidth( GetDesignSettings().m_ModuleSegmentWidth );
266  module->CalculateBoundingBox();
267  OnModify();
268  }
269 }
270 
271 
273 {
274  if( aEdge == NULL )
275  return;
276 
277  if( aEdge->Type() != PCB_MODULE_EDGE_T )
278  {
279  DisplayError( this, wxT( "StructType error: PCB_MODULE_EDGE_T expected" ) );
280  return;
281  }
282 
283  MODULE* module = (MODULE*) aEdge->GetParent();
284 
285  // Delete segment.
286  aEdge->DeleteStructure();
287  module->SetLastEditTime();
288  module->CalculateBoundingBox();
289  OnModify();
290 }
291 
292 
293 /* abort function in moving outline.
294  */
295 static void Abort_Move_ModuleOutline( EDA_DRAW_PANEL* Panel, wxDC* DC )
296 {
297  EDGE_MODULE* edge = (EDGE_MODULE*) Panel->GetScreen()->GetCurItem();
298 
299  Panel->SetMouseCapture( NULL, NULL );
300 
301  if( edge && ( edge->Type() == PCB_MODULE_EDGE_T ) )
302  {
303  if( edge->IsNew() ) // On aborting, delete new outline.
304  {
305  MODULE* module = (MODULE*) edge->GetParent();
306  edge->Draw( Panel, DC, GR_XOR, MoveVector );
307  edge->DeleteStructure();
308  module->CalculateBoundingBox();
309  }
310  else // On aborting, move existing outline to its initial position.
311  {
312  edge->Draw( Panel, DC, GR_XOR, MoveVector );
313  edge->ClearFlags();
314  edge->Draw( Panel, DC, GR_OR );
315  }
316  }
317 
318  Panel->GetScreen()->SetCurItem( NULL );
319 }
320 
321 
323  wxDC* DC,
324  STROKE_T type_edge )
325 {
326  MODULE* module = GetBoard()->m_Modules;
327 
328  if( module == NULL )
329  return NULL;
330 
331  if( aEdge == NULL ) // Start a new edge item
332  {
333  SaveCopyInUndoList( module, UR_CHANGED );
334 
335  aEdge = new EDGE_MODULE( module );
336  MoveVector.x = MoveVector.y = 0;
337 
338  // Add the new item to the Drawings list head
339  module->GraphicalItems().PushFront( aEdge );
340 
341  // Update characteristics of the segment or arc.
342  aEdge->SetFlags( IS_NEW );
343  aEdge->SetAngle( 0 );
344  aEdge->SetShape( type_edge );
345 
346  if( aEdge->GetShape() == S_ARC )
347  aEdge->SetAngle( ArcValue );
348 
349  aEdge->SetWidth( GetDesignSettings().m_ModuleSegmentWidth );
350  aEdge->SetLayer( GetActiveLayer() );
351 
352  // Initialize the starting point of the new segment or arc
353  aEdge->SetStart( GetCrossHairPosition() );
354 
355  // Initialize the ending point of the new segment or arc
356  aEdge->SetEnd( aEdge->GetStart() );
357 
358  // Initialize the relative coordinates
359  aEdge->SetStart0( aEdge->GetStart() - module->GetPosition() );
360 
361  RotatePoint( &aEdge->m_Start0, -module->GetOrientation() );
362 
363  aEdge->m_End0 = aEdge->m_Start0;
364  module->CalculateBoundingBox();
366  }
367  /* Segment creation in progress.
368  * The ending coordinate is updated by the function
369  * ShowNewEdgeModule() called on move mouse event
370  * during the segment creation
371  */
372  else
373  {
374  if( type_edge == S_SEGMENT )
375  {
376  if( aEdge->m_Start0 != aEdge->m_End0 )
377  {
378  aEdge->Draw( m_canvas, DC, GR_OR );
379 
380  EDGE_MODULE* newedge = new EDGE_MODULE( *aEdge );
381 
382  // insert _after_ aEdge, which is the same as inserting before aEdge->Next()
383  module->GraphicalItems().Insert( newedge, aEdge->Next() );
384  aEdge->ClearFlags();
385 
386  aEdge = newedge; // point now new item
387 
388  aEdge->SetFlags( IS_NEW );
389  aEdge->SetWidth( GetDesignSettings().m_ModuleSegmentWidth );
390  aEdge->SetStart( GetCrossHairPosition() );
391  aEdge->SetEnd( aEdge->GetStart() );
392 
393  // Update relative coordinate.
394  aEdge->SetStart0( aEdge->GetStart() - module->GetPosition() );
395 
396  wxPoint pt( aEdge->GetStart0() );
397 
398  RotatePoint( &pt, -module->GetOrientation() );
399 
400  aEdge->SetStart0( pt );
401 
402  aEdge->SetEnd0( aEdge->GetStart0() );
403 
404  module->CalculateBoundingBox();
405  module->SetLastEditTime();
406  OnModify();
407  }
408  }
409  else
410  {
411  wxMessageBox( wxT( "Begin_Edge() error" ) );
412  }
413  }
414 
415  return aEdge;
416 }
417 
418 
420 {
421  MODULE* module = GetBoard()->m_Modules;
422 
423  if( aEdge )
424  {
425  aEdge->ClearFlags();
426 
427  // If last segment length is 0: remove it
428  if( aEdge->GetStart() == aEdge->GetEnd() )
429  aEdge->DeleteStructure();
430  }
431 
432  module->CalculateBoundingBox();
433  module->SetLastEditTime();
434  OnModify();
435  m_canvas->SetMouseCapture( NULL, NULL );
436 }
KICAD_T Type() const
Function Type()
Definition: base_struct.h:198
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 of class FOOTPRINT_EDIT_FRAME.
void SetShape(STROKE_T aShape)
static void Abort_Move_ModuleOutline(EDA_DRAW_PANEL *Panel, wxDC *DC)
Definition: edgemod.cpp:295
BOARD_DESIGN_SETTINGS & GetDesignSettings() const override
Function GetDesignSettings returns the BOARD_DESIGN_SETTINGS for the BOARD owned by this frame...
EDA_ITEM * GetCurItem() const
virtual void Refresh(bool eraseBackground=true, const wxRect *rect=NULL) override
Definition: draw_panel.cpp:326
void PushFront(T *aNewElement)
Function PushFront puts aNewElement at front of list sequence.
Definition: dlist.h:240
static wxPoint MoveVector
Definition: edgemod.cpp:57
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:216
Class BOARD_ITEM is a base class for any item which can be embedded within the BOARD container class...
int m_ModuleSegmentWidth
Default width for all graphic lines.
void CalculateBoundingBox()
Function CalculateBoundingBox calculates the bounding box in board coordinates.
Class BOARD to handle a board.
const wxPoint & GetPosition() const override
Definition: class_module.h:143
wxString StringFromValue(EDA_UNITS_T aUnit, int aValue, bool aAddUnitSymbol)
Function StringFromValue returns the string from aValue according to units (inch, mm ...
Definition: base_units.cpp:203
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:102
BOARD * GetBoard() const
usual segment : line with rounded ends
void RotatePoint(int *pX, int *pY, double angle)
Definition: trigo.cpp:317
void SetLastEditTime(time_t aTime)
Definition: class_module.h:269
static double ArcValue
Definition: edgemod.cpp:56
class EDGE_MODULE, a footprint edge
Definition: typeinfo.h:106
DLIST< BOARD_ITEM > & GraphicalItems()
Definition: class_module.h:136
Casted dyn_cast(From aObject)
Function dyn_cast()
Definition: typeinfo.h:73
wxPoint m_End0
void Enter_Edge_Width(EDGE_MODULE *aEdge)
Function Enter_Edge_Width Edition of width of module outlines Ask for a new width.
Definition: edgemod.cpp:249
#define IS_NEW
New item, just created.
Definition: base_struct.h:113
BOARD_ITEM * Next() const
void Edit_Edge_Width(EDGE_MODULE *aEdge)
Function Edit_Edge_Width changes the width of module perimeter lines, EDGE_MODULEs.
Definition: edgemod.cpp:162
static wxPoint CursorInitialPosition
Definition: edgemod.cpp:58
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:253
virtual void OnModify() override
Virtual Function OnModify() Must be called after a footprint change in order to set the "modify" flag...
double GetOrientation() const
Definition: class_module.h:147
Class BASE_SCREEN handles how to draw a screen (a board, a schematic ...)
Arcs (with rounded ends)
void CallMouseCapture(wxDC *aDC, const wxPoint &aPosition, bool aErase)
Function CallMouseCapture calls the mouse capture callback.
int ValueFromString(EDA_UNITS_T aUnits, const wxString &aTextValue)
Function ValueFromString converts aTextValue in aUnits to internal units used by the application...
Definition: base_units.cpp:368
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)
Function Begin_Edge_Module creates a new edge item (line, arc ..).
Definition: edgemod.cpp:322
EDA_DRAW_FRAME * GetParent() const
Definition: draw_panel.cpp:175
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:172
static void ShowNewEdgeModule(EDA_DRAW_PANEL *aPanel, wxDC *aDC, const wxPoint &aPosition, bool erase)
Definition: edgemod.cpp:129
void SetStart(const wxPoint &aStart)
EDA_UNITS_T g_UserUnit
Global variables definitions.
Definition: common.cpp:56
Definition: gr_basic.h:42
EDA_DRAW_PANEL * m_canvas
The area to draw on.
Definition: draw_frame.h:92
PCB_LAYER_ID GetLayer() const
Function GetLayer returns the primary layer this item is on.
const wxPoint & GetStart0() const
void Place_EdgeMod(EDGE_MODULE *drawitem)
Function to place a graphic item type EDGE_MODULE currently moved.
Definition: edgemod.cpp:76
DLIST< MODULE > m_Modules
Definition: class_board.h:243
void SetStart0(const wxPoint &aPoint)
void Delete_Edge_Module(EDGE_MODULE *Edge)
Function Delete_Edge_Module deletes EDGE_MODULE Edge.
Definition: edgemod.cpp:272
BASE_SCREEN * GetScreen()
Definition: draw_panel.cpp:188
void End_Edge_Module(EDGE_MODULE *Edge)
Function End_Edge_Module terminates a move or create edge function.
Definition: edgemod.cpp:419
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:254
Module description (excepted pads)
wxPoint m_Start0
void SetMouseCapture(MOUSE_CAPTURE_CALLBACK aMouseCaptureCallback, END_MOUSE_CAPTURE_CALLBACK aEndMouseCaptureCallback)
Function SetMouseCapture sets the mouse capture and end mouse capture callbacks to aMouseCaptureCallb...
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:61
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:69
wxPoint GetCrossHairPosition(bool aInvertY=false) const
Function GetCrossHairPosition 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:111
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:220
void Edit_Edge_Layer(EDGE_MODULE *Edge)
Function Edit_Edge_Layer changes the EDGE_MODULE Edge layer, (The new layer will be asked) if Edge ==...
Definition: edgemod.cpp:191
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:112
void SetWidth(int aWidth)