]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/generic/wizard.cpp
we now send iconize events
[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#ifndef WX_PRECOMP
32 #include "wx/dynarray.h"
33 #include "wx/intl.h"
34 #include "wx/statbmp.h"
35 #include "wx/button.h"
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
48// ----------------------------------------------------------------------------
49// event tables and such
50// ----------------------------------------------------------------------------
51
52DEFINE_EVENT_TYPE(wxEVT_WIZARD_PAGE_CHANGED)
53DEFINE_EVENT_TYPE(wxEVT_WIZARD_PAGE_CHANGING)
54DEFINE_EVENT_TYPE(wxEVT_WIZARD_CANCEL)
55
56BEGIN_EVENT_TABLE(wxWizard, wxDialog)
57 EVT_BUTTON(wxID_CANCEL, wxWizard::OnCancel)
58 EVT_BUTTON(-1, wxWizard::OnBackOrNext)
59END_EVENT_TABLE()
60
61IMPLEMENT_DYNAMIC_CLASS(wxWizard, wxDialog)
62IMPLEMENT_ABSTRACT_CLASS(wxWizardPage, wxPanel)
63IMPLEMENT_DYNAMIC_CLASS(wxWizardPageSimple, wxWizardPage)
64IMPLEMENT_DYNAMIC_CLASS(wxWizardEvent, wxNotifyEvent)
65
66// ============================================================================
67// implementation
68// ============================================================================
69
70// ----------------------------------------------------------------------------
71// wxWizardPage
72// ----------------------------------------------------------------------------
73
74wxWizardPage::wxWizardPage(wxWizard *parent, const wxBitmap& bitmap)
75 : wxPanel(parent), m_bitmap(bitmap)
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}
94// ----------------------------------------------------------------------------
95// generic wxWizard implementation
96// ----------------------------------------------------------------------------
97
98wxWizard::wxWizard(wxWindow *parent,
99 int id,
100 const wxString& title,
101 const wxBitmap& bitmap,
102 const wxPoint& pos)
103 : m_posWizard(pos), m_bitmap(bitmap)
104{
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
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
144 // create controls
145 // ---------------
146
147 wxSize sizeBtn = wxButton::GetDefaultSize();
148
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;
154
155 int defaultHeight;
156 if ( m_bitmap.Ok() )
157 {
158 m_statbmp = new wxStaticBitmap(this, -1, m_bitmap, wxPoint(m_x, m_y));
159
160 m_x += m_bitmap.GetWidth() + BITMAP_X_MARGIN;
161
162 defaultHeight = m_bitmap.GetHeight();
163 }
164 else
165 {
166 m_statbmp = (wxStaticBitmap *)NULL;
167
168 defaultHeight = DEFAULT_PAGE_HEIGHT;
169 }
170
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;
179
180 int x = X_MARGIN;
181 int y = m_y + m_height + BITMAP_Y_MARGIN;
182
183#if wxUSE_STATLINE
184 (void)new wxStaticLine(this, -1, wxPoint(x, y),
185 wxSize(m_x + m_width - x, 2));
186#endif // wxUSE_STATLINE
187
188 x = m_x + m_width - 3*sizeBtn.x - BUTTON_MARGIN;
189 y += SEPARATOR_LINE_MARGIN;
190 m_btnPrev = new wxButton(this, wxID_BACKWARD, _("< &Back"), wxPoint(x, y), sizeBtn);
191
192 x += sizeBtn.x;
193 m_btnNext = new wxButton(this, wxID_FORWARD, _("&Next >"), wxPoint(x, y), sizeBtn);
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
201 SetClientSize(m_x + m_width + X_MARGIN,
202 m_y + m_height + BITMAP_Y_MARGIN +
203 SEPARATOR_LINE_MARGIN + sizeBtn.y + Y_MARGIN);
204
205 if ( m_posWizard == wxDefaultPosition )
206 {
207 CentreOnScreen();
208 }
209}
210
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
219bool wxWizard::ShowPage(wxWizardPage *page, bool goingForward)
220{
221 wxASSERT_MSG( page != m_page, wxT("this is useless") );
222
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;
226
227 // and this tells us whether we already had the default bitmap before
228 bool bmpWasDefault = TRUE;
229
230 if ( m_page )
231 {
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
238 return FALSE;
239 }
240
241 m_page->Hide();
242
243 btnLabelWasNext = m_page->GetNext() != (wxWizardPage *)NULL;
244 bmpWasDefault = !m_page->GetBitmap().Ok();
245 }
246
247 // set the new one
248 m_page = page;
249
250 // is this the end?
251 if ( !m_page )
252 {
253 // terminate successfully
254 EndModal(wxID_OK);
255
256 return TRUE;
257 }
258
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);
262
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();
267
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 {
272 wxBitmap bmp;
273 if ( bmpIsDefault )
274 bmp = m_bitmap;
275 else
276 bmp = m_page->GetBitmap();
277 m_statbmp->SetBitmap(bmp);
278 }
279
280 // and update the buttons state
281 m_btnPrev->Enable(m_page->GetPrev() != (wxWizardPage *)NULL);
282
283 bool hasNext = m_page->GetNext() != (wxWizardPage *)NULL;
284 if ( btnLabelWasNext != hasNext )
285 {
286 // need to update
287 if (btnLabelWasNext)
288 m_btnNext->SetLabel(_("&Finish"));
289 else
290 m_btnNext->SetLabel(_("&Next >"));
291 }
292 // nothing to do: the label was already correct
293
294 return TRUE;
295}
296
297bool wxWizard::RunWizard(wxWizardPage *firstPage)
298{
299 wxCHECK_MSG( firstPage, FALSE, wxT("can't run empty wizard") );
300
301 DoCreateControls();
302
303 // can't return FALSE here because there is no old page
304 (void)ShowPage(firstPage, TRUE /* forward */);
305
306 return ShowModal() == wxID_OK;
307}
308
309wxWizardPage *wxWizard::GetCurrentPage() const
310{
311 return m_page;
312}
313
314wxSize wxWizard::GetPageSize() const
315{
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
320 return wxSize(m_width, m_height);
321}
322
323void wxWizard::OnCancel(wxCommandEvent& WXUNUSED(event))
324{
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
329 wxWizardEvent event(wxEVT_WIZARD_CANCEL, GetId());
330 if ( !win->GetEventHandler()->ProcessEvent(event) || event.IsAllowed() )
331 {
332 // no objections - close the dialog
333 EndModal(wxID_CANCEL);
334 }
335 //else: request to Cancel ignored
336}
337
338void wxWizard::OnBackOrNext(wxCommandEvent& event)
339{
340 wxASSERT_MSG( (event.GetEventObject() == m_btnNext) ||
341 (event.GetEventObject() == m_btnPrev),
342 wxT("unknown button") );
343
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
353 bool forward = event.GetEventObject() == m_btnNext;
354
355 wxWizardPage *page;
356 if ( forward )
357 {
358 page = m_page->GetNext();
359 }
360 else // back
361 {
362 page = m_page->GetPrev();
363
364 wxASSERT_MSG( page, wxT("\"<Back\" button should have been disabled") );
365 }
366
367 // just pass to the new page (or may be not - but we don't care here)
368 (void)ShowPage(page, forward);
369}
370
371// ----------------------------------------------------------------------------
372// our public interface
373// ----------------------------------------------------------------------------
374
375/* static */
376wxWizard *wxWizardBase::Create(wxWindow *parent,
377 int id,
378 const wxString& title,
379 const wxBitmap& bitmap,
380 const wxPoint& pos,
381 const wxSize& WXUNUSED(size))
382{
383 return new wxWizard(parent, id, title, bitmap, pos);
384}
385
386// ----------------------------------------------------------------------------
387// wxWizardEvent
388// ----------------------------------------------------------------------------
389
390wxWizardEvent::wxWizardEvent(wxEventType type, int id, bool direction)
391 : wxNotifyEvent(type, id)
392{
393 m_direction = direction;
394}
395