Fixed "Bound pointer address" error under GCC-2.95
[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 // wxWizardGeneric - generic implementation of wxWizard
49 // ----------------------------------------------------------------------------
50
51 class wxWizardGeneric : public wxWizard
52 {
53 public:
54 // ctor
55 wxWizardGeneric(wxWindow *parent,
56 int id,
57 const wxString& title,
58 const wxBitmap& bitmap,
59 const wxPoint& pos,
60 const wxSize& size);
61
62 // implement base class pure virtuals
63 virtual void AddPage(wxPanel *page);
64 virtual void InsertPage(int nPage, wxPanel *page);
65 virtual bool RunWizard();
66 virtual wxPanel *GetCurrentPage() const;
67
68 // implementation only from now on
69 // -------------------------------
70
71 // is the wizard running?
72 bool IsRunning() const { return m_page != -1; }
73
74 // show the given page calling TransferDataFromWindow - if it returns
75 // FALSE, the old page is not hidden and the function returns FALSE
76 bool ShowPage(size_t page);
77
78 // get the current page assuming the wizard is running
79 wxPanel *DoGetCurrentPage() const
80 {
81 wxASSERT_MSG( IsRunning(), _T("no current page!") );
82
83 return m_pages[(size_t)m_page];
84 }
85
86 // place the given page correctly and hide it
87 void DoAddPage(wxPanel *page);
88
89 private:
90 // event handlers
91 void OnCancel(wxCommandEvent& event);
92 void OnBackOrNext(wxCommandEvent& event);
93
94 // wizard dimensions
95 int m_x, m_y; // the origin for the pages
96 int m_width, // the size of the page itself
97 m_height; // (total width is m_width + m_x)
98
99 // wizard state
100 int m_page; // the current page or -1
101 wxArrayPages m_pages; // the array with all wizards pages
102
103 // wizard controls
104 wxButton *m_btnPrev, // the "<Back" button
105 *m_btnNext; // the "Next>" or "Finish" button
106
107 DECLARE_EVENT_TABLE()
108 };
109
110 // ----------------------------------------------------------------------------
111 // event tables and such
112 // ----------------------------------------------------------------------------
113
114 BEGIN_EVENT_TABLE(wxWizardGeneric, wxDialog)
115 EVT_BUTTON(wxID_CANCEL, wxWizardGeneric::OnCancel)
116 EVT_BUTTON(-1, wxWizardGeneric::OnBackOrNext)
117 END_EVENT_TABLE()
118
119 IMPLEMENT_ABSTRACT_CLASS(wxWizard, wxDialog)
120 IMPLEMENT_DYNAMIC_CLASS(wxWizardEvent, wxNotifyEvent)
121
122 // ============================================================================
123 // implementation
124 // ============================================================================
125
126 // ----------------------------------------------------------------------------
127 // generic wxWizard implementation
128 // ----------------------------------------------------------------------------
129
130 wxWizardGeneric::wxWizardGeneric(wxWindow *parent,
131 int id,
132 const wxString& title,
133 const wxBitmap& bitmap,
134 const wxPoint& pos,
135 const wxSize& size)
136 {
137 // constants defining the dialog layout
138 // ------------------------------------
139
140 // these constants define the position of the upper left corner of the
141 // bitmap or the page in the wizard
142 static const int X_MARGIN = 10;
143 static const int Y_MARGIN = 10;
144
145 // margin between the bitmap and the panel
146 static const int BITMAP_X_MARGIN = 15;
147
148 // margin between the bitmap and the static line
149 static const int BITMAP_Y_MARGIN = 15;
150
151 // margin between the static line and the buttons
152 static const int SEPARATOR_LINE_MARGIN = 15;
153
154 // margin between "Next >" and "Cancel" buttons
155 static const int BUTTON_MARGIN = 10;
156
157 // default width and height of the page
158 static const int DEFAULT_PAGE_WIDTH = 270;
159 static const int DEFAULT_PAGE_HEIGHT = 290;
160
161 // init members
162 // ------------
163
164 m_page = -1;
165
166 // create controls
167 // ---------------
168
169 wxSize sizeBtn = wxButton::GetDefaultSize();
170
171 (void)wxDialog::Create(parent, id, title, pos, size);
172
173 // the global dialog layout is: a row of buttons at the bottom (aligned to
174 // the right), the static line above them, the bitmap (if any) on the left
175 // of the upper part of the dialog and the panel in the remaining space
176 m_x = X_MARGIN;
177 m_y = Y_MARGIN;
178 if ( bitmap.Ok() )
179 {
180 (void)new wxStaticBitmap(this, -1, bitmap, wxPoint(m_x, m_y));
181
182 m_x += bitmap.GetWidth() + BITMAP_X_MARGIN;
183 m_height = bitmap.GetHeight();
184 }
185 else
186 {
187 m_height = DEFAULT_PAGE_HEIGHT;
188 }
189
190 m_width = DEFAULT_PAGE_WIDTH;
191
192 int x = X_MARGIN;
193 int y = m_y + m_height + BITMAP_Y_MARGIN;
194 (void)new wxStaticLine(this, -1, wxPoint(x, y),
195 wxSize(m_x + m_width - x, 2));
196
197 x = m_x + m_width - 3*sizeBtn.x - BUTTON_MARGIN;
198 y += SEPARATOR_LINE_MARGIN;
199 m_btnPrev = new wxButton(this, -1, _("< &Back"), wxPoint(x, y), sizeBtn);
200
201 x += sizeBtn.x;
202 m_btnNext = new wxButton(this, -1, _("&Next >"), wxPoint(x, y), sizeBtn);
203
204 x += sizeBtn.x + BUTTON_MARGIN;
205 (void)new wxButton(this, wxID_CANCEL, _("Cancel"), wxPoint(x, y), sizeBtn);
206
207 // position and size the dialog
208 // ----------------------------
209
210 if ( size == wxDefaultSize )
211 {
212 SetClientSize(m_x + m_width + X_MARGIN,
213 m_y + m_height + BITMAP_Y_MARGIN +
214 SEPARATOR_LINE_MARGIN + sizeBtn.y + Y_MARGIN);
215 }
216
217 if ( pos == wxDefaultPosition )
218 {
219 Centre();
220 }
221 }
222
223 bool wxWizardGeneric::ShowPage(size_t page)
224 {
225 wxCHECK_MSG( page < m_pages.GetCount(), FALSE,
226 _T("invalid wizard page index") );
227
228 wxASSERT_MSG( page != (size_t)m_page, _T("this is useless") );
229
230 size_t last = m_pages.GetCount() - 1;
231 bool mustChangeNextBtnLabel = (size_t)m_page == last || page == last;
232
233 if ( m_page != -1 )
234 {
235 wxPanel *panel = DoGetCurrentPage();
236 if ( !panel->TransferDataFromWindow() )
237 return FALSE;
238
239 panel->Hide();
240 }
241
242 m_page = page;
243 DoGetCurrentPage()->Show();
244
245 // update the buttons state
246 m_btnPrev->Enable(m_page != 0);
247 if ( mustChangeNextBtnLabel )
248 {
249 m_btnNext->SetLabel((size_t)m_page == last ? _("&Finish")
250 : _("&Next >"));
251 }
252
253 return TRUE;
254 }
255
256 void wxWizardGeneric::DoAddPage(wxPanel *page)
257 {
258 page->Hide();
259 page->SetSize(m_x, m_y, m_width, m_height);
260 }
261
262 void wxWizardGeneric::AddPage(wxPanel *page)
263 {
264 m_pages.Add(page);
265
266 DoAddPage(page);
267 }
268
269 void wxWizardGeneric::InsertPage(int nPage, wxPanel *page)
270 {
271 m_pages.Insert(page, nPage);
272 if ( nPage < m_page )
273 {
274 // the indices of all pages after the inserted one are shifted by 1
275 m_page++;
276 }
277
278 DoAddPage(page);
279 }
280
281 bool wxWizardGeneric::RunWizard()
282 {
283 wxCHECK_MSG( m_pages.GetCount() != 0, FALSE, _T("can't run empty wizard") );
284
285 // can't return FALSE here because there is no old page
286 (void)ShowPage(0u);
287
288 return ShowModal() == wxID_OK;
289 }
290
291 wxPanel *wxWizardGeneric::GetCurrentPage() const
292 {
293 return IsRunning() ? DoGetCurrentPage() : (wxPanel *)NULL;
294 }
295
296 void wxWizardGeneric::OnCancel(wxCommandEvent& WXUNUSED(event))
297 {
298 wxWizardEvent event(wxEVT_WIZARD_CANCEL, GetId());
299 if ( !GetEventHandler()->ProcessEvent(event) || event.IsAllowed() )
300 {
301 // no objections - close the dialog
302 EndModal(wxID_CANCEL);
303 }
304 //else: request to Cancel ignored
305 }
306
307 void wxWizardGeneric::OnBackOrNext(wxCommandEvent& event)
308 {
309 wxASSERT_MSG( (event.GetEventObject() == m_btnNext) ||
310 (event.GetEventObject() == m_btnPrev),
311 _T("unknown button") );
312
313 int delta = event.GetEventObject() == m_btnNext ? 1 : -1;
314 int page = m_page + delta;
315
316 wxASSERT_MSG( page >= 0, _T("'Back' button should have been disabled!") );
317
318 if ( (size_t)page == m_pages.GetCount() )
319 {
320 // check that we have valid data in the last page too
321 if ( m_pages.Last()->TransferDataFromWindow() )
322 {
323 // that's all, folks!
324 EndModal(wxID_OK);
325 }
326 }
327 else
328 {
329 // just pass to the next page (or may be not - but we don't care here)
330 (void)ShowPage(page);
331 }
332 }
333
334 // ----------------------------------------------------------------------------
335 // our public interface
336 // ----------------------------------------------------------------------------
337
338 /* static */ wxWizard *wxWizard::Create(wxWindow *parent,
339 int id,
340 const wxString& title,
341 const wxBitmap& bitmap,
342 const wxPoint& pos,
343 const wxSize& size)
344 {
345 return new wxWizardGeneric(parent, id, title, bitmap, pos, size);
346 }
347
348 // ----------------------------------------------------------------------------
349 // wxWizardEvent
350 // ----------------------------------------------------------------------------
351
352 wxWizardEvent::wxWizardEvent(wxEventType type, int id)
353 : wxNotifyEvent(type, id)
354 {
355 m_page = m_pageOld = -1;
356 }