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/log.h>
28#include <wx/statline.h>
29#include <wx/wx.h>
30#include <wx/wizard.h>
36#include <ui_events.h>
37#include <wx/hyperlink.h>
38
39
40class STARTWIZARD_PAGE : public wxWizardPageSimple
41{
42public:
43 STARTWIZARD_PAGE( wxWizard* aParent, const wxString& aPageTitle ) :
44 wxWizardPageSimple( aParent )
45 {
46 wxBoxSizer* outerSizer = new wxBoxSizer( wxVERTICAL );
47
48 m_scrolledWindow = new wxScrolledWindow( this, wxID_ANY, wxDefaultPosition, wxDefaultSize,
49 wxVSCROLL | wxBORDER_NONE );
50 m_scrolledWindow->SetScrollRate( 0, 5 );
51
52 m_mainSizer = new wxBoxSizer( wxVERTICAL );
53
54 wxStaticText* pageTitle = new wxStaticText( m_scrolledWindow, -1, aPageTitle );
55 pageTitle->SetFont(
56 wxFont( 14, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD ) );
57 m_mainSizer->Add( pageTitle, 0, wxALIGN_CENTRE | wxALL, 5 );
58
59 wxStaticLine* pageDivider = new wxStaticLine( m_scrolledWindow, wxID_ANY,
60 wxDefaultPosition, wxDefaultSize,
61 wxLI_HORIZONTAL );
62 m_mainSizer->Add( pageDivider, 0, wxEXPAND | wxALL, 5 );
63
64 m_scrolledWindow->SetSizer( m_mainSizer );
65
66 outerSizer->Add( m_scrolledWindow, 1, wxEXPAND );
67 SetSizer( outerSizer );
68 }
69
70 // Returns the scrolled content area; use this as the parent for panel content
71 // so the content is scrollable when the wizard is smaller than the page requires.
72 wxWindow* GetContentParent() const { return m_scrolledWindow; }
73
74 void AddContent( wxPanel* aContent )
75 {
76 m_mainSizer->Add( aContent, 0, wxEXPAND );
77 m_scrolledWindow->FitInside();
78 }
79
80 // Returns the minimum size of the scrolled content, independent of the page size.
81 wxSize GetContentMinSize() const { return m_mainSizer->CalcMin(); }
82
83private:
84 wxScrolledWindow* m_scrolledWindow;
85 wxBoxSizer* m_mainSizer;
86};
87
88
89class STARTWIZARD_WELCOME_PAGE : public wxWizardPageSimple
90{
91public:
92 STARTWIZARD_WELCOME_PAGE( wxWizard* aParent ) : wxWizardPageSimple( aParent )
93 {
94 m_mainSizer = new wxBoxSizer( wxVERTICAL );
95
96 wxStaticText* pageTitle = new wxStaticText(
97 this, -1, wxString::Format( _( "Welcome to KiCad %s" ), GetMajorMinorVersion() ) );
98 pageTitle->SetFont(
99 wxFont( 14, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD ) );
100 m_mainSizer->Add( pageTitle, 0, wxALIGN_CENTRE | wxALL, 5 );
101
102 wxStaticLine* pageDivider = new wxStaticLine( this, wxID_ANY, wxDefaultPosition,
103 wxDefaultSize, wxLI_HORIZONTAL );
104 m_mainSizer->Add( pageDivider, 0, wxEXPAND | wxALL, 5 );
105
106 m_welcomeText = new wxStaticText( this, -1,
107 _( "KiCad is starting for the first time, or some of its configuration files are missing.\n\n"
108 "Let's take a moment to configure some basic settings. You can always modify these "
109 "settings later by opening the Preferences dialog." ) );
110 m_mainSizer->Add( m_welcomeText, 0, wxEXPAND | wxALL, 5 );
111
112 wxBoxSizer* helpSizer = new wxBoxSizer( wxHORIZONTAL );
113 wxStaticText* helpLabel = new wxStaticText( this, -1, _( "For help, please visit " ) );
114 wxString docsUrl = wxString::Format( "https://go.kicad.org/docs/%s", GetMajorMinorVersion() );
115 wxHyperlinkCtrl* helpLink = new wxHyperlinkCtrl( this, -1, wxT( "docs.kicad.org" ), docsUrl );
116 helpSizer->Add( helpLabel, 0, wxLEFT | wxTOP | wxBOTTOM | wxALIGN_CENTER_VERTICAL, 5 );
117 helpSizer->Add( helpLink, 0, wxRIGHT | wxTOP | wxBOTTOM | wxALIGN_CENTER_VERTICAL, 5 );
118 m_mainSizer->Add( helpSizer, 0, wxEXPAND, 5 );
119
120 SetSizerAndFit( m_mainSizer );
121 }
122
123 void SetWrap( int aWidth ) const
124 {
125 m_welcomeText->Wrap( aWidth );
126 }
127
128private:
129 wxBoxSizer* m_mainSizer;
130 wxStaticText* m_welcomeText;
131};
132
133
135 m_wizard( nullptr )
136{
137}
138
139
143
144
146{
147 if( auto it = std::ranges::find_if( m_providers,
148 [&]( const std::unique_ptr<STARTWIZARD_PROVIDER>& aProvider )
149 {
150 return aProvider->Name() == aName;
151 } ); it != m_providers.end() )
152 {
153 return it->get();
154 }
155
156 return nullptr;
157}
158
159
160void STARTWIZARD::CheckAndRun( wxWindow* aParent )
161{
162 m_providers.clear();
163
164 m_providers.push_back( std::make_unique<STARTWIZARD_PROVIDER_SETTINGS>() );
165 m_providers.push_back( std::make_unique<STARTWIZARD_PROVIDER_LIBRARIES>() );
166 m_providers.push_back( std::make_unique<STARTWIZARD_PROVIDER_PRIVACY>() );
167 //providers.push_back( std::make_unique<STARTWIZARD_PROVIDER_LOOK_AND_FEEL>() );
168
169 if( m_providers.size() == 0 )
170 return;
171
172 bool wizardRequired = std::ranges::any_of( std::as_const( m_providers ),
173 []( const std::unique_ptr<STARTWIZARD_PROVIDER>& aProvider ) -> bool
174 {
175 return aProvider->NeedsUserInput();
176 } );
177
178 if( !wizardRequired )
179 return;
180
181 Pgm().HideSplash();
182
183 // wxLogGui shows queued messages when a modal opens
184 // A second modal inside RunWizard makes GTK fail
185 wxLog::FlushActive();
186
187 m_wizard = new wxWizard( aParent, wxID_ANY, _( "KiCad Setup" ) );
188 m_wizard->SetWindowStyleFlag( wxRESIZE_BORDER );
189
191 wxWizardPageSimple* lastPage = nullptr;
192 wxSize minPageSize;
193
194 for( std::unique_ptr<STARTWIZARD_PROVIDER>& provider : m_providers )
195 {
196 if( !provider->NeedsUserInput() )
197 continue;
198
199 provider->SetWasShown( true );
200
201 STARTWIZARD_PAGE* page = new STARTWIZARD_PAGE( m_wizard, provider->GetPageName() );
202 wxPanel* panel = provider->GetWizardPanel( page->GetContentParent(), this );
203 page->AddContent( panel );
204
205 if( lastPage != nullptr )
206 {
207 lastPage->Chain( page );
208 }
209 else
210 {
211 firstPage->Chain( page );
212 }
213
214 lastPage = page;
215
216 wxSize size = page->GetContentMinSize();
217
218 if( size.x > minPageSize.x )
219 minPageSize.x = size.x;
220
221 if( size.y > minPageSize.y )
222 minPageSize.y = size.y;
223 }
224
225 // Clamp the page size to the available display area so the wizard is fully
226 // accessible on small or low-resolution screens. Reserve space for the
227 // wizard title bar, the Back/Next/Cancel button row, and a small margin.
228 static constexpr int WIZARD_CHROME_HEIGHT = 120;
229 static constexpr int WIZARD_MARGIN = 40;
230
231 wxSize pageSize = minPageSize + wxSize( 20, 20 );
232
233 int displayIdx = wxDisplay::GetFromWindow( aParent ? aParent : wxTheApp->GetTopWindow() );
234
235 if( displayIdx == wxNOT_FOUND )
236 displayIdx = 0;
237
238 wxRect displayArea = wxDisplay( (unsigned int) displayIdx ).GetClientArea();
239 int maxPageHeight = displayArea.GetHeight() - WIZARD_CHROME_HEIGHT - WIZARD_MARGIN;
240
241 if( maxPageHeight > 0 && pageSize.y > maxPageHeight )
242 pageSize.y = maxPageHeight;
243
244 m_wizard->SetPageSize( pageSize );
245 firstPage->SetWrap( pageSize.x );
246
247 m_wizard->Bind( wxEVT_WIZARD_CANCEL,
248 [&]( wxWizardEvent& aEvt )
249 {
250 if( IsOK( aParent, _( "Are you sure? If you cancel KiCad setup, default settings "
251 "will be chosen for you." ) ) )
252 {
253 for( std::unique_ptr<STARTWIZARD_PROVIDER>& provider : m_providers )
254 {
255 provider->ApplyDefaults();
256 }
257 }
258 else
259 {
260 aEvt.Veto();
261 }
262 } );
263
264 int languageBefore = Pgm().GetSelectedLanguageIdentifier();
265
266 if( m_wizard->RunWizard( firstPage ) )
267 {
268 for( std::unique_ptr<STARTWIZARD_PROVIDER>& provider : m_providers )
269 {
270 if( !provider->WasShown() )
271 continue;
272
273 provider->Finish();
274 }
275 }
276
277 m_wizard->Destroy();
278 m_wizard = nullptr;
279
280 // Settings import can switch the language after the parent frame was already built in the
281 // system locale, so retranslate it to avoid requiring a restart.
282 if( Pgm().GetSelectedLanguageIdentifier() != languageBefore && aParent )
283 {
284 // A dynamic_cast could be better, but creates link issues because EDA_BASE_FRAME lives in
285 // the common library while this code lives in kicommon, so a static_cast is used. Every
286 // caller passes an EDA_BASE_FRAME-derived frame.
287 EDA_BASE_FRAME* frame = static_cast<EDA_BASE_FRAME*>( aParent );
288
289 frame->ShowChangedLanguage();
290
291 wxCommandEvent e( EDA_LANG_CHANGED );
292 frame->GetEventHandler()->ProcessEvent( e );
293 }
294}
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:229
void HideSplash()
Definition pgm_base.cpp:307
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