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  zone->SetSelectedCorner( RefPos( true ) );
192  }
193  break;
194 
195  default:
196  break;
197  }
198  }
199 
200  if( m_Collector->GetCount() <= 1 )
201  {
202  item = (*m_Collector)[0];
203  SetCurItem( item );
204  }
205 
206  // If the count is 2, and first item is a pad or module text, and the 2nd item is its
207  // parent module:
208  else if( m_Collector->GetCount() == 2
209  && ( (*m_Collector)[0]->Type() == PCB_PAD_T || (*m_Collector)[0]->Type() ==
211  && (*m_Collector)[1]->Type() == PCB_MODULE_T && (*m_Collector)[0]->GetParent()==
212  (*m_Collector)[1] )
213  {
214  item = (*m_Collector)[0];
215  SetCurItem( item );
216  }
217  // if all are modules, find the smallest one among the primary choices
218  else if( ( item = AllAreModulesAndReturnSmallestIfSo( m_Collector ) ) != NULL )
219  {
220  SetCurItem( item );
221  }
222 
223  else // we can't figure out which item user wants, do popup menu so user can choose
224  {
225  wxMenu itemMenu;
226 
227  // Give a title to the selection menu. This is also a cancel menu item
228  AddMenuItem( &itemMenu, wxID_NONE, _( "Clarify Selection" ),
229  KiBitmap( info_xpm ) );
230  itemMenu.AppendSeparator();
231 
233 
234  for( int i = 0; i<limit; ++i )
235  {
236  wxString text;
237  item = (*m_Collector)[i];
238 
239  text = item->GetSelectMenuText( m_UserUnits );
240 
241  BITMAP_DEF xpm = item->GetMenuImage();
242 
243  AddMenuItem( &itemMenu, ID_POPUP_PCB_ITEM_SELECTION_START + i, text, KiBitmap( xpm ) );
244  }
245 
246  /* @todo: rather than assignment to true, these should be increment and decrement
247  * operators throughout _everywhere_.
248  * That way we can handle nesting.
249  * But I tried that and found there cases where the assignment to true (converted to
250  * a m_IgnoreMouseEvents++ )
251  * was not balanced with the -- (now m_IgnoreMouseEvents=false), so I had to revert.
252  * Somebody should track down these and make them balanced.
253  * m_canvas->SetIgnoreMouseEvents( true );
254  */
255 
256  // this menu's handler is void PCB_BASE_FRAME::ProcessItemSelection()
257  // and it calls SetCurItem() which in turn calls DisplayInfo() on the item.
258  m_canvas->SetAbortRequest( true ); // changed in false if an item is selected
259  PopupMenu( &itemMenu );
260 
262 
263  // The function ProcessItemSelection() has set the current item, return it.
264  if( m_canvas->GetAbortRequest() ) // Nothing selected
265  item = NULL;
266  else
267  item = GetCurItem();
268  }
269 
270  return item;
271 }
272 
273 
274 bool PCB_EDIT_FRAME::GeneralControl( wxDC* aDC, const wxPoint& aPosition, EDA_KEY aHotKey )
275 {
276  // Filter out the 'fake' mouse motion after a keyboard movement
277  if( !aHotKey && m_movingCursorWithKeyboard )
278  {
280  return false;
281  }
282 
283  // when moving mouse, use the "magnetic" grid, unless the shift+ctrl keys is pressed
284  // for next cursor position
285  // ( shift or ctrl key down are PAN command with mouse wheel)
286  bool snapToGrid = true;
287 
288  if( !aHotKey && wxGetKeyState( WXK_SHIFT ) && wxGetKeyState( WXK_CONTROL ) )
289  snapToGrid = false;
290 
291  wxPoint oldpos = GetCrossHairPosition();
292  wxPoint pos = aPosition;
293  bool keyHandled = GeneralControlKeyMovement( aHotKey, &pos, snapToGrid );
294 
295  // Put cursor in new position, according to the zoom keys (if any).
296  SetCrossHairPosition( pos, snapToGrid );
297 
298  /* Put cursor on grid or a pad centre if requested. If the tool DELETE is active the
299  * cursor is left off grid this is better to reach items to delete off grid,
300  */
302  snapToGrid = false;
303 
304  // Cursor is left off grid if no block in progress
305  if( GetScreen()->m_BlockLocate.GetState() != STATE_NO_BLOCK )
306  snapToGrid = true;
307 
308  wxPoint curs_pos = pos;
309 
310  wxRealPoint gridSize = GetScreen()->GetGridSize();
311  wxSize igridsize;
312  igridsize.x = KiROUND( gridSize.x );
313  igridsize.y = KiROUND( gridSize.y );
314 
315  if( Magnetize( this, GetToolId(), igridsize, curs_pos, &pos ) )
316  {
317  SetCrossHairPosition( pos, false );
318  }
319  else
320  {
321  // If there's no intrusion and DRC is active, we pass the cursor
322  // "as is", and let ShowNewTrackWhenMovingCursor figure out what to do.
323  if( !Settings().m_legacyDrcOn || !g_CurrentTrackSegment ||
326  GetScreen()->m_Active_Layer, RefPos( true ) ) )
327  {
328  SetCrossHairPosition( curs_pos, snapToGrid );
329  }
330  }
331 
332  RefreshCrossHair( oldpos, aPosition, aDC );
333 
334  if( aHotKey && OnHotKey( aDC, aHotKey, aPosition ) )
335  {
336  keyHandled = true;
337  }
338 
339  UpdateStatusBar(); // Display new cursor coordinates
340 
341  return keyHandled;
342 }
int GetCount() const
Function GetCount returns the number of objects in the list.
Definition: collector.h:106
#define g_CurrentTrackSegment
most recently created segment
Definition: pcbnew.h:95
KICAD_T Type() const
Function Type()
Definition: base_struct.h:198
Class ZONE_CONTAINER handles a list of polygons defining a copper zone.
Definition: class_zone.h:60
static const KICAD_T AllBoardItems[]
A scan list for all editable board items, like PcbGeneralLocateAndDisplay()
Definition: collectors.h:259
PNG memory record (file in memory).
Definition: bitmap_types.h:41
static const KICAD_T Tracks[]
A scan list for only TRACKS.
Definition: collectors.h:305
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:280
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:194
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:456
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:264
Classes to handle copper zones.
class D_PAD, a pad in a footprint
Definition: typeinfo.h:90
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:237
void Remove(int aIndex)
Function Remove removes the item at aIndex (first position is 0);.
Definition: collector.h:135
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)
Function GeneralControlKeyMovement Handle the common part of GeneralControl dedicated to global curso...
GENERAL_COLLECTOR * m_Collector
wxBitmap KiBitmap(BITMAP_DEF aBitmap)
Function KiBitmap constructs a wxBitmap from a memory record, held in a BITMAP_DEF.
Definition: bitmap.cpp:78
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:269
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:216
class TEXTE_MODULE, text in a footprint
Definition: typeinfo.h:93
wxPoint RefPos(bool useMouse) const
Function RefPos Return the reference position, coming from either the mouse position or the cursor po...
EDA_DRAW_PANEL * m_canvas
The area to draw on.
Definition: draw_frame.h:108
virtual void UpdateStatusBar() override
Function UpdateStatusBar updates the status bar information.
static const KICAD_T PadsOrModules[]
A scan list for PADs or MODULEs.
Definition: collectors.h:285
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:232
int GetToolId() const
Definition: draw_frame.h:512
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
Function GetScreen returns 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:249
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:376
void SetCrossHairPosition(const wxPoint &aPosition, bool aSnapToGrid=true)
Function SetCrossHairPosition sets the screen cross hair position to aPosition in logical (drawing) u...
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:105
wxPoint GetCrossHairPosition(bool aInvertY=false) const
Function GetCrossHairPosition 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:158
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:204
bool GeneralControl(wxDC *aDC, const wxPoint &aPosition, EDA_KEY aHotKey=0) override
Function GeneralControl performs application specific control using aDC at aPosition in logical units...
#define min(a, b)
Definition: auxiliary.h:85