From 66cd017c29f69d178d09f6c6a05040461a325709 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sun, 15 Aug 1999 20:59:50 +0000 Subject: [PATCH] wxWizard draft git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@3389 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- include/wx/wizard.h | 87 +++++++++ samples/wizard/Wiztest.bmp | Bin 0 -> 15718 bytes samples/wizard/wiztest.cpp | 125 +++++++++++++ src/generic/wizard.cpp | 355 +++++++++++++++++++++++++++++++++++++ 4 files changed, 567 insertions(+) create mode 100644 include/wx/wizard.h create mode 100644 samples/wizard/Wiztest.bmp create mode 100644 samples/wizard/wiztest.cpp create mode 100644 src/generic/wizard.cpp diff --git a/include/wx/wizard.h b/include/wx/wizard.h new file mode 100644 index 0000000000..118a6f5c0f --- /dev/null +++ b/include/wx/wizard.h @@ -0,0 +1,87 @@ +/////////////////////////////////////////////////////////////////////////////// +// Name: wizard.h +// Purpose: wxWizard class: a GUI control presenting the user with a +// sequence of dialogs which allows to simply perform some task +// Author: Vadim Zeitlin (partly based on work by Ron Kuris and Kevin B. +// Smith) +// Modified by: +// Created: 15.08.99 +// RCS-ID: $Id$ +// Copyright: (c) 1999 Vadim Zeitlin +// Licence: wxWindows license +/////////////////////////////////////////////////////////////////////////////// + +#ifndef _WX_WIZARD_H_ +#define _WX_WIZARD_H_ + +// ---------------------------------------------------------------------------- +// wxWizard +// ---------------------------------------------------------------------------- + +class WXDLLEXPORT wxWizard : public wxDialog +{ +public: + // create the wizard control + static wxWizard *Create(wxWindow *parent, + int id = -1, + const wxString& title = wxEmptyString, + const wxBitmap& bitmap = wxNullBitmap, + const wxPoint& pos = wxDefaultPosition, + const wxSize& size = wxDefaultSize); + + // wizard construction: add/insert new page into it + // adds a page at the end + virtual void AddPage(wxPanel *page) = 0; + // adds a page before the page nPage (the new page will have this index) + virtual void InsertPage(int nPage, wxPanel *page) = 0; + + // executes the wizard, returns TRUE if it was successfully finished, FALSE + // if user cancelled it + virtual bool RunWizard() = 0; + + // get the current page (NULL if RunWizard() isn't running) + virtual wxPanel *GetCurrentPage() const = 0; + +private: + DECLARE_DYNAMIC_CLASS(wxWizard) +}; + +// ---------------------------------------------------------------------------- +// wxWizardEvent class represents an event generated by the wizard +// ---------------------------------------------------------------------------- + +class WXDLLEXPORT wxWizardEvent : public wxNotifyEvent +{ +public: + wxWizardEvent(wxEventType type = wxEVT_NULL, int id = 0); + + // get the previously active page or -1 if none + int GetOldPage() const { return m_pageOld; } + + // get the current page or -1 if none + int GetPage() const { return m_page; } + +private: + int m_pageOld, m_page; + + DECLARE_DYNAMIC_CLASS(wxWizardEvent) +}; + +// ---------------------------------------------------------------------------- +// macros for handling wxWizardEvents +// ---------------------------------------------------------------------------- + +typedef void (wxEvtHandler::*wxWizardEventFunction)(wxWizardEvent&); + +// notifies that the page has just been changed +#define EVT_WIZARD_PAGE_CHANGED(id, fn) { wxEVT_WIZARD_PAGE_CHANGED, id, -1, (wxObjectEventFunction) (wxEventFunction) (wxWizardEventFunction) & fn, (wxObject *)NULL }, + +// the user pressed "" button and the page is going to be +// changed - unless the event handler vetoes the event +#define EVT_WIZARD_PAGE_CHANGING(id, fn) { wxEVT_WIZARD_PAGE_CHANGING, id, -1, (wxObjectEventFunction) (wxEventFunction) (wxWizardEventFunction) & fn, (wxObject *)NULL }, + +// the user pressed "Cancel" button and the wizard is going to be dismissed - +// unless the event handler vetoes the event +#define EVT_WIZARD_CANCEL(id, fn) { wxEVT_WIZARD_CANCEL, id, -1, (wxObjectEventFunction) (wxEventFunction) (wxWizardEventFunction) & fn, (wxObject *)NULL }, + +#endif // _WX_WIZARD_H_ diff --git a/samples/wizard/Wiztest.bmp b/samples/wizard/Wiztest.bmp new file mode 100644 index 0000000000000000000000000000000000000000..d70d3f25bea80a37140ee1379acc3a59afd21e35 GIT binary patch literal 15718 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 literal 0 HcmV?d00001 diff --git a/samples/wizard/wiztest.cpp b/samples/wizard/wiztest.cpp new file mode 100644 index 0000000000..4172763ded --- /dev/null +++ b/samples/wizard/wiztest.cpp @@ -0,0 +1,125 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: wiztest.cpp +// Purpose: wxWindows sample demonstrating wxWizard control +// Author: Vadim Zeitlin +// Modified by: +// Created: 15.08.99 +// RCS-ID: $Id$ +// Copyright: (c) Vadim Zeitlin +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +#ifdef __GNUG__ + #pragma implementation "wiztest.cpp" + #pragma interface "wiztest.cpp" +#endif + +// For compilers that support precompilation, includes "wx/wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +// for all others, include the necessary headers (this file is usually all you +// need because it includes almost all "standard" wxWindows headers +#ifndef WX_PRECOMP + #include "wx/wx.h" +#endif + +#include "wx/wizard.h" + +// ---------------------------------------------------------------------------- +// private classes +// ---------------------------------------------------------------------------- + +// Define a new application type, each program should derive a class from wxApp +class MyApp : public wxApp +{ +public: + // override base class virtuals + virtual bool OnInit(); +}; + +IMPLEMENT_APP(MyApp) + +// ---------------------------------------------------------------------------- +// some pages for our wizard +// ---------------------------------------------------------------------------- + +// this shows how to simply control the validity of the user input by just +// overriding TransferDataFromWindow() - of course, in a real program, the +// check wouldn't be so trivial and the data will be probably saved somewhere +// too +class wxCheckboxPage : public wxPanel +{ +public: + wxCheckboxPage(wxWizard *parent) : wxPanel(parent) + { + m_checkbox = new wxCheckBox(this, -1, "Check me", wxPoint(20, 20)); + } + + virtual bool TransferDataFromWindow() + { + if ( m_checkbox->GetValue() ) + { + wxMessageBox("Clear the checkbox first", "No way", + wxICON_WARNING, this); + + return FALSE; + } + + return TRUE; + } + +private: + wxCheckBox *m_checkbox; +}; + +// ============================================================================ +// implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// the application class +// ---------------------------------------------------------------------------- + +// `Main program' equivalent: the program execution "starts" here +bool MyApp::OnInit() +{ + wxBitmap bmpWizard("wiztest.bmp", wxBITMAP_TYPE_BMP); + + wxWizard *wizard = wxWizard::Create(NULL, -1, + "Absolutely Useless Wizard", + bmpWizard); + + wxPanel *panel = new wxPanel(wizard); + (void)new wxStaticText(panel, -1, + "This wizard doesn't help you to do anything at " + "all.\n" + "\n" + "The next pages will present you with more useless " + "controls."); + wizard->AddPage(panel); + + wizard->AddPage(new wxCheckboxPage(wizard)); + + if ( wizard->RunWizard() ) + { + wxMessageBox("The wizard successfully completed", "That's all", + wxICON_INFORMATION); + } + + wizard->Destroy(); + + // we're done + return FALSE; +} diff --git a/src/generic/wizard.cpp b/src/generic/wizard.cpp new file mode 100644 index 0000000000..6fec89ad79 --- /dev/null +++ b/src/generic/wizard.cpp @@ -0,0 +1,355 @@ +/////////////////////////////////////////////////////////////////////////////// +// Name: generic/wizard.cpp +// Purpose: generic implementation of wxWizard class +// Author: Vadim Zeitlin +// Modified by: +// Created: 15.08.99 +// RCS-ID: $Id$ +// Copyright: (c) 1999 Vadim Zeitlin +// Licence: wxWindows license +/////////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +#ifdef __GNUG__ + #pragma implementation ".h" +#endif + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#ifndef WX_PRECOMP + #include "wx/dynarray.h" + #include "wx/intl.h" +#endif //WX_PRECOMP + +#include "wx/statline.h" + +#include "wx/wizard.h" + +// ---------------------------------------------------------------------------- +// simple types +// ---------------------------------------------------------------------------- + +WX_DEFINE_ARRAY(wxPanel *, wxArrayPages); + +// ---------------------------------------------------------------------------- +// wxWizardGeneric - generic implementation of wxWizard +// ---------------------------------------------------------------------------- + +class wxWizardGeneric : public wxWizard +{ +public: + // ctor + wxWizardGeneric(wxWindow *parent, + int id, + const wxString& title, + const wxBitmap& bitmap, + const wxPoint& pos, + const wxSize& size); + + // implement base class pure virtuals + virtual void AddPage(wxPanel *page); + virtual void InsertPage(int nPage, wxPanel *page); + virtual bool RunWizard(); + virtual wxPanel *GetCurrentPage() const; + + // implementation only from now on + // ------------------------------- + + // is the wizard running? + bool IsRunning() const { return m_page != -1; } + + // show the given page calling TransferDataFromWindow - if it returns + // FALSE, the old page is not hidden and the function returns FALSE + bool ShowPage(size_t page); + + // get the current page assuming the wizard is running + wxPanel *DoGetCurrentPage() const + { + wxASSERT_MSG( IsRunning(), _T("no current page!") ); + + return m_pages[(size_t)m_page]; + } + + // place the given page correctly and hide it + void DoAddPage(wxPanel *page); + +private: + // event handlers + void OnCancel(wxCommandEvent& event); + void OnBackOrNext(wxCommandEvent& event); + + // wizard dimensions + int m_x, m_y; // the origin for the pages + int m_width, // the size of the page itself + m_height; // (total width is m_width + m_x) + + // wizard state + int m_page; // the current page or -1 + wxArrayPages m_pages; // the array with all wizards pages + + // wizard controls + wxButton *m_btnPrev, // the "" or "Finish" button + + DECLARE_EVENT_TABLE() +}; + +// ---------------------------------------------------------------------------- +// event tables and such +// ---------------------------------------------------------------------------- + +BEGIN_EVENT_TABLE(wxWizardGeneric, wxDialog) + EVT_BUTTON(wxID_CANCEL, OnCancel) + EVT_BUTTON(-1, OnBackOrNext) +END_EVENT_TABLE() + +IMPLEMENT_ABSTRACT_CLASS(wxWizard, wxDialog) +IMPLEMENT_DYNAMIC_CLASS(wxWizardEvent, wxNotifyEvent) + +// ============================================================================ +// implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// generic wxWizard implementation +// ---------------------------------------------------------------------------- + +wxWizardGeneric::wxWizardGeneric(wxWindow *parent, + int id, + const wxString& title, + const wxBitmap& bitmap, + const wxPoint& pos, + const wxSize& size) +{ + // constants defining the dialog layout + // ------------------------------------ + + // these constants define the position of the upper left corner of the + // bitmap or the page in the wizard + static const int X_MARGIN = 10; + static const int Y_MARGIN = 10; + + // margin between the bitmap and the panel + static const int BITMAP_X_MARGIN = 15; + + // margin between the bitmap and the static line + static const int BITMAP_Y_MARGIN = 15; + + // margin between the static line and the buttons + static const int SEPARATOR_LINE_MARGIN = 15; + + // margin between "Next >" and "Cancel" buttons + static const int BUTTON_MARGIN = 10; + + // default width and height of the page + static const int DEFAULT_PAGE_WIDTH = 270; + static const int DEFAULT_PAGE_HEIGHT = 290; + + // init members + // ------------ + + m_page = -1; + + // create controls + // --------------- + + wxSize sizeBtn = wxButton::GetDefaultSize(); + + (void)wxDialog::Create(parent, id, title, pos, size); + + // the global dialog layout is: a row of buttons at the bottom (aligned to + // the right), the static line above them, the bitmap (if any) on the left + // of the upper part of the dialog and the panel in the remaining space + m_x = X_MARGIN; + m_y = Y_MARGIN; + if ( bitmap.Ok() ) + { + (void)new wxStaticBitmap(this, -1, bitmap, wxPoint(m_x, m_y)); + + m_x += bitmap.GetWidth() + BITMAP_X_MARGIN; + m_height = bitmap.GetHeight(); + } + else + { + m_height = DEFAULT_PAGE_HEIGHT; + } + + m_width = DEFAULT_PAGE_WIDTH; + + int x = X_MARGIN; + int y = m_y + m_height + BITMAP_Y_MARGIN; + (void)new wxStaticLine(this, -1, wxPoint(x, y), + wxSize(m_x + m_width - x, 2)); + + x = m_x + m_width - 3*sizeBtn.x - BUTTON_MARGIN; + y += SEPARATOR_LINE_MARGIN; + m_btnPrev = new wxButton(this, -1, _("< &Back"), wxPoint(x, y), sizeBtn); + + x += sizeBtn.x; + m_btnNext = new wxButton(this, -1, _("&Next >"), wxPoint(x, y), sizeBtn); + + x += sizeBtn.x + BUTTON_MARGIN; + (void)new wxButton(this, wxID_CANCEL, _("Cancel"), wxPoint(x, y), sizeBtn); + + // position and size the dialog + // ---------------------------- + + if ( size == wxDefaultSize ) + { + SetClientSize(m_x + m_width + X_MARGIN, + m_y + m_height + BITMAP_Y_MARGIN + + SEPARATOR_LINE_MARGIN + sizeBtn.y + Y_MARGIN); + } + + if ( pos == wxDefaultPosition ) + { + Centre(); + } +} + +bool wxWizardGeneric::ShowPage(size_t page) +{ + wxCHECK_MSG( page < m_pages.GetCount(), FALSE, + _T("invalid wizard page index") ); + + wxASSERT_MSG( page != (size_t)m_page, _T("this is useless") ); + + size_t last = m_pages.GetCount() - 1; + bool mustChangeNextBtnLabel = (size_t)m_page == last || page == last; + + if ( m_page != -1 ) + { + wxPanel *panel = DoGetCurrentPage(); + if ( !panel->TransferDataFromWindow() ) + return FALSE; + + panel->Hide(); + } + + m_page = page; + DoGetCurrentPage()->Show(); + + // update the buttons state + m_btnPrev->Enable(m_page != 0); + if ( mustChangeNextBtnLabel ) + { + m_btnNext->SetLabel((size_t)m_page == last ? _("&Finish") + : _("&Next >")); + } + + return TRUE; +} + +void wxWizardGeneric::DoAddPage(wxPanel *page) +{ + page->Hide(); + page->SetSize(m_x, m_y, m_width, m_height); +} + +void wxWizardGeneric::AddPage(wxPanel *page) +{ + m_pages.Add(page); + + DoAddPage(page); +} + +void wxWizardGeneric::InsertPage(int nPage, wxPanel *page) +{ + m_pages.Insert(page, nPage); + if ( nPage < m_page ) + { + // the indices of all pages after the inserted one are shifted by 1 + m_page++; + } + + DoAddPage(page); +} + +bool wxWizardGeneric::RunWizard() +{ + wxCHECK_MSG( m_pages.GetCount() != 0, FALSE, _T("can't run empty wizard") ); + + // can't return FALSE here because there is no old page + (void)ShowPage(0u); + + return ShowModal() == wxID_OK; +} + +wxPanel *wxWizardGeneric::GetCurrentPage() const +{ + return IsRunning() ? DoGetCurrentPage() : (wxPanel *)NULL; +} + +void wxWizardGeneric::OnCancel(wxCommandEvent& WXUNUSED(event)) +{ + wxWizardEvent event(wxEVT_WIZARD_CANCEL, GetId()); + if ( !GetEventHandler()->ProcessEvent(event) || event.IsAllowed() ) + { + // no objections - close the dialog + EndModal(wxID_CANCEL); + } + //else: request to Cancel ignored +} + +void wxWizardGeneric::OnBackOrNext(wxCommandEvent& event) +{ + wxASSERT_MSG( (event.GetEventObject() == m_btnNext) || + (event.GetEventObject() == m_btnPrev), + _T("unknown button") ); + + int delta = event.GetEventObject() == m_btnNext ? 1 : -1; + int page = m_page + delta; + + wxASSERT_MSG( page >= 0, _T("'Back' button should have been disabled!") ); + + if ( (size_t)page == m_pages.GetCount() ) + { + // check that we have valid data in the last page too + if ( m_pages.Last()->TransferDataFromWindow() ) + { + // that's all, folks! + EndModal(wxID_OK); + } + } + else + { + // just pass to the next page (or may be not - but we don't care here) + (void)ShowPage(page); + } +} + +// ---------------------------------------------------------------------------- +// our public interface +// ---------------------------------------------------------------------------- + +/* static */ wxWizard *wxWizard::Create(wxWindow *parent, + int id, + const wxString& title, + const wxBitmap& bitmap, + const wxPoint& pos, + const wxSize& size) +{ + return new wxWizardGeneric(parent, id, title, bitmap, pos, size); +} + +// ---------------------------------------------------------------------------- +// wxWizardEvent +// ---------------------------------------------------------------------------- + +wxWizardEvent::wxWizardEvent(wxEventType type, int id) + : wxNotifyEvent(type, id) +{ + m_page = m_pageOld = -1; +} -- 2.47.2