KiCad PCB EDA Suite
base_screen.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 
32 #include <fctsys.h>
33 #include <macros.h>
34 #include <common.h>
35 #include <base_struct.h>
36 #include <class_base_screen.h>
37 #include <id.h>
38 #include <base_units.h>
39 
40 wxString BASE_SCREEN::m_PageLayoutDescrFileName; // the name of the page layout descr file.
41 
43  EDA_ITEM( aType )
44 {
46  m_FirstRedraw = true;
47  m_ScreenNumber = 1;
48  m_NumberOfScreens = 1; // Hierarchy: Root: ScreenNumber = 1
49  m_Zoom = 32.0;
50  m_Grid.m_Size = wxRealPoint( 50, 50 ); // Default grid size
52  m_Center = true;
53  m_IsPrinting = false;
56 
57  m_FlagModified = false; // Set when any change is made on board.
58  m_FlagSave = false; // Used in auto save set when an auto save is required.
59 
60  SetCurItem( NULL );
61 }
62 
63 
65 {
66 }
67 
68 
69 void BASE_SCREEN::InitDataPoints( const wxSize& aPageSizeIU )
70 {
71  if( m_Center )
72  {
75 
76  m_DrawOrg.x = -aPageSizeIU.x / 2;
77  m_DrawOrg.y = -aPageSizeIU.y / 2;
78  }
79  else
80  {
81  m_crossHairPosition.x = aPageSizeIU.x / 2;
82  m_crossHairPosition.y = aPageSizeIU.y / 2;
83 
84  m_DrawOrg.x = 0;
85  m_DrawOrg.y = 0;
86  }
87 
88  m_O_Curseur.x = m_O_Curseur.y = 0;
89 }
90 
91 
93 {
94  double scale = 1.0 / GetZoom();
95  return scale;
96 }
97 
98 
99 void BASE_SCREEN::SetScalingFactor( double aScale )
100 {
101  // Limit zoom to max and min allowed values:
102  double zoom = Clamp( GetMinAllowedZoom(), aScale, GetMaxAllowedZoom() );
103 
104  SetZoom( zoom );
105 }
106 
107 
109 {
110  return SetZoom( GetMinAllowedZoom() );
111 }
112 
113 
115 {
116  return SetZoom( GetMaxAllowedZoom() );
117 }
118 
119 
120 bool BASE_SCREEN::SetZoom( double iu_per_du )
121 {
122  if( iu_per_du == m_Zoom )
123  return false;
124 
125  //wxLogDebug( "Zoom:%.16g 1/Zoom:%.16g", iu_per_du, 1/iu_per_du );
126 
127  if( iu_per_du < GetMinAllowedZoom() )
128  return false;
129 
130  if( iu_per_du > GetMaxAllowedZoom() )
131  return false;
132 
133  m_Zoom = iu_per_du;
134 
135  return true;
136 }
137 
138 
140 {
141  for( unsigned i=0; i < m_ZoomList.size(); ++i )
142  {
143  if( m_Zoom < m_ZoomList[i] )
144  {
145  SetZoom( m_ZoomList[i] );
146  return true;
147  }
148  }
149 
150  return false;
151 }
152 
153 
155 {
156  for( unsigned i = m_ZoomList.size(); i != 0; --i )
157  {
158  if( m_Zoom > m_ZoomList[i - 1] )
159  {
160  SetZoom( m_ZoomList[i - 1] );
161  return true;
162  }
163  }
164 
165  return false;
166 }
167 
168 /* Build the list of human readable grid list.
169  * The list shows the grid size both in mils or mm.
170  * aMmFirst = true to have mm first and mils after
171  * false to have mils first and mm after
172  */
173 int BASE_SCREEN::BuildGridsChoiceList( wxArrayString& aGridsList, bool aMmFirst) const
174 {
175  wxString msg;
176  wxRealPoint curr_grid_size = GetGridSize();
177  int idx = -1;
178  int idx_usergrid = -1;
179 
180  for( size_t i = 0; i < GetGridCount(); i++ )
181  {
182  const GRID_TYPE& grid = m_grids[i];
183  double gridValueMils = To_User_Unit( INCHES, grid.m_Size.x ) * 1000;
184  double gridValue_mm = To_User_Unit( MILLIMETRES, grid.m_Size.x );
185 
186  if( grid.m_CmdId == ID_POPUP_GRID_USER )
187  {
188  msg = _( "Custom User Grid" );
189  idx_usergrid = i;
190  }
191  else
192  {
193  if( aMmFirst )
194  msg.Printf( _( "Grid: %.4f mm (%.2f mils)" ),
195  gridValue_mm, gridValueMils );
196  else
197  msg.Printf( _( "Grid: %.2f mils (%.4f mm)" ),
198  gridValueMils, gridValue_mm );
199  }
200 
201  aGridsList.Add( msg );
202 
203  if( curr_grid_size == grid.m_Size )
204  idx = i;
205  }
206 
207  if( idx < 0 )
208  idx = idx_usergrid;
209 
210  return idx;
211 }
212 
213 
215 {
216  if( !m_grids.empty() )
217  m_grids.clear();
218 
219  m_grids = gridlist;
220 }
221 
222 
223 int BASE_SCREEN::SetGrid( const wxRealPoint& size )
224 {
225  wxASSERT( !m_grids.empty() );
226 
227  GRID_TYPE nearest_grid = m_grids[0];
228  int gridIdx = 0;
229 
230  for( unsigned i = 0; i < m_grids.size(); i++ )
231  {
232  if( m_grids[i].m_Size == size )
233  {
234  m_Grid = m_grids[i];
235  return m_grids[i].m_CmdId - ID_POPUP_GRID_LEVEL_1000;
236  }
237 
238  // keep track of the nearest larger grid size, if the exact size is not found
239  if ( size.x < m_grids[i].m_Size.x )
240  {
241  gridIdx = m_grids[i].m_CmdId - ID_POPUP_GRID_LEVEL_1000;
242  nearest_grid = m_grids[i];
243  }
244  }
245 
246  m_Grid = nearest_grid;
247 
248  wxLogWarning( wxT( "Grid size( %f, %f ) not in grid list, falling back " ) \
249  wxT( "to grid size( %f, %f )." ),
250  size.x, size.y, m_Grid.m_Size.x, m_Grid.m_Size.y );
251 
252  return gridIdx;
253 }
254 
255 
256 int BASE_SCREEN::SetGrid( int aCommandId )
257 {
258  wxASSERT( !m_grids.empty() );
259 
260  for( unsigned i = 0; i < m_grids.size(); i++ )
261  {
262  if( m_grids[i].m_CmdId == aCommandId )
263  {
264  m_Grid = m_grids[i];
265  return m_grids[i].m_CmdId - ID_POPUP_GRID_LEVEL_1000;
266  }
267  }
268 
269  m_Grid = m_grids[0];
270 
271  wxLogWarning( wxT( "Grid ID %d not in grid list, falling back to " ) \
272  wxT( "grid size( %g, %g )." ), aCommandId,
273  m_Grid.m_Size.x, m_Grid.m_Size.y );
274 
275  return m_grids[0].m_CmdId - ID_POPUP_GRID_LEVEL_1000;
276 }
277 
278 
279 
280 void BASE_SCREEN::AddGrid( const GRID_TYPE& grid )
281 {
282  for( unsigned i = 0; i < m_grids.size(); i++ )
283  {
284  if( m_grids[i].m_Size == grid.m_Size && grid.m_CmdId != ID_POPUP_GRID_USER )
285  {
286  wxLogDebug( wxT( "Discarding duplicate grid size( %g, %g )." ),
287  grid.m_Size.x, grid.m_Size.y );
288  return;
289  }
290 
291  if( m_grids[i].m_CmdId == grid.m_CmdId )
292  {
293  wxLogDebug( wxT( "Changing grid ID %d from size( %g, %g ) to " ) \
294  wxT( "size( %g, %g )." ),
295  grid.m_CmdId, m_grids[i].m_Size.x,
296  m_grids[i].m_Size.y, grid.m_Size.x, grid.m_Size.y );
297  m_grids[i].m_Size = grid.m_Size;
298  return;
299  }
300  }
301 
302  m_grids.push_back( grid );
303 }
304 
305 
306 void BASE_SCREEN::AddGrid( const wxRealPoint& size, int id )
307 {
308  GRID_TYPE grid;
309 
310  grid.m_Size = size;
311  grid.m_CmdId = id;
312  AddGrid( grid );
313 }
314 
315 
316 void BASE_SCREEN::AddGrid( const wxRealPoint& size, EDA_UNITS_T aUnit, int id )
317 {
318  wxRealPoint new_size;
319  GRID_TYPE new_grid;
320 
321  new_size.x = From_User_Unit( aUnit, size.x );
322  new_size.y = From_User_Unit( aUnit, size.y );
323  new_grid.m_CmdId = id;
324  new_grid.m_Size = new_size;
325 
326  AddGrid( new_grid );
327 }
328 
329 
331 {
332  wxCHECK_MSG( !m_grids.empty() && aIndex < m_grids.size(), m_Grid,
333  wxT( "Cannot get grid object outside the bounds of the grid list." ) );
334 
335  return m_grids[ aIndex ];
336 }
337 
338 
339 bool BASE_SCREEN::GridExists( int aCommandId )
340 {
341  // tests for grid command ID (not an index in grid list, but a wxID) exists in grid list.
342  for( unsigned i = 0; i < m_grids.size(); i++ )
343  {
344  if( m_grids[i].m_CmdId == aCommandId )
345  return true;
346  }
347 
348  return false;
349 }
350 
351 
353  const wxPoint& aGridOrigin, wxRealPoint* aGridSize ) const
354 {
355  wxPoint pt;
356  wxRealPoint gridSize;
357 
358  if( aGridSize )
359  gridSize = *aGridSize;
360  else
361  gridSize = GetGridSize();
362 
363  double offset = fmod( aGridOrigin.x, gridSize.x );
364  int x = KiROUND( (aPosition.x - offset) / gridSize.x );
365 
366  pt.x = KiROUND( x * gridSize.x + offset );
367 
368  offset = fmod( aGridOrigin.y, gridSize.y );
369 
370  int y = KiROUND( (aPosition.y - offset) / gridSize.y );
371  pt.y = KiROUND ( y * gridSize.y + offset );
372 
373  return pt;
374 }
375 
376 
377 wxPoint BASE_SCREEN::getCursorPosition( bool aOnGrid, const wxPoint& aGridOrigin, wxRealPoint* aGridSize ) const
378 {
379  if( aOnGrid )
380  return getNearestGridPosition( m_crossHairPosition, aGridOrigin, aGridSize );
381 
382  return m_crossHairPosition;
383 }
384 
385 
387 {
389  double scalar = GetScalingFactor();
390 
391  pos.x = KiROUND( (double) pos.x * scalar );
392  pos.y = KiROUND( (double) pos.y * scalar );
393 
394  return pos;
395 }
396 
397 
398 void BASE_SCREEN::setCrossHairPosition( const wxPoint& aPosition, const wxPoint& aGridOrigin, bool aSnapToGrid )
399 {
400  if( aSnapToGrid )
401  m_crossHairPosition = getNearestGridPosition( aPosition, aGridOrigin, NULL );
402  else
403  m_crossHairPosition = aPosition;
404 }
405 
406 
408 {
411 }
412 
413 
415 {
416  m_UndoList.PushCommand( aNewitem );
417 
418  // Delete the extra items, if count max reached
419  if( m_UndoRedoCountMax > 0 )
420  {
421  int extraitems = GetUndoCommandCount() - m_UndoRedoCountMax;
422  if( extraitems > 0 )
423  ClearUndoORRedoList( m_UndoList, extraitems );
424  }
425 }
426 
427 
429 {
430  m_RedoList.PushCommand( aNewitem );
431 
432  // Delete the extra items, if count max reached
433  if( m_UndoRedoCountMax > 0 )
434  {
435  int extraitems = GetRedoCommandCount() - m_UndoRedoCountMax;
436  if( extraitems > 0 )
437  ClearUndoORRedoList( m_RedoList, extraitems );
438  }
439 }
440 
441 
443 {
444  return m_UndoList.PopCommand( );
445 }
446 
447 
449 {
450  return m_RedoList.PopCommand( );
451 }
452 
453 
454 #if defined(DEBUG)
455 
456 void BASE_SCREEN::Show( int nestLevel, std::ostream& os ) const
457 {
458  // for now, make it look like XML, expand on this later.
459  NestedSpace( nestLevel, os ) << '<' << GetClass().Lower().mb_str() << ">\n";
460 
461  /* this class will eventually go away, but here's a place holder until then.
462  for( EDA_ITEM* item = m_drawList; item; item = item->Next() )
463  {
464  item->Show( nestLevel+1, os );
465  }
466  */
467 
468  NestedSpace( nestLevel, os ) << "</" << GetClass().Lower().mb_str() << ">\n";
469 }
470 
471 #endif
virtual void PushCommandToUndoList(PICKED_ITEMS_LIST *aItem)
Function PushCommandToUndoList add a command to undo in undo list delete the very old commands when t...
void SetGridList(GRIDS &sizelist)
long y
Definition: auxiliary.h:25
void SetCurItem(EDA_ITEM *aItem)
Function SetCurItem sets the currently selected object, m_CurrentItem.
int m_UndoRedoCountMax
undo/Redo command Max depth
wxPoint getCursorPosition(bool aOnGrid, const wxPoint &aGridOrigin, wxRealPoint *aGridSize) const
Function getCursorPosition returns the current cursor position in logical (drawing) units...
const T & Clamp(const T &lower, const T &value, const T &upper)
Function Clamp limits value within the range lower <= value <= upper.
Definition: macros.h:127
bool m_FlagModified
Indicates current drawing has been modified.
int m_ScrollPixelsPerUnitY
Pixels per scroll unit in the vertical direction.
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
double GetScalingFactor() const
Function GetScalingFactor returns the inverse of the current scale used to draw items on screen...
Definition: base_screen.cpp:92
Implementation of conversion functions that require both schematic and board internal units...
virtual wxString GetClass() const override
Function GetClass returns the class name.
wxPoint m_crossHairPosition
The cross hair position in logical (drawing) units.
#define DEFAULT_MAX_UNDO_ITEMS
Definition: draw_frame.h:46
double GetZoom() const
Function GetZoom returns the current "zoom factor", which is a measure of "internal units per device ...
wxPoint getCrossHairScreenPosition() const
Function getCursorScreenPosition returns the cross hair position in device (display) units...
GRID_TYPE m_Grid
Current grid selection.
virtual void ClearUndoORRedoList(UNDO_REDO_CONTAINER &aList, int aItemCount=-1)=0
Function ClearUndoORRedoList (virtual).
bool SetPreviousZoom()
wxPoint m_O_Curseur
Relative Screen cursor coordinate (on grid) in user units.
PICKED_ITEMS_LIST * PopCommand()
std::vector< GRID_TYPE > GRIDS
KICAD_T
Enum KICAD_T is the set of class identification values, stored in EDA_ITEM::m_StructType.
Definition: typeinfo.h:78
size_t GetGridCount() const
Function GetGridCount().
double GetMinAllowedZoom() const
Function GetMinAllowedZoom returns the minimum allowed zoom factor, which was established as the firs...
bool SetNextZoom()
This file contains miscellaneous commonly used macros and functions.
void PushCommand(PICKED_ITEMS_LIST *aCommand)
static wxString m_PageLayoutDescrFileName
the name of the page layout descr file, or emty to used the default pagelayout
virtual PICKED_ITEMS_LIST * PopCommandFromUndoList()
PopCommandFromUndoList return the last command to undo and remove it from list nothing is deleted...
void InitDataPoints(const wxSize &aPageSizeInternalUnits)
Definition: base_screen.cpp:69
int BuildGridsChoiceList(wxArrayString &aGridsList, bool aMmFirst) const
Function BuildGridsChoiceList().
int GetUndoCommandCount() const
const GRID_TYPE & GetGrid() const
Return the grid object of the currently selected grid.
long x
Definition: auxiliary.h:24
wxPoint getNearestGridPosition(const wxPoint &aPosition, const wxPoint &aGridOrigin, wxRealPoint *aGridSize) const
Function getNearestGridPosition returns the nearest aGridSize location to aPosition.
bool m_Center
Center on screen.
UNDO_REDO_CONTAINER m_UndoList
Objects list for the undo command (old data)
void SetScalingFactor(double iu_per_du)
Function SetScalingFactor sets the scaling factor of "internal unit per device unit".
Definition: base_screen.cpp:99
Definition: common.h:145
virtual PICKED_ITEMS_LIST * PopCommandFromRedoList()
PopCommandFromRedoList return the last command to undo and remove it from list nothing is deleted...
virtual void ClearUndoRedoList()
Function ClearUndoRedoList clear undo and redo list, using ClearUndoORRedoList() picked items are del...
double From_User_Unit(EDA_UNITS_T aUnit, double aValue)
Return in internal units the value "val" given in a real unit such as "in", "mm" or "deg"...
Definition: base_units.cpp:274
int m_ScrollPixelsPerUnitX
Pixels per scroll unit in the horizontal direction.
wxRealPoint m_Size
bool SetZoom(double iu_per_du)
Function SetZoom adjusts the current zoom factor.
Class PICKED_ITEMS_LIST is a holder to handle information on schematic or board items.
ID_POPUP_GRID_USER
Definition: draw_frame.cpp:108
UNDO_REDO_CONTAINER m_RedoList
Objects list for the redo command (old data)
void setCrossHairPosition(const wxPoint &aPosition, const wxPoint &aGridOrigin, bool aSnapToGrid)
Function setCrossHairPosition sets the screen cross hair position to aPosition in logical (drawing) u...
void AddGrid(const GRID_TYPE &grid)
GRIDS m_grids
List of valid grid sizes.
const int scale
bool GridExists(int aCommandId)
Function GridExists tests for grid command ID (not an index in grid list, but a wxID) exists in grid ...
BASE_SCREEN class implementation.
Class GRID_TYPE is for grid arrays.
BASE_SCREEN(KICAD_T aType=SCREEN_T)
Definition: base_screen.cpp:42
const wxRealPoint & GetGridSize() const
Return the grid size of the currently selected grid.
virtual void PushCommandToRedoList(PICKED_ITEMS_LIST *aItem)
Function PushCommandToRedoList add a command to redo in redo list delete the very old commands when t...
wxPoint m_DrawOrg
offsets for drawing the circuit on the screen
Class EDA_ITEM is a base class for most all the KiCad significant classes, used in schematics and boa...
Definition: base_struct.h:178
The common library.
bool m_FlagSave
Indicates automatic file save.
double To_User_Unit(EDA_UNITS_T aUnit, double aValue)
Function To_User_Unit convert aValue in internal units to the appropriate user units defined by aUnit...
Definition: base_units.cpp:91
double GetMaxAllowedZoom() const
Function GetMaxAllowedZoom returns the maximum allowed zoom factor, which was established as the last...
double m_Zoom
Current zoom coefficient.
Basic classes for most KiCad items.
int SetGrid(const wxRealPoint &size)
set the current grid size m_Grid.
bool SetLastZoom()
bool SetFirstZoom()
EDA_UNITS_T
Definition: common.h:144
int GetRedoCommandCount() const
std::vector< double > m_ZoomList
standard zoom (i.e. scale) coefficients.