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