| 1 | ///////////////////////////////////////////////////////////////////////////// |
| 2 | // Name: wizard.cpp |
| 3 | // Purpose: wxWidgets sample demonstrating wxWizard control |
| 4 | // Author: Vadim Zeitlin |
| 5 | // Modified by: Robert Vazan (sizers) |
| 6 | // Created: 15.08.99 |
| 7 | // RCS-ID: $Id$ |
| 8 | // Copyright: (c) Vadim Zeitlin |
| 9 | // Licence: wxWindows licence |
| 10 | ///////////////////////////////////////////////////////////////////////////// |
| 11 | |
| 12 | // ============================================================================ |
| 13 | // declarations |
| 14 | // ============================================================================ |
| 15 | |
| 16 | // ---------------------------------------------------------------------------- |
| 17 | // headers |
| 18 | // ---------------------------------------------------------------------------- |
| 19 | |
| 20 | // For compilers that support precompilation, includes "wx/wx.h". |
| 21 | #include "wx/wxprec.h" |
| 22 | |
| 23 | #ifdef __BORLANDC__ |
| 24 | #pragma hdrstop |
| 25 | #endif |
| 26 | |
| 27 | // for all others, include the necessary headers |
| 28 | #ifndef WX_PRECOMP |
| 29 | #include "wx/frame.h" |
| 30 | #include "wx/stattext.h" |
| 31 | #include "wx/log.h" |
| 32 | #include "wx/app.h" |
| 33 | #include "wx/checkbox.h" |
| 34 | #include "wx/checklst.h" |
| 35 | #include "wx/msgdlg.h" |
| 36 | #include "wx/radiobox.h" |
| 37 | #include "wx/menu.h" |
| 38 | #include "wx/sizer.h" |
| 39 | #endif |
| 40 | |
| 41 | #include "wx/textctrl.h" |
| 42 | #include "wx/wizard.h" |
| 43 | |
| 44 | #include "wiztest.xpm" |
| 45 | #include "wiztest2.xpm" |
| 46 | |
| 47 | #include "../sample.xpm" |
| 48 | |
| 49 | // ---------------------------------------------------------------------------- |
| 50 | // constants |
| 51 | // ---------------------------------------------------------------------------- |
| 52 | |
| 53 | // ids for menu items |
| 54 | enum |
| 55 | { |
| 56 | Wizard_About = wxID_ABOUT, |
| 57 | Wizard_Quit = wxID_EXIT, |
| 58 | Wizard_RunModal = wxID_HIGHEST, |
| 59 | |
| 60 | Wizard_RunNoSizer, |
| 61 | Wizard_RunModeless, |
| 62 | |
| 63 | Wizard_LargeWizard, |
| 64 | Wizard_ExpandBitmap |
| 65 | }; |
| 66 | |
| 67 | // ---------------------------------------------------------------------------- |
| 68 | // private classes |
| 69 | // ---------------------------------------------------------------------------- |
| 70 | |
| 71 | // Define a new application type, each program should derive a class from wxApp |
| 72 | class MyApp : public wxApp |
| 73 | { |
| 74 | public: |
| 75 | // override base class virtuals |
| 76 | virtual bool OnInit(); |
| 77 | }; |
| 78 | |
| 79 | class MyFrame : public wxFrame |
| 80 | { |
| 81 | public: |
| 82 | // ctor(s) |
| 83 | MyFrame(const wxString& title); |
| 84 | |
| 85 | // event handlers (these functions should _not_ be virtual) |
| 86 | void OnQuit(wxCommandEvent& event); |
| 87 | void OnAbout(wxCommandEvent& event); |
| 88 | void OnRunWizard(wxCommandEvent& event); |
| 89 | void OnRunWizardNoSizer(wxCommandEvent& event); |
| 90 | void OnRunWizardModeless(wxCommandEvent& event); |
| 91 | void OnWizardCancel(wxWizardEvent& event); |
| 92 | void OnWizardFinished(wxWizardEvent& event); |
| 93 | |
| 94 | private: |
| 95 | // any class wishing to process wxWidgets events must use this macro |
| 96 | DECLARE_EVENT_TABLE() |
| 97 | }; |
| 98 | |
| 99 | // ---------------------------------------------------------------------------- |
| 100 | // our wizard |
| 101 | // ---------------------------------------------------------------------------- |
| 102 | |
| 103 | class MyWizard : public wxWizard |
| 104 | { |
| 105 | public: |
| 106 | MyWizard(wxFrame *frame, bool useSizer = true); |
| 107 | |
| 108 | wxWizardPage *GetFirstPage() const { return m_page1; } |
| 109 | |
| 110 | private: |
| 111 | wxWizardPageSimple *m_page1; |
| 112 | }; |
| 113 | |
| 114 | // ---------------------------------------------------------------------------- |
| 115 | // some pages for our wizard |
| 116 | // ---------------------------------------------------------------------------- |
| 117 | |
| 118 | // This shows how to simply control the validity of the user input by just |
| 119 | // overriding TransferDataFromWindow() - of course, in a real program, the |
| 120 | // check wouldn't be so trivial and the data will be probably saved somewhere |
| 121 | // too. |
| 122 | // |
| 123 | // It also shows how to use a different bitmap for one of the pages. |
| 124 | class wxValidationPage : public wxWizardPageSimple |
| 125 | { |
| 126 | public: |
| 127 | wxValidationPage(wxWizard *parent) : wxWizardPageSimple(parent) |
| 128 | { |
| 129 | m_bitmap = wxBitmap(wiztest2_xpm); |
| 130 | |
| 131 | m_checkbox = new wxCheckBox(this, wxID_ANY, _T("&Check me")); |
| 132 | |
| 133 | wxBoxSizer *mainSizer = new wxBoxSizer(wxVERTICAL); |
| 134 | mainSizer->Add( |
| 135 | new wxStaticText(this, wxID_ANY, |
| 136 | _T("You need to check the checkbox\n") |
| 137 | _T("below before going to the next page\n")), |
| 138 | 0, |
| 139 | wxALL, |
| 140 | 5 |
| 141 | ); |
| 142 | |
| 143 | mainSizer->Add( |
| 144 | m_checkbox, |
| 145 | 0, // No stretching |
| 146 | wxALL, |
| 147 | 5 // Border |
| 148 | ); |
| 149 | SetSizerAndFit(mainSizer); |
| 150 | } |
| 151 | |
| 152 | virtual bool TransferDataFromWindow() |
| 153 | { |
| 154 | if ( !m_checkbox->GetValue() ) |
| 155 | { |
| 156 | wxMessageBox(_T("Check the checkbox first!"), _T("No way"), |
| 157 | wxICON_WARNING | wxOK, this); |
| 158 | |
| 159 | return false; |
| 160 | } |
| 161 | |
| 162 | return true; |
| 163 | } |
| 164 | |
| 165 | private: |
| 166 | wxCheckBox *m_checkbox; |
| 167 | }; |
| 168 | |
| 169 | // This is a more complicated example of validity checking: using events we may |
| 170 | // allow to return to the previous page, but not to proceed. It also |
| 171 | // demonstrates how to intercept [Cancel] button press. |
| 172 | class wxRadioboxPage : public wxWizardPageSimple |
| 173 | { |
| 174 | public: |
| 175 | // directions in which we allow the user to proceed from this page |
| 176 | enum |
| 177 | { |
| 178 | Forward, Backward, Both, Neither |
| 179 | }; |
| 180 | |
| 181 | wxRadioboxPage(wxWizard *parent) : wxWizardPageSimple(parent) |
| 182 | { |
| 183 | // should correspond to the enum above |
| 184 | // static wxString choices[] = { "forward", "backward", "both", "neither" }; |
| 185 | // The above syntax can cause an internal compiler error with gcc. |
| 186 | wxString choices[4]; |
| 187 | choices[0] = _T("forward"); |
| 188 | choices[1] = _T("backward"); |
| 189 | choices[2] = _T("both"); |
| 190 | choices[3] = _T("neither"); |
| 191 | |
| 192 | m_radio = new wxRadioBox(this, wxID_ANY, _T("Allow to proceed:"), |
| 193 | wxDefaultPosition, wxDefaultSize, |
| 194 | WXSIZEOF(choices), choices, |
| 195 | 1, wxRA_SPECIFY_COLS); |
| 196 | m_radio->SetSelection(Both); |
| 197 | |
| 198 | wxBoxSizer *mainSizer = new wxBoxSizer(wxVERTICAL); |
| 199 | mainSizer->Add( |
| 200 | m_radio, |
| 201 | 0, // No stretching |
| 202 | wxALL, |
| 203 | 5 // Border |
| 204 | ); |
| 205 | |
| 206 | SetSizerAndFit(mainSizer); |
| 207 | } |
| 208 | |
| 209 | // wizard event handlers |
| 210 | void OnWizardCancel(wxWizardEvent& event) |
| 211 | { |
| 212 | if ( wxMessageBox(_T("Do you really want to cancel?"), _T("Question"), |
| 213 | wxICON_QUESTION | wxYES_NO, this) != wxYES ) |
| 214 | { |
| 215 | // not confirmed |
| 216 | event.Veto(); |
| 217 | } |
| 218 | } |
| 219 | |
| 220 | void OnWizardPageChanging(wxWizardEvent& event) |
| 221 | { |
| 222 | int sel = m_radio->GetSelection(); |
| 223 | |
| 224 | if ( sel == Both ) |
| 225 | return; |
| 226 | |
| 227 | if ( event.GetDirection() && sel == Forward ) |
| 228 | return; |
| 229 | |
| 230 | if ( !event.GetDirection() && sel == Backward ) |
| 231 | return; |
| 232 | |
| 233 | wxMessageBox(_T("You can't go there"), _T("Not allowed"), |
| 234 | wxICON_WARNING | wxOK, this); |
| 235 | |
| 236 | event.Veto(); |
| 237 | } |
| 238 | |
| 239 | private: |
| 240 | wxRadioBox *m_radio; |
| 241 | |
| 242 | DECLARE_EVENT_TABLE() |
| 243 | }; |
| 244 | |
| 245 | // This shows how to dynamically (i.e. during run-time) arrange the page order. |
| 246 | class wxCheckboxPage : public wxWizardPage |
| 247 | { |
| 248 | public: |
| 249 | wxCheckboxPage(wxWizard *parent, |
| 250 | wxWizardPage *prev, |
| 251 | wxWizardPage *next) |
| 252 | : wxWizardPage(parent) |
| 253 | { |
| 254 | m_prev = prev; |
| 255 | m_next = next; |
| 256 | |
| 257 | wxBoxSizer *mainSizer = new wxBoxSizer(wxVERTICAL); |
| 258 | |
| 259 | mainSizer->Add( |
| 260 | new wxStaticText(this, wxID_ANY, _T("Try checking the box below and\n") |
| 261 | _T("then going back and clearing it")), |
| 262 | 0, // No vertical stretching |
| 263 | wxALL, |
| 264 | 5 // Border width |
| 265 | ); |
| 266 | |
| 267 | m_checkbox = new wxCheckBox(this, wxID_ANY, _T("&Skip the next page")); |
| 268 | mainSizer->Add( |
| 269 | m_checkbox, |
| 270 | 0, // No vertical stretching |
| 271 | wxALL, |
| 272 | 5 // Border width |
| 273 | ); |
| 274 | |
| 275 | #if wxUSE_CHECKLISTBOX |
| 276 | static const wxChar *aszChoices[] = |
| 277 | { |
| 278 | _T("Zeroth"), |
| 279 | _T("First"), |
| 280 | _T("Second"), |
| 281 | _T("Third"), |
| 282 | _T("Fourth"), |
| 283 | _T("Fifth"), |
| 284 | _T("Sixth"), |
| 285 | _T("Seventh"), |
| 286 | _T("Eighth"), |
| 287 | _T("Nineth") |
| 288 | }; |
| 289 | |
| 290 | m_checklistbox = new wxCheckListBox |
| 291 | ( |
| 292 | this, |
| 293 | wxID_ANY, |
| 294 | wxDefaultPosition, |
| 295 | wxSize(100,100), |
| 296 | wxArrayString(WXSIZEOF(aszChoices), aszChoices) |
| 297 | ); |
| 298 | |
| 299 | mainSizer->Add( |
| 300 | m_checklistbox, |
| 301 | 0, // No vertical stretching |
| 302 | wxALL, |
| 303 | 5 // Border width |
| 304 | ); |
| 305 | #endif // wxUSE_CHECKLISTBOX |
| 306 | |
| 307 | wxSize textSize = wxSize(150, 200); |
| 308 | if (((wxFrame*) wxTheApp->GetTopWindow())->GetMenuBar()->IsChecked(Wizard_LargeWizard)) |
| 309 | textSize = wxSize(150, wxGetClientDisplayRect().GetHeight() - 200); |
| 310 | |
| 311 | |
| 312 | wxTextCtrl* textCtrl = new wxTextCtrl(this, wxID_ANY, wxEmptyString, wxDefaultPosition, textSize, wxTE_MULTILINE); |
| 313 | mainSizer->Add(textCtrl, 0, wxALL|wxEXPAND, 5); |
| 314 | |
| 315 | SetSizerAndFit(mainSizer); |
| 316 | } |
| 317 | |
| 318 | // implement wxWizardPage functions |
| 319 | virtual wxWizardPage *GetPrev() const { return m_prev; } |
| 320 | virtual wxWizardPage *GetNext() const |
| 321 | { |
| 322 | return m_checkbox->GetValue() ? m_next->GetNext() : m_next; |
| 323 | } |
| 324 | |
| 325 | private: |
| 326 | wxWizardPage *m_prev, |
| 327 | *m_next; |
| 328 | |
| 329 | wxCheckBox *m_checkbox; |
| 330 | #if wxUSE_CHECKLISTBOX |
| 331 | wxCheckListBox *m_checklistbox; |
| 332 | #endif |
| 333 | }; |
| 334 | |
| 335 | // ============================================================================ |
| 336 | // implementation |
| 337 | // ============================================================================ |
| 338 | |
| 339 | // ---------------------------------------------------------------------------- |
| 340 | // event tables and such |
| 341 | // ---------------------------------------------------------------------------- |
| 342 | |
| 343 | BEGIN_EVENT_TABLE(MyFrame, wxFrame) |
| 344 | EVT_MENU(Wizard_Quit, MyFrame::OnQuit) |
| 345 | EVT_MENU(Wizard_About, MyFrame::OnAbout) |
| 346 | EVT_MENU(Wizard_RunModal, MyFrame::OnRunWizard) |
| 347 | EVT_MENU(Wizard_RunNoSizer, MyFrame::OnRunWizardNoSizer) |
| 348 | EVT_MENU(Wizard_RunModeless, MyFrame::OnRunWizardModeless) |
| 349 | |
| 350 | EVT_WIZARD_CANCEL(wxID_ANY, MyFrame::OnWizardCancel) |
| 351 | EVT_WIZARD_FINISHED(wxID_ANY, MyFrame::OnWizardFinished) |
| 352 | END_EVENT_TABLE() |
| 353 | |
| 354 | BEGIN_EVENT_TABLE(wxRadioboxPage, wxWizardPageSimple) |
| 355 | EVT_WIZARD_PAGE_CHANGING(wxID_ANY, wxRadioboxPage::OnWizardPageChanging) |
| 356 | EVT_WIZARD_CANCEL(wxID_ANY, wxRadioboxPage::OnWizardCancel) |
| 357 | END_EVENT_TABLE() |
| 358 | |
| 359 | IMPLEMENT_APP(MyApp) |
| 360 | |
| 361 | // ---------------------------------------------------------------------------- |
| 362 | // the application class |
| 363 | // ---------------------------------------------------------------------------- |
| 364 | |
| 365 | // `Main program' equivalent: the program execution "starts" here |
| 366 | bool MyApp::OnInit() |
| 367 | { |
| 368 | if ( !wxApp::OnInit() ) |
| 369 | return false; |
| 370 | |
| 371 | MyFrame *frame = new MyFrame(_T("wxWizard Sample")); |
| 372 | |
| 373 | // and show it (the frames, unlike simple controls, are not shown when |
| 374 | // created initially) |
| 375 | frame->Show(true); |
| 376 | |
| 377 | // we're done |
| 378 | return true; |
| 379 | } |
| 380 | |
| 381 | // ---------------------------------------------------------------------------- |
| 382 | // MyWizard |
| 383 | // ---------------------------------------------------------------------------- |
| 384 | |
| 385 | MyWizard::MyWizard(wxFrame *frame, bool useSizer) |
| 386 | : wxWizard(frame,wxID_ANY,_T("Absolutely Useless Wizard"), |
| 387 | wxBitmap(wiztest_xpm),wxDefaultPosition, |
| 388 | wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER) |
| 389 | { |
| 390 | SetIcon(wxIcon(sample_xpm)); |
| 391 | |
| 392 | // Allow the bitmap to be expanded to fit the page height |
| 393 | if (frame->GetMenuBar()->IsChecked(Wizard_ExpandBitmap)) |
| 394 | SetBitmapPlacement(wxWIZARD_VALIGN_CENTRE); |
| 395 | |
| 396 | // Enable scrolling adaptation |
| 397 | if (frame->GetMenuBar()->IsChecked(Wizard_LargeWizard)) |
| 398 | SetLayoutAdaptationMode(wxDIALOG_ADAPTATION_MODE_ENABLED); |
| 399 | |
| 400 | // a wizard page may be either an object of predefined class |
| 401 | m_page1 = new wxWizardPageSimple(this); |
| 402 | |
| 403 | /* wxStaticText *text = */ new wxStaticText(m_page1, wxID_ANY, |
| 404 | _T("This wizard doesn't help you\nto do anything at all.\n") |
| 405 | _T("\n") |
| 406 | _T("The next pages will present you\nwith more useless controls."), |
| 407 | wxPoint(5,5) |
| 408 | ); |
| 409 | |
| 410 | // ... or a derived class |
| 411 | wxRadioboxPage *page3 = new wxRadioboxPage(this); |
| 412 | wxValidationPage *page4 = new wxValidationPage(this); |
| 413 | |
| 414 | // set the page order using a convenience function - could also use |
| 415 | // SetNext/Prev directly as below |
| 416 | wxWizardPageSimple::Chain(page3, page4); |
| 417 | |
| 418 | // this page is not a wxWizardPageSimple, so we use SetNext/Prev to insert |
| 419 | // it into the chain of pages |
| 420 | wxCheckboxPage *page2 = new wxCheckboxPage(this, m_page1, page3); |
| 421 | m_page1->SetNext(page2); |
| 422 | page3->SetPrev(page2); |
| 423 | |
| 424 | if ( useSizer ) |
| 425 | { |
| 426 | // allow the wizard to size itself around the pages |
| 427 | GetPageAreaSizer()->Add(m_page1); |
| 428 | } |
| 429 | } |
| 430 | |
| 431 | // ---------------------------------------------------------------------------- |
| 432 | // MyFrame |
| 433 | // ---------------------------------------------------------------------------- |
| 434 | |
| 435 | MyFrame::MyFrame(const wxString& title) |
| 436 | :wxFrame((wxFrame *)NULL, wxID_ANY, title, |
| 437 | wxDefaultPosition, wxSize(250, 150)) // small frame |
| 438 | { |
| 439 | wxMenu *menuFile = new wxMenu; |
| 440 | menuFile->Append(Wizard_RunModal, _T("&Run wizard modal...\tCtrl-R")); |
| 441 | menuFile->Append(Wizard_RunNoSizer, _T("Run wizard &without sizer...")); |
| 442 | menuFile->Append(Wizard_RunModeless, _T("Run wizard &modeless...")); |
| 443 | menuFile->AppendSeparator(); |
| 444 | menuFile->Append(Wizard_Quit, _T("E&xit\tAlt-X"), _T("Quit this program")); |
| 445 | |
| 446 | wxMenu *menuOptions = new wxMenu; |
| 447 | menuOptions->AppendCheckItem(Wizard_LargeWizard, _T("&Scroll Wizard Pages")); |
| 448 | menuOptions->AppendCheckItem(Wizard_ExpandBitmap, _T("Si&ze Bitmap To Page")); |
| 449 | |
| 450 | wxMenu *helpMenu = new wxMenu; |
| 451 | helpMenu->Append(Wizard_About, _T("&About...\tF1"), _T("Show about dialog")); |
| 452 | |
| 453 | // now append the freshly created menu to the menu bar... |
| 454 | wxMenuBar *menuBar = new wxMenuBar(); |
| 455 | menuBar->Append(menuFile, _T("&File")); |
| 456 | menuBar->Append(menuOptions, _T("&Options")); |
| 457 | menuBar->Append(helpMenu, _T("&Help")); |
| 458 | |
| 459 | // ... and attach this menu bar to the frame |
| 460 | SetMenuBar(menuBar); |
| 461 | |
| 462 | // also create status bar which we use in OnWizardCancel |
| 463 | #if wxUSE_STATUSBAR |
| 464 | CreateStatusBar(); |
| 465 | #endif // wxUSE_STATUSBAR |
| 466 | } |
| 467 | |
| 468 | void MyFrame::OnQuit(wxCommandEvent& WXUNUSED(event)) |
| 469 | { |
| 470 | // true is to force the frame to close |
| 471 | Close(true); |
| 472 | } |
| 473 | |
| 474 | void MyFrame::OnAbout(wxCommandEvent& WXUNUSED(event)) |
| 475 | { |
| 476 | wxMessageBox(_T("Demo of wxWizard class\n") |
| 477 | _T("(c) 1999, 2000 Vadim Zeitlin"), |
| 478 | _T("About wxWizard sample"), wxOK | wxICON_INFORMATION, this); |
| 479 | } |
| 480 | |
| 481 | void MyFrame::OnRunWizard(wxCommandEvent& WXUNUSED(event)) |
| 482 | { |
| 483 | MyWizard wizard(this); |
| 484 | |
| 485 | wizard.RunWizard(wizard.GetFirstPage()); |
| 486 | } |
| 487 | |
| 488 | void MyFrame::OnRunWizardNoSizer(wxCommandEvent& WXUNUSED(event)) |
| 489 | { |
| 490 | MyWizard wizard(this, false); |
| 491 | |
| 492 | wizard.RunWizard(wizard.GetFirstPage()); |
| 493 | } |
| 494 | |
| 495 | void MyFrame::OnRunWizardModeless(wxCommandEvent& WXUNUSED(event)) |
| 496 | { |
| 497 | MyWizard *wizard = new MyWizard(this); |
| 498 | wizard->ShowPage(wizard->GetFirstPage()); |
| 499 | wizard->Show(true); |
| 500 | } |
| 501 | |
| 502 | void MyFrame::OnWizardFinished(wxWizardEvent& WXUNUSED(event)) |
| 503 | { |
| 504 | wxMessageBox(wxT("The wizard finished successfully."), wxT("Wizard notification")); |
| 505 | } |
| 506 | |
| 507 | void MyFrame::OnWizardCancel(wxWizardEvent& WXUNUSED(event)) |
| 508 | { |
| 509 | wxMessageBox(wxT("The wizard was cancelled."), wxT("Wizard notification")); |
| 510 | } |