KiCad PCB EDA Suite
Loading...
Searching...
No Matches
zoom_correction_ctrl.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 The KiCad Developers, see AUTHORS.txt for contributors.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 3
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * Inspired by the Inkscape preferences widget, which is
17 * Authors:
18 * Marco Scholten
19 * Bruno Dilly <[email protected]>
20 *
21 * Copyright (C) 2004, 2006, 2007 Authors
22 *
23 * Released under GNU GPL v2+
24 */
25
26#include <advanced_config.h>
28#include <widgets/ui_common.h>
29
30#include <wx/dcclient.h>
31#include <wx/display.h>
32#include <wx/math.h>
33#include <wx/sizer.h>
34#include <wx/spinctrl.h>
35#include <wx/settings.h>
36
37class ZOOM_CORRECTION_RULER : public wxPanel
38{
39public:
40 ZOOM_CORRECTION_RULER( wxWindow* aParent ) :
41 wxPanel( aParent, wxID_ANY, wxDefaultPosition, aParent->FromDIP( wxSize( 200, 30 ) ),
42 wxTAB_TRAVERSAL | wxNO_BORDER | wxFULL_REPAINT_ON_RESIZE )
43 {
44 Bind( wxEVT_PAINT, &ZOOM_CORRECTION_RULER::OnPaint, this );
45 }
46
47private:
48 void OnPaint( wxPaintEvent& )
49 {
50 wxPaintDC dc( this );
51 wxSize size = GetClientSize();
52
53 dc.SetPen( wxPen( wxSystemSettings::GetColour( wxSYS_COLOUR_BTNTEXT ) ) );
54
55 // Draw baseline
56 dc.DrawLine( 0, size.y - 1, size.x, size.y - 1 );
57 ZOOM_CORRECTION_CTRL* parent = static_cast<ZOOM_CORRECTION_CTRL*>( GetParent() );
58
59 if( !parent )
60 return;
61
62 double value = parent->GetValue();
63 ZOOM_CORRECTION_UNITS units = static_cast<ZOOM_CORRECTION_UNITS>( parent->GetUnitsSelection() );
64
65 double dpi = ADVANCED_CFG::GetCfg().m_ScreenDPI;
66 double unitsPerInch = 25.4;
67
68 if( units == ZOOM_CORRECTION_UNITS::CM )
69 unitsPerInch = 2.54;
70 else if( units == ZOOM_CORRECTION_UNITS::INCH )
71 unitsPerInch = 1.0;
72
73 double pxPerUnit = dpi / unitsPerInch * value;
74
75 // Minimum spacing between number labels to prevent overlap (in pixels)
76 int minLabelSpacing = GetTextExtent( wxT( "000_" ) ).x;
77 double lastLabelX = -minLabelSpacing;
78 int majorTickEvery = 10;
79 double tickLabelDiv = 1;
80 double pxPerMinorTick;
81
82 // Draw major and minor tick marks with numbering
83 if( units == ZOOM_CORRECTION_UNITS::INCH )
84 {
85 majorTickEvery = 4;
86 tickLabelDiv = 4;
87 pxPerMinorTick = pxPerUnit / 4.0; // 1/4 inch intervals
88 }
89 else if( units == ZOOM_CORRECTION_UNITS::CM )
90 {
91 majorTickEvery = 10;
92 tickLabelDiv = 10;
93 pxPerMinorTick = pxPerUnit / 10.0; // 1mm intervals
94 }
95 else // MM
96 {
97 // For mm: Same as cm ruler but numbers count by 10 (so 10mm, 20mm, etc.)
98 majorTickEvery = 10;
99 tickLabelDiv = 1;
100 pxPerMinorTick = pxPerUnit;
101 }
102
103 if( pxPerMinorTick < 3 )
104 {
105 pxPerMinorTick *= 2;
106 majorTickEvery /= 2;
107 tickLabelDiv /= 2;
108 }
109
110 for( double x = 0; x <= size.x; x += pxPerMinorTick )
111 {
112 int tickCount = (int) round( x / pxPerMinorTick );
113
114 if( tickCount % majorTickEvery == 0 )
115 {
116 // Major tick
117 dc.DrawLine( x, size.y - 1, x, size.y - 16 );
118
119 int labelNum = wxRound(tickCount / tickLabelDiv);
120
121 if( labelNum > 0 && x < size.x - 10 && ( x - lastLabelX ) >= minLabelSpacing )
122 {
123 wxString label = wxString::Format( wxT( "%d" ), labelNum );
124 wxSize textSize = dc.GetTextExtent( label );
125 dc.DrawText( label, x - textSize.x / 2, 0 );
126 lastLabelX = x;
127 }
128 }
129 else
130 {
131 // Minor tick
132 dc.DrawLine( x, size.y - 1, x, size.y - 8 );
133 }
134 }
135 }
136};
137
138
139ZOOM_CORRECTION_CTRL::ZOOM_CORRECTION_CTRL( wxWindow* aParent, double& aValue, double aBaseValue ) :
140 wxPanel( aParent, wxID_ANY ),
141 m_baseValue( aBaseValue ),
142 m_value( &aValue )
143{
144 wxBoxSizer* topSizer = new wxBoxSizer( wxVERTICAL );
145
146 // Top section: Label, spinner, auto button
147 wxBoxSizer* controlsSizer = new wxBoxSizer( wxHORIZONTAL );
148
149 m_label = new wxStaticText( this, wxID_ANY, _( "Display PPI: " ) );
150 controlsSizer->Add( m_label, 0, wxALIGN_CENTER_VERTICAL | wxLEFT | wxRIGHT, KIUI::GetStdMargin() );
151
152 m_spinner = new wxSpinCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize,
153 wxSP_ARROW_KEYS, 10, 1000, (int)( aValue * m_baseValue ) );
154 controlsSizer->Add( m_spinner, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, KIUI::GetStdMargin() );
155
156 m_autoButton = new wxButton( this, wxID_ANY, _( "Detect" ) );
157 controlsSizer->Add( m_autoButton, 0, wxALIGN_CENTER_VERTICAL | wxLEFT | wxRIGHT, KIUI::GetStdMargin() );
158
159 topSizer->Add( controlsSizer, 0, wxEXPAND, KIUI::GetStdMargin() );
160
161 // Middle section: Ruler and units choice
162 wxBoxSizer* rulerSizer = new wxBoxSizer( wxHORIZONTAL );
163
164 m_ruler = new ZOOM_CORRECTION_RULER( this );
165 rulerSizer->Add( m_ruler, 1, wxEXPAND | wxLEFT | wxRIGHT | wxTOP, KIUI::GetStdMargin() );
166
167 wxArrayString choices;
168 choices.Add( wxT( "mm" ) );
169 choices.Add( wxT( "cm" ) );
170 choices.Add( wxT( "in" ) );
171 m_unitsChoice = new wxChoice( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, choices );
172 m_unitsChoice->SetSelection( 0 ); // Default to MM
173 rulerSizer->Add( m_unitsChoice, 0, wxALIGN_CENTER_VERTICAL | wxLEFT | wxRIGHT | wxTOP, KIUI::GetStdMargin() );
174
175 topSizer->Add( rulerSizer, 0, wxEXPAND | wxTOP, KIUI::GetStdMargin() );
176
177 SetSizer( topSizer );
178
179 m_autoButton->Bind( wxEVT_BUTTON, &ZOOM_CORRECTION_CTRL::autoPressed, this );
180 m_spinner->Bind( wxEVT_SPINCTRL, &ZOOM_CORRECTION_CTRL::spinnerChanged, this );
181 m_unitsChoice->Bind( wxEVT_CHOICE, &ZOOM_CORRECTION_CTRL::unitsChanged, this );
182
183 // Ensure initial synchronization of all controls
184 m_ruler->Refresh();
185}
186
187
189{
190 m_spinner->SetValue( (int)( aValue * m_baseValue ) );
191 m_ruler->Refresh();
192}
193
194
196{
197 return (double) m_spinner->GetValue() / m_baseValue;
198}
199
200
202{
203 return m_unitsChoice->GetSelection();
204}
205
206
208{
209 m_spinner->SetValue( (int)( *m_value * m_baseValue ) );
210 m_ruler->Refresh();
211 return true;
212}
213
214
216{
217 *m_value = GetValue();
218 return true;
219}
220
221
223{
224 *m_value = m_spinner->GetValue() / m_baseValue;
225 m_ruler->Refresh();
226}
227
228
230{
231 m_ruler->Refresh();
232}
233
234
235void ZOOM_CORRECTION_CTRL::autoPressed( wxCommandEvent& aEvent )
236{
237 wxDisplay dpy( this );
238 double val = 0.0;
239
240#if wxCHECK_VERSION( 3, 3, 2 )
241 wxSize rawPPI = dpy.GetRawPPI();
242 val = wxRound( ( rawPPI.x + rawPPI.y ) / 2.0 );
243#endif
244
245 if( val < 10 )
246 {
247#ifdef wxHAS_DPI_INDEPENDENT_PIXELS
248 val = dpy.GetStdPPIValue() / dpy.GetScaleFactor();
249#else
250 wxSize ppi = dpy.GetPPI();
251 val = wxRound( ( ppi.x + ppi.y ) / 2.0 );
252#endif
253 }
254
255 m_spinner->SetValue( val );
256 m_ruler->Refresh();
257}
static const ADVANCED_CFG & GetCfg()
Get the singleton instance's config, which is shared by all consumers.
Control to calibrate screen zoom to match real-world size.
void spinnerChanged(wxSpinEvent &aEvent)
void unitsChanged(wxCommandEvent &aEvent)
ZOOM_CORRECTION_RULER * m_ruler
void autoPressed(wxCommandEvent &aEvent)
bool TransferDataToWindow() override
void SetDisplayedValue(double aValue)
ZOOM_CORRECTION_CTRL(wxWindow *aParent, double &aValue, double aBaseValue)
bool TransferDataFromWindow() override
ZOOM_CORRECTION_RULER(wxWindow *aParent)
void OnPaint(wxPaintEvent &)
#define _(s)
int m_ScreenDPI
Screen DPI setting for display calculations.
KICOMMON_API int GetStdMargin()
Get the standard margin around a widget in the KiCad UI.
Definition ui_common.cpp:49
Functions to provide common constants and other functions to assist in making a consistent UI.
ZOOM_CORRECTION_UNITS