]> git.saurik.com Git - wxWidgets.git/blame - src/generic/wizard.cpp
Committing in .
[wxWidgets.git] / src / generic / wizard.cpp
CommitLineData
66cd017c
VZ
1///////////////////////////////////////////////////////////////////////////////
2// Name: generic/wizard.cpp
3// Purpose: generic implementation of wxWizard class
4// Author: Vadim Zeitlin
5// Modified by:
6// Created: 15.08.99
7// RCS-ID: $Id$
8// Copyright: (c) 1999 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
9// Licence: wxWindows license
10///////////////////////////////////////////////////////////////////////////////
11
12// ============================================================================
13// declarations
14// ============================================================================
15
16// ----------------------------------------------------------------------------
17// headers
18// ----------------------------------------------------------------------------
19
20#ifdef __GNUG__
21 #pragma implementation ".h"
22#endif
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#ifndef WX_PRECOMP
32 #include "wx/dynarray.h"
33 #include "wx/intl.h"
b87654f3 34 #include "wx/statbmp.h"
f6bcfd97 35 #include "wx/button.h"
66cd017c
VZ
36#endif //WX_PRECOMP
37
38#include "wx/statline.h"
39
40#include "wx/wizard.h"
41
42// ----------------------------------------------------------------------------
43// simple types
44// ----------------------------------------------------------------------------
45
46WX_DEFINE_ARRAY(wxPanel *, wxArrayPages);
47
66cd017c
VZ
48// ----------------------------------------------------------------------------
49// event tables and such
50// ----------------------------------------------------------------------------
51
74b31181
VZ
52BEGIN_EVENT_TABLE(wxWizard, wxDialog)
53 EVT_BUTTON(wxID_CANCEL, wxWizard::OnCancel)
54 EVT_BUTTON(-1, wxWizard::OnBackOrNext)
66cd017c
VZ
55END_EVENT_TABLE()
56
74b31181
VZ
57IMPLEMENT_DYNAMIC_CLASS(wxWizard, wxDialog)
58IMPLEMENT_ABSTRACT_CLASS(wxWizardPage, wxPanel)
59IMPLEMENT_DYNAMIC_CLASS(wxWizardPageSimple, wxWizardPage)
66cd017c
VZ
60IMPLEMENT_DYNAMIC_CLASS(wxWizardEvent, wxNotifyEvent)
61
62// ============================================================================
63// implementation
64// ============================================================================
65
74b31181
VZ
66// ----------------------------------------------------------------------------
67// wxWizardPage
68// ----------------------------------------------------------------------------
69
f1df0927
VZ
70wxWizardPage::wxWizardPage(wxWizard *parent, const wxBitmap& bitmap)
71 : wxPanel(parent), m_bitmap(bitmap)
74b31181
VZ
72{
73 // initially the page is hidden, it's shown only when it becomes current
74 Hide();
75}
76
77// ----------------------------------------------------------------------------
78// wxWizardPageSimple
79// ----------------------------------------------------------------------------
80
81wxWizardPage *wxWizardPageSimple::GetPrev() const
82{
83 return m_prev;
84}
85
86wxWizardPage *wxWizardPageSimple::GetNext() const
87{
88 return m_next;
89}
66cd017c
VZ
90// ----------------------------------------------------------------------------
91// generic wxWizard implementation
92// ----------------------------------------------------------------------------
93
74b31181
VZ
94wxWizard::wxWizard(wxWindow *parent,
95 int id,
96 const wxString& title,
97 const wxBitmap& bitmap,
f6bcfd97
BP
98 const wxPoint& pos)
99 : m_posWizard(pos), m_bitmap(bitmap)
66cd017c 100{
f6bcfd97
BP
101 // just create the dialog itself here, the controls will be created in
102 // DoCreateControls() called later when we know our final size
103 m_page = (wxWizardPage *)NULL;
104 m_btnPrev = m_btnNext = NULL;
105 m_statbmp = NULL;
106
107 (void)wxDialog::Create(parent, id, title, pos);
108}
109
110void wxWizard::DoCreateControls()
111{
112 // do nothing if the controls were already created
113 if ( WasCreated() )
114 return;
115
66cd017c
VZ
116 // constants defining the dialog layout
117 // ------------------------------------
118
119 // these constants define the position of the upper left corner of the
120 // bitmap or the page in the wizard
121 static const int X_MARGIN = 10;
122 static const int Y_MARGIN = 10;
123
124 // margin between the bitmap and the panel
125 static const int BITMAP_X_MARGIN = 15;
126
127 // margin between the bitmap and the static line
128 static const int BITMAP_Y_MARGIN = 15;
129
130 // margin between the static line and the buttons
131 static const int SEPARATOR_LINE_MARGIN = 15;
132
133 // margin between "Next >" and "Cancel" buttons
134 static const int BUTTON_MARGIN = 10;
135
136 // default width and height of the page
137 static const int DEFAULT_PAGE_WIDTH = 270;
138 static const int DEFAULT_PAGE_HEIGHT = 290;
139
66cd017c
VZ
140 // create controls
141 // ---------------
142
143 wxSize sizeBtn = wxButton::GetDefaultSize();
144
66cd017c
VZ
145 // the global dialog layout is: a row of buttons at the bottom (aligned to
146 // the right), the static line above them, the bitmap (if any) on the left
147 // of the upper part of the dialog and the panel in the remaining space
148 m_x = X_MARGIN;
149 m_y = Y_MARGIN;
f6bcfd97
BP
150
151 int defaultHeight;
152 if ( m_bitmap.Ok() )
66cd017c 153 {
f6bcfd97 154 m_statbmp = new wxStaticBitmap(this, -1, m_bitmap, wxPoint(m_x, m_y));
66cd017c 155
f6bcfd97
BP
156 m_x += m_bitmap.GetWidth() + BITMAP_X_MARGIN;
157
158 defaultHeight = m_bitmap.GetHeight();
66cd017c
VZ
159 }
160 else
161 {
f1df0927
VZ
162 m_statbmp = (wxStaticBitmap *)NULL;
163
f6bcfd97 164 defaultHeight = DEFAULT_PAGE_HEIGHT;
66cd017c
VZ
165 }
166
f6bcfd97
BP
167 // use default size if none given and also make sure that the dialog is
168 // not less than the default size
169 m_height = m_sizePage.y == -1 ? defaultHeight : m_sizePage.y;
170 m_width = m_sizePage.x == -1 ? DEFAULT_PAGE_WIDTH : m_sizePage.x;
171 if ( m_height < defaultHeight )
172 m_height = defaultHeight;
173 if ( m_width < DEFAULT_PAGE_WIDTH )
174 m_width = DEFAULT_PAGE_WIDTH;
66cd017c
VZ
175
176 int x = X_MARGIN;
177 int y = m_y + m_height + BITMAP_Y_MARGIN;
74b31181
VZ
178
179#if wxUSE_STATLINE
66cd017c
VZ
180 (void)new wxStaticLine(this, -1, wxPoint(x, y),
181 wxSize(m_x + m_width - x, 2));
f6bcfd97 182#endif // wxUSE_STATLINE
74b31181 183
66cd017c
VZ
184 x = m_x + m_width - 3*sizeBtn.x - BUTTON_MARGIN;
185 y += SEPARATOR_LINE_MARGIN;
f6bcfd97 186 m_btnPrev = new wxButton(this, wxID_BACKWARD, _("< &Back"), wxPoint(x, y), sizeBtn);
66cd017c
VZ
187
188 x += sizeBtn.x;
f6bcfd97 189 m_btnNext = new wxButton(this, wxID_FORWARD, _("&Next >"), wxPoint(x, y), sizeBtn);
66cd017c
VZ
190
191 x += sizeBtn.x + BUTTON_MARGIN;
192 (void)new wxButton(this, wxID_CANCEL, _("Cancel"), wxPoint(x, y), sizeBtn);
193
194 // position and size the dialog
195 // ----------------------------
196
f6bcfd97
BP
197 SetClientSize(m_x + m_width + X_MARGIN,
198 m_y + m_height + BITMAP_Y_MARGIN +
199 SEPARATOR_LINE_MARGIN + sizeBtn.y + Y_MARGIN);
66cd017c 200
f6bcfd97 201 if ( m_posWizard == wxDefaultPosition )
66cd017c 202 {
91b4c08d 203 CentreOnScreen();
66cd017c
VZ
204 }
205}
206
f6bcfd97
BP
207void wxWizard::SetPageSize(const wxSize& size)
208{
209 // otherwise it will have no effect now as it's too late...
210 wxASSERT_MSG( !WasCreated(), _T("should be called before RunWizard()!") );
211
212 m_sizePage = size;
213}
214
74b31181 215bool wxWizard::ShowPage(wxWizardPage *page, bool goingForward)
66cd017c 216{
223d09f6 217 wxASSERT_MSG( page != m_page, wxT("this is useless") );
66cd017c 218
74b31181
VZ
219 // we'll use this to decide whether we have to change the label of this
220 // button or not (initially the label is "Next")
221 bool btnLabelWasNext = TRUE;
66cd017c 222
f1df0927
VZ
223 // and this tells us whether we already had the default bitmap before
224 bool bmpWasDefault = TRUE;
225
74b31181 226 if ( m_page )
66cd017c 227 {
74b31181
VZ
228 // send the event to the old page
229 wxWizardEvent event(wxEVT_WIZARD_PAGE_CHANGING, GetId(), goingForward);
230 if ( m_page->GetEventHandler()->ProcessEvent(event) &&
231 !event.IsAllowed() )
232 {
233 // vetoed by the page
66cd017c 234 return FALSE;
74b31181 235 }
66cd017c 236
74b31181
VZ
237 m_page->Hide();
238
239 btnLabelWasNext = m_page->GetNext() != (wxWizardPage *)NULL;
f1df0927 240 bmpWasDefault = !m_page->GetBitmap().Ok();
66cd017c
VZ
241 }
242
74b31181 243 // set the new one
66cd017c 244 m_page = page;
66cd017c 245
74b31181
VZ
246 // is this the end?
247 if ( !m_page )
66cd017c 248 {
74b31181
VZ
249 // terminate successfully
250 EndModal(wxID_OK);
66cd017c 251
74b31181
VZ
252 return TRUE;
253 }
66cd017c 254
74b31181
VZ
255 // send the event to the new page now
256 wxWizardEvent event(wxEVT_WIZARD_PAGE_CHANGED, GetId(), goingForward);
257 (void)m_page->GetEventHandler()->ProcessEvent(event);
66cd017c 258
74b31181
VZ
259 // position and show the new page
260 (void)m_page->TransferDataToWindow();
261 m_page->SetSize(m_x, m_y, m_width, m_height);
262 m_page->Show();
66cd017c 263
f1df0927
VZ
264 // change the bitmap if necessary (and if we have it at all)
265 bool bmpIsDefault = !m_page->GetBitmap().Ok();
266 if ( m_statbmp && (bmpIsDefault != bmpWasDefault) )
267 {
cfd88569
VZ
268 wxBitmap bmp;
269 if ( bmpIsDefault )
270 bmp = m_bitmap;
271 else
272 bmp = m_page->GetBitmap();
273 m_statbmp->SetBitmap(bmp);
f1df0927
VZ
274 }
275
74b31181
VZ
276 // and update the buttons state
277 m_btnPrev->Enable(m_page->GetPrev() != (wxWizardPage *)NULL);
66cd017c 278
8f177c8e
VZ
279 bool hasNext = m_page->GetNext() != (wxWizardPage *)NULL;
280 if ( btnLabelWasNext != hasNext )
66cd017c 281 {
74b31181 282 // need to update
e9fa7581
OK
283 if (btnLabelWasNext)
284 m_btnNext->SetLabel(_("&Finish"));
285 else
286 m_btnNext->SetLabel(_("&Next >"));
66cd017c 287 }
74b31181 288 // nothing to do: the label was already correct
66cd017c 289
74b31181 290 return TRUE;
66cd017c
VZ
291}
292
74b31181 293bool wxWizard::RunWizard(wxWizardPage *firstPage)
66cd017c 294{
223d09f6 295 wxCHECK_MSG( firstPage, FALSE, wxT("can't run empty wizard") );
66cd017c 296
f6bcfd97
BP
297 DoCreateControls();
298
66cd017c 299 // can't return FALSE here because there is no old page
74b31181 300 (void)ShowPage(firstPage, TRUE /* forward */);
66cd017c
VZ
301
302 return ShowModal() == wxID_OK;
303}
304
74b31181 305wxWizardPage *wxWizard::GetCurrentPage() const
66cd017c 306{
74b31181 307 return m_page;
66cd017c
VZ
308}
309
4fe5383d
VZ
310wxSize wxWizard::GetPageSize() const
311{
f6bcfd97
BP
312 // make sure that the controls are created because otherwise m_width and
313 // m_height would be both still -1
314 wxConstCast(this, wxWizard)->DoCreateControls();
315
4fe5383d
VZ
316 return wxSize(m_width, m_height);
317}
318
74b31181 319void wxWizard::OnCancel(wxCommandEvent& WXUNUSED(event))
66cd017c 320{
74b31181
VZ
321 // this function probably can never be called when we don't have an active
322 // page, but a small extra check won't hurt
323 wxWindow *win = m_page ? (wxWindow *)m_page : (wxWindow *)this;
324
66cd017c 325 wxWizardEvent event(wxEVT_WIZARD_CANCEL, GetId());
74b31181 326 if ( !win->GetEventHandler()->ProcessEvent(event) || event.IsAllowed() )
66cd017c
VZ
327 {
328 // no objections - close the dialog
329 EndModal(wxID_CANCEL);
330 }
331 //else: request to Cancel ignored
332}
333
74b31181 334void wxWizard::OnBackOrNext(wxCommandEvent& event)
66cd017c
VZ
335{
336 wxASSERT_MSG( (event.GetEventObject() == m_btnNext) ||
337 (event.GetEventObject() == m_btnPrev),
223d09f6 338 wxT("unknown button") );
66cd017c 339
f6bcfd97
BP
340 // ask the current page first: notice that we do it before calling
341 // GetNext/Prev() because the data transfered from the controls of the page
342 // may change the value returned by these methods
343 if ( m_page && !m_page->TransferDataFromWindow() )
344 {
345 // the page data is incorrect, don't do anything
346 return;
347 }
348
74b31181 349 bool forward = event.GetEventObject() == m_btnNext;
66cd017c 350
74b31181
VZ
351 wxWizardPage *page;
352 if ( forward )
66cd017c 353 {
74b31181 354 page = m_page->GetNext();
66cd017c 355 }
74b31181 356 else // back
66cd017c 357 {
74b31181
VZ
358 page = m_page->GetPrev();
359
223d09f6 360 wxASSERT_MSG( page, wxT("\"<Back\" button should have been disabled") );
66cd017c 361 }
74b31181
VZ
362
363 // just pass to the new page (or may be not - but we don't care here)
364 (void)ShowPage(page, forward);
66cd017c
VZ
365}
366
367// ----------------------------------------------------------------------------
368// our public interface
369// ----------------------------------------------------------------------------
370
74b31181
VZ
371/* static */
372wxWizard *wxWizardBase::Create(wxWindow *parent,
373 int id,
374 const wxString& title,
375 const wxBitmap& bitmap,
376 const wxPoint& pos,
f6bcfd97 377 const wxSize& WXUNUSED(size))
66cd017c 378{
f6bcfd97 379 return new wxWizard(parent, id, title, bitmap, pos);
66cd017c
VZ
380}
381
382// ----------------------------------------------------------------------------
383// wxWizardEvent
384// ----------------------------------------------------------------------------
385
74b31181 386wxWizardEvent::wxWizardEvent(wxEventType type, int id, bool direction)
66cd017c
VZ
387 : wxNotifyEvent(type, id)
388{
74b31181 389 m_direction = direction;
66cd017c 390}
74b31181 391