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->SetStart( aEdge->GetStart() - MoveVector );
83  aEdge->SetEnd( aEdge->GetEnd() - MoveVector );
84 
85  aEdge->SetStart0( aEdge->GetStart0() - MoveVector );
86  aEdge->SetEnd0( aEdge->GetEnd0() - MoveVector );
87 
88  aEdge->ClearFlags();
89  m_canvas->SetMouseCapture( NULL, NULL );
90  SetCurItem( NULL );
91  OnModify();
92 
93  MODULE* module = (MODULE*) aEdge->GetParent();
94  module->CalculateBoundingBox();
95 
96  m_canvas->Refresh( );
97 }
98 
99 
100 /* Redraw the current moved graphic item when mouse is moving
101  * Use this function to show an existing outline, in move command
102 */
103 static void ShowCurrentOutlineWhileMoving( EDA_DRAW_PANEL* aPanel, wxDC* aDC,
104  const wxPoint& aPosition, bool aErase )
105 {
106  BASE_SCREEN* screen = aPanel->GetScreen();
107  EDGE_MODULE* edge = (EDGE_MODULE*) screen->GetCurItem();
108 
109  if( edge == NULL )
110  return;
111 
112  MODULE* module = (MODULE*) edge->GetParent();
113 
114  if( aErase )
115  {
116  edge->Draw( aPanel, aDC, GR_XOR, MoveVector );
117  }
118 
119  MoveVector = -(aPanel->GetParent()->GetCrossHairPosition() - CursorInitialPosition);
120 
121  edge->Draw( aPanel, aDC, GR_XOR, MoveVector );
122 
123  module->CalculateBoundingBox();
124 }
125 
126 
127 /* Redraw the current graphic item during its creation
128  * Use this function to show a new outline, in begin command
129  */
130 static void ShowNewEdgeModule( EDA_DRAW_PANEL* aPanel, wxDC* aDC, const wxPoint& aPosition,
131  bool aErase )
132 {
133  BASE_SCREEN* screen = aPanel->GetScreen();
134  EDGE_MODULE* edge = (EDGE_MODULE*) screen->GetCurItem();
135 
136  if( edge == NULL )
137  return;
138 
139  MODULE* module = (MODULE*) edge->GetParent();
140 
141  // if( erase )
142  {
143  edge->Draw( aPanel, aDC, GR_XOR );
144  }
145 
146  edge->SetEnd( aPanel->GetParent()->GetCrossHairPosition() );
147 
148  // Update relative coordinate.
149  edge->SetEnd0( edge->GetEnd() - module->GetPosition() );
150 
151  wxPoint pt( edge->GetEnd0() );
152 
153  RotatePoint( &pt, -module->GetOrientation() );
154 
155  edge->SetEnd0( pt );
156 
157  edge->Draw( aPanel, aDC, GR_XOR );
158 
159  module->CalculateBoundingBox();
160 }
161 
162 
164 {
165  MODULE* module = GetBoard()->m_Modules;
166 
167  SaveCopyInUndoList( module, UR_CHANGED );
168 
169  if( aEdge == NULL )
170  {
171  aEdge = (EDGE_MODULE*) (BOARD_ITEM*) module->GraphicalItemsList();
172 
173  for( BOARD_ITEM *item = module->GraphicalItemsList(); item; item = item->Next() )
174  {
175  aEdge = dyn_cast<EDGE_MODULE*>( item );
176 
177  if( aEdge )
178  aEdge->SetWidth( GetDesignSettings().m_ModuleSegmentWidth );
179  }
180  }
181  else
182  {
183  aEdge->SetWidth( GetDesignSettings().m_ModuleSegmentWidth );
184  }
185 
186  OnModify();
187  module->CalculateBoundingBox();
188  module->SetLastEditTime();
189 }
190 
191 
193 {
194  // note: if aEdge == NULL, all outline segments will be modified
195 
196  MODULE* module = GetBoard()->m_Modules;
197  PCB_LAYER_ID layer = F_SilkS;
198  bool modified = false;
199 
200  if( aEdge )
201  layer = aEdge->GetLayer();
202 
203  // Ask for the new layer
204  PCB_LAYER_ID new_layer = SelectLayer( layer, Edge_Cuts );
205 
206  if( layer < 0 )
207  return;
208 
209  if( IsCopperLayer( new_layer ) )
210  {
211  // an edge is put on a copper layer, and it is very dangerous.
212  // A confirmation is requested
213  if( !IsOK( this,
214  _( "The graphic item will be on a copper layer.\n"
215  "This is very dangerous. Are you sure?" ) ) )
216  return;
217  }
218 
219  if( !aEdge )
220  {
221  for( BOARD_ITEM *item = module->GraphicalItemsList() ; item != NULL;
222  item = item->Next() )
223  {
224  aEdge = dyn_cast<EDGE_MODULE*>( item );
225 
226  if( aEdge && (aEdge->GetLayer() != new_layer) )
227  {
228  if( ! modified ) // save only once
229  SaveCopyInUndoList( module, UR_CHANGED );
230  aEdge->SetLayer( new_layer );
231  modified = true;
232  }
233  }
234  }
235  else if( aEdge->GetLayer() != new_layer )
236  {
237  SaveCopyInUndoList( module, UR_CHANGED );
238  aEdge->SetLayer( new_layer );
239  modified = true;
240  }
241 
242  if( modified )
243  {
244  module->CalculateBoundingBox();
245  module->SetLastEditTime();
246  }
247 }
248 
249 
251 {
252  wxString buffer;
253 
254  buffer = StringFromValue( g_UserUnit, GetDesignSettings().m_ModuleSegmentWidth );
255  WX_TEXT_ENTRY_DIALOG dlg( this, _( "New Width:" ), _( "Edge Width" ), buffer );
256 
257  if( dlg.ShowModal() != wxID_OK )
258  return; // canceled by user
259 
260  buffer = dlg.GetValue( );
262 
263  if( aEdge )
264  {
265  MODULE* module = GetBoard()->m_Modules;
266  aEdge->SetWidth( GetDesignSettings().m_ModuleSegmentWidth );
267  module->CalculateBoundingBox();
268  OnModify();
269  }
270 }
271 
272 
274 {
275  if( aEdge == NULL )
276  return;
277 
278  if( aEdge->Type() != PCB_MODULE_EDGE_T )
279  {
280  DisplayError( this, wxT( "StructType error: PCB_MODULE_EDGE_T expected" ) );
281  return;
282  }
283 
284  MODULE* module = (MODULE*) aEdge->GetParent();
285 
286  // Delete segment.
287  aEdge->DeleteStructure();
288  module->SetLastEditTime();
289  module->CalculateBoundingBox();
290  OnModify();
291 }
292 
293 
294 /* abort function in moving outline.
295  */
296 static void Abort_Move_ModuleOutline( EDA_DRAW_PANEL* Panel, wxDC* DC )
297 {
298  EDGE_MODULE* edge = (EDGE_MODULE*) Panel->GetScreen()->GetCurItem();
299 
300  Panel->SetMouseCapture( NULL, NULL );
301 
302  if( edge && ( edge->Type() == PCB_MODULE_EDGE_T ) )
303  {
304  if( edge->IsNew() ) // On aborting, delete new outline.
305  {
306  MODULE* module = (MODULE*) edge->GetParent();
307  edge->Draw( Panel, DC, GR_XOR, MoveVector );
308  edge->DeleteStructure();
309  module->CalculateBoundingBox();
310  }
311  else // On aborting, move existing outline to its initial position.
312  {
313  edge->Draw( Panel, DC, GR_XOR, MoveVector );
314  edge->ClearFlags();
315  edge->Draw( Panel, DC, GR_OR );
316  }
317  }
318 
319  Panel->GetScreen()->SetCurItem( NULL );
320 }
321 
322 
324  wxDC* DC,
325  STROKE_T type_edge )
326 {
327  MODULE* module = GetBoard()->m_Modules;
328 
329  if( module == NULL )
330  return NULL;
331 
332  if( aEdge == NULL ) // Start a new edge item
333  {
334  SaveCopyInUndoList( module, UR_CHANGED );
335 
336  aEdge = new EDGE_MODULE( module );
337  MoveVector.x = MoveVector.y = 0;
338 
339  // Add the new item to the Drawings list head
340  module->GraphicalItemsList().PushFront( aEdge );
341 
342  // Update characteristics of the segment or arc.
343  aEdge->SetFlags( IS_NEW );
344  aEdge->SetAngle( 0 );
345  aEdge->SetShape( type_edge );
346 
347  if( aEdge->GetShape() == S_ARC )
348  aEdge->SetAngle( ArcValue );
349 
350  aEdge->SetWidth( GetDesignSettings().m_ModuleSegmentWidth );
351  aEdge->SetLayer( GetActiveLayer() );
352 
353  // Initialize the starting point of the new segment or arc
354  aEdge->SetStart( GetCrossHairPosition() );
355 
356  // Initialize the ending point of the new segment or arc
357  aEdge->SetEnd( aEdge->GetStart() );
358 
359  // Initialize the relative coordinates
360  aEdge->SetStart0( aEdge->GetStart() - module->GetPosition() );
361 
362  RotatePoint( &aEdge->m_Start0, -module->GetOrientation() );
363 
364  aEdge->m_End0 = aEdge->m_Start0;
365  module->CalculateBoundingBox();
367  }
368  /* Segment creation in progress.
369  * The ending coordinate is updated by the function
370  * ShowNewEdgeModule() called on move mouse event
371  * during the segment creation
372  */
373  else
374  {
375  if( type_edge == S_SEGMENT )
376  {
377  if( aEdge->m_Start0 != aEdge->m_End0 )
378  {
379  aEdge->Draw( m_canvas, DC, GR_OR );
380 
381  EDGE_MODULE* newedge = new EDGE_MODULE( *aEdge );
382 
383  // insert _after_ aEdge, which is the same as inserting before aEdge->Next()
384  module->GraphicalItemsList().Insert( newedge, aEdge->Next() );
385  aEdge->ClearFlags();
386 
387  aEdge = newedge; // point now new item
388 
389  aEdge->SetFlags( IS_NEW );
390  aEdge->SetWidth( GetDesignSettings().m_ModuleSegmentWidth );
391  aEdge->SetStart( GetCrossHairPosition() );
392  aEdge->SetEnd( aEdge->GetStart() );
393 
394  // Update relative coordinate.
395  aEdge->SetStart0( aEdge->GetStart() - module->GetPosition() );
396 
397  wxPoint pt( aEdge->GetStart0() );
398 
399  RotatePoint( &pt, -module->GetOrientation() );
400 
401  aEdge->SetStart0( pt );
402 
403  aEdge->SetEnd0( aEdge->GetStart0() );
404 
405  module->CalculateBoundingBox();
406  module->SetLastEditTime();
407  OnModify();
408  }
409  }
410  else
411  {
412  wxMessageBox( wxT( "Begin_Edge() error" ) );
413  }
414  }
415 
416  return aEdge;
417 }
418 
419 
421 {
422  MODULE* module = GetBoard()->m_Modules;
423 
424  if( aEdge )
425  {
426  aEdge->ClearFlags();
427 
428  // If last segment length is 0: remove it
429  if( aEdge->GetStart() == aEdge->GetEnd() )
430  aEdge->DeleteStructure();
431  }
432 
433  module->CalculateBoundingBox();
434  module->SetLastEditTime();
435  OnModify();
436  m_canvas->SetMouseCapture( NULL, NULL );
437 }
KICAD_T Type() const
Function Type()
Definition: base_struct.h:209
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:296
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
virtual void Refresh(bool eraseBackground=true, const wxRect *rect=NULL) override
Update the board display after modifying it bu a python script (note: it is automatically called by a...
Definition: draw_panel.cpp:338
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:227
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.
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.
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:205
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:103
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
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:250
#define IS_NEW
New item, just created.
Definition: base_struct.h:109
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:163
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:264
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:187
Class BASE_SCREEN handles how to draw a screen (a board, a schematic ...)
Definition: base_screen.h:76
Arcs (with rounded ends)
void SetLastEditTime(timestamp_t aTime)
Definition: class_module.h:309
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:370
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:323
EDA_DRAW_FRAME * GetParent() const
Definition: draw_panel.cpp:180
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:130
void SetStart(const wxPoint &aStart)
EDA_UNITS_T g_UserUnit
Global variables definitions.
Definition: common.cpp:57
Definition: gr_basic.h:38
EDA_DRAW_PANEL * m_canvas
The area to draw on.
Definition: draw_frame.h:98
wxString GetValue()
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:245
void SetStart0(const wxPoint &aPoint)
void Delete_Edge_Module(EDGE_MODULE *Edge)
Function Delete_Edge_Module deletes EDGE_MODULE Edge.
Definition: edgemod.cpp:273
BASE_SCREEN * GetScreen()
Definition: draw_panel.cpp:193
void End_Edge_Module(EDGE_MODULE *Edge)
Function End_Edge_Module terminates a move or create edge function.
Definition: edgemod.cpp:420
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:265
DLIST< BOARD_ITEM > & GraphicalItemsList()
Definition: class_module.h:164
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: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:185
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:233
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:221
const wxPoint GetPosition() const override
Definition: class_module.h:182
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:192
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:108
void SetWidth(int aWidth)