]> git.saurik.com Git - wxWidgets.git/blame - src/generic/wizard.cpp
Use wxIsalnum to test for word delimiters
[wxWidgets.git] / src / generic / wizard.cpp
CommitLineData
66cd017c 1///////////////////////////////////////////////////////////////////////////////
94c09a19 2// Name: src/generic/wizard.cpp
66cd017c
VZ
3// Purpose: generic implementation of wxWizard class
4// Author: Vadim Zeitlin
a0a48a3f
VZ
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
07f20d9a 9// Robert Vazan (sizers)
66cd017c
VZ
10// Created: 15.08.99
11// RCS-ID: $Id$
12// Copyright: (c) 1999 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
65571936 13// Licence: wxWindows licence
66cd017c
VZ
14///////////////////////////////////////////////////////////////////////////////
15
16// ============================================================================
17// declarations
18// ============================================================================
19
20// ----------------------------------------------------------------------------
21// headers
22// ----------------------------------------------------------------------------
23
66cd017c
VZ
24// For compilers that support precompilation, includes "wx.h".
25#include "wx/wxprec.h"
26
27#ifdef __BORLANDC__
28 #pragma hdrstop
29#endif
30
1e6feb95
VZ
31#if wxUSE_WIZARDDLG
32
66cd017c
VZ
33#ifndef WX_PRECOMP
34 #include "wx/dynarray.h"
35 #include "wx/intl.h"
b87654f3 36 #include "wx/statbmp.h"
f6bcfd97 37 #include "wx/button.h"
9eddec69 38 #include "wx/settings.h"
ed2fbeb8 39 #include "wx/sizer.h"
66cd017c
VZ
40#endif //WX_PRECOMP
41
42#include "wx/statline.h"
43
44#include "wx/wizard.h"
45
aedd6d6a
VZ
46// ----------------------------------------------------------------------------
47// wxWizardSizer
48// ----------------------------------------------------------------------------
49
50class wxWizardSizer : public wxSizer
51{
52public:
53 wxWizardSizer(wxWizard *owner);
54
0a9ed8f1
VZ
55 virtual wxSizerItem *Insert(size_t index, wxSizerItem *item);
56
88517d90
VZ
57 virtual void RecalcSizes();
58 virtual wxSize CalcMin();
aedd6d6a 59
88517d90 60 // get the max size of all wizard pages
aedd6d6a 61 wxSize GetMaxChildSize();
88517d90
VZ
62
63 // return the border which can be either set using wxWizard::SetBorder() or
64 // have default value
65 int GetBorder() const;
ca65c044 66
0a9ed8f1
VZ
67 // hide the pages which we temporarily "show" when they're added to this
68 // sizer (see Insert())
69 void HidePages();
70
aedd6d6a
VZ
71private:
72 wxSize SiblingSize(wxSizerItem *child);
ca65c044 73
aedd6d6a 74 wxWizard *m_owner;
aedd6d6a
VZ
75 wxSize m_childSize;
76};
77
66cd017c
VZ
78// ----------------------------------------------------------------------------
79// event tables and such
80// ----------------------------------------------------------------------------
81
2e4df4bf
VZ
82DEFINE_EVENT_TYPE(wxEVT_WIZARD_PAGE_CHANGED)
83DEFINE_EVENT_TYPE(wxEVT_WIZARD_PAGE_CHANGING)
84DEFINE_EVENT_TYPE(wxEVT_WIZARD_CANCEL)
1d30a0a1 85DEFINE_EVENT_TYPE(wxEVT_WIZARD_FINISHED)
f80bf901 86DEFINE_EVENT_TYPE(wxEVT_WIZARD_HELP)
2e4df4bf 87
74b31181
VZ
88BEGIN_EVENT_TABLE(wxWizard, wxDialog)
89 EVT_BUTTON(wxID_CANCEL, wxWizard::OnCancel)
f80bf901
VZ
90 EVT_BUTTON(wxID_BACKWARD, wxWizard::OnBackOrNext)
91 EVT_BUTTON(wxID_FORWARD, wxWizard::OnBackOrNext)
92 EVT_BUTTON(wxID_HELP, wxWizard::OnHelp)
91c68292 93
ca65c044
WS
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)
66cd017c
VZ
99END_EVENT_TABLE()
100
74b31181 101IMPLEMENT_DYNAMIC_CLASS(wxWizard, wxDialog)
066f1b7a
SC
102
103/*
ca65c044
WS
104 TODO PROPERTIES :
105 wxWizard
106 extstyle
107 title
066f1b7a
SC
108*/
109
74b31181
VZ
110IMPLEMENT_ABSTRACT_CLASS(wxWizardPage, wxPanel)
111IMPLEMENT_DYNAMIC_CLASS(wxWizardPageSimple, wxWizardPage)
66cd017c
VZ
112IMPLEMENT_DYNAMIC_CLASS(wxWizardEvent, wxNotifyEvent)
113
114// ============================================================================
115// implementation
116// ============================================================================
117
74b31181
VZ
118// ----------------------------------------------------------------------------
119// wxWizardPage
120// ----------------------------------------------------------------------------
121
c7de4135
VS
122void wxWizardPage::Init()
123{
124 m_bitmap = wxNullBitmap;
125}
126
a0a48a3f
VZ
127wxWizardPage::wxWizardPage(wxWizard *parent,
128 const wxBitmap& bitmap,
129 const wxChar *resource)
74b31181 130{
c7de4135
VS
131 Create(parent, bitmap, resource);
132}
91c68292 133
c7de4135
VS
134bool wxWizardPage::Create(wxWizard *parent,
135 const wxBitmap& bitmap,
136 const wxChar *resource)
137{
ca65c044
WS
138 if ( !wxPanel::Create(parent, wxID_ANY) )
139 return false;
c7de4135 140
a0a48a3f
VZ
141 if ( resource != NULL )
142 {
5d5da6f6 143#if wxUSE_WX_RESOURCES
96f4ca42
JJ
144#if 0
145 if ( !LoadFromResource(this, resource) )
a0a48a3f
VZ
146 {
147 wxFAIL_MSG(wxT("wxWizardPage LoadFromResource failed!!!!"));
148 }
96f4ca42 149#endif
c8804076 150#endif // wxUSE_RESOURCES
a0a48a3f
VZ
151 }
152
636d266b 153 m_bitmap = bitmap;
a0a48a3f 154
74b31181
VZ
155 // initially the page is hidden, it's shown only when it becomes current
156 Hide();
91c68292 157
ca65c044 158 return true;
74b31181
VZ
159}
160
161// ----------------------------------------------------------------------------
162// wxWizardPageSimple
163// ----------------------------------------------------------------------------
164
165wxWizardPage *wxWizardPageSimple::GetPrev() const
166{
167 return m_prev;
168}
169
170wxWizardPage *wxWizardPageSimple::GetNext() const
171{
172 return m_next;
173}
07f20d9a
VZ
174
175// ----------------------------------------------------------------------------
176// wxWizardSizer
177// ----------------------------------------------------------------------------
178
07f20d9a 179wxWizardSizer::wxWizardSizer(wxWizard *owner)
0a089246
VZ
180 : m_owner(owner),
181 m_childSize(wxDefaultSize)
07f20d9a 182{
07f20d9a
VZ
183}
184
0a9ed8f1
VZ
185wxSizerItem *wxWizardSizer::Insert(size_t index, wxSizerItem *item)
186{
0a089246
VZ
187 m_owner->m_usingSizer = true;
188
0a9ed8f1
VZ
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
200void 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
07f20d9a
VZ
212void 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 {
0a089246 218 m_owner->m_page->SetSize(wxRect(m_position, m_size));
07f20d9a
VZ
219 }
220}
221
222wxSize wxWizardSizer::CalcMin()
223{
224 return m_owner->GetPageSize();
225}
226
227wxSize wxWizardSizer::GetMaxChildSize()
228{
229#if !defined(__WXDEBUG__)
0a089246 230 if ( m_childSize.IsFullySpecified() )
07f20d9a
VZ
231 return m_childSize;
232#endif
233
234 wxSize maxOfMin;
07f20d9a 235
0a089246
VZ
236 for ( wxSizerItemList::compatibility_iterator childNode = m_children.GetFirst();
237 childNode;
238 childNode = childNode->GetNext() )
07f20d9a
VZ
239 {
240 wxSizerItem *child = childNode->GetData();
241 maxOfMin.IncTo(child->CalcMin());
242 maxOfMin.IncTo(SiblingSize(child));
243 }
244
245#ifdef __WXDEBUG__
0a089246 246 if ( m_childSize.IsFullySpecified() && m_childSize != maxOfMin )
07f20d9a
VZ
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 {
07f20d9a
VZ
259 m_childSize = maxOfMin;
260 }
ca65c044 261
07f20d9a
VZ
262 return maxOfMin;
263}
264
88517d90 265int wxWizardSizer::GetBorder() const
07f20d9a 266{
0a089246 267 return m_owner->m_border;
07f20d9a
VZ
268}
269
270wxSize wxWizardSizer::SiblingSize(wxSizerItem *child)
271{
272 wxSize maxSibling;
ca65c044 273
07f20d9a
VZ
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 }
ca65c044 290
07f20d9a
VZ
291 return maxSibling;
292}
293
66cd017c
VZ
294// ----------------------------------------------------------------------------
295// generic wxWizard implementation
296// ----------------------------------------------------------------------------
297
77436c4c
JS
298void wxWizard::Init()
299{
300 m_posWizard = wxDefaultPosition;
301 m_page = (wxWizardPage *)NULL;
302 m_btnPrev = m_btnNext = NULL;
303 m_statbmp = NULL;
aedd6d6a 304 m_sizerBmpAndPage = NULL;
07f20d9a 305 m_sizerPage = NULL;
0a089246 306 m_border = 5;
07f20d9a 307 m_started = false;
94c09a19 308 m_wasModal = false;
0a089246 309 m_usingSizer = false;
77436c4c
JS
310}
311
312bool wxWizard::Create(wxWindow *parent,
aedd6d6a
VZ
313 int id,
314 const wxString& title,
315 const wxBitmap& bitmap,
316 const wxPoint& pos,
317 long style)
66cd017c 318{
07f20d9a 319 bool result = wxDialog::Create(parent,id,title,pos,wxDefaultSize,style);
ca65c044 320
77436c4c
JS
321 m_posWizard = pos;
322 m_bitmap = bitmap ;
636d266b 323
07f20d9a 324 DoCreateControls();
ca65c044 325
07f20d9a 326 return result;
f6bcfd97
BP
327}
328
07f20d9a 329void wxWizard::AddBitmapRow(wxBoxSizer *mainColumn)
f6bcfd97 330{
07f20d9a
VZ
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 );
66cd017c 341
461dae94 342#if wxUSE_STATBMP
f6bcfd97 343 if ( m_bitmap.Ok() )
66cd017c 344 {
ca65c044 345 m_statbmp = new wxStaticBitmap(this, wxID_ANY, m_bitmap);
07f20d9a
VZ
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 );
66cd017c 357 }
461dae94 358#endif
f1df0927 359
0a089246 360 // Added to m_sizerBmpAndPage later
07f20d9a
VZ
361 m_sizerPage = new wxWizardSizer(this);
362}
74b31181 363
07f20d9a
VZ
364void wxWizard::AddStaticLine(wxBoxSizer *mainColumn)
365{
74b31181 366#if wxUSE_STATLINE
07f20d9a 367 mainColumn->Add(
ca65c044 368 new wxStaticLine(this, wxID_ANY),
07f20d9a
VZ
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;
f6bcfd97 379#endif // wxUSE_STATLINE
07f20d9a 380}
74b31181 381
07f20d9a
VZ
382void wxWizard::AddBackNextPair(wxBoxSizer *buttonRow)
383{
54cf600d
VZ
384 wxASSERT_MSG( m_btnNext && m_btnPrev,
385 _T("You must create the buttons before calling ")
386 _T("wxWizard::AddBackNextPair") );
387
07f20d9a
VZ
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
66cd017c 394
07f20d9a
VZ
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 );
ca65c044 402
07f20d9a
VZ
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 );
07f20d9a
VZ
408 backNextPair->Add(m_btnNext);
409}
66cd017c 410
07f20d9a
VZ
411void wxWizard::AddButtonRow(wxBoxSizer *mainColumn)
412{
9473e9a4
VZ
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
a6328131 423 bool isPda = (wxSystemSettings::GetScreenType() <= wxSYS_SCREEN_PDA);
94c09a19 424 int buttonStyle = isPda ? wxBU_EXACTFIT : 0;
a6328131 425
07f20d9a 426 wxBoxSizer *buttonRow = new wxBoxSizer(wxHORIZONTAL);
977a3818
JS
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
07f20d9a
VZ
436 mainColumn->Add(
437 buttonRow,
438 0, // Vertically unstretchable
439 wxALIGN_RIGHT // Right aligned, no border
440 );
66cd017c 441
9473e9a4
VZ
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...
977a3818
JS
444 wxButton *btnHelp=0;
445#ifdef __WXMAC__
446 if (GetExtraStyle() & wxWIZARD_EX_HELPBUTTON)
a6328131 447 btnHelp=new wxButton(this, wxID_HELP, _("&Help"), wxDefaultPosition, wxDefaultSize, buttonStyle);
977a3818
JS
448#endif
449
9473e9a4 450 m_btnNext = new wxButton(this, wxID_FORWARD, _("&Next >"));
a6328131 451 wxButton *btnCancel=new wxButton(this, wxID_CANCEL, _("&Cancel"), wxDefaultPosition, wxDefaultSize, buttonStyle);
977a3818 452#ifndef __WXMAC__
07f20d9a 453 if (GetExtraStyle() & wxWIZARD_EX_HELPBUTTON)
a6328131 454 btnHelp=new wxButton(this, wxID_HELP, _("&Help"), wxDefaultPosition, wxDefaultSize, buttonStyle);
977a3818 455#endif
a6328131 456 m_btnPrev = new wxButton(this, wxID_BACKWARD, _("< &Back"), wxDefaultPosition, wxDefaultSize, buttonStyle);
9473e9a4
VZ
457
458 if (btnHelp)
977a3818 459 {
07f20d9a 460 buttonRow->Add(
9473e9a4 461 btnHelp,
07f20d9a
VZ
462 0, // Horizontally unstretchable
463 wxALL, // Border all around, top aligned
464 5 // Border width
977a3818
JS
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 }
07f20d9a
VZ
471
472 AddBackNextPair(buttonRow);
ca65c044 473
07f20d9a 474 buttonRow->Add(
9473e9a4 475 btnCancel,
07f20d9a
VZ
476 0, // Horizontally unstretchable
477 wxALL, // Border all around, top aligned
478 5 // Border width
479 );
480}
66cd017c 481
07f20d9a
VZ
482void wxWizard::DoCreateControls()
483{
484 // do nothing if the controls were already created
485 if ( WasCreated() )
486 return;
ca65c044 487
a6328131 488 bool isPda = (wxSystemSettings::GetScreenType() <= wxSYS_SCREEN_PDA);
94c09a19 489
a6328131
JS
490 // Horizontal stretching, and if not PDA, border all around
491 int mainColumnSizerFlags = isPda ? wxEXPAND : wxALL|wxEXPAND ;
94c09a19 492
07f20d9a
VZ
493 // wxWindow::SetSizer will be called at end
494 wxBoxSizer *windowSizer = new wxBoxSizer(wxVERTICAL);
ca65c044 495
07f20d9a
VZ
496 wxBoxSizer *mainColumn = new wxBoxSizer(wxVERTICAL);
497 windowSizer->Add(
498 mainColumn,
499 1, // Vertical stretching
a6328131 500 mainColumnSizerFlags,
07f20d9a
VZ
501 5 // Border width
502 );
ca65c044 503
07f20d9a 504 AddBitmapRow(mainColumn);
94c09a19 505
a6328131
JS
506 if (!isPda)
507 AddStaticLine(mainColumn);
94c09a19 508
07f20d9a 509 AddButtonRow(mainColumn);
ca65c044 510
07f20d9a 511 SetSizer(windowSizer);
66cd017c
VZ
512}
513
f6bcfd97
BP
514void wxWizard::SetPageSize(const wxSize& size)
515{
0a089246 516 wxCHECK_RET(!m_started, wxT("wxWizard::SetPageSize after RunWizard"));
f6bcfd97
BP
517 m_sizePage = size;
518}
519
07f20d9a
VZ
520void wxWizard::FitToPage(const wxWizardPage *page)
521{
0a089246 522 wxCHECK_RET(!m_started, wxT("wxWizard::FitToPage after RunWizard"));
ca65c044 523
c73b439f
VZ
524 while ( page )
525 {
526 wxSize size = page->GetBestSize();
527
07f20d9a 528 m_sizePage.IncTo(size);
c73b439f
VZ
529
530 page = page->GetNext();
531 }
c73b439f
VZ
532}
533
74b31181 534bool wxWizard::ShowPage(wxWizardPage *page, bool goingForward)
66cd017c 535{
223d09f6 536 wxASSERT_MSG( page != m_page, wxT("this is useless") );
66cd017c 537
0a089246
VZ
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
74b31181
VZ
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")
ca65c044 556 bool btnLabelWasNext = true;
66cd017c 557
0a089246
VZ
558 // remember the old bitmap (if any) to compare with the new one later
559 wxBitmap bmpPrev;
7cc5041d
VZ
560
561 // check for previous page
74b31181 562 if ( m_page )
66cd017c 563 {
74b31181 564 // send the event to the old page
0a089246
VZ
565 wxWizardEvent event(wxEVT_WIZARD_PAGE_CHANGING, GetId(),
566 goingForward, m_page);
74b31181
VZ
567 if ( m_page->GetEventHandler()->ProcessEvent(event) &&
568 !event.IsAllowed() )
569 {
570 // vetoed by the page
ca65c044 571 return false;
74b31181 572 }
66cd017c 573
74b31181
VZ
574 m_page->Hide();
575
2b5f62a0 576 btnLabelWasNext = HasNextPage(m_page);
7cc5041d 577
0a089246
VZ
578 bmpPrev = m_page->GetBitmap();
579
580 if ( !m_usingSizer )
581 m_sizerBmpAndPage->Detach(m_page);
dee5b92f 582 }
66cd017c 583
7cc5041d 584 // set the new page
66cd017c 585 m_page = page;
66cd017c 586
74b31181
VZ
587 // is this the end?
588 if ( !m_page )
66cd017c 589 {
74b31181 590 // terminate successfully
0a089246 591 if ( IsModal() )
b3eb133b
WS
592 {
593 EndModal(wxID_OK);
594 }
595 else
596 {
597 SetReturnCode(wxID_OK);
598 Hide();
599 }
64c2fa13
VZ
600
601 // and notify the user code (this is especially useful for modeless
602 // wizards)
ca65c044 603 wxWizardEvent event(wxEVT_WIZARD_FINISHED, GetId(), false, 0);
64c2fa13
VZ
604 (void)GetEventHandler()->ProcessEvent(event);
605
ca65c044 606 return true;
74b31181 607 }
66cd017c 608
74b31181
VZ
609 // position and show the new page
610 (void)m_page->TransferDataToWindow();
ca65c044 611
0a089246 612 if ( m_usingSizer )
7cc5041d 613 {
0a089246
VZ
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());
7cc5041d
VZ
621 }
622
461dae94 623#if wxUSE_STATBMP
0a089246
VZ
624 // update the bitmap if:it changed
625 if ( m_statbmp )
f1df0927 626 {
0a089246
VZ
627 wxBitmap bmp = m_page->GetBitmap();
628 if ( !bmp.Ok() )
cfd88569 629 bmp = m_bitmap;
0a089246
VZ
630
631 if ( !bmpPrev.Ok() )
632 bmpPrev = m_bitmap;
633
634 if ( bmp != bmpPrev )
635 m_statbmp->SetBitmap(bmp);
f1df0927 636 }
0a089246
VZ
637#endif // wxUSE_STATBMP
638
f1df0927 639
74b31181 640 // and update the buttons state
2b5f62a0 641 m_btnPrev->Enable(HasPrevPage(m_page));
66cd017c 642
2b5f62a0 643 bool hasNext = HasNextPage(m_page);
8f177c8e 644 if ( btnLabelWasNext != hasNext )
66cd017c 645 {
0a089246 646 m_btnNext->SetLabel(hasNext ? _("&Next >") : _("&Finish"));
66cd017c 647 }
74b31181 648 // nothing to do: the label was already correct
66cd017c 649
0a089246
VZ
650 m_btnNext->SetDefault();
651
652
5bc28e84 653 // send the change event to the new page now
2365e5cb 654 wxWizardEvent event(wxEVT_WIZARD_PAGE_CHANGED, GetId(), goingForward, m_page);
5bc28e84
VZ
655 (void)m_page->GetEventHandler()->ProcessEvent(event);
656
657 // and finally show it
658 m_page->Show();
659 m_page->SetFocus();
660
0a089246
VZ
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
ca65c044 676 return true;
66cd017c
VZ
677}
678
74b31181 679bool wxWizard::RunWizard(wxWizardPage *firstPage)
66cd017c 680{
ca65c044
WS
681 wxCHECK_MSG( firstPage, false, wxT("can't run empty wizard") );
682
ca65c044
WS
683 // can't return false here because there is no old page
684 (void)ShowPage(firstPage, true /* forward */);
66cd017c 685
94c09a19 686 m_wasModal = true;
37f6a080 687
66cd017c
VZ
688 return ShowModal() == wxID_OK;
689}
690
74b31181 691wxWizardPage *wxWizard::GetCurrentPage() const
66cd017c 692{
74b31181 693 return m_page;
66cd017c
VZ
694}
695
4fe5383d 696wxSize wxWizard::GetPageSize() const
07f20d9a
VZ
697{
698 // default width and height of the page
0a089246
VZ
699 int DEFAULT_PAGE_WIDTH,
700 DEFAULT_PAGE_HEIGHT;
701 if ( wxSystemSettings::GetScreenType() <= wxSYS_SCREEN_PDA )
a6328131
JS
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 }
0a089246
VZ
707 else // !PDA
708 {
709 DEFAULT_PAGE_WIDTH =
710 DEFAULT_PAGE_HEIGHT = 270;
711 }
94c09a19 712
0a089246
VZ
713 // start with default minimal size
714 wxSize pageSize(DEFAULT_PAGE_WIDTH, DEFAULT_PAGE_HEIGHT);
ca65c044 715
0a089246
VZ
716 // make the page at least as big as specified by user
717 pageSize.IncTo(m_sizePage);
ca65c044 718
aedd6d6a
VZ
719 if ( m_statbmp )
720 {
0a089246
VZ
721 // make the page at least as tall as the bitmap
722 pageSize.IncTo(wxSize(0, m_bitmap.GetHeight()));
aedd6d6a 723 }
ca65c044 724
0a089246
VZ
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
734wxSizer *wxWizard::GetPageAreaSizer() const
735{
736 return m_sizerPage;
737}
738
739void wxWizard::SetBorder(int border)
740{
741 wxCHECK_RET(!m_started, wxT("wxWizard::SetBorder after RunWizard"));
742
743 m_border = border;
4fe5383d
VZ
744}
745
20f18ea1 746void wxWizard::OnCancel(wxCommandEvent& WXUNUSED(eventUnused))
66cd017c 747{
74b31181
VZ
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
ca65c044 752 wxWizardEvent event(wxEVT_WIZARD_CANCEL, GetId(), false, m_page);
74b31181 753 if ( !win->GetEventHandler()->ProcessEvent(event) || event.IsAllowed() )
66cd017c
VZ
754 {
755 // no objections - close the dialog
b3eb133b
WS
756 if(IsModal())
757 {
758 EndModal(wxID_CANCEL);
759 }
760 else
761 {
762 SetReturnCode(wxID_CANCEL);
763 Hide();
764 }
66cd017c
VZ
765 }
766 //else: request to Cancel ignored
767}
768
74b31181 769void wxWizard::OnBackOrNext(wxCommandEvent& event)
66cd017c
VZ
770{
771 wxASSERT_MSG( (event.GetEventObject() == m_btnNext) ||
772 (event.GetEventObject() == m_btnPrev),
223d09f6 773 wxT("unknown button") );
66cd017c 774
47e64664
VZ
775 wxCHECK_RET( m_page, _T("should have a valid current page") );
776
f6bcfd97
BP
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
47e64664 780 if ( !m_page->Validate() || !m_page->TransferDataFromWindow() )
f6bcfd97
BP
781 {
782 // the page data is incorrect, don't do anything
783 return;
784 }
785
74b31181 786 bool forward = event.GetEventObject() == m_btnNext;
66cd017c 787
74b31181
VZ
788 wxWizardPage *page;
789 if ( forward )
66cd017c 790 {
74b31181 791 page = m_page->GetNext();
66cd017c 792 }
74b31181 793 else // back
66cd017c 794 {
74b31181
VZ
795 page = m_page->GetPrev();
796
223d09f6 797 wxASSERT_MSG( page, wxT("\"<Back\" button should have been disabled") );
66cd017c 798 }
74b31181 799
0a089246 800 // just pass to the new page (or maybe not - but we don't care here)
74b31181 801 (void)ShowPage(page, forward);
66cd017c
VZ
802}
803
f80bf901
VZ
804void 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
ca65c044 813 wxWizardEvent eventHelp(wxEVT_WIZARD_HELP, GetId(), true, m_page);
f80bf901
VZ
814 (void)m_page->GetEventHandler()->ProcessEvent(eventHelp);
815 }
816}
817
91c68292
VZ
818void 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
0a640208 825 event.Skip();
91c68292 826 }
b3eb133b
WS
827 else
828 {
829 wxWindow *parent = GetParent();
91c68292 830
b3eb133b
WS
831 if ( !parent || !parent->GetEventHandler()->ProcessEvent(event) )
832 {
833 event.Skip();
834 }
835 }
37f6a080 836
94c09a19 837 if ( ( !m_wasModal ) &&
37f6a080
JS
838 event.IsAllowed() &&
839 ( event.GetEventType() == wxEVT_WIZARD_FINISHED ||
840 event.GetEventType() == wxEVT_WIZARD_CANCEL
841 )
842 )
843 {
37f6a080
JS
844 Destroy();
845 }
91c68292 846}
f80bf901 847
66cd017c
VZ
848// ----------------------------------------------------------------------------
849// wxWizardEvent
850// ----------------------------------------------------------------------------
851
f80bf901 852wxWizardEvent::wxWizardEvent(wxEventType type, int id, bool direction, wxWizardPage* page)
66cd017c
VZ
853 : wxNotifyEvent(type, id)
854{
f80bf901
VZ
855 // Modified 10-20-2001 Robert Cavanaugh
856 // add the active page to the event data
74b31181 857 m_direction = direction;
f80bf901 858 m_page = page;
66cd017c 859}
74b31181 860
1e6feb95 861#endif // wxUSE_WIZARDDLG