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