wizards not using sizers for the page layout now work again
[wxWidgets.git] / src / generic / wizard.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: src/generic/wizard.cpp
3 // Purpose: generic implementation of wxWizard class
4 // Author: Vadim Zeitlin
5 // Modified by: Robert Cavanaugh
6 // 1) Added capability for wxWizardPage to accept resources
7 // 2) Added "Help" button handler stub
8 // 3) Fixed ShowPage() bug on displaying bitmaps
9 // Robert Vazan (sizers)
10 // Created: 15.08.99
11 // RCS-ID: $Id$
12 // Copyright: (c) 1999 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
13 // Licence: wxWindows licence
14 ///////////////////////////////////////////////////////////////////////////////
15
16 // ============================================================================
17 // declarations
18 // ============================================================================
19
20 // ----------------------------------------------------------------------------
21 // headers
22 // ----------------------------------------------------------------------------
23
24 // For compilers that support precompilation, includes "wx.h".
25 #include "wx/wxprec.h"
26
27 #ifdef __BORLANDC__
28 #pragma hdrstop
29 #endif
30
31 #if wxUSE_WIZARDDLG
32
33 #ifndef WX_PRECOMP
34 #include "wx/dynarray.h"
35 #include "wx/intl.h"
36 #include "wx/statbmp.h"
37 #include "wx/button.h"
38 #include "wx/settings.h"
39 #endif //WX_PRECOMP
40
41 #include "wx/statline.h"
42 #include "wx/sizer.h"
43
44 #include "wx/wizard.h"
45
46 // ----------------------------------------------------------------------------
47 // wxWizardSizer
48 // ----------------------------------------------------------------------------
49
50 class wxWizardSizer : public wxSizer
51 {
52 public:
53 wxWizardSizer(wxWizard *owner);
54
55 virtual wxSizerItem *Insert(size_t index, wxSizerItem *item);
56
57 virtual void RecalcSizes();
58 virtual wxSize CalcMin();
59
60 // get the max size of all wizard pages
61 wxSize GetMaxChildSize();
62
63 // return the border which can be either set using wxWizard::SetBorder() or
64 // have default value
65 int GetBorder() const;
66
67 // hide the pages which we temporarily "show" when they're added to this
68 // sizer (see Insert())
69 void HidePages();
70
71 private:
72 wxSize SiblingSize(wxSizerItem *child);
73
74 wxWizard *m_owner;
75 wxSize m_childSize;
76 };
77
78 // ----------------------------------------------------------------------------
79 // event tables and such
80 // ----------------------------------------------------------------------------
81
82 DEFINE_EVENT_TYPE(wxEVT_WIZARD_PAGE_CHANGED)
83 DEFINE_EVENT_TYPE(wxEVT_WIZARD_PAGE_CHANGING)
84 DEFINE_EVENT_TYPE(wxEVT_WIZARD_CANCEL)
85 DEFINE_EVENT_TYPE(wxEVT_WIZARD_FINISHED)
86 DEFINE_EVENT_TYPE(wxEVT_WIZARD_HELP)
87
88 BEGIN_EVENT_TABLE(wxWizard, wxDialog)
89 EVT_BUTTON(wxID_CANCEL, wxWizard::OnCancel)
90 EVT_BUTTON(wxID_BACKWARD, wxWizard::OnBackOrNext)
91 EVT_BUTTON(wxID_FORWARD, wxWizard::OnBackOrNext)
92 EVT_BUTTON(wxID_HELP, wxWizard::OnHelp)
93
94 EVT_WIZARD_PAGE_CHANGED(wxID_ANY, wxWizard::OnWizEvent)
95 EVT_WIZARD_PAGE_CHANGING(wxID_ANY, wxWizard::OnWizEvent)
96 EVT_WIZARD_CANCEL(wxID_ANY, wxWizard::OnWizEvent)
97 EVT_WIZARD_FINISHED(wxID_ANY, wxWizard::OnWizEvent)
98 EVT_WIZARD_HELP(wxID_ANY, wxWizard::OnWizEvent)
99 END_EVENT_TABLE()
100
101 IMPLEMENT_DYNAMIC_CLASS(wxWizard, wxDialog)
102
103 /*
104 TODO PROPERTIES :
105 wxWizard
106 extstyle
107 title
108 */
109
110 IMPLEMENT_ABSTRACT_CLASS(wxWizardPage, wxPanel)
111 IMPLEMENT_DYNAMIC_CLASS(wxWizardPageSimple, wxWizardPage)
112 IMPLEMENT_DYNAMIC_CLASS(wxWizardEvent, wxNotifyEvent)
113
114 // ============================================================================
115 // implementation
116 // ============================================================================
117
118 // ----------------------------------------------------------------------------
119 // wxWizardPage
120 // ----------------------------------------------------------------------------
121
122 void wxWizardPage::Init()
123 {
124 m_bitmap = wxNullBitmap;
125 }
126
127 wxWizardPage::wxWizardPage(wxWizard *parent,
128 const wxBitmap& bitmap,
129 const wxChar *resource)
130 {
131 Create(parent, bitmap, resource);
132 }
133
134 bool wxWizardPage::Create(wxWizard *parent,
135 const wxBitmap& bitmap,
136 const wxChar *resource)
137 {
138 if ( !wxPanel::Create(parent, wxID_ANY) )
139 return false;
140
141 if ( resource != NULL )
142 {
143 #if wxUSE_WX_RESOURCES
144 #if 0
145 if ( !LoadFromResource(this, resource) )
146 {
147 wxFAIL_MSG(wxT("wxWizardPage LoadFromResource failed!!!!"));
148 }
149 #endif
150 #endif // wxUSE_RESOURCES
151 }
152
153 m_bitmap = bitmap;
154
155 // initially the page is hidden, it's shown only when it becomes current
156 Hide();
157
158 return true;
159 }
160
161 // ----------------------------------------------------------------------------
162 // wxWizardPageSimple
163 // ----------------------------------------------------------------------------
164
165 wxWizardPage *wxWizardPageSimple::GetPrev() const
166 {
167 return m_prev;
168 }
169
170 wxWizardPage *wxWizardPageSimple::GetNext() const
171 {
172 return m_next;
173 }
174
175 // ----------------------------------------------------------------------------
176 // wxWizardSizer
177 // ----------------------------------------------------------------------------
178
179 wxWizardSizer::wxWizardSizer(wxWizard *owner)
180 : m_owner(owner),
181 m_childSize(wxDefaultSize)
182 {
183 }
184
185 wxSizerItem *wxWizardSizer::Insert(size_t index, wxSizerItem *item)
186 {
187 m_owner->m_usingSizer = true;
188
189 if ( item->IsWindow() )
190 {
191 // we must pretend that the window is shown as otherwise it wouldn't be
192 // taken into account for the layout -- but avoid really showing it, so
193 // just set the internal flag instead of calling wxWindow::Show()
194 item->GetWindow()->wxWindowBase::Show();
195 }
196
197 return wxSizer::Insert(index, item);
198 }
199
200 void wxWizardSizer::HidePages()
201 {
202 for ( wxSizerItemList::compatibility_iterator node = GetChildren().GetFirst();
203 node;
204 node = node->GetNext() )
205 {
206 wxSizerItem * const item = node->GetData();
207 if ( item->IsWindow() )
208 item->GetWindow()->wxWindowBase::Show(false);
209 }
210 }
211
212 void wxWizardSizer::RecalcSizes()
213 {
214 // Effect of this function depends on m_owner->m_page and
215 // it should be called whenever it changes (wxWizard::ShowPage)
216 if ( m_owner->m_page )
217 {
218 m_owner->m_page->SetSize(wxRect(m_position, m_size));
219 }
220 }
221
222 wxSize wxWizardSizer::CalcMin()
223 {
224 return m_owner->GetPageSize();
225 }
226
227 wxSize wxWizardSizer::GetMaxChildSize()
228 {
229 #if !defined(__WXDEBUG__)
230 if ( m_childSize.IsFullySpecified() )
231 return m_childSize;
232 #endif
233
234 wxSize maxOfMin;
235
236 for ( wxSizerItemList::compatibility_iterator childNode = m_children.GetFirst();
237 childNode;
238 childNode = childNode->GetNext() )
239 {
240 wxSizerItem *child = childNode->GetData();
241 maxOfMin.IncTo(child->CalcMin());
242 maxOfMin.IncTo(SiblingSize(child));
243 }
244
245 #ifdef __WXDEBUG__
246 if ( m_childSize.IsFullySpecified() && m_childSize != maxOfMin )
247 {
248 wxFAIL_MSG( _T("Size changed in wxWizard::GetPageAreaSizer()")
249 _T("after RunWizard().\n")
250 _T("Did you forget to call GetSizer()->Fit(this) ")
251 _T("for some page?")) ;
252
253 return m_childSize;
254 }
255 #endif // __WXDEBUG__
256
257 if ( m_owner->m_started )
258 {
259 m_childSize = maxOfMin;
260 }
261
262 return maxOfMin;
263 }
264
265 int wxWizardSizer::GetBorder() const
266 {
267 return m_owner->m_border;
268 }
269
270 wxSize wxWizardSizer::SiblingSize(wxSizerItem *child)
271 {
272 wxSize maxSibling;
273
274 if ( child->IsWindow() )
275 {
276 wxWizardPage *page = wxDynamicCast(child->GetWindow(), wxWizardPage);
277 if ( page )
278 {
279 for ( wxWizardPage *sibling = page->GetNext();
280 sibling;
281 sibling = sibling->GetNext() )
282 {
283 if ( sibling->GetSizer() )
284 {
285 maxSibling.IncTo(sibling->GetSizer()->CalcMin());
286 }
287 }
288 }
289 }
290
291 return maxSibling;
292 }
293
294 // ----------------------------------------------------------------------------
295 // generic wxWizard implementation
296 // ----------------------------------------------------------------------------
297
298 void wxWizard::Init()
299 {
300 m_posWizard = wxDefaultPosition;
301 m_page = (wxWizardPage *)NULL;
302 m_btnPrev = m_btnNext = NULL;
303 m_statbmp = NULL;
304 m_sizerBmpAndPage = NULL;
305 m_sizerPage = NULL;
306 m_border = 5;
307 m_started = false;
308 m_wasModal = false;
309 m_usingSizer = false;
310 }
311
312 bool wxWizard::Create(wxWindow *parent,
313 int id,
314 const wxString& title,
315 const wxBitmap& bitmap,
316 const wxPoint& pos,
317 long style)
318 {
319 bool result = wxDialog::Create(parent,id,title,pos,wxDefaultSize,style);
320
321 m_posWizard = pos;
322 m_bitmap = bitmap ;
323
324 DoCreateControls();
325
326 return result;
327 }
328
329 void wxWizard::AddBitmapRow(wxBoxSizer *mainColumn)
330 {
331 m_sizerBmpAndPage = new wxBoxSizer(wxHORIZONTAL);
332 mainColumn->Add(
333 m_sizerBmpAndPage,
334 1, // Vertically stretchable
335 wxEXPAND // Horizonal stretching, no border
336 );
337 mainColumn->Add(0,5,
338 0, // No vertical stretching
339 wxEXPAND // No border, (mostly useless) horizontal stretching
340 );
341
342 #if wxUSE_STATBMP
343 if ( m_bitmap.Ok() )
344 {
345 m_statbmp = new wxStaticBitmap(this, wxID_ANY, m_bitmap);
346 m_sizerBmpAndPage->Add(
347 m_statbmp,
348 0, // No horizontal stretching
349 wxALL, // Border all around, top alignment
350 5 // Border width
351 );
352 m_sizerBmpAndPage->Add(
353 5,0,
354 0, // No horizontal stretching
355 wxEXPAND // No border, (mostly useless) vertical stretching
356 );
357 }
358 #endif
359
360 // Added to m_sizerBmpAndPage later
361 m_sizerPage = new wxWizardSizer(this);
362 }
363
364 void wxWizard::AddStaticLine(wxBoxSizer *mainColumn)
365 {
366 #if wxUSE_STATLINE
367 mainColumn->Add(
368 new wxStaticLine(this, wxID_ANY),
369 0, // Vertically unstretchable
370 wxEXPAND | wxALL, // Border all around, horizontally stretchable
371 5 // Border width
372 );
373 mainColumn->Add(0,5,
374 0, // No vertical stretching
375 wxEXPAND // No border, (mostly useless) horizontal stretching
376 );
377 #else
378 (void)mainColumn;
379 #endif // wxUSE_STATLINE
380 }
381
382 void wxWizard::AddBackNextPair(wxBoxSizer *buttonRow)
383 {
384 wxASSERT_MSG( m_btnNext && m_btnPrev,
385 _T("You must create the buttons before calling ")
386 _T("wxWizard::AddBackNextPair") );
387
388 // margin between Back and Next buttons
389 #ifdef __WXMAC__
390 static const int BACKNEXT_MARGIN = 10;
391 #else
392 static const int BACKNEXT_MARGIN = 0;
393 #endif
394
395 wxBoxSizer *backNextPair = new wxBoxSizer(wxHORIZONTAL);
396 buttonRow->Add(
397 backNextPair,
398 0, // No horizontal stretching
399 wxALL, // Border all around
400 5 // Border width
401 );
402
403 backNextPair->Add(m_btnPrev);
404 backNextPair->Add(BACKNEXT_MARGIN,0,
405 0, // No horizontal stretching
406 wxEXPAND // No border, (mostly useless) vertical stretching
407 );
408 backNextPair->Add(m_btnNext);
409 }
410
411 void wxWizard::AddButtonRow(wxBoxSizer *mainColumn)
412 {
413 // the order in which the buttons are created determines the TAB order - at least under MSWindows...
414 // although the 'back' button appears before the 'next' button, a more userfriendly tab order is
415 // to activate the 'next' button first (create the next button before the back button).
416 // The reason is: The user will repeatedly enter information in the wizard pages and then wants to
417 // press 'next'. If a user uses mostly the keyboard, he would have to skip the 'back' button
418 // everytime. This is annoying. There is a second reason: RETURN acts as TAB. If the 'next'
419 // button comes first in the TAB order, the user can enter information very fast using the RETURN
420 // key to TAB to the next entry field and page. This would not be possible, if the 'back' button
421 // was created before the 'next' button.
422
423 bool isPda = (wxSystemSettings::GetScreenType() <= wxSYS_SCREEN_PDA);
424 int buttonStyle = isPda ? wxBU_EXACTFIT : 0;
425
426 wxBoxSizer *buttonRow = new wxBoxSizer(wxHORIZONTAL);
427 #ifdef __WXMAC__
428 if (GetExtraStyle() & wxWIZARD_EX_HELPBUTTON)
429 mainColumn->Add(
430 buttonRow,
431 0, // Vertically unstretchable
432 wxGROW|wxALIGN_CENTRE
433 );
434 else
435 #endif
436 mainColumn->Add(
437 buttonRow,
438 0, // Vertically unstretchable
439 wxALIGN_RIGHT // Right aligned, no border
440 );
441
442 // Desired TAB order is 'next', 'cancel', 'help', 'back'. This makes the 'back' button the last control on the page.
443 // Create the buttons in the right order...
444 wxButton *btnHelp=0;
445 #ifdef __WXMAC__
446 if (GetExtraStyle() & wxWIZARD_EX_HELPBUTTON)
447 btnHelp=new wxButton(this, wxID_HELP, _("&Help"), wxDefaultPosition, wxDefaultSize, buttonStyle);
448 #endif
449
450 m_btnNext = new wxButton(this, wxID_FORWARD, _("&Next >"));
451 wxButton *btnCancel=new wxButton(this, wxID_CANCEL, _("&Cancel"), wxDefaultPosition, wxDefaultSize, buttonStyle);
452 #ifndef __WXMAC__
453 if (GetExtraStyle() & wxWIZARD_EX_HELPBUTTON)
454 btnHelp=new wxButton(this, wxID_HELP, _("&Help"), wxDefaultPosition, wxDefaultSize, buttonStyle);
455 #endif
456 m_btnPrev = new wxButton(this, wxID_BACKWARD, _("< &Back"), wxDefaultPosition, wxDefaultSize, buttonStyle);
457
458 if (btnHelp)
459 {
460 buttonRow->Add(
461 btnHelp,
462 0, // Horizontally unstretchable
463 wxALL, // Border all around, top aligned
464 5 // Border width
465 );
466 #ifdef __WXMAC__
467 // Put stretchable space between help button and others
468 buttonRow->Add(0, 0, 1, wxALIGN_CENTRE, 0);
469 #endif
470 }
471
472 AddBackNextPair(buttonRow);
473
474 buttonRow->Add(
475 btnCancel,
476 0, // Horizontally unstretchable
477 wxALL, // Border all around, top aligned
478 5 // Border width
479 );
480 }
481
482 void wxWizard::DoCreateControls()
483 {
484 // do nothing if the controls were already created
485 if ( WasCreated() )
486 return;
487
488 bool isPda = (wxSystemSettings::GetScreenType() <= wxSYS_SCREEN_PDA);
489
490 // Horizontal stretching, and if not PDA, border all around
491 int mainColumnSizerFlags = isPda ? wxEXPAND : wxALL|wxEXPAND ;
492
493 // wxWindow::SetSizer will be called at end
494 wxBoxSizer *windowSizer = new wxBoxSizer(wxVERTICAL);
495
496 wxBoxSizer *mainColumn = new wxBoxSizer(wxVERTICAL);
497 windowSizer->Add(
498 mainColumn,
499 1, // Vertical stretching
500 mainColumnSizerFlags,
501 5 // Border width
502 );
503
504 AddBitmapRow(mainColumn);
505
506 if (!isPda)
507 AddStaticLine(mainColumn);
508
509 AddButtonRow(mainColumn);
510
511 SetSizer(windowSizer);
512 }
513
514 void wxWizard::SetPageSize(const wxSize& size)
515 {
516 wxCHECK_RET(!m_started, wxT("wxWizard::SetPageSize after RunWizard"));
517 m_sizePage = size;
518 }
519
520 void wxWizard::FitToPage(const wxWizardPage *page)
521 {
522 wxCHECK_RET(!m_started, wxT("wxWizard::FitToPage after RunWizard"));
523
524 while ( page )
525 {
526 wxSize size = page->GetBestSize();
527
528 m_sizePage.IncTo(size);
529
530 page = page->GetNext();
531 }
532 }
533
534 bool wxWizard::ShowPage(wxWizardPage *page, bool goingForward)
535 {
536 wxASSERT_MSG( page != m_page, wxT("this is useless") );
537
538 wxSizerFlags flags(1);
539 flags.Border(wxALL, m_border).Expand();
540
541 if ( !m_started )
542 {
543 if ( m_usingSizer )
544 {
545 m_sizerBmpAndPage->Add(m_sizerPage, flags);
546
547 // now that our layout is computed correctly, hide the pages
548 // artificially shown in wxWizardSizer::Insert() back again
549 m_sizerPage->HidePages();
550 }
551 }
552
553
554 // we'll use this to decide whether we have to change the label of this
555 // button or not (initially the label is "Next")
556 bool btnLabelWasNext = true;
557
558 // remember the old bitmap (if any) to compare with the new one later
559 wxBitmap bmpPrev;
560
561 // check for previous page
562 if ( m_page )
563 {
564 // send the event to the old page
565 wxWizardEvent event(wxEVT_WIZARD_PAGE_CHANGING, GetId(),
566 goingForward, m_page);
567 if ( m_page->GetEventHandler()->ProcessEvent(event) &&
568 !event.IsAllowed() )
569 {
570 // vetoed by the page
571 return false;
572 }
573
574 m_page->Hide();
575
576 btnLabelWasNext = HasNextPage(m_page);
577
578 bmpPrev = m_page->GetBitmap();
579
580 if ( !m_usingSizer )
581 m_sizerBmpAndPage->Detach(m_page);
582 }
583
584 // set the new page
585 m_page = page;
586
587 // is this the end?
588 if ( !m_page )
589 {
590 // terminate successfully
591 if ( IsModal() )
592 {
593 EndModal(wxID_OK);
594 }
595 else
596 {
597 SetReturnCode(wxID_OK);
598 Hide();
599 }
600
601 // and notify the user code (this is especially useful for modeless
602 // wizards)
603 wxWizardEvent event(wxEVT_WIZARD_FINISHED, GetId(), false, 0);
604 (void)GetEventHandler()->ProcessEvent(event);
605
606 return true;
607 }
608
609 // position and show the new page
610 (void)m_page->TransferDataToWindow();
611
612 if ( m_usingSizer )
613 {
614 // wxWizardSizer::RecalcSizes wants to be called when m_page changes
615 m_sizerPage->RecalcSizes();
616 }
617 else // pages are not managed by the sizer
618 {
619 m_sizerBmpAndPage->Add(m_page, flags);
620 m_sizerBmpAndPage->SetItemMinSize(m_page, GetPageSize());
621 }
622
623 #if wxUSE_STATBMP
624 // update the bitmap if:it changed
625 if ( m_statbmp )
626 {
627 wxBitmap bmp = m_page->GetBitmap();
628 if ( !bmp.Ok() )
629 bmp = m_bitmap;
630
631 if ( !bmpPrev.Ok() )
632 bmpPrev = m_bitmap;
633
634 if ( bmp != bmpPrev )
635 m_statbmp->SetBitmap(bmp);
636 }
637 #endif // wxUSE_STATBMP
638
639
640 // and update the buttons state
641 m_btnPrev->Enable(HasPrevPage(m_page));
642
643 bool hasNext = HasNextPage(m_page);
644 if ( btnLabelWasNext != hasNext )
645 {
646 m_btnNext->SetLabel(hasNext ? _("&Next >") : _("&Finish"));
647 }
648 // nothing to do: the label was already correct
649
650 m_btnNext->SetDefault();
651
652
653 // send the change event to the new page now
654 wxWizardEvent event(wxEVT_WIZARD_PAGE_CHANGED, GetId(), goingForward, m_page);
655 (void)m_page->GetEventHandler()->ProcessEvent(event);
656
657 // and finally show it
658 m_page->Show();
659 m_page->SetFocus();
660
661 if ( !m_usingSizer )
662 m_sizerBmpAndPage->Layout();
663
664 if ( !m_started )
665 {
666 m_started = true;
667
668 if ( wxSystemSettings::GetScreenType() > wxSYS_SCREEN_PDA )
669 {
670 GetSizer()->SetSizeHints(this);
671 if ( m_posWizard == wxDefaultPosition )
672 CentreOnScreen();
673 }
674 }
675
676 return true;
677 }
678
679 bool wxWizard::RunWizard(wxWizardPage *firstPage)
680 {
681 wxCHECK_MSG( firstPage, false, wxT("can't run empty wizard") );
682
683 // can't return false here because there is no old page
684 (void)ShowPage(firstPage, true /* forward */);
685
686 m_wasModal = true;
687
688 return ShowModal() == wxID_OK;
689 }
690
691 wxWizardPage *wxWizard::GetCurrentPage() const
692 {
693 return m_page;
694 }
695
696 wxSize wxWizard::GetPageSize() const
697 {
698 // default width and height of the page
699 int DEFAULT_PAGE_WIDTH,
700 DEFAULT_PAGE_HEIGHT;
701 if ( wxSystemSettings::GetScreenType() <= wxSYS_SCREEN_PDA )
702 {
703 // Make the default page size small enough to fit on screen
704 DEFAULT_PAGE_WIDTH = wxSystemSettings::GetMetric(wxSYS_SCREEN_X) / 2;
705 DEFAULT_PAGE_HEIGHT = wxSystemSettings::GetMetric(wxSYS_SCREEN_Y) / 2;
706 }
707 else // !PDA
708 {
709 DEFAULT_PAGE_WIDTH =
710 DEFAULT_PAGE_HEIGHT = 270;
711 }
712
713 // start with default minimal size
714 wxSize pageSize(DEFAULT_PAGE_WIDTH, DEFAULT_PAGE_HEIGHT);
715
716 // make the page at least as big as specified by user
717 pageSize.IncTo(m_sizePage);
718
719 if ( m_statbmp )
720 {
721 // make the page at least as tall as the bitmap
722 pageSize.IncTo(wxSize(0, m_bitmap.GetHeight()));
723 }
724
725 if ( m_usingSizer )
726 {
727 // make it big enough to contain all pages added to the sizer
728 pageSize.IncTo(m_sizerPage->GetMaxChildSize());
729 }
730
731 return pageSize;
732 }
733
734 wxSizer *wxWizard::GetPageAreaSizer() const
735 {
736 return m_sizerPage;
737 }
738
739 void wxWizard::SetBorder(int border)
740 {
741 wxCHECK_RET(!m_started, wxT("wxWizard::SetBorder after RunWizard"));
742
743 m_border = border;
744 }
745
746 void wxWizard::OnCancel(wxCommandEvent& WXUNUSED(eventUnused))
747 {
748 // this function probably can never be called when we don't have an active
749 // page, but a small extra check won't hurt
750 wxWindow *win = m_page ? (wxWindow *)m_page : (wxWindow *)this;
751
752 wxWizardEvent event(wxEVT_WIZARD_CANCEL, GetId(), false, m_page);
753 if ( !win->GetEventHandler()->ProcessEvent(event) || event.IsAllowed() )
754 {
755 // no objections - close the dialog
756 if(IsModal())
757 {
758 EndModal(wxID_CANCEL);
759 }
760 else
761 {
762 SetReturnCode(wxID_CANCEL);
763 Hide();
764 }
765 }
766 //else: request to Cancel ignored
767 }
768
769 void wxWizard::OnBackOrNext(wxCommandEvent& event)
770 {
771 wxASSERT_MSG( (event.GetEventObject() == m_btnNext) ||
772 (event.GetEventObject() == m_btnPrev),
773 wxT("unknown button") );
774
775 wxCHECK_RET( m_page, _T("should have a valid current page") );
776
777 // ask the current page first: notice that we do it before calling
778 // GetNext/Prev() because the data transfered from the controls of the page
779 // may change the value returned by these methods
780 if ( !m_page->Validate() || !m_page->TransferDataFromWindow() )
781 {
782 // the page data is incorrect, don't do anything
783 return;
784 }
785
786 bool forward = event.GetEventObject() == m_btnNext;
787
788 wxWizardPage *page;
789 if ( forward )
790 {
791 page = m_page->GetNext();
792 }
793 else // back
794 {
795 page = m_page->GetPrev();
796
797 wxASSERT_MSG( page, wxT("\"<Back\" button should have been disabled") );
798 }
799
800 // just pass to the new page (or maybe not - but we don't care here)
801 (void)ShowPage(page, forward);
802 }
803
804 void wxWizard::OnHelp(wxCommandEvent& WXUNUSED(event))
805 {
806 // this function probably can never be called when we don't have an active
807 // page, but a small extra check won't hurt
808 if(m_page != NULL)
809 {
810 // Create and send the help event to the specific page handler
811 // event data contains the active page so that context-sensitive
812 // help is possible
813 wxWizardEvent eventHelp(wxEVT_WIZARD_HELP, GetId(), true, m_page);
814 (void)m_page->GetEventHandler()->ProcessEvent(eventHelp);
815 }
816 }
817
818 void wxWizard::OnWizEvent(wxWizardEvent& event)
819 {
820 // the dialogs have wxWS_EX_BLOCK_EVENTS style on by default but we want to
821 // propagate wxEVT_WIZARD_XXX to the parent (if any), so do it manually
822 if ( !(GetExtraStyle() & wxWS_EX_BLOCK_EVENTS) )
823 {
824 // the event will be propagated anyhow
825 event.Skip();
826 }
827 else
828 {
829 wxWindow *parent = GetParent();
830
831 if ( !parent || !parent->GetEventHandler()->ProcessEvent(event) )
832 {
833 event.Skip();
834 }
835 }
836
837 if ( ( !m_wasModal ) &&
838 event.IsAllowed() &&
839 ( event.GetEventType() == wxEVT_WIZARD_FINISHED ||
840 event.GetEventType() == wxEVT_WIZARD_CANCEL
841 )
842 )
843 {
844 Destroy();
845 }
846 }
847
848 // ----------------------------------------------------------------------------
849 // wxWizardEvent
850 // ----------------------------------------------------------------------------
851
852 wxWizardEvent::wxWizardEvent(wxEventType type, int id, bool direction, wxWizardPage* page)
853 : wxNotifyEvent(type, id)
854 {
855 // Modified 10-20-2001 Robert Cavanaugh
856 // add the active page to the event data
857 m_direction = direction;
858 m_page = page;
859 }
860
861 #endif // wxUSE_WIZARDDLG