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