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 <wxPcbStruct.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_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 
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  if( m_mainToolBar->GetToolToggled( ID_TOOLBARH_PCB_MODE_MODULE ) )
122  scanList = GENERAL_COLLECTOR::Modules;
123  else
124  scanList = (displ_opts->m_DisplayZonesMode == 0) ?
127  }
128  else
129  {
130  switch( GetToolId() )
131  {
134  break;
135 
136  case ID_TRACK_BUTT:
137  scanList = GENERAL_COLLECTOR::Tracks;
138  break;
139 
140  case ID_PCB_MODULE_BUTT:
141  scanList = GENERAL_COLLECTOR::Modules;
142  break;
143 
144  case ID_PCB_ZONES_BUTT:
146  scanList = GENERAL_COLLECTOR::Zones;
147  break;
148 
149  default:
150  scanList = displ_opts->m_DisplayZonesMode == 0 ?
153  }
154  }
155 
156  m_Collector->Collect( m_Pcb, scanList, RefPos( true ), guide );
157 
158 #if 0
159  // debugging: print out the collected items, showing their priority order too.
160  for( int i = 0; i<m_Collector->GetCount(); ++i )
161  (*m_Collector)[i]->Show( 0, std::cout );
162 #endif
163 
164  /* Remove redundancies: sometime, legacy zones are found twice,
165  * because zones can be filled by overlapping segments (this is a fill option)
166  * Trigger the selection of the current edge for new-style zones
167  */
168  time_t timestampzone = 0;
169 
170  for( int ii = 0; ii < m_Collector->GetCount(); ii++ )
171  {
172  item = (*m_Collector)[ii];
173 
174  switch( item->Type() )
175  {
176  case PCB_ZONE_T:
177  // Found a TYPE ZONE
178  if( item->GetTimeStamp() == timestampzone ) // Remove it, redundant, zone already found
179  {
180  m_Collector->Remove( ii );
181  ii--;
182  }
183  else
184  {
185  timestampzone = item->GetTimeStamp();
186  }
187  break;
188 
189  case PCB_ZONE_AREA_T:
190  {
191  /* We need to do the selection now because the menu text
192  * depends on it */
193  ZONE_CONTAINER *zone = static_cast<ZONE_CONTAINER*>( item );
194  zone->SetSelectedCorner( RefPos( true ) );
195  }
196  break;
197 
198  default:
199  break;
200  }
201  }
202 
203  if( m_Collector->GetCount() <= 1 )
204  {
205  item = (*m_Collector)[0];
206  SetCurItem( item );
207  }
208 
209  // If the count is 2, and first item is a pad or module text, and the 2nd item is its
210  // parent module:
211  else if( m_Collector->GetCount() == 2
212  && ( (*m_Collector)[0]->Type() == PCB_PAD_T || (*m_Collector)[0]->Type() ==
214  && (*m_Collector)[1]->Type() == PCB_MODULE_T && (*m_Collector)[0]->GetParent()==
215  (*m_Collector)[1] )
216  {
217  item = (*m_Collector)[0];
218  SetCurItem( item );
219  }
220  // if all are modules, find the smallest one among the primary choices
221  else if( ( item = AllAreModulesAndReturnSmallestIfSo( m_Collector ) ) != NULL )
222  {
223  SetCurItem( item );
224  }
225 
226  else // we can't figure out which item user wants, do popup menu so user can choose
227  {
228  wxMenu itemMenu;
229 
230  // Give a title to the selection menu. This is also a cancel menu item
231  AddMenuItem( &itemMenu, wxID_NONE, _( "Clarify Selection" ),
232  KiBitmap( info_xpm ) );
233  itemMenu.AppendSeparator();
234 
236 
237  for( int i = 0; i<limit; ++i )
238  {
239  wxString text;
240  item = (*m_Collector)[i];
241 
242  text = item->GetSelectMenuText();
243 
244  BITMAP_DEF xpm = item->GetMenuImage();
245 
246  AddMenuItem( &itemMenu, ID_POPUP_PCB_ITEM_SELECTION_START + i, text, KiBitmap( xpm ) );
247  }
248 
249  /* @todo: rather than assignment to true, these should be increment and decrement
250  * operators throughout _everywhere_.
251  * That way we can handle nesting.
252  * But I tried that and found there cases where the assignment to true (converted to
253  * a m_IgnoreMouseEvents++ )
254  * was not balanced with the -- (now m_IgnoreMouseEvents=false), so I had to revert.
255  * Somebody should track down these and make them balanced.
256  * m_canvas->SetIgnoreMouseEvents( true );
257  */
258 
259  // this menu's handler is void PCB_BASE_FRAME::ProcessItemSelection()
260  // and it calls SetCurItem() which in turn calls DisplayInfo() on the item.
261  m_canvas->SetAbortRequest( true ); // changed in false if an item is selected
262  PopupMenu( &itemMenu );
263 
265 
266  // The function ProcessItemSelection() has set the current item, return it.
267  if( m_canvas->GetAbortRequest() ) // Nothing selected
268  item = NULL;
269  else
270  item = GetCurItem();
271  }
272 
273  return item;
274 }
275 
276 
277 bool PCB_EDIT_FRAME::GeneralControl( wxDC* aDC, const wxPoint& aPosition, EDA_KEY aHotKey )
278 {
279  bool eventHandled = true;
280 
281  // Filter out the 'fake' mouse motion after a keyboard movement
282  if( !aHotKey && m_movingCursorWithKeyboard )
283  {
285  return false;
286  }
287 
288  // when moving mouse, use the "magnetic" grid, unless the shift+ctrl keys is pressed
289  // for next cursor position
290  // ( shift or ctrl key down are PAN command with mouse wheel)
291  bool snapToGrid = true;
292 
293  if( !aHotKey && wxGetKeyState( WXK_SHIFT ) && wxGetKeyState( WXK_CONTROL ) )
294  snapToGrid = false;
295 
296  wxPoint oldpos = GetCrossHairPosition();
297  wxPoint pos = aPosition;
298  GeneralControlKeyMovement( aHotKey, &pos, snapToGrid );
299 
300  // Put cursor in new position, according to the zoom keys (if any).
301  SetCrossHairPosition( pos, snapToGrid );
302 
303  /* Put cursor on grid or a pad centre if requested. If the tool DELETE is active the
304  * cursor is left off grid this is better to reach items to delete off grid,
305  */
307  snapToGrid = false;
308 
309  // Cursor is left off grid if no block in progress
310  if( GetScreen()->m_BlockLocate.GetState() != STATE_NO_BLOCK )
311  snapToGrid = true;
312 
313  wxPoint curs_pos = pos;
314 
315  wxRealPoint gridSize = GetScreen()->GetGridSize();
316  wxSize igridsize;
317  igridsize.x = KiROUND( gridSize.x );
318  igridsize.y = KiROUND( gridSize.y );
319 
320  if( Magnetize( this, GetToolId(), igridsize, curs_pos, &pos ) )
321  {
322  SetCrossHairPosition( pos, false );
323  }
324  else
325  {
326  // If there's no intrusion and DRC is active, we pass the cursor
327  // "as is", and let ShowNewTrackWhenMovingCursor figure out what to do.
328  if( !Settings().m_legacyDrcOn || !g_CurrentTrackSegment ||
331  GetScreen()->m_Active_Layer, RefPos( true ) ) )
332  {
333  SetCrossHairPosition( curs_pos, snapToGrid );
334  }
335  }
336 
337  RefreshCrossHair( oldpos, aPosition, aDC );
338 
339  if( aHotKey )
340  {
341  eventHandled = OnHotKey( aDC, aHotKey, aPosition );
342  }
343 
344  UpdateStatusBar(); // Display new cursor coordinates
345 
346  return eventHandled;
347 }
int GetCount() const
Function GetCount returns the number of objects in the list.
#define g_CurrentTrackSegment
most recently created segment
Definition: pcbnew.h:95
KICAD_T Type() const
Function Type()
Definition: base_struct.h:212
Class ZONE_CONTAINER handles a list of polygons defining a copper zone.
Definition: class_zone.h:78
static const KICAD_T AllBoardItems[]
A scan list for all editable board items, like PcbGeneralLocateAndDisplay()
Definition: collectors.h:241
PNG memory record (file in memory).
Definition: bitmap_types.h:38
static const KICAD_T Tracks[]
A scan list for only TRACKS.
Definition: collectors.h:294
static int KiROUND(double v)
KiROUND rounds a floating point number to an int using "round halfway cases away from zero"...
Definition: common.h:107
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 all primary board items, omitting items which are subordinate to a MODULE...
Definition: collectors.h:265
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:55
void Collect(BOARD_ITEM *aItem, const KICAD_T aScanList[], const wxPoint &aRefPos, const COLLECTORS_GUIDE &aGuide)
Function Collect scans a BOARD_ITEM using this class's Inspector method, which does the collection...
Definition: collectors.cpp:447
Class BOARD to handle a board.
class ZONE_CONTAINER, a zone area
Definition: typeinfo.h:114
void SetCurItem(BOARD_ITEM *aItem, bool aDisplayInfo=true)
Function SetCurItem sets the currently selected item and displays it in the MsgPanel.
int GetHeight() const
static const KICAD_T AllButZones[]
A scan list for all editable board items, except zones.
Definition: collectors.h:247
Classes to handle copper zones.
class D_PAD, a pad in a footprint
Definition: typeinfo.h:102
void MoveCursorToCrossHair()
Function MoveCursorToCrossHair warps the cursor to the current cross hair position.
Definition: draw_panel.cpp:347
int GetState(int type) const
Definition: base_struct.h:251
virtual wxString GetSelectMenuText() const
Function GetSelectMenuText returns the text to display to be used in the selection clarification cont...
void Remove(int aIndex)
Function Remove removes the item at aIndex (first position is 0);.
KICAD_T
Enum KICAD_T is the set of class identification values, stored in EDA_ITEM::m_StructType.
Definition: typeinfo.h:90
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
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:36
class MODULE, a footprint
Definition: typeinfo.h:101
const EDA_RECT GetBoundingBox() const override
Function GetBoundingBox returns the orthogonal, bounding box of this object for display purposes...
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:252
bool Magnetize(PCB_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:52
int m_DisplayZonesMode
Definition: pcbstruct.h:77
class SEGZONE, a segment used to fill a zone area (segment on a copper layer)
Definition: typeinfo.h:109
TRACK * LocateIntrusion(TRACK *listStart, TRACK *aTrack, LAYER_NUM aLayer, const wxPoint &aRef)
Definition: editrack.cpp:539
bool OnHotKey(wxDC *aDC, int aHotkeyCode, const wxPoint &aPosition, EDA_ITEM *aItem=NULL) override
Function OnHotKey.
static BOARD_ITEM * AllAreModulesAndReturnSmallestIfSo(GENERAL_COLLECTOR *aCollector)
Function AllAreModulesAndReturnSmallestIfSo tests that all items in the collection are MODULEs and if...
wxAuiToolBar * m_mainToolBar
Standard horizontal Toolbar.
Definition: wxstruct.h:140
void SetAbortRequest(bool aAbortRequest)
void SetSelectedCorner(int aCorner)
Definition: class_zone.h:221
time_t GetTimeStamp() const
Definition: base_struct.h:218
Class DISPLAY_OPTIONS handles display options like enable/disable some optional drawings.
Definition: pcbstruct.h:62
class TEXTE_MODULE, text in a footprint
Definition: typeinfo.h:105
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:93
bool GetAbortRequest() const
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:271
void GeneralControlKeyMovement(int aHotKey, wxPoint *aPos, bool aSnapToGrid)
Function GeneralControlKeyMovement Handle the common part of GeneralControl dedicated to global curso...
int GetPrimaryCount()
Function GetPrimaryCount.
Definition: collectors.h:344
Class GENERAL_COLLECTOR is intended for use when the right click button is pressed, or when the plain "arrow" tool is in effect.
Definition: collectors.h:211
int GetToolId() const
Definition: draw_frame.h:458
const wxRealPoint & GetGridSize() const
Return the grid size of the currently selected grid.
int GetWidth() const
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:246
Module description (excepted pads)
BOARD_ITEM * PcbGeneralLocateAndDisplay(int aHotKeyCode=0)
Function PcbGeneralLocateAndDisplay searches for an item under the mouse cursor.
Class GENERAL_COLLECTORS_GUIDE is a general implementation of a COLLECTORS_GUIDE. ...
Definition: collectors.h:378
void SetCrossHairPosition(const wxPoint &aPosition, bool aSnapToGrid=true)
Function SetCrossHairPosition sets the screen cross hair position to aPosition in logical (drawing) u...
BOARD_ITEM * GetCurItem()
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:139
virtual BITMAP_DEF GetMenuImage() const
Function GetMenuImage returns a pointer to an image to be used in menus.
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