home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / wxos2240.zip / wxWindows-2.4.0 / src / generic / wizard.cpp < prev   
C/C++ Source or Header  |  2002-12-09  |  17KB  |  568 lines

  1. ///////////////////////////////////////////////////////////////////////////////
  2. // Name:        generic/wizard.cpp
  3. // Purpose:     generic implementation of wxWizard class
  4. // Author:      Vadim Zeitlin
  5. // Modified by: Robert Cavanaugh
  6. //              1) Added capability for wxWizardPage to accept resources
  7. //              2) Added "Help" button handler stub
  8. //              3) Fixed ShowPage() bug on displaying bitmaps
  9. // Created:     15.08.99
  10. // RCS-ID:      $Id: wizard.cpp,v 1.34.2.2 2002/12/09 09:46:04 JS Exp $
  11. // Copyright:   (c) 1999 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
  12. // Licence:     wxWindows license
  13. ///////////////////////////////////////////////////////////////////////////////
  14.  
  15. // ============================================================================
  16. // declarations
  17. // ============================================================================
  18.  
  19. // ----------------------------------------------------------------------------
  20. // headers
  21. // ----------------------------------------------------------------------------
  22.  
  23. #ifdef __GNUG__
  24.     #pragma implementation "wizardg.h"
  25. #endif
  26.  
  27. // For compilers that support precompilation, includes "wx.h".
  28. #include "wx/wxprec.h"
  29.  
  30. #ifdef __BORLANDC__
  31.     #pragma hdrstop
  32. #endif
  33.  
  34. #if wxUSE_WIZARDDLG
  35.  
  36. #ifndef WX_PRECOMP
  37.     #include "wx/dynarray.h"
  38.     #include "wx/intl.h"
  39.     #include "wx/statbmp.h"
  40.     #include "wx/button.h"
  41. #endif //WX_PRECOMP
  42.  
  43. #include "wx/statline.h"
  44.  
  45. #include "wx/wizard.h"
  46.  
  47. // ----------------------------------------------------------------------------
  48. // simple types
  49. // ----------------------------------------------------------------------------
  50.  
  51. WX_DEFINE_ARRAY(wxPanel *, wxArrayPages);
  52.  
  53. // ----------------------------------------------------------------------------
  54. // event tables and such
  55. // ----------------------------------------------------------------------------
  56.  
  57. DEFINE_EVENT_TYPE(wxEVT_WIZARD_PAGE_CHANGED)
  58. DEFINE_EVENT_TYPE(wxEVT_WIZARD_PAGE_CHANGING)
  59. DEFINE_EVENT_TYPE(wxEVT_WIZARD_CANCEL)
  60. DEFINE_EVENT_TYPE(wxEVT_WIZARD_FINISHED)
  61. DEFINE_EVENT_TYPE(wxEVT_WIZARD_HELP)
  62.  
  63. BEGIN_EVENT_TABLE(wxWizard, wxDialog)
  64.     EVT_BUTTON(wxID_CANCEL, wxWizard::OnCancel)
  65.     EVT_BUTTON(wxID_BACKWARD, wxWizard::OnBackOrNext)
  66.     EVT_BUTTON(wxID_FORWARD, wxWizard::OnBackOrNext)
  67.     EVT_BUTTON(wxID_HELP, wxWizard::OnHelp)
  68.  
  69.     EVT_WIZARD_PAGE_CHANGED(-1, wxWizard::OnWizEvent)
  70.     EVT_WIZARD_PAGE_CHANGING(-1, wxWizard::OnWizEvent)
  71.     EVT_WIZARD_CANCEL(-1, wxWizard::OnWizEvent)
  72.     EVT_WIZARD_FINISHED(-1, wxWizard::OnWizEvent)
  73.     EVT_WIZARD_HELP(-1, wxWizard::OnWizEvent)
  74. END_EVENT_TABLE()
  75.  
  76. IMPLEMENT_DYNAMIC_CLASS(wxWizard, wxDialog)
  77. IMPLEMENT_ABSTRACT_CLASS(wxWizardPage, wxPanel)
  78. IMPLEMENT_DYNAMIC_CLASS(wxWizardPageSimple, wxWizardPage)
  79. IMPLEMENT_DYNAMIC_CLASS(wxWizardEvent, wxNotifyEvent)
  80.  
  81. // ============================================================================
  82. // implementation
  83. // ============================================================================
  84.  
  85. // ----------------------------------------------------------------------------
  86. // wxWizardPage
  87. // ----------------------------------------------------------------------------
  88.  
  89. void wxWizardPage::Init()
  90. {
  91.     m_bitmap = wxNullBitmap;
  92. }
  93.  
  94. wxWizardPage::wxWizardPage(wxWizard *parent,
  95.                            const wxBitmap& bitmap,
  96.                            const wxChar *resource)
  97. {
  98.     Create(parent, bitmap, resource);
  99. }
  100.  
  101. bool wxWizardPage::Create(wxWizard *parent,
  102.                           const wxBitmap& bitmap,
  103.                           const wxChar *resource)
  104. {
  105.     if ( !wxPanel::Create(parent, -1) )
  106.         return FALSE;
  107.  
  108.     if ( resource != NULL )
  109.     {
  110. #if wxUSE_WX_RESOURCES
  111.         if ( !LoadFromResource(this, resource) )
  112.         {
  113.             wxFAIL_MSG(wxT("wxWizardPage LoadFromResource failed!!!!"));
  114.         }
  115. #endif // wxUSE_RESOURCES
  116.     }
  117.  
  118.     m_bitmap = bitmap;
  119.  
  120.     // initially the page is hidden, it's shown only when it becomes current
  121.     Hide();
  122.  
  123.     return TRUE;
  124. }
  125.  
  126. // ----------------------------------------------------------------------------
  127. // wxWizardPageSimple
  128. // ----------------------------------------------------------------------------
  129.  
  130. wxWizardPage *wxWizardPageSimple::GetPrev() const
  131. {
  132.     return m_prev;
  133. }
  134.  
  135. wxWizardPage *wxWizardPageSimple::GetNext() const
  136. {
  137.     return m_next;
  138. }
  139. // ----------------------------------------------------------------------------
  140. // generic wxWizard implementation
  141. // ----------------------------------------------------------------------------
  142.  
  143. void wxWizard::Init()
  144. {
  145.     m_posWizard = wxDefaultPosition;
  146.     m_page = (wxWizardPage *)NULL;
  147.     m_btnPrev = m_btnNext = NULL;
  148.     m_statbmp = NULL;
  149. }
  150.  
  151. bool wxWizard::Create(wxWindow *parent,
  152.                    int id,
  153.                    const wxString& title,
  154.                    const wxBitmap& bitmap,
  155.                    const wxPoint& pos)
  156. {
  157.     m_posWizard = pos;
  158.     m_bitmap = bitmap ;
  159.  
  160.     // just create the dialog itself here, the controls will be created in
  161.     // DoCreateControls() called later when we know our final size
  162.     m_page = (wxWizardPage *)NULL;
  163.     m_btnPrev = m_btnNext = NULL;
  164.     m_statbmp = NULL;
  165.  
  166.     return wxDialog::Create(parent, id, title, pos);
  167. }
  168.  
  169. void wxWizard::DoCreateControls()
  170. {
  171.     // do nothing if the controls were already created
  172.     if ( WasCreated() )
  173.         return;
  174.  
  175.     // constants defining the dialog layout
  176.     // ------------------------------------
  177.  
  178.     // these constants define the position of the upper left corner of the
  179.     // bitmap or the page in the wizard
  180.     static const int X_MARGIN = 10;
  181.     static const int Y_MARGIN = 10;
  182.  
  183.     // margin between the bitmap and the panel
  184.     static const int BITMAP_X_MARGIN = 15;
  185.  
  186.     // margin between the bitmap and the static line
  187.     static const int BITMAP_Y_MARGIN = 15;
  188.  
  189.     // margin between the static line and the buttons
  190.     static const int SEPARATOR_LINE_MARGIN = 15;
  191.  
  192.     // margin between "Next >" and "Cancel" buttons
  193.     static const int BUTTON_MARGIN = 10;
  194.  
  195.     // margin between Back and Next buttons
  196. #ifdef __WXMAC__
  197.     static const int BACKNEXT_MARGIN = 10;
  198. #else
  199.     static const int BACKNEXT_MARGIN = 0;
  200. #endif
  201.  
  202.     // default width and height of the page
  203.     static const int DEFAULT_PAGE_WIDTH = 270;
  204.     static const int DEFAULT_PAGE_HEIGHT = 290;
  205.  
  206.     // create controls
  207.     // ---------------
  208.  
  209.     wxSize sizeBtn = wxButton::GetDefaultSize();
  210.  
  211.     // the global dialog layout is: a row of buttons at the bottom (aligned to
  212.     // the right), the static line above them, the bitmap (if any) on the left
  213.     // of the upper part of the dialog and the panel in the remaining space
  214.     m_x = X_MARGIN;
  215.     m_y = Y_MARGIN;
  216.  
  217.     int defaultHeight;
  218.     if ( m_bitmap.Ok() )
  219.     {
  220.         m_statbmp = new wxStaticBitmap(this, -1, m_bitmap, wxPoint(m_x, m_y));
  221.  
  222.         m_x += m_bitmap.GetWidth() + BITMAP_X_MARGIN;
  223.  
  224.         defaultHeight = m_bitmap.GetHeight();
  225.     }
  226.     else
  227.     {
  228.         m_statbmp = (wxStaticBitmap *)NULL;
  229.  
  230.         defaultHeight = DEFAULT_PAGE_HEIGHT;
  231.     }
  232.  
  233.     // use default size if none given and also make sure that the dialog is
  234.     // not less than the default size
  235.     m_height = m_sizePage.y == -1 ? defaultHeight : m_sizePage.y;
  236.     m_width = m_sizePage.x == -1 ? DEFAULT_PAGE_WIDTH : m_sizePage.x;
  237.     if ( m_height < defaultHeight )
  238.         m_height = defaultHeight;
  239.     if ( m_width < DEFAULT_PAGE_WIDTH )
  240.         m_width = DEFAULT_PAGE_WIDTH;
  241.  
  242.     int x = X_MARGIN;
  243.     int y = m_y + m_height + BITMAP_Y_MARGIN;
  244.  
  245. #if wxUSE_STATLINE
  246.     (void)new wxStaticLine(this, -1, wxPoint(x, y),
  247.                            wxSize(m_x + m_width - x, 2));
  248. #endif // wxUSE_STATLINE
  249.  
  250.     x = m_x + m_width - 3*sizeBtn.x - BUTTON_MARGIN - BACKNEXT_MARGIN;
  251.     y += SEPARATOR_LINE_MARGIN;
  252.  
  253.     if (GetExtraStyle() & wxWIZARD_EX_HELPBUTTON)
  254.     {
  255.         x -= sizeBtn.x;
  256.         x -= BUTTON_MARGIN ;
  257.  
  258.         (void)new wxButton(this, wxID_HELP, _("&Help"), wxPoint(x, y), sizeBtn);
  259.         x += sizeBtn.x;
  260.         x += BUTTON_MARGIN ;
  261.     }
  262.  
  263.     m_btnPrev = new wxButton(this, wxID_BACKWARD, _("< &Back"), wxPoint(x, y), sizeBtn);
  264.  
  265.     x += sizeBtn.x;
  266.     x += BACKNEXT_MARGIN;
  267.  
  268.     m_btnNext = new wxButton(this, wxID_FORWARD, _("&Next >"), wxPoint(x, y), sizeBtn);
  269.  
  270.     x += sizeBtn.x + BUTTON_MARGIN;
  271.     (void)new wxButton(this, wxID_CANCEL, _("&Cancel"), wxPoint(x, y), sizeBtn);
  272.  
  273.     // position and size the dialog
  274.     // ----------------------------
  275.  
  276.     SetClientSize(m_x + m_width + X_MARGIN,
  277.                   m_y + m_height + BITMAP_Y_MARGIN +
  278.                     SEPARATOR_LINE_MARGIN + sizeBtn.y + Y_MARGIN);
  279.  
  280.     if ( m_posWizard == wxDefaultPosition )
  281.     {
  282.         CentreOnScreen();
  283.     }
  284. }
  285.  
  286. void wxWizard::SetPageSize(const wxSize& size)
  287. {
  288.     // otherwise it will have no effect now as it's too late...
  289.     wxASSERT_MSG( !WasCreated(), _T("should be called before RunWizard()!") );
  290.  
  291.     m_sizePage = size;
  292. }
  293.  
  294. void wxWizard::FitToPage(const wxWizardPage *page)
  295. {
  296.     // otherwise it will have no effect now as it's too late...
  297.     wxASSERT_MSG( !WasCreated(), _T("should be called before RunWizard()!") );
  298.  
  299.     wxSize sizeMax;
  300.     while ( page )
  301.     {
  302.         wxSize size = page->GetBestSize();
  303.  
  304.         if ( size.x > sizeMax.x )
  305.             sizeMax.x = size.x;
  306.  
  307.         if ( size.y > sizeMax.y )
  308.             sizeMax.y = size.y;
  309.  
  310.         page = page->GetNext();
  311.     }
  312.  
  313.     if ( sizeMax.x > m_sizePage.x )
  314.         m_sizePage.x = sizeMax.x;
  315.  
  316.     if ( sizeMax.y > m_sizePage.y )
  317.         m_sizePage.y = sizeMax.y;
  318. }
  319.  
  320. bool wxWizard::ShowPage(wxWizardPage *page, bool goingForward)
  321. {
  322.     wxASSERT_MSG( page != m_page, wxT("this is useless") );
  323.  
  324.     // we'll use this to decide whether we have to change the label of this
  325.     // button or not (initially the label is "Next")
  326.     bool btnLabelWasNext = TRUE;
  327.  
  328.     // Modified 10-20-2001 Robert Cavanaugh.
  329.     // Fixed bug for displaying a new bitmap
  330.     // in each *consecutive* page
  331.  
  332.     // flag to indicate if this page uses a new bitmap
  333.     bool bmpIsDefault = TRUE;
  334.  
  335.     // use these labels to determine if we need to change the bitmap
  336.     // for this page
  337.     wxBitmap bmpPrev, bmpCur;
  338.  
  339.     // check for previous page
  340.     if ( m_page )
  341.     {
  342.         // send the event to the old page
  343.         wxWizardEvent event(wxEVT_WIZARD_PAGE_CHANGING, GetId(), goingForward, m_page);
  344.         if ( m_page->GetEventHandler()->ProcessEvent(event) &&
  345.              !event.IsAllowed() )
  346.         {
  347.             // vetoed by the page
  348.             return FALSE;
  349.         }
  350.  
  351.         m_page->Hide();
  352.  
  353.         btnLabelWasNext = HasNextPage(m_page);
  354.  
  355.         // Get the bitmap of the previous page (if it exists)
  356.         if ( m_page->GetBitmap().Ok() )
  357.         {
  358.             bmpPrev = m_page->GetBitmap();
  359.         }
  360.     }
  361.  
  362.     // set the new page
  363.     m_page = page;
  364.  
  365.     // is this the end?
  366.     if ( !m_page )
  367.     {
  368.         // terminate successfully
  369.         EndModal(wxID_OK);
  370.         if ( !IsModal() )
  371.          {
  372.            wxWizardEvent event(wxEVT_WIZARD_FINISHED, GetId(),FALSE, 0);
  373.            (void)GetEventHandler()->ProcessEvent(event);
  374.          }
  375.         return TRUE;
  376.     }
  377.  
  378.     // position and show the new page
  379.     (void)m_page->TransferDataToWindow();
  380.     m_page->SetSize(m_x, m_y, m_width, m_height);
  381.  
  382.     // check if bitmap needs to be updated
  383.     // update default flag as well
  384.     if ( m_page->GetBitmap().Ok() )
  385.     {
  386.         bmpCur = m_page->GetBitmap();
  387.         bmpIsDefault = FALSE;
  388.     }
  389.  
  390.     // change the bitmap if:
  391.     // 1) a default bitmap was selected in constructor
  392.     // 2) this page was constructed with a bitmap
  393.     // 3) this bitmap is not the previous bitmap
  394.     if ( m_statbmp && (bmpCur != bmpPrev) )
  395.     {
  396.         wxBitmap bmp;
  397.         if ( bmpIsDefault )
  398.             bmp = m_bitmap;
  399.         else
  400.             bmp = m_page->GetBitmap();
  401.         m_statbmp->SetBitmap(bmp);
  402.     }
  403.  
  404.     // and update the buttons state
  405.     m_btnPrev->Enable(HasPrevPage(m_page));
  406.  
  407.     bool hasNext = HasNextPage(m_page);
  408.     if ( btnLabelWasNext != hasNext )
  409.     {
  410.         // need to update
  411.         if (btnLabelWasNext)
  412.             m_btnNext->SetLabel(_("&Finish"));
  413.         else
  414.             m_btnNext->SetLabel(_("&Next >"));
  415.     }
  416.     // nothing to do: the label was already correct
  417.  
  418.     // send the change event to the new page now
  419.     wxWizardEvent event(wxEVT_WIZARD_PAGE_CHANGED, GetId(), goingForward, m_page);
  420.     (void)m_page->GetEventHandler()->ProcessEvent(event);
  421.  
  422.     // and finally show it
  423.     m_page->Show();
  424.     m_page->SetFocus();
  425.  
  426.     return TRUE;
  427. }
  428.  
  429. bool wxWizard::RunWizard(wxWizardPage *firstPage)
  430. {
  431.     wxCHECK_MSG( firstPage, FALSE, wxT("can't run empty wizard") );
  432.  
  433.     DoCreateControls();
  434.  
  435.     // can't return FALSE here because there is no old page
  436.     (void)ShowPage(firstPage, TRUE /* forward */);
  437.  
  438.     return ShowModal() == wxID_OK;
  439. }
  440.  
  441. wxWizardPage *wxWizard::GetCurrentPage() const
  442. {
  443.     return m_page;
  444. }
  445.  
  446. wxSize wxWizard::GetPageSize() const
  447. {
  448.     // make sure that the controls are created because otherwise m_width and
  449.     // m_height would be both still -1
  450.     wxConstCast(this, wxWizard)->DoCreateControls();
  451.  
  452.     return wxSize(m_width, m_height);
  453. }
  454.  
  455. void wxWizard::OnCancel(wxCommandEvent& WXUNUSED(event))
  456. {
  457.     // this function probably can never be called when we don't have an active
  458.     // page, but a small extra check won't hurt
  459.     wxWindow *win = m_page ? (wxWindow *)m_page : (wxWindow *)this;
  460.  
  461.     wxWizardEvent event(wxEVT_WIZARD_CANCEL, GetId(), FALSE, m_page);
  462.     if ( !win->GetEventHandler()->ProcessEvent(event) || event.IsAllowed() )
  463.     {
  464.         // no objections - close the dialog
  465.         EndModal(wxID_CANCEL);
  466.     }
  467.     //else: request to Cancel ignored
  468. }
  469.  
  470. void wxWizard::OnBackOrNext(wxCommandEvent& event)
  471. {
  472.     wxASSERT_MSG( (event.GetEventObject() == m_btnNext) ||
  473.                   (event.GetEventObject() == m_btnPrev),
  474.                   wxT("unknown button") );
  475.  
  476.     // ask the current page first: notice that we do it before calling
  477.     // GetNext/Prev() because the data transfered from the controls of the page
  478.     // may change the value returned by these methods
  479.     if ( m_page && !m_page->TransferDataFromWindow() )
  480.     {
  481.         // the page data is incorrect, don't do anything
  482.         return;
  483.     }
  484.  
  485.     bool forward = event.GetEventObject() == m_btnNext;
  486.  
  487.     wxWizardPage *page;
  488.     if ( forward )
  489.     {
  490.         page = m_page->GetNext();
  491.     }
  492.     else // back
  493.     {
  494.         page = m_page->GetPrev();
  495.  
  496.         wxASSERT_MSG( page, wxT("\"<Back\" button should have been disabled") );
  497.     }
  498.  
  499.     // just pass to the new page (or may be not - but we don't care here)
  500.     (void)ShowPage(page, forward);
  501. }
  502.  
  503. void wxWizard::OnHelp(wxCommandEvent& WXUNUSED(event))
  504. {
  505.     // this function probably can never be called when we don't have an active
  506.     // page, but a small extra check won't hurt
  507.     if(m_page != NULL)
  508.     {
  509.         // Create and send the help event to the specific page handler
  510.         // event data contains the active page so that context-sensitive
  511.         // help is possible
  512.         wxWizardEvent eventHelp(wxEVT_WIZARD_HELP, GetId(), TRUE, m_page);
  513.         (void)m_page->GetEventHandler()->ProcessEvent(eventHelp);
  514.     }
  515. }
  516.  
  517. void wxWizard::OnWizEvent(wxWizardEvent& event)
  518. {
  519.     // the dialogs have wxWS_EX_BLOCK_EVENTS style on by default but we want to
  520.     // propagate wxEVT_WIZARD_XXX to the parent (if any), so do it manually
  521.     if ( !(GetExtraStyle() & wxWS_EX_BLOCK_EVENTS) )
  522.     {
  523.         // the event will be propagated anyhow
  524.         return;
  525.     }
  526.  
  527.     wxWindow *parent = GetParent();
  528.  
  529.     if ( !parent || !parent->GetEventHandler()->ProcessEvent(event) )
  530.     {
  531.         event.Skip();
  532.     }
  533. }
  534.  
  535. // ----------------------------------------------------------------------------
  536. // our public interface
  537. // ----------------------------------------------------------------------------
  538.  
  539. #ifdef WXWIN_COMPATIBILITY_2_2
  540.  
  541. /* static */
  542. wxWizard *wxWizardBase::Create(wxWindow *parent,
  543.                                int id,
  544.                                const wxString& title,
  545.                                const wxBitmap& bitmap,
  546.                                const wxPoint& pos,
  547.                                const wxSize& WXUNUSED(size))
  548. {
  549.     return new wxWizard(parent, id, title, bitmap, pos);
  550. }
  551.  
  552. #endif // WXWIN_COMPATIBILITY_2_2
  553.  
  554. // ----------------------------------------------------------------------------
  555. // wxWizardEvent
  556. // ----------------------------------------------------------------------------
  557.  
  558. wxWizardEvent::wxWizardEvent(wxEventType type, int id, bool direction, wxWizardPage* page)
  559.              : wxNotifyEvent(type, id)
  560. {
  561.     // Modified 10-20-2001 Robert Cavanaugh
  562.     // add the active page to the event data
  563.     m_direction = direction;
  564.     m_page = page;
  565. }
  566.  
  567. #endif // wxUSE_WIZARDDLG
  568.