~brian-sidebotham/wxwidgets-cmake/wxpython-2.9.4

« back to all changes in this revision

Viewing changes to src/generic/wizard.cpp

  • Committer: Brian Sidebotham
  • Date: 2013-08-03 14:30:08 UTC
  • Revision ID: brian.sidebotham@gmail.com-20130803143008-c7806tkych1tp6fc
Initial import into Bazaar

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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: wizard.cpp 70630 2012-02-20 11:38:52Z JS $
 
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
    #include "wx/sizer.h"
 
40
#endif //WX_PRECOMP
 
41
 
 
42
#include "wx/statline.h"
 
43
 
 
44
#include "wx/scrolwin.h"
 
45
#include "wx/wizard.h"
 
46
#include "wx/dcmemory.h"
 
47
 
 
48
// ----------------------------------------------------------------------------
 
49
// wxWizardSizer
 
50
// ----------------------------------------------------------------------------
 
51
 
 
52
class wxWizardSizer : public wxSizer
 
53
{
 
54
public:
 
55
    wxWizardSizer(wxWizard *owner);
 
56
 
 
57
    virtual wxSizerItem *Insert(size_t index, wxSizerItem *item);
 
58
 
 
59
    virtual void RecalcSizes();
 
60
    virtual wxSize CalcMin();
 
61
 
 
62
    // get the max size of all wizard pages
 
63
    wxSize GetMaxChildSize();
 
64
 
 
65
    // return the border which can be either set using wxWizard::SetBorder() or
 
66
    // have default value
 
67
    int GetBorder() const;
 
68
 
 
69
    // hide the pages which we temporarily "show" when they're added to this
 
70
    // sizer (see Insert())
 
71
    void HidePages();
 
72
 
 
73
private:
 
74
    wxSize SiblingSize(wxSizerItem *child);
 
75
 
 
76
    wxWizard *m_owner;
 
77
    wxSize m_childSize;
 
78
};
 
79
 
 
80
// ----------------------------------------------------------------------------
 
81
// event tables and such
 
82
// ----------------------------------------------------------------------------
 
83
 
 
84
wxDEFINE_EVENT( wxEVT_WIZARD_PAGE_CHANGED, wxWizardEvent );
 
85
wxDEFINE_EVENT( wxEVT_WIZARD_PAGE_CHANGING, wxWizardEvent );
 
86
wxDEFINE_EVENT( wxEVT_WIZARD_BEFORE_PAGE_CHANGED, wxWizardEvent );
 
87
wxDEFINE_EVENT( wxEVT_WIZARD_CANCEL, wxWizardEvent );
 
88
wxDEFINE_EVENT( wxEVT_WIZARD_FINISHED, wxWizardEvent );
 
89
wxDEFINE_EVENT( wxEVT_WIZARD_HELP, wxWizardEvent );
 
90
wxDEFINE_EVENT( wxEVT_WIZARD_PAGE_SHOWN, wxWizardEvent );
 
91
 
 
92
BEGIN_EVENT_TABLE(wxWizard, wxDialog)
 
93
    EVT_BUTTON(wxID_CANCEL, wxWizard::OnCancel)
 
94
    EVT_BUTTON(wxID_BACKWARD, wxWizard::OnBackOrNext)
 
95
    EVT_BUTTON(wxID_FORWARD, wxWizard::OnBackOrNext)
 
96
    EVT_BUTTON(wxID_HELP, wxWizard::OnHelp)
 
97
 
 
98
    EVT_WIZARD_PAGE_CHANGED(wxID_ANY, wxWizard::OnWizEvent)
 
99
    EVT_WIZARD_PAGE_CHANGING(wxID_ANY, wxWizard::OnWizEvent)
 
100
    EVT_WIZARD_CANCEL(wxID_ANY, wxWizard::OnWizEvent)
 
101
    EVT_WIZARD_FINISHED(wxID_ANY, wxWizard::OnWizEvent)
 
102
    EVT_WIZARD_HELP(wxID_ANY, wxWizard::OnWizEvent)
 
103
END_EVENT_TABLE()
 
104
 
 
105
IMPLEMENT_DYNAMIC_CLASS(wxWizard, wxDialog)
 
106
 
 
107
/*
 
108
    TODO PROPERTIES :
 
109
    wxWizard
 
110
        extstyle
 
111
        title
 
112
*/
 
113
 
 
114
IMPLEMENT_ABSTRACT_CLASS(wxWizardPage, wxPanel)
 
115
IMPLEMENT_DYNAMIC_CLASS(wxWizardPageSimple, wxWizardPage)
 
116
IMPLEMENT_DYNAMIC_CLASS(wxWizardEvent, wxNotifyEvent)
 
117
 
 
118
// ============================================================================
 
119
// implementation
 
120
// ============================================================================
 
121
 
 
122
// ----------------------------------------------------------------------------
 
123
// wxWizardPage
 
124
// ----------------------------------------------------------------------------
 
125
 
 
126
void wxWizardPage::Init()
 
127
{
 
128
    m_bitmap = wxNullBitmap;
 
129
}
 
130
 
 
131
wxWizardPage::wxWizardPage(wxWizard *parent,
 
132
                           const wxBitmap& bitmap)
 
