KiCad PCB EDA Suite
Loading...
Searching...
No Matches
dialog_export_3d_image.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 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <https://www.gnu.org/licenses/>.
18 */
19
21
22#include <wx/sizer.h>
23#include <wx/stattext.h>
24#include <wx/button.h>
25#include <wx/spinctrl.h>
26#include <wx/choice.h>
27#include <wx/bmpbuttn.h>
28#include <wx/statline.h>
29#include <wx/gbsizer.h>
30
31#include <bitmaps.h>
33
34
35DIALOG_EXPORT_3D_IMAGE::DIALOG_EXPORT_3D_IMAGE( wxWindow* aParent, const wxSize& aCanvasSize,
37 DIALOG_SHIM( aParent, wxID_ANY, _( "Export 3D View" ), wxDefaultPosition, wxDefaultSize,
38 wxDEFAULT_DIALOG_STYLE ),
39 m_cfg( aCfg ),
40 m_originalSize( aCanvasSize ),
41 m_width( aCanvasSize.GetWidth() ),
42 m_height( aCanvasSize.GetHeight() ),
43 m_xResolution( 300.0 ),
44 m_yResolution( 300.0 ),
45 m_lockAspectRatio( true ),
48{
49 m_aspectRatio = static_cast<double>(m_width) / static_cast<double>(m_height);
50
51 // State is persisted through EXPORT_IMAGE_SETTINGS, so opt out of the generic
52 // control-state save and restore.
53 OptOut( this );
54
55 if( aCfg )
56 {
57 if( aCfg->width )
58 m_width = aCfg->width;
59
60 if( aCfg->height )
61 m_height = aCfg->height;
62
66 m_sizeUnits = static_cast<SIZE_UNITS>( aCfg->size_units );
68 }
69
70 wxBoxSizer* mainSizer = new wxBoxSizer( wxVERTICAL );
71
72 // Image Size section
73 wxStaticText* imageSizeHeader = new wxStaticText( this, wxID_ANY, _( "Image Size" ) );
74 imageSizeHeader->SetFont( imageSizeHeader->GetFont().Bold() );
75 mainSizer->Add( imageSizeHeader, 0, wxLEFT | wxTOP, 10 );
76
77 wxGridBagSizer* sizeGrid = new wxGridBagSizer( 5, 2 );
78 sizeGrid->SetFlexibleDirection( wxHORIZONTAL );
79 sizeGrid->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED );
80
81 // Width row
82 sizeGrid->Add( new wxStaticText( this, wxID_ANY, _( "Width:" ) ), {0, 0}, {1, 1}, wxALIGN_CENTER_VERTICAL );
83 m_spinWidth = new wxSpinCtrlDouble( this, wxID_ANY );
84 m_spinWidth->SetRange( 1, 50000 );
85 m_spinWidth->SetDigits( 0 );
86 sizeGrid->Add( m_spinWidth, {0, 1}, {1, 1}, wxALIGN_CENTER_VERTICAL );
87
88 // Lock button - will span 2 rows
89 m_lockButton = new BITMAP_BUTTON( this, wxID_ANY, wxNullBitmap );
91 m_lockButton->SetToolTip( _( "Lock/unlock aspect ratio" ) );
92 m_lockButton->SetIsCheckButton();
93 sizeGrid->Add( m_lockButton, {0, 2}, {2, 1}, wxALIGN_CENTER | wxALIGN_CENTER_VERTICAL | wxLEFT | wxRIGHT, 10 );
94
95 // Size units choice
96 m_choiceSizeUnits = new wxChoice( this, wxID_ANY );
97 m_choiceSizeUnits->Append( _( "pixels" ) );
98 m_choiceSizeUnits->Append( _( "%" ) );
99 m_choiceSizeUnits->Append( _( "mm" ) );
100 m_choiceSizeUnits->Append( _( "in" ) );
101 m_choiceSizeUnits->SetSelection( static_cast<int>( m_sizeUnits ) );
102 m_choiceSizeUnits->SetMinSize( wxSize( 100, -1 ) ); // Try to keep two units choice boxes the same size
103 sizeGrid->Add( m_choiceSizeUnits, {0, 4}, {2, 1}, wxALIGN_CENTER_VERTICAL | wxLEFT, 15 );
104
105 // Height row
106 sizeGrid->Add( new wxStaticText( this, wxID_ANY, _( "Height:" ) ), {1, 0}, {1, 1}, wxALIGN_CENTER_VERTICAL );
107 m_spinHeight = new wxSpinCtrlDouble( this, wxID_ANY );
108 m_spinHeight->SetRange( 1, 50000 );
109 m_spinHeight->SetDigits( 0 );
110 sizeGrid->Add( m_spinHeight, {1, 1}, {1, 1}, wxALIGN_CENTER_VERTICAL );
111
112 mainSizer->Add( sizeGrid, 0, wxEXPAND | wxLEFT | wxRIGHT | wxTOP, 10 );
113
114 // Pixel size display
115 m_pixelSizeLabel = new wxStaticText( this, wxID_ANY, wxEmptyString );
116 m_pixelSizeLabel->SetFont( m_pixelSizeLabel->GetFont().Smaller() );
117 mainSizer->Add( m_pixelSizeLabel, 0, wxLEFT | wxTOP, 10 );
118
119 // Separator
120 mainSizer->AddSpacer( 15 );
121 wxStaticLine* line = new wxStaticLine( this );
122 mainSizer->Add( line, 0, wxEXPAND | wxLEFT | wxRIGHT, 5 );
123
124 // Resolution section
125 wxStaticText* resolutionHeader = new wxStaticText( this, wxID_ANY, _( "Resolution" ) );
126 resolutionHeader->SetFont( resolutionHeader->GetFont().Bold() );
127 mainSizer->Add( resolutionHeader, 0, wxLEFT | wxTOP, 10 );
128
129 wxGridBagSizer* resGrid = new wxGridBagSizer( 5, 2 );
130 resGrid->SetFlexibleDirection( wxHORIZONTAL );
131 resGrid->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED );
132
133 // X Resolution row
134 resGrid->Add( new wxStaticText( this, wxID_ANY, _( "X resolution:" ) ), {0, 0}, {1, 1}, wxALIGN_CENTER_VERTICAL );
135 m_spinXResolution = new wxSpinCtrlDouble( this, wxID_ANY );
136 m_spinXResolution->SetRange( 1, 10000 );
137 m_spinXResolution->SetDigits( 3 );
138 resGrid->Add( m_spinXResolution, {0, 1}, {1, 1}, wxEXPAND );
139
140 // Resolution units choice
141 m_choiceResolutionUnits = new wxChoice( this, wxID_ANY );
142 m_choiceResolutionUnits->Append( _( "pixels/in" ) );
143 m_choiceResolutionUnits->Append( _( "pixels/mm" ) );
144 m_choiceResolutionUnits->SetMinSize( wxSize( 100, -1 ) ); // Try to keep two units choice boxes the same size
145 m_choiceResolutionUnits->SetSelection( static_cast<int>( m_resolutionUnits ) );
146 resGrid->Add( m_choiceResolutionUnits, {0, 2}, {2, 1}, wxALIGN_CENTER_VERTICAL | wxLEFT, 15 );
147
148 // Y Resolution row
149 resGrid->Add( new wxStaticText( this, wxID_ANY, _( "Y resolution:" ) ), {1, 0}, {1, 1}, wxALIGN_CENTER_VERTICAL );
150 m_spinYResolution = new wxSpinCtrlDouble( this, wxID_ANY );
151 m_spinYResolution->SetRange( 1, 10000 );
152 m_spinYResolution->SetDigits( 3 );
153 resGrid->Add( m_spinYResolution, {1, 1}, {1, 1}, wxEXPAND );
154
155 mainSizer->Add( resGrid, 0, wxEXPAND | wxALL, 10 );
156 mainSizer->AddSpacer( 5 );
157
158 // Dialog buttons
159 wxStdDialogButtonSizer* btnSizer = CreateStdDialogButtonSizer( wxOK | wxCANCEL );
160 mainSizer->Add( btnSizer, 0, wxEXPAND | wxALL, 5 );
161
162 SetSizerAndFit( mainSizer );
163 Centre();
164
165 // Set initial values AFTER creating all controls
166 m_spinWidth->SetValue( m_width );
167 m_spinHeight->SetValue( m_height );
169 m_spinXResolution->SetValue( m_xResolution );
170 m_spinYResolution->SetValue( m_yResolution );
172
173 // Bind events AFTER setting initial values
174 m_lockButton->Bind( wxEVT_BUTTON, &DIALOG_EXPORT_3D_IMAGE::OnLockToggle, this );
175 m_spinWidth->Bind( wxEVT_SPINCTRLDOUBLE, &DIALOG_EXPORT_3D_IMAGE::OnWidthChange, this );
176 m_spinHeight->Bind( wxEVT_SPINCTRLDOUBLE, &DIALOG_EXPORT_3D_IMAGE::OnHeightChange, this );
177 m_spinXResolution->Bind( wxEVT_SPINCTRLDOUBLE, &DIALOG_EXPORT_3D_IMAGE::OnXResolutionChange, this );
178 m_spinYResolution->Bind( wxEVT_SPINCTRLDOUBLE, &DIALOG_EXPORT_3D_IMAGE::OnYResolutionChange, this );
181}
182
183
185{
186 double width = m_spinWidth->GetValue();
187 double height = m_spinHeight->GetValue();
188 double xRes = m_spinXResolution->GetValue();
189 double yRes = m_spinYResolution->GetValue();
190
192 {
193 xRes *= 25.4;
194 yRes *= 25.4;
195 }
196
197 wxSize pixelSize = GetPixelSize( width, height, xRes, yRes, m_sizeUnits );
198 m_width = pixelSize.GetWidth();
199 m_height = pixelSize.GetHeight();
200
201 m_xResolution = m_spinXResolution->GetValue();
202 m_yResolution = m_spinYResolution->GetValue();
203
204 if( m_cfg )
205 {
206 m_cfg->width = m_width;
207 m_cfg->height = m_height;
208 m_cfg->x_resolution = m_xResolution;
209 m_cfg->y_resolution = m_yResolution;
210 m_cfg->size_units = static_cast<int>( m_sizeUnits );
211 m_cfg->resolution_units = static_cast<int>( m_resolutionUnits );
212 m_cfg->lock_aspect_ratio = m_lockAspectRatio;
213 }
214
215 return true;
216}
217
218
219void DIALOG_EXPORT_3D_IMAGE::OnLockToggle( wxCommandEvent& aEvent )
220{
222
225}
226
227
228void DIALOG_EXPORT_3D_IMAGE::OnWidthChange( wxSpinDoubleEvent& aEvent )
229{
231 {
232 double width = m_spinWidth->GetValue();
233 double height;
234
236 height = m_originalSize.GetWidth() * width / 100.0 / m_aspectRatio;
237 else
238 height = width / m_aspectRatio;
239
240 // Ensure height is not less than 1
241 if( height < 1 )
242 height = 1;
243
244 m_spinHeight->SetValue( height );
245 }
246
248}
249
250
251void DIALOG_EXPORT_3D_IMAGE::OnHeightChange( wxSpinDoubleEvent& aEvent )
252{
254 {
255 double height = m_spinHeight->GetValue();
256 double width;
257
259 width = m_originalSize.GetHeight() * height / 100.0 * m_aspectRatio;
260 else
261 width = height * m_aspectRatio;
262
263 // Ensure width is not less than 1
264 if( width < 1 )
265 width = 1;
266
267 m_spinWidth->SetValue( width );
268 }
269
271}
272
273
274void DIALOG_EXPORT_3D_IMAGE::OnXResolutionChange( wxSpinDoubleEvent& aEvent )
275{
277}
278
279
280void DIALOG_EXPORT_3D_IMAGE::OnYResolutionChange( wxSpinDoubleEvent& aEvent )
281{
283}
284
285
286void DIALOG_EXPORT_3D_IMAGE::OnSizeUnitChange( wxCommandEvent& aEvent )
287{
288 SIZE_UNITS oldUnits = m_sizeUnits;
289 m_sizeUnits = static_cast<SIZE_UNITS>( m_choiceSizeUnits->GetSelection() );
290 ConvertSizeUnits( oldUnits, m_sizeUnits );
292}
293
294
296{
298 m_resolutionUnits = static_cast<RESOLUTION_UNITS>( m_choiceResolutionUnits->GetSelection() );
301}
302
303
304wxSize DIALOG_EXPORT_3D_IMAGE::GetPixelSize( double aWidth, double aHeight, double aXResolution, double aYResolution, SIZE_UNITS aSizeUnits ) const
305{
306 switch( aSizeUnits )
307 {
309 return wxSize( static_cast<int>( aWidth ), static_cast<int>( aHeight ) );
311 return wxSize( static_cast<int>( aWidth * m_originalSize.GetWidth() / 100.0 ),
312 static_cast<int>( aHeight * m_originalSize.GetHeight() / 100.0 ) );
313 case SIZE_UNITS::MM:
314 return wxSize( static_cast<int>( aWidth * aXResolution / 25.4 ),
315 static_cast<int>( aHeight * aYResolution / 25.4 ) );
317 return wxSize( static_cast<int>( aWidth * aXResolution ),
318 static_cast<int>( aHeight * aYResolution ) );
319 default:
320 break;
321 }
322
323 return wxSize( 10, 10 ); // Should not happen
324}
325
326
328{
329 double width = m_spinWidth->GetValue();
330 double height = m_spinHeight->GetValue();
331 double xRes = m_spinXResolution->GetValue();
332 double yRes = m_spinYResolution->GetValue();
333
334 // Convert resolution to standard pixels/inch
336 {
337 xRes *= 25.4; // Convert mm to inches
338 yRes *= 25.4;
339 }
340
341 wxSize pixelSize = GetPixelSize( width, height, xRes, yRes, m_sizeUnits );
342
343 m_pixelSizeLabel->SetLabel( wxString::Format( _( "%d × %d pixels" ), pixelSize.GetWidth(), pixelSize.GetHeight() ) );
344}
345
346
348{
349 m_aspectRatio = m_spinWidth->GetValue() / m_spinHeight->GetValue();
350}
351
352
354{
355 if( aFromUnit == aToUnit )
356 return;
357
358 double width = m_spinWidth->GetValue();
359 double height = m_spinHeight->GetValue();
360 double xRes = m_spinXResolution->GetValue();
361 double yRes = m_spinYResolution->GetValue();
362
363 // Convert resolution to standard pixels/inch
365 {
366 xRes *= 25.4; // Convert mm to inches
367 yRes *= 25.4;
368 }
369
370 // Convert to pixels first
371 wxSize pixelSize = GetPixelSize( width, height, xRes, yRes, aFromUnit );
372
373 // Convert from pixels to target unit
374 switch( aToUnit )
375 {
377 m_spinWidth->SetValue( pixelSize.GetWidth() );
378 m_spinHeight->SetValue( pixelSize.GetHeight() );
379 break;
381 m_spinWidth->SetValue( pixelSize.GetWidth() * 100.0 / m_originalSize.GetWidth() );
382 m_spinHeight->SetValue( pixelSize.GetHeight() * 100.0 / m_originalSize.GetHeight() );
383 break;
384 case SIZE_UNITS::MM:
385 m_spinWidth->SetValue( pixelSize.GetWidth() * 25.4 / xRes );
386 m_spinHeight->SetValue( pixelSize.GetHeight() * 25.4 / yRes );
387 break;
389 m_spinWidth->SetValue( pixelSize.GetWidth() / xRes );
390 m_spinHeight->SetValue( pixelSize.GetHeight() / yRes );
391 break;
392 }
393}
394
395
397{
398 if( aFromUnit == aToUnit )
399 return;
400
401 double xRes = m_spinXResolution->GetValue();
402 double yRes = m_spinYResolution->GetValue();
403
405 {
406 // Convert from pixels/inch to pixels/mm
407 m_spinXResolution->SetValue( xRes / 25.4 );
408 m_spinYResolution->SetValue( yRes / 25.4 );
409 }
410 else if( aFromUnit == RESOLUTION_UNITS::PIXELS_PER_MM && aToUnit == RESOLUTION_UNITS::PIXELS_PER_INCH )
411 {
412 // Convert from pixels/mm to pixels/inch
413 m_spinXResolution->SetValue( xRes * 25.4 );
414 m_spinYResolution->SetValue( yRes * 25.4 );
415 }
416}
wxBitmapBundle KiBitmapBundle(BITMAPS aBitmap, int aMinHeight)
Definition bitmap.cpp:106
A bitmap button widget that behaves like an AUI toolbar item's button when it is drawn.
DIALOG_EXPORT_3D_IMAGE(wxWindow *aParent, const wxSize &aCanvasSize, EDA_3D_VIEWER_SETTINGS::EXPORT_IMAGE_SETTINGS *aCfg)
void OnWidthChange(wxSpinDoubleEvent &aEvent)
void OnXResolutionChange(wxSpinDoubleEvent &aEvent)
void OnLockToggle(wxCommandEvent &aEvent)
void OnHeightChange(wxSpinDoubleEvent &aEvent)
wxSize GetPixelSize(double aWidth, double aHeight, double aXResolution, double aYResolution, SIZE_UNITS aSizeUnits) const
void OnResolutionUnitChange(wxCommandEvent &aEvent)
void OnYResolutionChange(wxSpinDoubleEvent &aEvent)
wxSpinCtrlDouble * m_spinYResolution
wxSpinCtrlDouble * m_spinHeight
void ConvertSizeUnits(SIZE_UNITS aFromUnit, SIZE_UNITS aToUnit)
wxSpinCtrlDouble * m_spinXResolution
void OnSizeUnitChange(wxCommandEvent &aEvent)
EDA_3D_VIEWER_SETTINGS::EXPORT_IMAGE_SETTINGS * m_cfg
void ConvertResolutionUnits(RESOLUTION_UNITS aFromUnit, RESOLUTION_UNITS aToUnit)
void OptOut(wxWindow *aWindow)
Opt out of control state saving.
DIALOG_SHIM(wxWindow *aParent, wxWindowID id, const wxString &title, const wxPoint &pos=wxDefaultPosition, const wxSize &size=wxDefaultSize, long style=wxDEFAULT_FRAME_STYLE|wxRESIZE_BORDER, const wxString &name=wxDialogNameStr)
#define _(s)