KiCad PCB EDA Suite
Loading...
Searching...
No Matches
startwizard.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) 2023 Mark Roszko <[email protected]>
5 * Copyright (C) 1992-2023 KiCad Developers, see AUTHORS.txt for contributors.
6 *
7 * This program is free software: you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation, either version 3 of the License, or (at your
10 * option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * 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, see <https://www.gnu.org/licenses/>.
19 */
20
21#include <build_version.h>
22#include <confirm.h>
23#include <eda_base_frame.h>
24#include <kiface_base.h>
25#include <pgm_base.h>
26#include <wx/display.h>
27#include <wx/statline.h>
28#include <wx/wx.h>
29#include <wx/wizard.h>
35#include <ui_events.h>
36#include <wx/hyperlink.h>
37
38
39class STARTWIZARD_PAGE : public wxWizardPageSimple
40{
41public:
42 STARTWIZARD_PAGE( wxWizard* aParent, const wxString& aPageTitle ) :
43 wxWizardPageSimple( aParent )
44 {
45 wxBoxSizer* outerSizer = new wxBoxSizer( wxVERTICAL );
46
47 m_scrolledWindow = new wxScrolledWindow( this, wxID_ANY, wxDefaultPosition, wxDefaultSize,
48 wxVSCROLL | wxBORDER_NONE );
49 m_scrolledWindow->SetScrollRate( 0, 5 );
50
51 m_mainSizer = new wxBoxSizer( wxVERTICAL );
52
53 wxStaticText* pageTitle = new wxStaticText( m_scrolledWindow, -1, aPageTitle );
54 pageTitle->SetFont(
55 wxFont( 14, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD ) );
56 m_mainSizer->Add( pageTitle, 0, wxALIGN_CENTRE | wxALL, 5 );
57
58 wxStaticLine* pageDivider = new wxStaticLine( m_scrolledWindow, wxID_ANY,
59 wxDefaultPosition, wxDefaultSize,
60 wxLI_HORIZONTAL );
61 m_mainSizer->Add( pageDivider, 0, wxEXPAND | wxALL, 5 );
62
63 m_scrolledWindow->SetSizer( m_mainSizer );
64
65 outerSizer->Add( m_scrolledWindow, 1, wxEXPAND );
66 SetSizer( outerSizer );
67 }
68
69 // Returns the scrolled content area; use this as the parent for panel content
70 // so the content is scrollable when the wizard is smaller than the page requires.
71 wxWindow* GetContentParent() const { return m_scrolledWindow; }
72
73 void AddContent( wxPanel* aContent )
74 {
75 m_mainSizer->Add( aContent, 0, wxEXPAND );
76 m_scrolledWindow->FitInside();
77 }
78
79 // Returns the minimum size of the scrolled content, independent of the page size.
80 wxSize GetContentMinSize() const { return m_mainSizer->CalcMin(); }
81
82private:
83 wxScrolledWindow* m_scrolledWindow;
84 wxBoxSizer* m_mainSizer;
85};
86
87
88class STARTWIZARD_WELCOME_PAGE : public wxWizardPageSimple
89{
90public:
91 STARTWIZARD_WELCOME_PAGE( wxWizard* aParent ) : wxWizardPageSimple( aParent )
92 {
93 m_mainSizer = new wxBoxSizer( wxVERTICAL );
94
95 wxStaticText* pageTitle = new wxStaticText(
96 this, -1, wxString::Format( _( "Welcome to KiCad %s" ), GetMajorMinorVersion() ) );
97 pageTitle->SetFont(
98 wxFont( 14, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD ) );
99 m_mainSizer->Add( pageTitle, 0, wxALIGN_CENTRE | wxALL, 5 );
100
101 wxStaticLine* pageDivider = new wxStaticLine( this, wxID_ANY, wxDefaultPosition,
102 wxDefaultSize, wxLI_HORIZONTAL );
103 m_mainSizer->Add( pageDivider, 0, wxEXPAND | wxALL, 5 );
104
105 m_welcomeText = new wxStaticText( this, -1,
106 _( "KiCad is starting for the first time, or some of its configuration files are missing.\n\n"
107 "Let's take a moment to configure some basic settings. You can always modify these "
108 "settings later by opening the Preferences dialog." ) );
109 m_mainSizer->Add( m_welcomeText, 0, wxEXPAND | wxALL, 5 );
110
111 wxBoxSizer* helpSizer = new wxBoxSizer( wxHORIZONTAL );
112 wxStaticText* helpLabel = new wxStaticText( this, -1, _( "For help, please visit " ) );
113 wxString docsUrl = wxString::Format( "https://go.kicad.org/docs/%s", GetMajorMinorVersion() );
114 wxHyperlinkCtrl* helpLink = new wxHyperlinkCtrl( this, -1, wxT( "docs.kicad.org" ), docsUrl );
115 helpSizer->Add( helpLabel, 0, wxLEFT | wxTOP | wxBOTTOM | wxALIGN_CENTER_VERTICAL, 5 );
116 helpSizer->Add( helpLink, 0, wxRIGHT | wxTOP | wxBOTTOM | wxALIGN_CENTER_VERTICAL, 5 );
117 m_mainSizer->Add( helpSizer, 0, wxEXPAND, 5 );
118
119 SetSizerAndFit( m_mainSizer );
120 }
121
122 void SetWrap( int aWidth ) const
123 {
124 m_welcomeText->Wrap( aWidth );
125 }
126
127private:
128 wxBoxSizer* m_mainSizer;
129 wxStaticText* m_welcomeText;
130};
131
132
134 m_wizard( nullptr )
135{
136}
137
138
142
143
145{
146 if( auto it = std::ranges::find_if( m_providers,
147 [&]( const std::unique_ptr<STARTWIZARD_PROVIDER>& aProvider )
148 {
149 return aProvider->Name() == aName;
150 } ); it != m_providers.end() )
151 {
152 return it->get();
153 }
154
155 return nullptr;
156}
157
158
159void STARTWIZARD::CheckAndRun( wxWindow* aParent )
160{
161 m_providers.clear();
162
163 m_providers.push_back( std::make_unique<STARTWIZARD_PROVIDER_SETTINGS>() );
164 m_providers.push_back( std::make_unique<STARTWIZARD_PROVIDER_LIBRARIES>() );
165 m_providers.push_back( std::make_unique<STARTWIZARD_PROVIDER_PRIVACY>() );
166 //providers.push_back( std::make_unique<STARTWIZARD_PROVIDER_LOOK_AND_FEEL>() );
167
168 if( m_providers.size() == 0 )
169 return;
170
171 bool wizardRequired = std::ranges::any_of( std::as_const( m_providers ),
172 []( const std::unique_ptr<STARTWIZARD_PROVIDER>& aProvider ) -> bool
173 {
174 return aProvider->NeedsUserInput();
175 } );
176
177 if( !wizardRequired )
178 return;
179
180 Pgm().HideSplash();
181
182 m_wizard = new wxWizard( aParent, wxID_ANY, _( "KiCad Setup" ) );
183 m_wizard->SetWindowStyleFlag( wxRESIZE_BORDER );
184
186 wxWizardPageSimple* lastPage = nullptr;
187 wxSize minPageSize;
188
189 for( std::unique_ptr<STARTWIZARD_PROVIDER>& provider : m_providers )
190 {
191 if( !provider->NeedsUserInput() )
192 continue;
193
194 provider->SetWasShown( true );
195
196 STARTWIZARD_PAGE* page = new STARTWIZARD_PAGE( m_wizard, provider->GetPageName() );
197 wxPanel* panel = provider->GetWizardPanel( page->GetContentParent(), this );
198 page->AddContent( panel );
199
200 if( lastPage != nullptr )
201 {
202 lastPage->Chain( page );
203 }
204 else
205 {
206 firstPage->Chain( page );
207 }
208
209 lastPage = page;
210
211 wxSize size = page->GetContentMinSize();
212
213 if( size.x > minPageSize.x )
214 minPageSize.x = size.x;
215
216 if( size.y > minPageSize.y )
217 minPageSize.y = size.y;
218 }
219
220 // Clamp the page size to the available display area so the wizard is fully
221 // accessible on small or low-resolution screens. Reserve space for the
222 // wizard title bar, the Back/Next/Cancel button row, and a small margin.
223 static constexpr int WIZARD_CHROME_HEIGHT = 120;
224 static constexpr int WIZARD_MARGIN = 40;
225
226 wxSize pageSize = minPageSize + wxSize( 20, 20 );
227
228 int displayIdx = wxDisplay::GetFromWindow( aParent ? aParent : wxTheApp->GetTopWindow() );
229
230 if( displayIdx == wxNOT_FOUND )
231 displayIdx = 0;
232
233 wxRect displayArea = wxDisplay( (unsigned int) displayIdx ).GetClientArea();
234 int maxPageHeight = displayArea.GetHeight() - WIZARD_CHROME_HEIGHT - WIZARD_MARGIN;
235
236 if( maxPageHeight > 0 && pageSize.y > maxPageHeight )
237 pageSize.y = maxPageHeight;
238
239 m_wizard->SetPageSize( pageSize );
240 firstPage->SetWrap( pageSize.x );
241
242 m_wizard->Bind( wxEVT_WIZARD_CANCEL,
243 [&]( wxWizardEvent& aEvt )
244 {
245 if( IsOK( aParent, _( "Are you sure? If you cancel KiCad setup, default settings "
246 "will be chosen for you." ) ) )
247 {
248 for( std::unique_ptr<STARTWIZARD_PROVIDER>& provider : m_providers )
249 {
250 provider->ApplyDefaults();
251 }
252 }
253 else
254 {
255 aEvt.Veto();
256 }
257 } );
258
259 int languageBefore = Pgm().GetSelectedLanguageIdentifier();
260
261 if( m_wizard->RunWizard( firstPage ) )
262 {
263 for( std::unique_ptr<STARTWIZARD_PROVIDER>& provider : m_providers )
264 {
265 if( !provider->WasShown() )
266 continue;
267
268 provider->Finish();
269 }
270 }
271
272 m_wizard->Destroy();
273 m_wizard = nullptr;
274
275 // Settings import can switch the language after the parent frame was already built in the
276 // system locale, so retranslate it to avoid requiring a restart.
277 if( Pgm().GetSelectedLanguageIdentifier() != languageBefore && aParent )
278 {
279 // A dynamic_cast could be better, but creates link issues because EDA_BASE_FRAME lives in
280 // the common library while this code lives in kicommon, so a static_cast is used. Every
281 // caller passes an EDA_BASE_FRAME-derived frame.
282 EDA_BASE_FRAME* frame = static_cast<EDA_BASE_FRAME*>( aParent );
283
284 frame->ShowChangedLanguage();
285
286 wxCommandEvent e( EDA_LANG_CHANGED );
287 frame->GetEventHandler()->ProcessEvent( e );
288 }
289}
wxString GetMajorMinorVersion()
Get only the major and minor version in a string major.minor.
The base frame for deriving all KiCad main window classes.
void ShowChangedLanguage() override
Redraw the menus and what not in current language.
bool ProcessEvent(wxEvent &aEvent) override
Override the default process event handler to implement the auto save feature.
virtual int GetSelectedLanguageIdentifier() const
Definition pgm_base.h:230
void HideSplash()
Definition pgm_base.cpp:309
STARTWIZARD_PAGE(wxWizard *aParent, const wxString &aPageTitle)
wxScrolledWindow * m_scrolledWindow
wxBoxSizer * m_mainSizer
void AddContent(wxPanel *aContent)
wxSize GetContentMinSize() const
wxWindow * GetContentParent() const
void SetWrap(int aWidth) const
wxStaticText * m_welcomeText
STARTWIZARD_WELCOME_PAGE(wxWizard *aParent)
STARTWIZARD_PROVIDER * GetProvider(const wxString &aName)
std::vector< std::unique_ptr< STARTWIZARD_PROVIDER > > m_providers
Definition startwizard.h:46
void CheckAndRun(wxWindow *parent)
wxWizard * m_wizard
Definition startwizard.h:45
bool IsOK(wxWindow *aParent, const wxString &aMessage)
Display a yes/no dialog with aMessage and returns the user response.
Definition confirm.cpp:274
This file is part of the common library.
#define _(s)
Base window classes and related definitions.
PGM_BASE & Pgm()
The global program "get" accessor.
see class PGM_BASE