133
{
 
134
    Create(parent, bitmap);
 
135
}
 
136
 
 
137
bool wxWizardPage::Create(wxWizard *parent,
 
138
                          const wxBitmap& bitmap)
 
139
{
 
140
    if ( !wxPanel::Create(parent, wxID_ANY) )
 
141
        return false;
 
142
 
 
143
    m_bitmap = bitmap;
 
144
 
 
145
    // initially the page is hidden, it's shown only when it becomes current
 
146
    Hide();
 
147
 
 
148
    return true;
 
149
}
 
150
 
 
151
// ----------------------------------------------------------------------------
 
152
// wxWizardPageSimple
 
153
// ----------------------------------------------------------------------------
 
154
 
 
155
wxWizardPage *wxWizardPageSimple::GetPrev() const
 
156
{
 
157
    return m_prev;
 
158
}
 
159
 
 
160
wxWizardPage *wxWizardPageSimple::GetNext() const
 
161
{
 
162
    return m_next;
 
163
}
 
164
 
 
165
// ----------------------------------------------------------------------------
 
166
// wxWizardSizer
 
167
// ----------------------------------------------------------------------------
 
168
 
 
169
wxWizardSizer::wxWizardSizer(wxWizard *owner)
 
170
             : m_owner(owner),
 
171
               m_childSize(wxDefaultSize)
 
172
{
 
173
}
 
174
 
 
175
wxSizerItem *wxWizardSizer::Insert(size_t index, wxSizerItem *item)
 
176
{
 
177
    m_owner->m_usingSizer = true;
 
178
 
 
179
    if ( item->IsWindow() )
 
180
    {
 
181
        // we must pretend that the window is shown as otherwise it wouldn't be
 
182
        // taken into account for the layout -- but avoid really showing it, so
 
183
        // just set the internal flag instead of calling wxWindow::Show()
 
184
        item->GetWindow()->wxWindowBase::Show();
 
185
    }
 
186
 
 
187
    return wxSizer::Insert(index, item);
 
188
}
 
189
 
 
190
void wxWizardSizer::HidePages()
 
191
{
 
192
    for ( wxSizerItemList::compatibility_iterator node = GetChildren().GetFirst();
 
193
          node;
 
194
          node = node->GetNext() )
 
195
    {
 
196
        wxSizerItem * const item = node->GetData();
 
197
        if ( item->IsWindow() )
 
198
            item->GetWindow()->wxWindowBase::Show(false);
 
199
    }
 
200
}
 
201
 
 
202
void wxWizardSizer::RecalcSizes()
 
203
{
 
204
    // Effect of this function depends on m_owner->m_page and
 
205
    // it should be called whenever it changes (wxWizard::ShowPage)
 
206
    if ( m_owner->m_page )
 
207
    {
 
208
        m_owner->m_page->SetSize(wxRect(m_position, m_size));
 
209
    }
 
210
}
 
211
 
 
212
wxSize wxWizardSizer::CalcMin()
 
213
{
 
214
    return m_owner->GetPageSize();
 
215
}
 
216
 
 
217
wxSize wxWizardSizer::GetMaxChildSize()
 
218
{
 
219
    wxSize maxOfMin;
 
220
 
 
221
    for ( wxSizerItemList::compatibility_iterator childNode = m_children.GetFirst();
 
222
          childNode;
 
223
          childNode = childNode->GetNext() )
 
224
    {
 
225
        wxSizerItem *child = childNode->GetData();
 
226
        maxOfMin.IncTo(child->CalcMin());
 
227
        maxOfMin.IncTo(SiblingSize(child));
 
228
    }
 
229
 
 
230
    if ( m_owner->m_started )
 
231
    {
 
232
        m_childSize = maxOfMin;
 
233
    }
 
234
 
 
235
    return maxOfMin;
 
236
}
 
237
 
 
238
int wxWizardSizer::GetBorder() const
 
239
{
 
240
    return m_owner->m_border;
 
241
}
 
242
 
 
243
wxSize wxWizardSizer::SiblingSize(wxSizerItem *child)
 
244
{
 
245
    wxSize maxSibling;
 
246
 
 
247
    if ( child->IsWindow() )
 
248
    {
 
249
        wxWizardPage *page = wxDynamicCast(child->GetWindow(), wxWizardPage);
 
250
        if ( page )
 
251
        {
 
252
            for ( wxWizardPage *sibling = page->GetNext();
 
253
                  sibling;
 
254
                  sibling = sibling->GetNext() )
 
255
            {
 
256
                if ( sibling->GetSizer() )
 
257
                {
 
258
                    maxSibling.IncTo(sibling->GetSizer()->CalcMin());
 
259
                }
 
260
            }
 
261
        }
 
262
    }
 
263
 
 
264
    return maxSibling;
 
265
}
 
266
 
 
267
// ----------------------------------------------------------------------------
 
268
// generic wxWizard implementation
 
269
// ----------------------------------------------------------------------------
 
270
 
 
271
void wxWizard::Init()
 
