KiCad PCB EDA Suite
zoom.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) 2017 Jean-Pierre Charras, jp.charras at wanadoo.fr
5  * Copyright (C) 1992-2018 KiCad Developers, see AUTHORS.txt for contributors.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, you may find one here:
19  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
20  * or you may search the http://www.gnu.org website for the version 2 license,
21  * or you may write to the Free Software Foundation, Inc.,
22  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
23  */
24 
29 /*
30  * Manage zoom, grid step, and auto crop.
31  */
32 
33 #include <fctsys.h>
34 #include <id.h>
35 #include <class_drawpanel.h>
36 #include <view/view.h>
37 #include <base_screen.h>
38 #include <draw_frame.h>
39 #include <kicad_device_context.h>
40 #include <hotkeys_basic.h>
41 #include <menus_helpers.h>
42 #include <base_units.h>
43 #include <tool/tool_manager.h>
44 
45 
46 void EDA_DRAW_FRAME::RedrawScreen( const wxPoint& aCenterPoint, bool aWarpPointer )
47 {
48  if( IsGalCanvasActive() )
49  return;
50 
51  AdjustScrollBars( aCenterPoint );
52 
53  // Move the mouse cursor to the on grid graphic cursor position
54  if( aWarpPointer )
56 
57  m_canvas->Refresh();
58  m_canvas->Update();
59 }
60 
61 
62 void EDA_DRAW_FRAME::RedrawScreen2( const wxPoint& posBefore )
63 {
64  if( IsGalCanvasActive() )
65  return;
66 
67  // relative screen position to center before zoom
68  wxPoint dPos = posBefore - m_canvas->GetClientSize() / 2;
69 
70  // screen position of crosshair after zoom
71  wxPoint newScreenPos = m_canvas->ToDeviceXY( GetCrossHairPosition() );
72  wxPoint newCenter = m_canvas->ToLogicalXY( newScreenPos - dPos );
73 
74  AdjustScrollBars( newCenter );
75 
76  m_canvas->Refresh();
77  m_canvas->Update();
78 }
79 
80 
81 // Factor out the calculation portion of the various BestZoom() implementations.
82 //
83 // Note that like it's forerunners this routine has an intentional side-effect: it
84 // sets the scroll centre position. While I'm not happy about that, it's probably
85 // not worth fixing as its days are numbered (GAL canvases use a different method).
86 double EDA_DRAW_FRAME::bestZoom( double sizeX, double sizeY, double scaleFactor, wxPoint centre )
87 {
88  double bestzoom = std::max( sizeX * scaleFactor / (double) m_canvas->GetClientSize().x,
89  sizeY * scaleFactor / (double) m_canvas->GetClientSize().y );
90 
91  // Take scrollbars into account
92  DSIZE scrollbarSize = m_canvas->GetSize() - m_canvas->GetClientSize();
93  centre.x -= int( bestzoom * scrollbarSize.x / 2.0 );
94  centre.y -= int( bestzoom * scrollbarSize.y / 2.0 );
95 
96  SetScrollCenterPosition( centre );
97 
98  return bestzoom;
99 }
100 
101 
102 void EDA_DRAW_FRAME::Zoom_Automatique( bool aWarpPointer )
103 {
104  BASE_SCREEN* screen = GetScreen();
105 
106  // Set the best zoom and get center point.
107 
108  // BestZoom() can compute an illegal zoom if the client window size
109  // is small, say because frame is not maximized. So use the clamping form
110  // of SetZoom():
111  double bestzoom = BestZoom();
112  screen->SetScalingFactor( bestzoom );
113 
114  if( screen->m_FirstRedraw )
116 
117  if( !IsGalCanvasActive() )
118  RedrawScreen( GetScrollCenterPosition(), aWarpPointer );
119  else
120  m_toolManager->RunAction( "common.Control.zoomFitScreen", true );
121 }
122 
123 
125 {
126  // Compute the best zoom
127  Rect.Normalize();
128 
129  wxSize size = m_canvas->GetClientSize();
130 
131  // Use ceil to at least show the full rect
132  double scalex = (double) Rect.GetSize().x / size.x;
133  double bestscale = (double) Rect.GetSize().y / size.y;
134 
135  bestscale = std::max( bestscale, scalex );
136 
137  GetScreen()->SetScalingFactor( bestscale );
138  RedrawScreen( Rect.Centre(), true );
139 }
140 
141 
142 void EDA_DRAW_FRAME::OnZoom( wxCommandEvent& event )
143 {
144  if( m_canvas == NULL )
145  return;
146 
147  int id = event.GetId();
148  bool zoom_at_cursor = false;
149  BASE_SCREEN* screen = GetScreen();
150  wxPoint center = GetScrollCenterPosition();
151 
152  if ( id == ID_KEY_ZOOM_IN )
153  {
154  id = GetCanvas()->GetEnableZoomNoCenter() ?
156  }
157  else if ( id == ID_KEY_ZOOM_OUT )
158  {
159  id = GetCanvas()->GetEnableZoomNoCenter() ?
161  }
162 
163  switch( id )
164  {
167 
168  if( screen->SetPreviousZoom() )
169  RedrawScreen2( center );
170  break;
171 
172  case ID_POPUP_ZOOM_IN:
173  zoom_at_cursor = true;
174  center = GetCrossHairPosition();
175 
176  // fall thru
177  case ID_VIEWER_ZOOM_IN:
178  case ID_ZOOM_IN:
179  if( screen->SetPreviousZoom() )
180  RedrawScreen( center, zoom_at_cursor );
181  break;
182 
185 
186  if( screen->SetNextZoom() )
187  RedrawScreen2( center );
188  break;
189 
190  case ID_POPUP_ZOOM_OUT:
191  zoom_at_cursor = true;
192  center = GetCrossHairPosition();
193 
194  // fall thru
195  case ID_VIEWER_ZOOM_OUT:
196  case ID_ZOOM_OUT:
197  if( screen->SetNextZoom() )
198  RedrawScreen( center, zoom_at_cursor );
199  break;
200 
203  case ID_ZOOM_REDRAW:
204  m_canvas->Refresh();
205  break;
206 
208  center = GetCrossHairPosition();
209  RedrawScreen( center, true );
210  break;
211 
212  case ID_POPUP_ZOOM_PAGE:
213  case ID_VIEWER_ZOOM_PAGE:
214  case ID_ZOOM_PAGE:
215  Zoom_Automatique( false );
216  break;
217 
219  break;
220 
221  case ID_POPUP_CANCEL:
223  break;
224 
225  default:
227  }
228 
229  UpdateStatusBar();
230 }
231 
232 
234 {
235  GetScreen()->SetNextZoom();
236 }
237 
238 
240 {
242 }
243 
244 
246 {
247  BASE_SCREEN* screen = GetScreen();
248 
249  if( aIndex >= (int) screen->m_ZoomList.size() )
250  {
251  wxLogDebug( wxT( "%s %d: index %d is outside the bounds of the zoom list." ),
252  __TFILE__, __LINE__, aIndex );
253  return;
254  }
255 
256  if( m_zoomSelectBox )
257  m_zoomSelectBox->SetSelection( aIndex );
258 
259  if( screen->SetZoom( screen->m_ZoomList[aIndex] ) )
261 
262  UpdateStatusBar();
263 }
264 
265 
266 void EDA_DRAW_FRAME::AddMenuZoomAndGrid( wxMenu* MasterMenu )
267 {
268  int maxZoomIds;
269  double zoom;
270  wxString msg;
271  BASE_SCREEN* screen = m_canvas->GetScreen();
272 
273  msg = AddHotkeyName( _( "Center" ), m_hotkeysDescrList, HK_ZOOM_CENTER );
274  AddMenuItem( MasterMenu, ID_POPUP_ZOOM_CENTER, msg, KiBitmap( zoom_center_on_screen_xpm ) );
275  msg = AddHotkeyName( _( "Zoom In" ), m_hotkeysDescrList, HK_ZOOM_IN );
276  AddMenuItem( MasterMenu, ID_POPUP_ZOOM_IN, msg, KiBitmap( zoom_in_xpm ) );
277  msg = AddHotkeyName( _( "Zoom Out" ), m_hotkeysDescrList, HK_ZOOM_OUT );
278  AddMenuItem( MasterMenu, ID_POPUP_ZOOM_OUT, msg, KiBitmap( zoom_out_xpm ) );
279  msg = AddHotkeyName( _( "Redraw View" ), m_hotkeysDescrList, HK_ZOOM_REDRAW );
280  AddMenuItem( MasterMenu, ID_POPUP_ZOOM_REDRAW, msg, KiBitmap( zoom_redraw_xpm ) );
281  msg = AddHotkeyName( _( "Zoom Auto" ), m_hotkeysDescrList, HK_ZOOM_AUTO );
282  AddMenuItem( MasterMenu, ID_POPUP_ZOOM_PAGE, msg, KiBitmap( zoom_fit_in_page_xpm ) );
283 
284 
285  wxMenu* zoom_choice = new wxMenu;
286  AddMenuItem( MasterMenu, zoom_choice,
287  ID_POPUP_ZOOM_SELECT, _( "Zoom Select" ),
288  KiBitmap( zoom_selection_xpm ) );
289 
290  zoom = screen->GetZoom();
292  maxZoomIds = ( (size_t) maxZoomIds < screen->m_ZoomList.size() ) ?
293  maxZoomIds : screen->m_ZoomList.size();
294 
295  // Populate zoom submenu.
296  for( int i = 0; i < maxZoomIds; i++ )
297  {
298  msg.Printf( wxT( "%.2f" ), m_zoomLevelCoeff / screen->m_ZoomList[i] );
299 
300  zoom_choice->Append( ID_POPUP_ZOOM_LEVEL_START + i, _( "Zoom: " ) + msg,
301  wxEmptyString, wxITEM_CHECK );
302  if( zoom == screen->m_ZoomList[i] )
303  zoom_choice->Check( ID_POPUP_ZOOM_LEVEL_START + i, true );
304  }
305 
306  // Create grid submenu as required.
307  if( screen->GetGridCount() )
308  {
309  wxMenu* gridMenu = new wxMenu;
310  AddMenuItem( MasterMenu, gridMenu, ID_POPUP_GRID_SELECT,
311  _( "Grid Select" ), KiBitmap( grid_select_xpm ) );
312 
313  wxArrayString gridsList;
314  int icurr = screen->BuildGridsChoiceList( gridsList, g_UserUnit != INCHES );
315 
316  for( unsigned i = 0; i < gridsList.GetCount(); i++ )
317  {
318  GRID_TYPE& grid = screen->GetGrid( i );
319  gridMenu->Append( grid.m_CmdId, gridsList[i], wxEmptyString, wxITEM_CHECK );
320 
321  if( (int)i == icurr )
322  gridMenu->Check( grid.m_CmdId, true );
323  }
324  }
325 
326  MasterMenu->AppendSeparator();
327  AddMenuItem( MasterMenu, ID_POPUP_CANCEL, _( "Close" ), KiBitmap( cancel_xpm ) );
328 }
TOOL_MANAGER * m_toolManager
Definition: draw_frame.h:95
void AdjustScrollBars(const wxPoint &aCenterPosition)
Definition: draw_frame.cpp:928
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:339
wxPoint ToDeviceXY(const wxPoint &pos)
Function ToDeviceXY transforms logical to device coordinates.
Definition: draw_panel.cpp:202
Implementation of conversion functions that require both schematic and board internal units...
EDA_DRAW_PANEL * GetCanvas()
Definition: draw_frame.h:342
const wxSize GetSize() const
Definition: eda_rect.h:101
double bestZoom(double sizeX, double sizeY, double scaleFactor, wxPoint centre)
Definition: zoom.cpp:86
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:174
virtual double BestZoom()=0
Return the zoom level which displays the full page on screen.
double GetZoom() const
Function GetZoom returns the current "zoom factor", which is a measure of "internal units per device ...
Definition: base_screen.h:340
void SetScrollCenterPosition(const wxPoint &aPoint)
Definition: id.h:241
bool RunAction(const std::string &aActionName, bool aNow=false, T aParam=NULL)
Function RunAction() Runs the specified action.
Definition: tool_manager.h:125
const wxPoint & GetScrollCenterPosition() const
virtual void OnZoom(wxCommandEvent &event)
Definition: zoom.cpp:142
void MoveCursorToCrossHair()
Function MoveCursorToCrossHair warps the cursor to the current cross hair position.
Definition: draw_panel.cpp:361
bool SetPreviousZoom()
size_t GetGridCount() const
Function GetGridCount().
Definition: base_screen.h:457
bool SetNextZoom()
int BuildGridsChoiceList(wxArrayString &aGridsList, bool aMmFirst) const
Function BuildGridsChoiceList().
wxPoint ToLogicalXY(const wxPoint &pos)
Function ToLogicalXY transforms device to logical coordinates.
Definition: draw_panel.cpp:212
wxBitmap KiBitmap(BITMAP_DEF aBitmap)
Function KiBitmap constructs a wxBitmap from a memory record, held in a BITMAP_DEF.
Definition: bitmap.cpp:78
void Zoom_Automatique(bool aWarpPointer)
Function Zoom_Automatique redraws the screen with best zoom level and the best centering that shows a...
Definition: zoom.cpp:102
bool m_FirstRedraw
Definition: base_screen.h:207
virtual BASE_SCREEN * GetScreen() const
Function GetScreen returns a pointer to a BASE_SCREEN or one of its derivatives.
Definition: draw_frame.h:352
a helper to handle the real device context used in KiCad
EDA_HOTKEY_CONFIG * m_hotkeysDescrList
Definition: draw_frame.h:77
const GRID_TYPE & GetGrid() const
Return the grid object of the currently selected grid.
Definition: base_screen.h:417
Class BASE_SCREEN handles how to draw a screen (a board, a schematic ...)
Definition: base_screen.h:76
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
wxChoice * m_zoomSelectBox
Choice box to choose the zoom value.
Definition: draw_frame.h:122
bool GetEnableZoomNoCenter() const
bool IsGalCanvasActive() const
Function IsGalCanvasActive is used to check which canvas (GAL-based or standard) is currently in use...
Definition: draw_frame.h:874
void SetPresetZoom(int aIndex)
Function SetPresetZoom() changes zoom to one of the preset values.
Definition: zoom.cpp:245
bool SetZoom(double iu_per_du)
Function SetZoom adjusts the current zoom factor.
wxPoint Centre() const
Definition: eda_rect.h:60
void RedrawScreen2(const wxPoint &posBefore)
Function RedrawScreen2 puts the crosshair back to the screen position it had before zooming...
Definition: zoom.cpp:62
EDA_UNITS_T g_UserUnit
Global variables definitions.
Definition: common.cpp:56
void Normalize()
Function Normalize ensures that the height ant width are positive.
EDA_DRAW_PANEL * m_canvas
The area to draw on.
Definition: draw_frame.h:93
void RedrawScreen(const wxPoint &aCenterPoint, bool aWarpPointer)
Function RedrawScreen redraws the entire screen area by updating the scroll bars and mouse pointer in...
Definition: zoom.cpp:46
double m_zoomLevelCoeff
a suitable value to convert the internal zoom scaling factor
Definition: draw_frame.h:86
wxString AddHotkeyName(const wxString &aText, EDA_HOTKEY **aList, int aCommandId, HOTKEY_ACTION_TYPE aShortCutType)
Function AddHotkeyName Add the key name from the Command id value ( m_Idcommand member value) ...
Class GRID_TYPE is for grid arrays.
Definition: base_screen.h:45
#define max(a, b)
Definition: auxiliary.h:86
Class EDA_RECT handles the component boundary box.
Definition: eda_rect.h:44
void SetNextZoom()
Function SetNextZoom() changes the zoom to the next one available.
Definition: zoom.cpp:233
BASE_SCREEN * GetScreen()
Definition: draw_panel.cpp:194
void Window_Zoom(EDA_RECT &Rect)
Definition: zoom.cpp:124
virtual void AddMenuZoomAndGrid(wxMenu *aMasterMenu)
Function AddMenuZoomAndGrid (virtual) Add standard zoom commands and submenu zoom and grid selection ...
Definition: zoom.cpp:266
Some functions to handle hotkeys in KiCad.
void SetCrossHairPosition(const wxPoint &aPosition, bool aSnapToGrid=true)
Function SetCrossHairPosition sets the screen cross hair position to aPosition in logical (drawing) u...
int m_CmdId
Definition: base_screen.h:48
BASE_SCREEN class implementation.
void SetPrevZoom()
Function SetPrevZoom() changes the zoom to the previous one available.
Definition: zoom.cpp:239
virtual void UpdateStatusBar()
Function UpdateStatusBar updates the status bar information.
Definition: draw_frame.cpp:683
wxPoint GetCrossHairPosition(bool aInvertY=false) const
Function GetCrossHairPosition return the current cross hair position in logical (drawing) coordinates...
std::vector< double > m_ZoomList
standard zoom (i.e. scale) coefficients.
Definition: base_screen.h:219