added sizers support; allow resizeable wizards (Robert Vazan)

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@22170 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Vadim Zeitlin
2003-07-20 20:48:52 +00:00
parent e066bd132d
commit 07f20d9a63
6 changed files with 489 additions and 166 deletions

View File

@@ -6,6 +6,7 @@
// 1) Added capability for wxWizardPage to accept resources
// 2) Added "Help" button handler stub
// 3) Fixed ShowPage() bug on displaying bitmaps
// Robert Vazan (sizers)
// Created: 15.08.99
// RCS-ID: $Id$
// Copyright: (c) 1999 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
@@ -41,6 +42,7 @@
#endif //WX_PRECOMP
#include "wx/statline.h"
#include "wx/sizer.h"
#include "wx/wizard.h"
@@ -132,6 +134,126 @@ wxWizardPage *wxWizardPageSimple::GetNext() const
{
return m_next;
}
// ----------------------------------------------------------------------------
// wxWizardSizer
// ----------------------------------------------------------------------------
class wxWizardSizer : public wxSizer
{
public:
wxWizardSizer(wxWizard *owner);
void RecalcSizes();
wxSize CalcMin();
wxSize GetMaxChildSize();
int Border() const;
private:
wxSize SiblingSize(wxSizerItem *child);
wxWizard *m_owner;
bool m_childSizeValid;
wxSize m_childSize;
DECLARE_CLASS(wxWizardSizer);
};
IMPLEMENT_CLASS(wxWizardSizer, wxSizer)
wxWizardSizer::wxWizardSizer(wxWizard *owner)
: m_owner(owner)
{
m_childSizeValid = false;
}
void wxWizardSizer::RecalcSizes()
{
// Effect of this function depends on m_owner->m_page and
// it should be called whenever it changes (wxWizard::ShowPage)
if ( m_owner->m_page )
{
m_owner->m_page->SetSize(m_position.x,m_position.y, m_size.x,m_size.y);
}
}
wxSize wxWizardSizer::CalcMin()
{
return m_owner->GetPageSize();
}
wxSize wxWizardSizer::GetMaxChildSize()
{
#if !defined(__WXDEBUG__)
if ( m_childSizeValid )
return m_childSize;
#endif
wxSize maxOfMin;
wxSizerItemList::Node *childNode;
for(childNode = m_children.GetFirst(); childNode;
childNode = childNode->GetNext())
{
wxSizerItem *child = childNode->GetData();
maxOfMin.IncTo(child->CalcMin());
maxOfMin.IncTo(SiblingSize(child));
}
#ifdef __WXDEBUG__
if ( m_childSizeValid && m_childSize != maxOfMin )
{
wxFAIL_MSG( _T("Size changed in wxWizard::GetPageAreaSizer()")
_T("after RunWizard().\n")
_T("Did you forget to call GetSizer()->Fit(this) ")
_T("for some page?")) ;
return m_childSize;
}
#endif // __WXDEBUG__
if ( m_owner->m_started )
{
m_childSizeValid = true;
m_childSize = maxOfMin;
}
return maxOfMin;
}
int wxWizardSizer::Border() const
{
if ( m_owner->m_calledSetBorder )
return m_owner->m_border;
return m_children.IsEmpty() ? 5 : 0;
}
wxSize wxWizardSizer::SiblingSize(wxSizerItem *child)
{
wxSize maxSibling;
if ( child->IsWindow() )
{
wxWizardPage *page = wxDynamicCast(child->GetWindow(), wxWizardPage);
if ( page )
{
for ( wxWizardPage *sibling = page->GetNext();
sibling;
sibling = sibling->GetNext() )
{
if ( sibling->GetSizer() )
{
maxSibling.IncTo(sibling->GetSizer()->CalcMin());
}
}
}
}
return maxSibling;
}
// ----------------------------------------------------------------------------
// generic wxWizard implementation
// ----------------------------------------------------------------------------
@@ -142,52 +264,84 @@ void wxWizard::Init()
m_page = (wxWizardPage *)NULL;
m_btnPrev = m_btnNext = NULL;
m_statbmp = NULL;
m_sizerPage = NULL;
m_calledSetBorder = false;
m_border = 0;
m_started = false;
}
bool wxWizard::Create(wxWindow *parent,
int id,
const wxString& title,
const wxBitmap& bitmap,
const wxPoint& pos)
const wxPoint& pos,
long style)
{
bool result = wxDialog::Create(parent,id,title,pos,wxDefaultSize,style);
m_posWizard = pos;
m_bitmap = bitmap ;
// just create the dialog itself here, the controls will be created in
// DoCreateControls() called later when we know our final size
m_page = (wxWizardPage *)NULL;
m_btnPrev = m_btnNext = NULL;
m_statbmp = NULL;
return wxDialog::Create(parent, id, title, pos);
DoCreateControls();
return result;
}
void wxWizard::DoCreateControls()
void wxWizard::AddBitmapRow(wxBoxSizer *mainColumn)
{
// do nothing if the controls were already created
if ( WasCreated() )
return;
m_sizerBmpAndPage = new wxBoxSizer(wxHORIZONTAL);
mainColumn->Add(
m_sizerBmpAndPage,
1, // Vertically stretchable
wxEXPAND // Horizonal stretching, no border
);
mainColumn->Add(0,5,
0, // No vertical stretching
wxEXPAND // No border, (mostly useless) horizontal stretching
);
// constants defining the dialog layout
// ------------------------------------
if ( m_bitmap.Ok() )
{
m_statbmp = new wxStaticBitmap(this, -1, m_bitmap);
m_sizerBmpAndPage->Add(
m_statbmp,
0, // No horizontal stretching
wxALL, // Border all around, top alignment
5 // Border width
);
m_sizerBmpAndPage->Add(
5,0,
0, // No horizontal stretching
wxEXPAND // No border, (mostly useless) vertical stretching
);
}
else
m_statbmp = (wxStaticBitmap *)NULL;
// 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;
// Added to m_sizerBmpAndPage in FinishLayout
m_sizerPage = new wxWizardSizer(this);
}
// 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;
void wxWizard::AddStaticLine(wxBoxSizer *mainColumn)
{
#if wxUSE_STATLINE
mainColumn->Add(
new wxStaticLine(this, -1),
0, // Vertically unstretchable
wxEXPAND | wxALL, // Border all around, horizontally stretchable
5 // Border width
);
mainColumn->Add(0,5,
0, // No vertical stretching
wxEXPAND // No border, (mostly useless) horizontal stretching
);
#else
(void)mainColumn;
#endif // wxUSE_STATLINE
}
void wxWizard::AddBackNextPair(wxBoxSizer *buttonRow)
{
// margin between Back and Next buttons
#ifdef __WXMAC__
static const int BACKNEXT_MARGIN = 10;
@@ -195,122 +349,109 @@ void wxWizard::DoCreateControls()
static const int BACKNEXT_MARGIN = 0;
#endif
// default width and height of the page
static const int DEFAULT_PAGE_WIDTH = 270;
static const int DEFAULT_PAGE_HEIGHT = 290;
wxBoxSizer *backNextPair = new wxBoxSizer(wxHORIZONTAL);
buttonRow->Add(
backNextPair,
0, // No horizontal stretching
wxALL, // Border all around
5 // Border width
);
m_btnPrev = new wxButton(this, wxID_BACKWARD, _("< &Back"));
backNextPair->Add(m_btnPrev);
backNextPair->Add(BACKNEXT_MARGIN,0,
0, // No horizontal stretching
wxEXPAND // No border, (mostly useless) vertical stretching
);
m_btnNext = new wxButton(this, wxID_FORWARD, _("&Next >"));
backNextPair->Add(m_btnNext);
}
// create controls
// ---------------
wxSize sizeBtn = wxButton::GetDefaultSize();
// 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;
int defaultHeight;
if ( m_bitmap.Ok() )
{
m_statbmp = new wxStaticBitmap(this, -1, m_bitmap, wxPoint(m_x, m_y));
m_x += m_bitmap.GetWidth() + BITMAP_X_MARGIN;
defaultHeight = m_bitmap.GetHeight();
}
else
{
m_statbmp = (wxStaticBitmap *)NULL;
defaultHeight = DEFAULT_PAGE_HEIGHT;
}
// use default size if none given and also make sure that the dialog is
// not less than the default size
m_height = m_sizePage.y == -1 ? defaultHeight : m_sizePage.y;
m_width = m_sizePage.x == -1 ? DEFAULT_PAGE_WIDTH : m_sizePage.x;
if ( m_height < defaultHeight )
m_height = defaultHeight;
if ( m_width < DEFAULT_PAGE_WIDTH )
m_width = DEFAULT_PAGE_WIDTH;
int x = X_MARGIN;
int y = m_y + m_height + BITMAP_Y_MARGIN;
#if wxUSE_STATLINE
(void)new wxStaticLine(this, -1, wxPoint(x, y),
wxSize(m_x + m_width - x, 2));
#endif // wxUSE_STATLINE
x = m_x + m_width - 3*sizeBtn.x - BUTTON_MARGIN - BACKNEXT_MARGIN;
y += SEPARATOR_LINE_MARGIN;
void wxWizard::AddButtonRow(wxBoxSizer *mainColumn)
{
wxBoxSizer *buttonRow = new wxBoxSizer(wxHORIZONTAL);
mainColumn->Add(
buttonRow,
0, // Vertically unstretchable
wxALIGN_RIGHT // Right aligned, no border
);
if (GetExtraStyle() & wxWIZARD_EX_HELPBUTTON)
{
x -= sizeBtn.x;
x -= BUTTON_MARGIN ;
buttonRow->Add(
new wxButton(this, wxID_HELP, _("&Help")),
0, // Horizontally unstretchable
wxALL, // Border all around, top aligned
5 // Border width
);
(void)new wxButton(this, wxID_HELP, _("&Help"), wxPoint(x, y), sizeBtn);
x += sizeBtn.x;
x += BUTTON_MARGIN ;
}
AddBackNextPair(buttonRow);
buttonRow->Add(
new wxButton(this, wxID_CANCEL, _("&Cancel")),
0, // Horizontally unstretchable
wxALL, // Border all around, top aligned
5 // Border width
);
}
m_btnPrev = new wxButton(this, wxID_BACKWARD, _("< &Back"), wxPoint(x, y), sizeBtn);
x += sizeBtn.x;
x += BACKNEXT_MARGIN;
m_btnNext = new wxButton(this, wxID_FORWARD, _("&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
// ----------------------------
SetClientSize(m_x + m_width + X_MARGIN,
m_y + m_height + BITMAP_Y_MARGIN +
SEPARATOR_LINE_MARGIN + sizeBtn.y + Y_MARGIN);
if ( m_posWizard == wxDefaultPosition )
{
CentreOnScreen();
}
void wxWizard::DoCreateControls()
{
// do nothing if the controls were already created
if ( WasCreated() )
return;
// wxWindow::SetSizer will be called at end
wxBoxSizer *windowSizer = new wxBoxSizer(wxVERTICAL);
wxBoxSizer *mainColumn = new wxBoxSizer(wxVERTICAL);
windowSizer->Add(
mainColumn,
1, // Vertical stretching
wxALL | wxEXPAND, // Border all around, horizontal stretching
5 // Border width
);
AddBitmapRow(mainColumn);
AddStaticLine(mainColumn);
AddButtonRow(mainColumn);
// wxWindow::SetSizer should be followed by wxWindow::Fit, but
// this is done in FinishLayout anyway so why duplicate it
SetSizer(windowSizer);
}
void wxWizard::SetPageSize(const wxSize& size)
{
// otherwise it will have no effect now as it's too late...
wxASSERT_MSG( !WasCreated(), _T("should be called before RunWizard()!") );
wxCHECK_RET(!m_started,wxT("wxWizard::SetPageSize after RunWizard"));
m_sizePage = size;
}
void wxWizard::FinishLayout()
{
m_sizerBmpAndPage->Add(
m_sizerPage,
1, // Horizontal stretching
wxEXPAND | wxALL, // Vertically stretchable
m_sizerPage->Border()
);
GetSizer()->SetSizeHints(this);
if ( m_posWizard == wxDefaultPosition )
CentreOnScreen();
}
void wxWizard::FitToPage(const wxWizardPage *page)
{
// otherwise it will have no effect now as it's too late...
wxASSERT_MSG( !WasCreated(), _T("should be called before RunWizard()!") );
wxSize sizeMax;
wxCHECK_RET(!m_started,wxT("wxWizard::FitToPage after RunWizard"));
while ( page )
{
wxSize size = page->GetBestSize();
if ( size.x > sizeMax.x )
sizeMax.x = size.x;
if ( size.y > sizeMax.y )
sizeMax.y = size.y;
m_sizePage.IncTo(size);
page = page->GetNext();
}
if ( sizeMax.x > m_sizePage.x )
m_sizePage.x = sizeMax.x;
if ( sizeMax.y > m_sizePage.y )
m_sizePage.y = sizeMax.y;
}
bool wxWizard::ShowPage(wxWizardPage *page, bool goingForward)
@@ -373,7 +514,9 @@ bool wxWizard::ShowPage(wxWizardPage *page, bool goingForward)
// position and show the new page
(void)m_page->TransferDataToWindow();
m_page->SetSize(m_x, m_y, m_width, m_height);
// wxWizardSizer::RecalcSizes wants to be called when m_page changes
m_sizerPage->RecalcSizes();
// check if bitmap needs to be updated
// update default flag as well
@@ -425,9 +568,14 @@ bool wxWizard::ShowPage(wxWizardPage *page, bool goingForward)
bool wxWizard::RunWizard(wxWizardPage *firstPage)
{
wxCHECK_MSG( firstPage, FALSE, wxT("can't run empty wizard") );
DoCreateControls();
// Set before FinishLayout to enable wxWizardSizer::GetMaxChildSize
m_started = true;
// This cannot be done sooner, because user can change layout options
// up to this moment
FinishLayout();
// can't return FALSE here because there is no old page
(void)ShowPage(firstPage, TRUE /* forward */);
@@ -441,11 +589,37 @@ wxWizardPage *wxWizard::GetCurrentPage() const
wxSize wxWizard::GetPageSize() const
{
// make sure that the controls are created because otherwise m_width and
// m_height would be both still -1
wxConstCast(this, wxWizard)->DoCreateControls();
wxSize pageSize(GetManualPageSize());
pageSize.IncTo(m_sizerPage->GetMaxChildSize());
return pageSize;
}
return wxSize(m_width, m_height);
wxSizer *wxWizard::GetPageAreaSizer() const
{
return m_sizerPage;
}
void wxWizard::SetBorder(int border)
{
wxCHECK_RET(!m_started,wxT("wxWizard::SetBorder after RunWizard"));
m_calledSetBorder = true;
m_border = border;
}
wxSize wxWizard::GetManualPageSize() const
{
// default width and height of the page
static const int DEFAULT_PAGE_WIDTH = 270;
static const int DEFAULT_PAGE_HEIGHT = 290;
wxSize totalPageSize(DEFAULT_PAGE_WIDTH,DEFAULT_PAGE_HEIGHT);
totalPageSize.IncTo(m_sizePage);
if(m_statbmp)
totalPageSize.IncTo(wxSize(0,m_bitmap.GetHeight()));
return totalPageSize;
}
void wxWizard::OnCancel(wxCommandEvent& WXUNUSED(eventUnused))