272
{
 
273
    m_posWizard = wxDefaultPosition;
 
274
    m_page = NULL;
 
275
    m_btnPrev = m_btnNext = NULL;
 
276
    m_statbmp = NULL;
 
277
    m_sizerBmpAndPage = NULL;
 
278
    m_sizerPage = NULL;
 
279
    m_border = 5;
 
280
    m_started = false;
 
281
    m_wasModal = false;
 
282
    m_usingSizer = false;
 
283
    m_bitmapBackgroundColour = *wxWHITE;
 
284
    m_bitmapPlacement = 0;
 
285
    m_bitmapMinimumWidth = 115;
 
286
}
 
287
 
 
288
bool wxWizard::Create(wxWindow *parent,
 
289
                      int id,
 
290
                      const wxString& title,
 
291
                      const wxBitmap& bitmap,
 
292
                      const wxPoint& pos,
 
293
                      long style)
 
294
{
 
295
    bool result = wxDialog::Create(parent,id,title,pos,wxDefaultSize,style);
 
296
 
 
297
    m_posWizard = pos;
 
298
    m_bitmap = bitmap ;
 
299
 
 
300
    DoCreateControls();
 
301
 
 
302
    return result;
 
303
}
 
304
 
 
305
wxWizard::~wxWizard()
 
306
{
 
307
    // normally we don't have to delete this sizer as it's deleted by the
 
308
    // associated window but if we never used it or didn't set it as the window
 
309
    // sizer yet, do delete it manually
 
310
    if ( !m_usingSizer || !m_started )
 
311
        delete m_sizerPage;
 
312
}
 
313
 
 
314
void wxWizard::AddBitmapRow(wxBoxSizer *mainColumn)
 
315
{
 
316
    m_sizerBmpAndPage = new wxBoxSizer(wxHORIZONTAL);
 
317
    mainColumn->Add(
 
318
        m_sizerBmpAndPage,
 
319
        1, // Vertically stretchable
 
320
        wxEXPAND // Horizontal stretching, no border
 
321
    );
 
322
    mainColumn->Add(0,5,
 
323
        0, // No vertical stretching
 
324
        wxEXPAND // No border, (mostly useless) horizontal stretching
 
325
    );
 
326
 
 
327
#if wxUSE_STATBMP
 
328
    if ( m_bitmap.IsOk() )
 
329
    {
 
330
        wxSize bitmapSize(wxDefaultSize);
 
331
        if (GetBitmapPlacement())
 
332
            bitmapSize.x = GetMinimumBitmapWidth();
 
333
 
 
334
        m_statbmp = new wxStaticBitmap(this, wxID_ANY, m_bitmap, wxDefaultPosition, bitmapSize);
 
335
        m_sizerBmpAndPage->Add(
 
336
            m_statbmp,
 
337
            0, // No horizontal stretching
 
338
            wxALL, // Border all around, top alignment
 
339
            5 // Border width
 
340
        );
 
341
        m_sizerBmpAndPage->Add(
 
342
            5,0,
 
343
            0, // No horizontal stretching
 
344
            wxEXPAND // No border, (mostly useless) vertical stretching
 
345
        );
 
346
    }
 
347
#endif
 
348
 
 
349
    // Added to m_sizerBmpAndPage later
 
350
    m_sizerPage = new wxWizardSizer(this);
 
351
}
 
352
 
 
353
void wxWizard::AddStaticLine(wxBoxSizer *mainColumn)
 
354
{
 
355
#if wxUSE_STATLINE
 
356
    mainColumn->Add(
 
357
        new wxStaticLine(this, wxID_ANY),
 
358
        0, // Vertically unstretchable
 
359
        wxEXPAND | wxALL, // Border all around, horizontally stretchable
 
360
        5 // Border width
 
361
    );
 
362
    mainColumn->Add(0,5,
 
363
        0, // No vertical stretching
 
364
        wxEXPAND // No border, (mostly useless) horizontal stretching
 
365
    );
 
366
#else
 
367
    (void)mainColumn;
 
368
#endif // wxUSE_STATLINE
 
369
}
 
370
 
 
371
void wxWizard::AddBackNextPair(wxBoxSizer *buttonRow)
 
372
{
 
373
    wxASSERT_MSG( m_btnNext && m_btnPrev,
 
374
                  wxT("You must create the buttons before calling ")
 
375
                  wxT("wxWizard::AddBackNextPair") );
 
376
 
 
377
    wxBoxSizer *backNextPair = new wxBoxSizer(wxHORIZONTAL);
 
378
    buttonRow->Add(
 
379
        backNextPair,
 
380
        0, // No horizontal stretching
 
381
        wxALL, // Border all around
 
382
        5 // Border width
 
383
    );
 
384
 
 
385
    backNextPair->Add(m_btnPrev);
 
386
    backNextPair->Add(10, 0,
 
387
        0, // No horizontal stretching
 
388
        wxEXPAND // No border, (mostly useless) vertical stretching
 
389
    );
 
390
    backNextPair->Add(m_btnNext);
 
391
}
 
392
 
 
393
void wxWizard::AddButtonRow(wxBoxSizer *mainColumn)
 
