KiCad PCB EDA Suite
pcbnew/controle.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) 2012 Jean-Pierre Charras, jean-pierre.charras@ujf-grenoble.fr
5  * Copyright (C) 2012 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
6  * Copyright (C) 2012 Wayne Stambaugh <stambaughw@verizon.net>
7  * Copyright (C) 1992-2012 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 
31 #include <fctsys.h>
32 #include <class_drawpanel.h>
33 #include <pcb_edit_frame.h>
34 #include <pcbnew_id.h>
35 #include <class_board.h>
36 #include <class_module.h>
37 #include <class_zone.h>
38 
39 #include <pcbnew.h>
40 #include <protos.h>
41 #include <collectors.h>
42 #include <menus_helpers.h>
43 
44 //external functions used here:
45 extern bool Magnetize( PCB_BASE_EDIT_FRAME* frame, int aCurrentTool,
46  wxSize aGridSize, wxPoint on_grid, wxPoint* curpos );
47 
48 
56 {
57 #if 0 // Dick: this is not consistent with name of this function, and does not
58  // work correctly using 'M' (move hotkey) when another module's (2nd module) reference
59  // is under a module (first module) and you want to move the reference.
60  // Another way to fix this would be to
61  // treat module text as copper layer content, and put the module text into
62  // the primary list. I like the coded behavior best. If it breaks something
63  // perhaps you need a different test before calling this function, which should
64  // do what its name says it does.
65  int count = aCollector->GetPrimaryCount(); // try to use preferred layer
66  if( 0 == count ) count = aCollector->GetCount();
67 #else
68  int count = aCollector->GetCount();
69 #endif
70 
71  for( int i = 0; i<count; ++i )
72  {
73  if( (*aCollector)[i]->Type() != PCB_MODULE_T )
74  return NULL;
75  }
76 
77  // all are modules, now find smallest MODULE
78 
79  int minDim = 0x7FFFFFFF;
80  int minNdx = 0;
81 
82  for( int i = 0; i<count; ++i )
83  {
84  MODULE* module = (MODULE*) (*aCollector)[i];
85 
86  int lx = module->GetBoundingBox().GetWidth();
87  int ly = module->GetBoundingBox().GetHeight();
88 
89  int lmin = std::min( lx, ly );
90 
91  if( lmin < minDim )
92  {
93  minDim = lmin;
94  minNdx = i;
95  }
96  }
97 
98  return (*aCollector)[minNdx];
99 }
100 
101 
103 {
104  BOARD_ITEM* item;
105 
107  auto displ_opts = (PCB_DISPLAY_OPTIONS*)( GetDisplayOptions() );
108 
109  // Assign to scanList the proper item types desired based on tool type
110  // or hotkey that is in play.
111 
112  const KICAD_T* scanList = NULL;
113 
114  if( aHotKeyCode )
115  {
116  // @todo: add switch here and add calls to PcbGeneralLocateAndDisplay( int aHotKeyCode )
117  // when searching is needed from a hotkey handler
118  }
119  else if( GetToolId() == ID_NO_TOOL_SELECTED )
120  {
121  scanList = (displ_opts->m_DisplayZonesMode == 0) ?
124  }
125  else
126  {
127  switch( GetToolId() )
128  {
131  break;
132 
133  case ID_TRACK_BUTT:
134  scanList = GENERAL_COLLECTOR::Tracks;
135  break;
136 
137  case ID_PCB_MODULE_BUTT:
138  scanList = GENERAL_COLLECTOR::Modules;
139  break;
140 
141  case ID_PCB_ZONES_BUTT:
143  scanList = GENERAL_COLLECTOR::Zones;
144  break;
145 
146  default:
147  scanList = displ_opts->m_DisplayZonesMode == 0 ?
150  }
151  }
152 
153  m_Collector->Collect( m_Pcb, scanList, RefPos( true ), guide );
154 
155 #if 0
156  // debugging: print out the collected items, showing their priority order too.
157  for( int i = 0; i<m_Collector->GetCount(); ++i )
158  (*m_Collector)[i]->Show( 0, std::cout );
159 #endif
160 
161  /* Remove redundancies: sometime, legacy zones are found twice,
162  * because zones can be filled by overlapping segments (this is a fill option)
163  * Trigger the selection of the current edge for new-style zones
164  */
165  timestamp_t timestampzone = 0;
166 
167  for( int ii = 0; ii < m_Collector->GetCount(); ii++ )
168  {
169  item = (*m_Collector)[ii];
170 
171  switch( item->Type() )
172  {
173  case PCB_SEGZONE_T:
174  // Found a TYPE ZONE
175  if( item->GetTimeStamp() == timestampzone ) // Remove it, redundant, zone already found
176  {
177  m_Collector->Remove( ii );
178  ii--;
179  }
180  else
181  {
182  timestampzone = item->GetTimeStamp();
183  }
184  break;
185 
186  case PCB_ZONE_AREA_T:
187  {
188  /* We need to do the selection now because the menu text
189  * depends on it */
190  ZONE_CONTAINER *zone = static_cast<ZONE_CONTAINER*>( item );
191  int accuracy = KiROUND( 5 * guide.OnePixelInIU() );
192  zone->SetSelectedCorner( RefPos( true ), accuracy );
193  }
194  break;
195 
196  default:
197  break;
198  }
199  }
200 
201  if( m_Collector->GetCount() <= 1 )
202  {
203  item = (*m_Collector)[0];
204  SetCurItem( item );
205  }
206 
207  // If the count is 2, and first item is a pad or module text, and the 2nd item is its
208  // parent module:
209  else if( m_Collector->GetCount() == 2
210  && ( (*m_Collector)[0]->Type() == PCB_PAD_T || (*m_Collector)[0]->Type() ==
212  && (*m_Collector)[1]->Type() == PCB_MODULE_T && (*m_Collector)[0]->GetParent()==
213  (*m_Collector)[1] )
214  {
215  item = (*m_Collector)[0];
216  SetCurItem( item );
217  }
218  // if all are modules, find the smallest one among the primary choices
219  else if( ( item = AllAreModulesAndReturnSmallestIfSo( m_Collector ) ) != NULL )
220  {
221  SetCurItem( item );
222  }
223 
224  else // we can't figure out which item user wants, do popup menu so user can choose
225  {
226  wxMenu itemMenu;
227 
228  // Give a title to the selection menu. This is also a cancel menu item
229  AddMenuItem( &itemMenu, wxID_NONE, _( "Clarify Selection" ),
230  KiBitmap( info_xpm ) );
231  itemMenu.AppendSeparator();
232 
234 
235  for( int i = 0; i<limit; ++i )
236  {
237  wxString text;
238  item = (*m_Collector)[i];
239 
240  text = item->GetSelectMenuText( m_UserUnits );
241 
242  BITMAP_DEF xpm = item->GetMenuImage();
243 
244  AddMenuItem( &itemMenu, ID_POPUP_PCB_ITEM_SELECTION_START + i, text, KiBitmap( xpm ) );
245  }
246 
247  /* @todo: rather than assignment to true, these should be increment and decrement
248  * operators throughout _everywhere_.
249  * That way we can handle nesting.
250  * But I tried that and found there cases where the assignment to true (converted to
251  * a m_IgnoreMouseEvents++ )
252  * was not balanced with the -- (now m_IgnoreMouseEvents=false), so I had to revert.
253  * Somebody should track down these and make them balanced.
254  * m_canvas->SetIgnoreMouseEvents( true );
255  */
256 
257  // this menu's handler is void PCB_BASE_FRAME::ProcessItemSelection()
258  // and it calls SetCurItem() which in turn calls DisplayInfo() on the item.
259  m_canvas->SetAbortRequest( true ); // changed in false if an item is selected
260  PopupMenu( &itemMenu );
261 
263 
264  // The function ProcessItemSelection() has set the current item, return it.
265  if( m_canvas->GetAbortRequest() ) // Nothing selected
266  item = NULL;
267  else
268  item = GetCurItem();
269  }
270 
271  return item;
272 }
273 
274 
275 bool PCB_EDIT_FRAME::GeneralControl( wxDC* aDC, const wxPoint& aPosition, EDA_KEY aHotKey )
276 {
277  // Filter out the 'fake' mouse motion after a keyboard movement
278  if( !aHotKey && m_movingCursorWithKeyboard )
279  {
281  return false;
282  }
283 
284  // when moving mouse, use the "magnetic" grid, unless the shift+ctrl keys is pressed
285  // for next cursor position
286  // ( shift or ctrl key down are PAN command with mouse wheel)
287  bool snapToGrid = true;
288 
289  if( !aHotKey && wxGetKeyState( WXK_SHIFT ) && wxGetKeyState( WXK_CONTROL ) )
290  snapToGrid = false;
291 
292  wxPoint oldpos = GetCrossHairPosition();
293  wxPoint pos = aPosition;
294  bool keyHandled = GeneralControlKeyMovement( aHotKey, &pos, snapToGrid );
295 
296  // Put cursor in new position, according to the zoom keys (if any).
297  SetCrossHairPosition( pos, snapToGrid );
298 
299  /* Put cursor on grid or a pad centre if requested. If the tool DELETE is active the
300  * cursor is left off grid this is better to reach items to delete off grid,
301  */
303  snapToGrid = false;
304 
305  // Cursor is left off grid if no block in progress
306  if( GetScreen()->m_BlockLocate.GetState() != STATE_NO_BLOCK )
307  snapToGrid = true;
308 
309  wxPoint curs_pos = pos;
310 
311  wxRealPoint gridSize = GetScreen()->GetGridSize();
312  wxSize igridsize;
313  igridsize.x = KiROUND( gridSize.x );
314  igridsize.y = KiROUND( gridSize.y );
315 
316  if( Magnetize( this, GetToolId(), igridsize, curs_pos, &pos ) )
317  {
318  SetCrossHairPosition( pos, false );
319  }
320  else
321  {
322  // If there's no intrusion and DRC is active, we pass the cursor
323  // "as is", and let ShowNewTrackWhenMovingCursor figure out what to do.
324  if( !Settings().m_legacyDrcOn || !g_CurrentTrackSegment ||
327  GetScreen()->m_Active_Layer, RefPos( true ) ) )
328  {
329  SetCrossHairPosition( curs_pos, snapToGrid );
330  }
331  }
332 
333  RefreshCrossHair( oldpos, aPosition, aDC );
334 
335  if( aHotKey && OnHotKey( aDC, aHotKey, aPosition ) )
336  {
337  keyHandled = true;
338  }
339 
340  UpdateStatusBar(); // Display new cursor coordinates
341 
342  return keyHandled;
343 }
int GetCount() const
Function GetCount returns the number of objects in the list.
Definition: collector.h:114
#define g_CurrentTrackSegment
most recently created segment
Definition: pcbnew.h:95
KICAD_T Type() const
Function Type()
Definition: base_struct.h:201
Class ZONE_CONTAINER handles a list of polygons defining a copper zone.
Definition: class_zone.h:59
static const KICAD_T AllBoardItems[]
A scan list for all editable board items, like PcbGeneralLocateAndDisplay()
Definition: collectors.h:272
PNG memory record (file in memory).
Definition: bitmap_types.h:43
static const KICAD_T Tracks[]
A scan list for only TRACKS.
Definition: collectors.h:318
long timestamp_t
timestamp_t is our type to represent unique IDs for all kinds of elements; historically simply the ti...
Definition: common.h:52
static int KiROUND(double v)
Round a floating point number to an integer using "round halfway cases away from zero".
Definition: common.h:120
Class BOARD_ITEM is a base class for any item which can be embedded within the BOARD container class...
static const KICAD_T Modules[]
A scan list for only MODULEs.
Definition: collectors.h:293
wxMenuItem * AddMenuItem(wxMenu *aMenu, int aId, const wxString &aText, const wxBitmap &aImage, wxItemKind aType=wxITEM_NORMAL)
Function AddMenuItem is an inline helper function to create and insert a menu item with an icon into ...
Definition: bitmap.cpp:223
void Collect(BOARD_ITEM *aItem, const KICAD_T aScanList[], const wxPoint &aRefPos, const COLLECTORS_GUIDE &aGuide)
Scan a BOARD_ITEM using this class&#39;s Inspector method, which does the collection. ...
Definition: collectors.cpp:482
Class BOARD to handle a board.
class ZONE_CONTAINER, a zone area
Definition: typeinfo.h:102
virtual bool OnHotKey(wxDC *aDC, int aHotKey, const wxPoint &aPosition, EDA_ITEM *aItem=NULL)
void SetCurItem(BOARD_ITEM *aItem, bool aDisplayInfo=true)
Function SetCurItem sets the currently selected item and displays it in the MsgPanel.
int GetHeight() const
Definition: eda_rect.h:118
static const KICAD_T AllButZones[]
A scan list for all editable board items, except zones.
Definition: collectors.h:277
Classes to handle copper zones.
class D_PAD, a pad in a footprint
Definition: typeinfo.h:90
double OnePixelInIU() const override
Definition: collectors.h:618
virtual wxString GetSelectMenuText(EDA_UNITS_T aUnits) const
Function GetSelectMenuText returns the text to display to be used in the selection clarification cont...
virtual void MoveCursorToCrossHair()
Function MoveCursorToCrossHair warps the cursor to the current cross hair position.
int GetState(int type) const
Definition: base_struct.h:240
void Remove(int aIndex)
Function Remove removes the item at aIndex (first position is 0);.
Definition: collector.h:143
KICAD_T
Enum KICAD_T is the set of class identification values, stored in EDA_ITEM::m_StructType.
Definition: typeinfo.h:78
void * GetDisplayOptions() override
Function GetDisplayOptions returns the display options current in use Display options are relative to...
void scanList(PTREE *aTree, DSNLEXER *aLexer)
Function scanList reads a sexpr list from the input stream into a new node with key aLexer->CurText()...
Definition: ptree.cpp:55
bool GeneralControlKeyMovement(int aHotKey, wxPoint *aPos, bool aSnapToGrid)
Handle the common part of GeneralControl dedicated to global cursor keys (i.e.
GENERAL_COLLECTOR * m_Collector
wxBitmap KiBitmap(BITMAP_DEF aBitmap)
Construct a wxBitmap from a memory record, held in a BITMAP_DEF.
Definition: bitmap.cpp:79
class MODULE, a footprint
Definition: typeinfo.h:89
const EDA_RECT GetBoundingBox() const override
Function GetBoundingBox returns the orthogonal, bounding box of this object for display purposes...
Class PCB_DISPLAY_OPTIONS handles display options like enable/disable some optional drawings...
GENERAL_COLLECTORS_GUIDE GetCollectorsGuide()
Function GetCollectorsGuide.
void RefreshCrossHair(const wxPoint &aOldPos, const wxPoint &aEvtPos, wxDC *aDC)
Move and refresh the crosshair after movement and call the mouse capture function.
PCB_GENERAL_SETTINGS & Settings()
static const KICAD_T Zones[]
A scan list for zones outlines only.
Definition: collectors.h:282
bool Magnetize(PCB_BASE_EDIT_FRAME *frame, int aCurrentTool, wxSize aGridSize, wxPoint on_grid, wxPoint *curpos)
Function Magnetize tests to see if there are any magnetic items within near reach of the given "curpo...
uint32_t EDA_KEY
Definition: common.h:73
TRACK * LocateIntrusion(TRACK *listStart, TRACK *aTrack, LAYER_NUM aLayer, const wxPoint &aRef)
Definition: editrack.cpp:533
static BOARD_ITEM * AllAreModulesAndReturnSmallestIfSo(GENERAL_COLLECTOR *aCollector)
Function AllAreModulesAndReturnSmallestIfSo tests that all items in the collection are MODULEs and if...
void SetAbortRequest(bool aAbortRequest)
void SetSelectedCorner(int aCorner)
Definition: class_zone.h:215
class TEXTE_MODULE, text in a footprint
Definition: typeinfo.h:93
wxPoint RefPos(bool useMouse) const
Return the reference position, coming from either the mouse position or the cursor position...
EDA_DRAW_PANEL * m_canvas
The area to draw on.
Definition: draw_frame.h:123
virtual void UpdateStatusBar() override
Update the status bar information.
static const KICAD_T PadsOrModules[]
A scan list for PADs or MODULEs.
Definition: collectors.h:298
Common, abstract interface for edit frames.
Used when the right click button is pressed, or when the select tool is in effect.
Definition: collectors.h:245
int GetToolId() const
Definition: draw_frame.h:519
size_t i
Definition: json11.cpp:597
const wxRealPoint & GetGridSize() const
Return the grid size of the currently selected grid.
Definition: base_screen.h:410
int GetWidth() const
Definition: eda_rect.h:117
PCB_SCREEN * GetScreen() const override
Return a pointer to a BASE_SCREEN or one of its derivatives.
#define MAX_ITEMS_IN_PICKER
Command IDs for the printed circuit board editor.
Definition: pcbnew_id.h:14
DLIST< TRACK > m_Track
Definition: class_board.h:250
Module description (excepted pads)
BOARD_ITEM * PcbGeneralLocateAndDisplay(int aHotKeyCode=0)
Function PcbGeneralLocateAndDisplay searches for an item under the mouse cursor.
A general implementation of a COLLECTORS_GUIDE.
Definition: collectors.h:391
void SetCrossHairPosition(const wxPoint &aPosition, bool aSnapToGrid=true)
Set the screen cross hair position to aPosition in logical (drawing) units.
class SEGZONE, a segment used to fill a zone area (segment on a
Definition: typeinfo.h:97
BOARD_ITEM * GetCurItem()
EDA_UNITS_T m_UserUnits
Definition: draw_frame.h:120
wxPoint GetCrossHairPosition(bool aInvertY=false) const
Return the current cross hair position in logical (drawing) coordinates.
bool m_movingCursorWithKeyboard
One-shot to avoid a recursive mouse event during hotkey movement.
Definition: draw_frame.h:173
virtual BITMAP_DEF GetMenuImage() const
Function GetMenuImage returns a pointer to an image to be used in menus.
timestamp_t GetTimeStamp() const
Definition: base_struct.h:207
bool GeneralControl(wxDC *aDC, const wxPoint &aPosition, EDA_KEY aHotKey=0) override
Perform application specific control using aDC at aPosition in logical units.
#define min(a, b)
Definition: auxiliary.h:85