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