394
{
 
395
    // the order in which the buttons are created determines the TAB order - at least under MSWindows...
 
396
    // although the 'back' button appears before the 'next' button, a more userfriendly tab order is
 
397
    // to activate the 'next' button first (create the next button before the back button).
 
398
    // The reason is: The user will repeatedly enter information in the wizard pages and then wants to
 
399
    // press 'next'. If a user uses mostly the keyboard, he would have to skip the 'back' button
 
400
    // every time. This is annoying. There is a second reason: RETURN acts as TAB. If the 'next'
 
401
    // button comes first in the TAB order, the user can enter information very fast using the RETURN
 
402
    // key to TAB to the next entry field and page. This would not be possible, if the 'back' button
 
403
    // was created before the 'next' button.
 
404
 
 
405
    bool isPda = (wxSystemSettings::GetScreenType() <= wxSYS_SCREEN_PDA);
 
406
    int buttonStyle = isPda ? wxBU_EXACTFIT : 0;
 
407
 
 
408
    wxBoxSizer *buttonRow = new wxBoxSizer(wxHORIZONTAL);
 
409
#ifdef __WXMAC__
 
410
    if (GetExtraStyle() & wxWIZARD_EX_HELPBUTTON)
 
411
        mainColumn->Add(
 
412
            buttonRow,
 
413
            0, // Vertically unstretchable
 
414
            wxGROW|wxALIGN_CENTRE
 
415
            );
 
416
    else
 
417
#endif
 
418
    mainColumn->Add(
 
419
        buttonRow,
 
420
        0, // Vertically unstretchable
 
421
        wxALIGN_RIGHT // Right aligned, no border
 
422
    );
 
423
 
 
424
    // Desired TAB order is 'next', 'cancel', 'help', 'back'. This makes the 'back' button the last control on the page.
 
425
    // Create the buttons in the right order...
 
426
    wxButton *btnHelp=0;
 
427
#ifdef __WXMAC__
 
428
    if (GetExtraStyle() & wxWIZARD_EX_HELPBUTTON)
 
429
        btnHelp=new wxButton(this, wxID_HELP, wxEmptyString, wxDefaultPosition, wxDefaultSize, buttonStyle);
 
430
#endif
 
431
 
 
432
    m_btnNext = new wxButton(this, wxID_FORWARD, _("&Next >"));
 
433
    wxButton *btnCancel=new wxButton(this, wxID_CANCEL, _("&Cancel"), wxDefaultPosition, wxDefaultSize, buttonStyle);
 
434
#ifndef __WXMAC__
 
435
    if (GetExtraStyle() & wxWIZARD_EX_HELPBUTTON)
 
436
        btnHelp=new wxButton(this, wxID_HELP, _("&Help"), wxDefaultPosition, wxDefaultSize, buttonStyle);
 
437
#endif
 
438
    m_btnPrev = new wxButton(this, wxID_BACKWARD, _("< &Back"), wxDefaultPosition, wxDefaultSize, buttonStyle);
 
439
 
 
440
    if (btnHelp)
 
441
    {
 
442
        buttonRow->Add(
 
443
            btnHelp,
 
444
            0, // Horizontally unstretchable
 
445
            wxALL, // Border all around, top aligned
 
446
            5 // Border width
 
447
            );
 
448
#ifdef __WXMAC__
 
449
        // Put stretchable space between help button and others
 
450
        buttonRow->Add(0, 0, 1, wxALIGN_CENTRE, 0);
 
451
#endif
 
452
    }
 
453
 
 
454
    AddBackNextPair(buttonRow);
 
455
 
 
456
    buttonRow->Add(
 
457
        btnCancel,
 
458
        0, // Horizontally unstretchable
 
459
        wxALL, // Border all around, top aligned
 
460
        5 // Border width
 
461
    );
 
462
}
 
463
 
 
464
void wxWizard::DoCreateControls()
 
465
{
 
466
    // do nothing if the controls were already created
 
467
    if ( WasCreated() )
 
468
        return;
 
469
 
 
470
    bool isPda = (wxSystemSettings::GetScreenType() <= wxSYS_SCREEN_PDA);
 
471
 
 
472
    // Horizontal stretching, and if not PDA, border all around
 
473
    int mainColumnSizerFlags = isPda ? wxEXPAND : wxALL|wxEXPAND ;
 
474
 
 
475
    // wxWindow::SetSizer will be called at end
 
476
    wxBoxSizer *windowSizer = new wxBoxSizer(wxVERTICAL);
 
477
 
 
478
    wxBoxSizer *mainColumn = new wxBoxSizer(wxVERTICAL);
 
479
    windowSizer->Add(
 
480
        mainColumn,
 
481
        1, // Vertical stretching
 
482
        mainColumnSizerFlags,
 
483
        5 // Border width
 
484
    );
 
485
 
 
486
    AddBitmapRow(mainColumn);
 
487
 
 
488
    if (!isPda)
 
489
        AddStaticLine(mainColumn);
 
490
 
 
491
    AddButtonRow(mainColumn);
 
492
 
 
493
    SetSizer(windowSizer);
 
494
}
 
495
 
 
496
void wxWizard::SetPageSize(const wxSize& size)
 
497
{
 
498
    wxCHECK_RET(!m_started, wxT("wxWizard::SetPageSize after RunWizard"));
 
499
    m_sizePage = size;
 
500
}
 
501
 
 
502
void wxWizard::FitToPage(const wxWizardPage *page)
 
503
{
 
504
    wxCHECK_RET(!m_started, wxT("wxWizard::FitToPage after RunWizard"));
 
505
 
 
506
    while ( page )
 
507
    {
 
508
        wxSize size = page->GetBestSize();
 
509
 
 
510
        m_sizePage.IncTo(size);
 
511
 
 
512
        page = page->GetNext();
 
513
    }
 
514
}
 
515
 
 
516
bool wxWizard::ShowPage(wxWizardPage *page, bool goingForward)
 
517
{
 
518
    wxASSERT_MSG( page != m_page, wxT("this is useless") );
 
519
 
 
520
    wxSizerFlags flags(1);
 
521
    flags.Border(wxALL, m_border).Expand();
 
522
 
 
523
    if ( !m_started )
 
524
    {
 
525
        if ( m_usingSizer )
 
526
        {
 
527
            m_sizerBmpAndPage->Add(m_sizerPage, flags);
 
528
 
 
529
            // now that our layout is computed correctly, hide the pages
 
530
            // artificially shown in wxWizardSizer::Insert() back again
 
531
            m_sizerPage->HidePages();
 
532
        }
 
533
    }
 
534
 
 
535
 
 
536
    // remember the old bitmap (if any) to compare with the new one later
 
537
    wxBitmap bmpPrev;
 
538
 
 
539
    // check for previous page
 
540
    if ( m_page )
 
541
    {
 
542
        // send the event to the old page
 
543
        wxWizardEvent event(wxEVT_WIZARD_PAGE_CHANGING, GetId(),
 
544
                            goingForward, m_page);
 
545
        if ( m_page->GetEventHandler()->ProcessEvent(event) &&
 
546
             !event.IsAllowed() )
 
547
        {
 
548
            // vetoed by the page
 
549
            return false;
 
550
        }
 
551
 
 
552
        m_page->Hide();
 
553
 
 
554
        bmpPrev = m_page->GetBitmap();
 
555
 
 
556
        if ( !m_usingSizer )
 
557
            m_sizerBmpAndPage->Detach(m_page);
 
558
    }
 
559
 
 
560
    // is this the end?
 
561
    if ( !page )
 
562
    {
 
563
        // terminate successfully
 
564
        if ( IsModal() )
 
565
        {
 
566
            EndModal(wxID_OK);
 
567
        }
 
568
        else
 
569
        {
 
570
            SetReturnCode(wxID_OK);
 
571
            Hide();
 
572
        }
 
573
 
 
574
        // and notify the user code (this is especially useful for modeless
 
575
        // wizards)
 
576
        wxWizardEvent event(wxEVT_WIZARD_FINISHED, GetId(), false, m_page);
 
577
        (void)GetEventHandler()->ProcessEvent(event);
 
578
 
 
579
        m_page = NULL;
 
580
 
 
581
        return true;
 
582
    }
 
583
 
 
584
    // notice that we change m_page only here so that wxEVT_WIZARD_FINISHED
 
585
    // event above could still use the correct (i.e. old) value of m_page
 
586
    m_page = page;
 
587
 
 
588
    // position and show the new page
 
589
    (void)m_page->TransferDataToWindow();
 
590
 
 
591
    if ( m_usingSizer )
 
592
    {
 
593
        // wxWizardSizer::RecalcSizes wants to be called when m_page changes
 
594
        m_sizerPage->RecalcSizes();
 
595
    }
 
596
    else // pages are not managed by the sizer
 
597
    {
 
598
        m_sizerBmpAndPage->Add(m_page, flags);
 
599
        m_sizerBmpAndPage->SetItemMinSize(m_page, GetPageSize());
 
600
    }
 
601
 
 
602
#if wxUSE_STATBMP
 
603
    // update the bitmap if:it changed
 
604
    wxBitmap bmp;
 
605
    if ( m_statbmp )
 
606
    {
 
607
        bmp = m_page->GetBitmap();
 
608
        if ( !bmp.IsOk() )
 
609
            bmp = m_bitmap;
 
610
 
 
611
        if ( !bmpPrev.IsOk() )
 
612
            bmpPrev = m_bitmap;
 
613
 
 
614
        if (!GetBitmapPlacement())
 
615
        {
 
616
            if ( !bmp.IsSameAs(bmpPrev) )
 
617
                m_statbmp->SetBitmap(bmp);
 
618
        }
 
619
    }
 
620
#endif // wxUSE_STATBMP
 
621
 
 
622
 
 
623
    // and update the buttons state
 
624
    m_btnPrev->Enable(HasPrevPage(m_page));
 
625
 
 
626
    const bool hasNext = HasNextPage(m_page);
 
627
    const wxString label = hasNext ? _("&Next >") : _("&Finish");
 
628
    if ( label != m_btnNext->GetLabel() )
 
629
        m_btnNext->SetLabel(label);
 
630
 
 
631
    m_btnNext->SetDefault();
 
632
 
 
633
 
 
634
    // send the change event to the new page now
 
635
    wxWizardEvent event(wxEVT_WIZARD_PAGE_CHANGED, GetId(), goingForward, m_page);
 
636
    (void)m_page->GetEventHandler()->ProcessEvent(event);
 
637
 
 
638
    // and finally show it
 
639
    m_page->Show();
 
640
    m_page->SetFocus();
 
641
 
 
642
    if ( !m_usingSizer )
 
643
        m_sizerBmpAndPage->Layout();
 
644
 
 
645
    if ( !m_started )
 
646
    {
 
647
        m_started = true;
 
648
 
 
649
        DoWizardLayout();
 
650
    }
 
651
 
 
652
    if (GetBitmapPlacement() && m_statbmp)
 
653
    {
 
654
        ResizeBitmap(bmp);
 
655
 
 
656
        if ( !bmp.IsSameAs(bmpPrev) )
 
657
            m_statbmp->SetBitmap(bmp);
 
658
 
 
659
        if (m_usingSizer)
 
660
            m_sizerPage->RecalcSizes();
 
661
    }
 
662
 
 
663
    wxWizardEvent pageShownEvent(wxEVT_WIZARD_PAGE_SHOWN, GetId(),
 
664
        goingForward, m_page);
 
665
    m_page->GetEventHandler()->ProcessEvent(pageShownEvent);
 
666
 
 
667
    return true;
 
668
}
 
669
 
 
670
/// Do fit, and adjust to screen size if necessary
 
671
void wxWizard::DoWizardLayout()
 
672
{
 
673
    if ( wxSystemSettings::GetScreenType() > wxSYS_SCREEN_PDA )
 
674
    {
 
675
        if (CanDoLayoutAdaptation())
 
676
            DoLayoutAdaptation();
 
677
        else
 
678
            GetSizer()->SetSizeHints(this);
 
679
 
 
680
        if ( m_posWizard == wxDefaultPosition )
 
681
            CentreOnScreen();
 
682
    }
 
683
 
 
684
    SetLayoutAdaptationDone(true);
 
685
}
 
686
 
 
687
bool wxWizard::RunWizard(wxWizardPage *firstPage)
 
688
{
 
689
    wxCHECK_MSG( firstPage, false, wxT("can't run empty wizard") );
 
690
 
 
691
    // can't return false here because there is no old page
 
692
    (void)ShowPage(firstPage, true /* forward */);
 
693
 
 
694
    m_wasModal = true;
 
695
 
 
696
    return ShowModal() == wxID_OK;
 
697
}
 
698
 
 
699
wxWizardPage *wxWizard::GetCurrentPage() const
 
700
{
 
701
    return m_page;
 
702
}
 
703
 
 
704
wxSize wxWizard::GetPageSize() const
 
705
{
 
706
    // default width and height of the page
 
707
    int DEFAULT_PAGE_WIDTH,
 
708
        DEFAULT_PAGE_HEIGHT;
 
709
    if ( wxSystemSettings::GetScreenType() <= wxSYS_SCREEN_PDA )
 
710
    {
 
711
        // Make the default page size small enough to fit on screen
 
712
        DEFAULT_PAGE_WIDTH = wxSystemSettings::GetMetric(wxSYS_SCREEN_X) / 2;
 
713
        DEFAULT_PAGE_HEIGHT = wxSystemSettings::GetMetric(wxSYS_SCREEN_Y) / 2;
 
714
    }
 
715
    else // !PDA
 
716
    {
 
717
        DEFAULT_PAGE_WIDTH =
 
718
        DEFAULT_PAGE_HEIGHT = 270;
 
719
    }
 
720
 
 
721
    // start with default minimal size
 
722
    wxSize pageSize(DEFAULT_PAGE_WIDTH, DEFAULT_PAGE_HEIGHT);
 
723
 
 
724
    // make the page at least as big as specified by user
 
725
    pageSize.IncTo(m_sizePage);
 
726
 
 
727
    if ( m_statbmp )
 
728
    {
 
729
        // make the page at least as tall as the bitmap
 
730
        pageSize.IncTo(wxSize(0, m_bitmap.GetHeight()));
 
731
    }
 
732
 
 
733
    if ( m_usingSizer )
 
734
    {
 
735
        // make it big enough to contain all pages added to the sizer
 
736
        pageSize.IncTo(m_sizerPage->GetMaxChildSize());
 
737
    }
 
738
 
 
739
    return pageSize;
 
740
}
 
741
 
 
742
wxSizer *wxWizard::GetPageAreaSizer() const
 
743
{
 
744
    return m_sizerPage;
 
745
}
 
746
 
 
747
void wxWizard::SetBorder(int border)
 
748
{
 
749
    wxCHECK_RET(!m_started, wxT("wxWizard::SetBorder after RunWizard"));
 
750
 
 
751
    m_border = border;
 
752
}
 
753
 
 
754
void wxWizard::OnCancel(wxCommandEvent& WXUNUSED(eventUnused))
 
755
{
 
756
    // this function probably can never be called when we don't have an active
 
757
    // page, but a small extra check won't hurt
 
758
    wxWindow *win = m_page ? (wxWindow *)m_page : (wxWindow *)this;
 
759
 
 
760
    wxWizardEvent event(wxEVT_WIZARD_CANCEL, GetId(), false, m_page);
 
761
    if ( !win->GetEventHandler()->ProcessEvent(event) || event.IsAllowed() )
 
762
    {
 
763
        // no objections - close the dialog
 
764
        if(IsModal())
 
765
        {
 
766
            EndModal(wxID_CANCEL);
 
767
        }
 
768
        else
 
769
        {
 
770
            SetReturnCode(wxID_CANCEL);
 
771
            Hide();
 
772
        }
 
773
    }
 
774
    //else: request to Cancel ignored
 
775
}
 
776
 
 
777
void wxWizard::OnBackOrNext(wxCommandEvent& event)
 
778
{
 
779
    wxASSERT_MSG( (event.GetEventObject() == m_btnNext) ||
 
780
                  (event.GetEventObject() == m_btnPrev),
 
781
                  wxT("unknown button") );
 
782
 
 
783
    wxCHECK_RET( m_page, wxT("should have a valid current page") );
 
784
 
 
785
    // ask the current page first: notice that we do it before calling
 
786
    // GetNext/Prev() because the data transferred from the controls of the page
 
787
    // may change the value returned by these methods
 
788
    if ( !m_page->Validate() || !m_page->TransferDataFromWindow() )
 
789
    {
 
790
        // the page data is incorrect, don't do anything
 
791
        return;
 
792
    }
 
793
 
 
794
    bool forward = event.GetEventObject() == m_btnNext;
 
795
 
 
796
    // Give the application a chance to set state which may influence GetNext()/GetPrev()
 
797
    wxWizardEvent eventPreChanged(wxEVT_WIZARD_BEFORE_PAGE_CHANGED, GetId(), forward, m_page);
 
798
    (void)m_page->GetEventHandler()->ProcessEvent(eventPreChanged);
 
799
 
 
800
    if (!eventPreChanged.IsAllowed())
 
801
        return;
 
802
 
 
803
    wxWizardPage *page;
 
804
    if ( forward )
 
805
    {
 
806
        page = m_page->GetNext();
 
807
    }
 
808
    else // back
 
809
    {
 
810
        page = m_page->GetPrev();
 
811
 
 
812
        wxASSERT_MSG( page, wxT("\"<Back\" button should have been disabled") );
 
813
    }
 
814
 
 
815
    // just pass to the new page (or maybe not - but we don't care here)
 
816
    (void)ShowPage(page, forward);
 
817
}
 
818
 
 
819
void wxWizard::OnHelp(wxCommandEvent& WXUNUSED(event))
 
820
{
 
821
    // this function probably can never be called when we don't have an active
 
822
    // page, but a small extra check won't hurt
 
823
    if(m_page != NULL)
 
824
    {
 
825
        // Create and send the help event to the specific page handler
 
826
        // event data contains the active page so that context-sensitive
 
827
        // help is possible
 
828
        wxWizardEvent eventHelp(wxEVT_WIZARD_HELP, GetId(), true, m_page);
 
829
        (void)m_page->GetEventHandler()->ProcessEvent(eventHelp);
 
830
    }
 
831
}
 
832
 
 
833
void wxWizard::OnWizEvent(wxWizardEvent& event)
 
834
{
 
835
    // the dialogs have wxWS_EX_BLOCK_EVENTS style on by default but we want to
 
836
    // propagate wxEVT_WIZARD_XXX to the parent (if any), so do it manually
 
837
    if ( !(GetExtraStyle() & wxWS_EX_BLOCK_EVENTS) )
 
838
    {
 
839
        // the event will be propagated anyhow
 
840
        event.Skip();
 
841
    }
 
842
    else
 
843
    {
 
844
        wxWindow *parent = GetParent();
 
845
 
 
846
        if ( !parent || !parent->GetEventHandler()->ProcessEvent(event) )
 
847
        {
 
848
            event.Skip();
 
849
        }
 
850
    }
 
851
 
 
852
    if ( ( !m_wasModal ) &&
 
853
         event.IsAllowed() &&
 
854
         ( event.GetEventType() == wxEVT_WIZARD_FINISHED ||
 
855
           event.GetEventType() == wxEVT_WIZARD_CANCEL
 
856
         )
 
857
       )
 
858
    {
 
859
        Destroy();
 
860
    }
 
861
}
 
862
 
 
863
void wxWizard::SetBitmap(const wxBitmap& bitmap)
 
864
{
 
865
    m_bitmap = bitmap;
 
866
    if (m_statbmp)
 
867
        m_statbmp->SetBitmap(m_bitmap);
 
868
}
 
869
 
 
870
// ----------------------------------------------------------------------------
 
871
// wxWizardEvent
 
872
// ----------------------------------------------------------------------------
 
873
 
 
874
wxWizardEvent::wxWizardEvent(wxEventType type, int id, bool direction, wxWizardPage* page)
 
875
             : wxNotifyEvent(type, id)
 
876
{
 
877
    // Modified 10-20-2001 Robert Cavanaugh
 
878
    // add the active page to the event data
 
879
    m_direction = direction;
 
880
    m_page = page;
 
881
}
 
882
 
 
883
/// Do the adaptation
 
884
bool wxWizard::DoLayoutAdaptation()
 
885
{
 
886
    wxWindowList windows;
 
887
    wxWindowList pages;
 
888
 
 
889
    // Make all the pages (that use sizers) scrollable
 
890
    for ( wxSizerItemList::compatibility_iterator node = m_sizerPage->GetChildren().GetFirst(); node; node = node->GetNext() )
 
891
    {
 
892
        wxSizerItem * const item = node->GetData();
 
893
        if ( item->IsWindow() )
 
894
        {
 
895
            wxWizardPage* page = wxDynamicCast(item->GetWindow(), wxWizardPage);
 
896
            if (page)
 
897
            {
 
898
                while (page)
 
899
                {
 
900
                    if (!pages.Find(page) && page->GetSizer())
 
901
                    {
 
902
                        // Create a scrolled window and reparent
 
903
                        wxScrolledWindow* scrolledWindow = new wxScrolledWindow(page, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL|wxVSCROLL|wxHSCROLL|wxBORDER_NONE);
 
904
                        wxSizer* oldSizer = page->GetSizer();
 
905
 
 
906
                        wxSizer* newSizer = new wxBoxSizer(wxVERTICAL);
 
907
                        newSizer->Add(scrolledWindow,1, wxEXPAND, 0);
 
908
 
 
909
                        page->SetSizer(newSizer, false /* don't delete the old sizer */);
 
910
 
 
911
                        scrolledWindow->SetSizer(oldSizer);
 
912
 
 
913
                        wxStandardDialogLayoutAdapter::DoReparentControls(page, scrolledWindow);
 
914
 
 
915
                        pages.Append(page);
 
916
                        windows.Append(scrolledWindow);
 
917
                    }
 
918
                    page = page->GetNext();
 
919
                }
 
920
            }
 
921
        }
 
922
    }
 
923
 
 
924
    wxStandardDialogLayoutAdapter::DoFitWithScrolling(this, windows);
 
925
 
 
926
    // Size event doesn't get sent soon enough on wxGTK
 
927
    DoLayout();
 
928
 
 
929
    SetLayoutAdaptationDone(true);
 
930
 
 
931
    return true;
 
932
}
 
933
 
 
934
bool wxWizard::ResizeBitmap(wxBitmap& bmp)
 
935
{
 
936
    if (!GetBitmapPlacement())
 
937
        return false;
 
938
 
 
939
    if (bmp.IsOk())
 
940
    {
 
941
        wxSize pageSize = m_sizerPage->GetSize();
 
942
        if (pageSize == wxSize(0,0))
 
943
            pageSize = GetPageSize();
 
944
        int bitmapWidth = wxMax(bmp.GetWidth(), GetMinimumBitmapWidth());
 
945
        int bitmapHeight = pageSize.y;
 
946
 
 
947
        if (!m_statbmp->GetBitmap().IsOk() || m_statbmp->GetBitmap().GetHeight() != bitmapHeight)
 
948
        {
 
949
            wxBitmap bitmap(bitmapWidth, bitmapHeight);
 
950
            {
 
951
                wxMemoryDC dc;
 
952
                dc.SelectObject(bitmap);
 
953
                dc.SetBackground(wxBrush(m_bitmapBackgroundColour));
 
954
                dc.Clear();
 
955
 
 
956
                if (GetBitmapPlacement() & wxWIZARD_TILE)
 
957
                {
 
958
                    TileBitmap(wxRect(0, 0, bitmapWidth, bitmapHeight), dc, bmp);
 
959
                }
 
960
                else
 
961
                {
 
962
                    int x, y;
 
963
 
 
964
                    if (GetBitmapPlacement() & wxWIZARD_HALIGN_LEFT)
 
965
                        x = 0;
 
966
                    else if (GetBitmapPlacement() & wxWIZARD_HALIGN_RIGHT)
 
967
                        x = bitmapWidth - bmp.GetWidth();
 
968
                    else
 
969
                        x = (bitmapWidth - bmp.GetWidth())/2;
 
970
 
 
971
                    if (GetBitmapPlacement() & wxWIZARD_VALIGN_TOP)
 
972
                        y = 0;
 
973
                    else if (GetBitmapPlacement() & wxWIZARD_VALIGN_BOTTOM)
 
974
                        y = bitmapHeight - bmp.GetHeight();
 
975
                    else
 
976
                        y = (bitmapHeight - bmp.GetHeight())/2;
 
977
 
 
978
                    dc.DrawBitmap(bmp, x, y, true);
 
979
                    dc.SelectObject(wxNullBitmap);
 
980
                }
 
981
            }
 
982
 
 
983
            bmp = bitmap;
 
984
        }
 
985
    }
 
986
 
 
987
    return true;
 
988
}
 
989
 
 
990
bool wxWizard::TileBitmap(const wxRect& rect, wxDC& dc, const wxBitmap& bitmap)
 
991
{
 
992
    int w = bitmap.GetWidth();
 
993
    int h = bitmap.GetHeight();
 
994
 
 
995
    wxMemoryDC dcMem;
 
996
 
 
997
    dcMem.SelectObjectAsSource(bitmap);
 
998
 
 
999
    int i, j;
 
1000
    for (i = rect.x; i < rect.x + rect.width; i += w)
 
1001
    {
 
1002
        for (j = rect.y; j < rect.y + rect.height; j+= h)
 
1003
            dc.Blit(i, j, bitmap.GetWidth(), bitmap.GetHeight(), & dcMem, 0, 0);
 
1004
    }
 
1005
    dcMem.SelectObject(wxNullBitmap);
 
1006
 
 
1007
    return true;
 
1008
}
 
1009
 
 
1010
#endif // wxUSE_WIZARDDLG