Files
wxWidgets/src/generic/wizard.cpp
Vadim Zeitlin c74a15eded Call wxTopLevelWindow::Layout() rather than DoLayout()
Ideal would be to completely get rid of the DoLayout() method later,
however this method seems to be used in the existing applications, so
for now it needs to be kept.
2019-08-22 14:04:54 +02:00

1016 lines
28 KiB
C++

///////////////////////////////////////////////////////////////////////////////
// Name: src/generic/wizard.cpp
// Purpose: generic implementation of wxWizard class
// Author: Vadim Zeitlin
// Modified by: Robert Cavanaugh
// 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
// Copyright: (c) 1999 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
// Licence: wxWindows licence
///////////////////////////////////////////////////////////////////////////////
// ============================================================================
// declarations
// ============================================================================
// ----------------------------------------------------------------------------
// headers
// ----------------------------------------------------------------------------
// For compilers that support precompilation, includes "wx.h".
#include "wx/wxprec.h"
#ifdef __BORLANDC__
#pragma hdrstop
#endif
#if wxUSE_WIZARDDLG
#ifndef WX_PRECOMP
#include "wx/dynarray.h"
#include "wx/intl.h"
#include "wx/statbmp.h"
#include "wx/button.h"
#include "wx/settings.h"
#include "wx/sizer.h"
#endif //WX_PRECOMP
#include "wx/statline.h"
#include "wx/scrolwin.h"
#include "wx/wizard.h"
#include "wx/dcmemory.h"
// ----------------------------------------------------------------------------
// wxWizardSizer
// ----------------------------------------------------------------------------
class wxWizardSizer : public wxSizer
{
public:
wxWizardSizer(wxWizard *owner);
virtual wxSizerItem *Insert(size_t index, wxSizerItem *item) wxOVERRIDE;
virtual void RecalcSizes() wxOVERRIDE;
virtual wxSize CalcMin() wxOVERRIDE;
// get the max size of all wizard pages
wxSize GetMaxChildSize();
// return the border which can be either set using wxWizard::SetBorder() or
// have default value
int GetBorder() const;
// hide the pages which we temporarily "show" when they're added to this
// sizer (see Insert())
void HidePages();
private:
wxSize SiblingSize(wxSizerItem *child);
wxWizard *m_owner;
wxSize m_childSize;
};
// ----------------------------------------------------------------------------
// event tables and such
// ----------------------------------------------------------------------------
wxDEFINE_EVENT( wxEVT_WIZARD_PAGE_CHANGED, wxWizardEvent );
wxDEFINE_EVENT( wxEVT_WIZARD_PAGE_CHANGING, wxWizardEvent );
wxDEFINE_EVENT( wxEVT_WIZARD_BEFORE_PAGE_CHANGED, wxWizardEvent );
wxDEFINE_EVENT( wxEVT_WIZARD_CANCEL, wxWizardEvent );
wxDEFINE_EVENT( wxEVT_WIZARD_FINISHED, wxWizardEvent );
wxDEFINE_EVENT( wxEVT_WIZARD_HELP, wxWizardEvent );
wxDEFINE_EVENT( wxEVT_WIZARD_PAGE_SHOWN, wxWizardEvent );
wxBEGIN_EVENT_TABLE(wxWizard, wxDialog)
EVT_BUTTON(wxID_CANCEL, wxWizard::OnCancel)
EVT_BUTTON(wxID_BACKWARD, wxWizard::OnBackOrNext)
EVT_BUTTON(wxID_FORWARD, wxWizard::OnBackOrNext)
EVT_BUTTON(wxID_HELP, wxWizard::OnHelp)
EVT_WIZARD_PAGE_CHANGED(wxID_ANY, wxWizard::OnWizEvent)
EVT_WIZARD_PAGE_CHANGING(wxID_ANY, wxWizard::OnWizEvent)
EVT_WIZARD_CANCEL(wxID_ANY, wxWizard::OnWizEvent)
EVT_WIZARD_FINISHED(wxID_ANY, wxWizard::OnWizEvent)
EVT_WIZARD_HELP(wxID_ANY, wxWizard::OnWizEvent)
wxEND_EVENT_TABLE()
wxIMPLEMENT_DYNAMIC_CLASS(wxWizard, wxDialog);
/*
TODO PROPERTIES :
wxWizard
extstyle
title
*/
wxIMPLEMENT_ABSTRACT_CLASS(wxWizardPage, wxPanel);
wxIMPLEMENT_DYNAMIC_CLASS(wxWizardPageSimple, wxWizardPage);
wxIMPLEMENT_DYNAMIC_CLASS(wxWizardEvent, wxNotifyEvent);
// ============================================================================
// implementation
// ============================================================================
// ----------------------------------------------------------------------------
// wxWizardPage
// ----------------------------------------------------------------------------
void wxWizardPage::Init()
{
m_bitmap = wxNullBitmap;
}
wxWizardPage::wxWizardPage(wxWizard *parent,
const wxBitmap& bitmap)
{
Create(parent, bitmap);
}
bool wxWizardPage::Create(wxWizard *parent,
const wxBitmap& bitmap)
{
if ( !wxPanel::Create(parent, wxID_ANY) )
return false;
m_bitmap = bitmap;
// initially the page is hidden, it's shown only when it becomes current
Hide();
return true;
}
// ----------------------------------------------------------------------------
// wxWizardPageSimple
// ----------------------------------------------------------------------------
wxWizardPage *wxWizardPageSimple::GetPrev() const
{
return m_prev;
}
wxWizardPage *wxWizardPageSimple::GetNext() const
{
return m_next;
}
// ----------------------------------------------------------------------------
// wxWizardSizer
// ----------------------------------------------------------------------------
wxWizardSizer::wxWizardSizer(wxWizard *owner)
: m_owner(owner),
m_childSize(wxDefaultSize)
{
}
wxSizerItem *wxWizardSizer::Insert(size_t index, wxSizerItem *item)
{
m_owner->m_usingSizer = true;
if ( item->IsWindow() )
{
// we must pretend that the window is shown as otherwise it wouldn't be
// taken into account for the layout -- but avoid really showing it, so
// just set the internal flag instead of calling wxWindow::Show()
item->GetWindow()->wxWindowBase::Show();
}
return wxSizer::Insert(index, item);
}
void wxWizardSizer::HidePages()
{
for ( wxSizerItemList::compatibility_iterator node = GetChildren().GetFirst();
node;
node = node->GetNext() )
{
wxSizerItem * const item = node->GetData();
if ( item->IsWindow() )
item->GetWindow()->wxWindowBase::Show(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(wxRect(m_position, m_size));
}
}
wxSize wxWizardSizer::CalcMin()
{
return m_owner->GetPageSize();
}
wxSize wxWizardSizer::GetMaxChildSize()
{
wxSize maxOfMin;
for ( wxSizerItemList::compatibility_iterator childNode = m_children.GetFirst();
childNode;
childNode = childNode->GetNext() )
{
wxSizerItem *child = childNode->GetData();
maxOfMin.IncTo(child->CalcMin());
maxOfMin.IncTo(SiblingSize(child));
}
if ( m_owner->m_started )
{
m_childSize = maxOfMin;
}
return maxOfMin;
}
int wxWizardSizer::GetBorder() const
{
return m_owner->m_border;
}
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
// ----------------------------------------------------------------------------
void wxWizard::Init()
{
m_posWizard = wxDefaultPosition;
m_page = NULL;
m_firstpage = NULL;
m_btnPrev = m_btnNext = NULL;
m_statbmp = NULL;
m_sizerBmpAndPage = NULL;
m_sizerPage = NULL;
m_border = 5;
m_started = false;
m_wasModal = false;
m_usingSizer = false;
m_bitmapBackgroundColour = *wxWHITE;
m_bitmapPlacement = 0;
m_bitmapMinimumWidth = 115;
}
bool wxWizard::Create(wxWindow *parent,
int id,
const wxString& title,
const wxBitmap& bitmap,
const wxPoint& pos,
long style)
{
bool result = wxDialog::Create(parent,id,title,pos,wxDefaultSize,style);
m_posWizard = pos;
m_bitmap = bitmap ;
DoCreateControls();
return result;
}
wxWizard::~wxWizard()
{
// normally we don't have to delete this sizer as it's deleted by the
// associated window but if we never used it or didn't set it as the window
// sizer yet, do delete it manually
if ( !m_usingSizer || !m_started )
delete m_sizerPage;
}
void wxWizard::AddBitmapRow(wxBoxSizer *mainColumn)
{
m_sizerBmpAndPage = new wxBoxSizer(wxHORIZONTAL);
mainColumn->Add(
m_sizerBmpAndPage,
1, // Vertically stretchable
wxEXPAND // Horizontal stretching, no border
);
mainColumn->Add(0,5,
0, // No vertical stretching
wxEXPAND // No border, (mostly useless) horizontal stretching
);
#if wxUSE_STATBMP
if ( m_bitmap.IsOk() )
{
wxSize bitmapSize(wxDefaultSize);
if (GetBitmapPlacement())
bitmapSize.x = GetMinimumBitmapWidth();
m_statbmp = new wxStaticBitmap(this, wxID_ANY, m_bitmap, wxDefaultPosition, bitmapSize);
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
);
}
#endif
// Added to m_sizerBmpAndPage later
m_sizerPage = new wxWizardSizer(this);
}
void wxWizard::AddStaticLine(wxBoxSizer *mainColumn)
{
#if wxUSE_STATLINE
mainColumn->Add(
new wxStaticLine(this, wxID_ANY),
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)
{
wxASSERT_MSG( m_btnNext && m_btnPrev,
wxT("You must create the buttons before calling ")
wxT("wxWizard::AddBackNextPair") );
wxBoxSizer *backNextPair = new wxBoxSizer(wxHORIZONTAL);
buttonRow->Add(
backNextPair,
0, // No horizontal stretching
wxALL, // Border all around
5 // Border width
);
backNextPair->Add(m_btnPrev);
backNextPair->Add(10, 0,
0, // No horizontal stretching
wxEXPAND // No border, (mostly useless) vertical stretching
);
backNextPair->Add(m_btnNext);
}
void wxWizard::AddButtonRow(wxBoxSizer *mainColumn)
{
// the order in which the buttons are created determines the TAB order - at least under MSWindows...
// although the 'back' button appears before the 'next' button, a more userfriendly tab order is
// to activate the 'next' button first (create the next button before the back button).
// The reason is: The user will repeatedly enter information in the wizard pages and then wants to
// press 'next'. If a user uses mostly the keyboard, he would have to skip the 'back' button
// every time. This is annoying. There is a second reason: RETURN acts as TAB. If the 'next'
// button comes first in the TAB order, the user can enter information very fast using the RETURN
// key to TAB to the next entry field and page. This would not be possible, if the 'back' button
// was created before the 'next' button.
bool isPda = (wxSystemSettings::GetScreenType() <= wxSYS_SCREEN_PDA);
int buttonStyle = isPda ? wxBU_EXACTFIT : 0;
wxBoxSizer *buttonRow = new wxBoxSizer(wxHORIZONTAL);
#ifdef __WXMAC__
if (GetExtraStyle() & wxWIZARD_EX_HELPBUTTON)
mainColumn->Add(
buttonRow,
0, // Vertically unstretchable
wxEXPAND
);
else
#endif
mainColumn->Add(
buttonRow,
0, // Vertically unstretchable
wxALIGN_RIGHT // Right aligned, no border
);
// Desired TAB order is 'next', 'cancel', 'help', 'back'. This makes the 'back' button the last control on the page.
// Create the buttons in the right order...
wxButton *btnHelp=0;
#ifdef __WXMAC__
if (GetExtraStyle() & wxWIZARD_EX_HELPBUTTON)
btnHelp=new wxButton(this, wxID_HELP, wxEmptyString, wxDefaultPosition, wxDefaultSize, buttonStyle);
#endif
m_nextLabel = _("&Next >");
m_finishLabel = _("&Finish");
m_btnNext = new wxButton(this, wxID_FORWARD, m_nextLabel);
wxButton *btnCancel=new wxButton(this, wxID_CANCEL, _("&Cancel"), wxDefaultPosition, wxDefaultSize, buttonStyle);
#ifndef __WXMAC__
if (GetExtraStyle() & wxWIZARD_EX_HELPBUTTON)
btnHelp=new wxButton(this, wxID_HELP, _("&Help"), wxDefaultPosition, wxDefaultSize, buttonStyle);
#endif
m_btnPrev = new wxButton(this, wxID_BACKWARD, _("< &Back"), wxDefaultPosition, wxDefaultSize, buttonStyle);
if (btnHelp)
{
buttonRow->Add(
btnHelp,
0, // Horizontally unstretchable
wxALL, // Border all around, top aligned
5 // Border width
);
#ifdef __WXMAC__
// Put stretchable space between help button and others
buttonRow->Add(0, 0, 1, wxALIGN_CENTRE, 0);
#endif
}
AddBackNextPair(buttonRow);
buttonRow->Add(
btnCancel,
0, // Horizontally unstretchable
wxALL, // Border all around, top aligned
5 // Border width
);
}
void wxWizard::DoCreateControls()
{
// do nothing if the controls were already created
if ( WasCreated() )
return;
bool isPda = (wxSystemSettings::GetScreenType() <= wxSYS_SCREEN_PDA);
// Horizontal stretching, and if not PDA, border all around
int mainColumnSizerFlags = isPda ? wxEXPAND : wxALL|wxEXPAND ;
// wxWindow::SetSizer will be called at end
wxBoxSizer *windowSizer = new wxBoxSizer(wxVERTICAL);
wxBoxSizer *mainColumn = new wxBoxSizer(wxVERTICAL);
windowSizer->Add(
mainColumn,
1, // Vertical stretching
mainColumnSizerFlags,
5 // Border width
);
AddBitmapRow(mainColumn);
if (!isPda)
AddStaticLine(mainColumn);
AddButtonRow(mainColumn);
SetSizer(windowSizer);
}
void wxWizard::SetPageSize(const wxSize& size)
{
wxCHECK_RET(!m_started, wxT("wxWizard::SetPageSize after RunWizard"));
m_sizePage = size;
}
void wxWizard::FitToPage(const wxWizardPage *page)
{
wxCHECK_RET(!m_started, wxT("wxWizard::FitToPage after RunWizard"));
while ( page )
{
wxSize size = page->GetBestSize();
m_sizePage.IncTo(size);
page = page->GetNext();
}
}
bool wxWizard::ShowPage(wxWizardPage *page, bool goingForward)
{
wxASSERT_MSG( page != m_page, wxT("this is useless") );
wxSizerFlags flags(1);
flags.Border(wxALL, m_border).Expand();
if ( !m_started )
{
if ( m_usingSizer )
{
m_sizerBmpAndPage->Add(m_sizerPage, flags);
// now that our layout is computed correctly, hide the pages
// artificially shown in wxWizardSizer::Insert() back again
m_sizerPage->HidePages();
}
}
// remember the old bitmap (if any) to compare with the new one later
wxBitmap bmpPrev;
// check for previous page
if ( m_page )
{
// send the event to the old page
wxWizardEvent event(wxEVT_WIZARD_PAGE_CHANGING, GetId(),
goingForward, m_page);
if ( m_page->GetEventHandler()->ProcessEvent(event) &&
!event.IsAllowed() )
{
// vetoed by the page
return false;
}
m_page->Hide();
bmpPrev = m_page->GetBitmap();
if ( !m_usingSizer )
m_sizerBmpAndPage->Detach(m_page);
}
// is this the end?
if ( !page )
{
// terminate successfully
if ( IsModal() )
{
EndModal(wxID_OK);
}
else
{
SetReturnCode(wxID_OK);
Hide();
}
// and notify the user code (this is especially useful for modeless
// wizards)
wxWizardEvent event(wxEVT_WIZARD_FINISHED, GetId(), false, m_page);
(void)GetEventHandler()->ProcessEvent(event);
m_page = NULL;
return true;
}
// notice that we change m_page only here so that wxEVT_WIZARD_FINISHED
// event above could still use the correct (i.e. old) value of m_page
m_page = page;
// position and show the new page
(void)m_page->TransferDataToWindow();
if ( m_usingSizer )
{
// wxWizardSizer::RecalcSizes wants to be called when m_page changes
m_sizerPage->RecalcSizes();
}
else // pages are not managed by the sizer
{
m_sizerBmpAndPage->Add(m_page, flags);
m_sizerBmpAndPage->SetItemMinSize(m_page, GetPageSize());
}
#if wxUSE_STATBMP
// update the bitmap if:it changed
wxBitmap bmp;
if ( m_statbmp )
{
bmp = m_page->GetBitmap();
if ( !bmp.IsOk() )
bmp = m_bitmap;
if ( !bmpPrev.IsOk() )
bmpPrev = m_bitmap;
if (!GetBitmapPlacement())
{
if ( !bmp.IsSameAs(bmpPrev) )
m_statbmp->SetBitmap(bmp);
}
}
#endif // wxUSE_STATBMP
// and update the buttons state
m_btnPrev->Enable(m_page != m_firstpage);
const bool hasNext = HasNextPage(m_page);
const wxString& label = hasNext ? m_nextLabel : m_finishLabel;
if ( label != m_btnNext->GetLabel() )
m_btnNext->SetLabel(label);
m_btnNext->SetDefault();
// send the change event to the new page now
wxWizardEvent event(wxEVT_WIZARD_PAGE_CHANGED, GetId(), goingForward, m_page);
(void)m_page->GetEventHandler()->ProcessEvent(event);
// and finally show it
m_page->Show();
m_page->SetFocus();
if ( !m_usingSizer )
m_sizerBmpAndPage->Layout();
if ( !m_started )
{
m_started = true;
DoWizardLayout();
}
if (GetBitmapPlacement() && m_statbmp)
{
ResizeBitmap(bmp);
if ( !bmp.IsSameAs(bmpPrev) )
m_statbmp->SetBitmap(bmp);
if (m_usingSizer)
m_sizerPage->RecalcSizes();
}
wxWizardEvent pageShownEvent(wxEVT_WIZARD_PAGE_SHOWN, GetId(),
goingForward, m_page);
m_page->GetEventHandler()->ProcessEvent(pageShownEvent);
return true;
}
/// Do fit, and adjust to screen size if necessary
void wxWizard::DoWizardLayout()
{
if ( wxSystemSettings::GetScreenType() > wxSYS_SCREEN_PDA )
{
if (CanDoLayoutAdaptation())
DoLayoutAdaptation();
else
GetSizer()->SetSizeHints(this);
if ( m_posWizard == wxDefaultPosition )
CentreOnScreen();
}
SetLayoutAdaptationDone(true);
}
bool wxWizard::RunWizard(wxWizardPage *firstPage)
{
wxCHECK_MSG( firstPage, false, wxT("can't run empty wizard") );
m_firstpage = firstPage;
// can't return false here because there is no old page
(void)ShowPage(firstPage, true /* forward */);
m_wasModal = true;
return ShowModal() == wxID_OK;
}
wxWizardPage *wxWizard::GetCurrentPage() const
{
return m_page;
}
wxSize wxWizard::GetPageSize() const
{
// default width and height of the page
int DEFAULT_PAGE_WIDTH,
DEFAULT_PAGE_HEIGHT;
if ( wxSystemSettings::GetScreenType() <= wxSYS_SCREEN_PDA )
{
// Make the default page size small enough to fit on screen
DEFAULT_PAGE_WIDTH = wxSystemSettings::GetMetric(wxSYS_SCREEN_X, m_parent) / 2;
DEFAULT_PAGE_HEIGHT = wxSystemSettings::GetMetric(wxSYS_SCREEN_Y, m_parent) / 2;
}
else // !PDA
{
DEFAULT_PAGE_WIDTH =
DEFAULT_PAGE_HEIGHT = 270;
}
// start with default minimal size
wxSize pageSize(DEFAULT_PAGE_WIDTH, DEFAULT_PAGE_HEIGHT);
// make the page at least as big as specified by user
pageSize.IncTo(m_sizePage);
if ( m_statbmp )
{
// make the page at least as tall as the bitmap
pageSize.IncTo(wxSize(0, m_bitmap.GetScaledHeight()));
}
if ( m_usingSizer )
{
// make it big enough to contain all pages added to the sizer
pageSize.IncTo(m_sizerPage->GetMaxChildSize());
}
return pageSize;
}
wxSizer *wxWizard::GetPageAreaSizer() const
{
return m_sizerPage;
}
void wxWizard::SetBorder(int border)
{
wxCHECK_RET(!m_started, wxT("wxWizard::SetBorder after RunWizard"));
m_border = border;
}
void wxWizard::OnCancel(wxCommandEvent& WXUNUSED(eventUnused))
{
// this function probably can never be called when we don't have an active
// page, but a small extra check won't hurt
wxWindow *win = m_page ? (wxWindow *)m_page : (wxWindow *)this;
wxWizardEvent event(wxEVT_WIZARD_CANCEL, GetId(), false, m_page);
if ( !win->GetEventHandler()->ProcessEvent(event) || event.IsAllowed() )
{
// no objections - close the dialog
if(IsModal())
{
EndModal(wxID_CANCEL);
}
else
{
SetReturnCode(wxID_CANCEL);
Hide();
}
}
//else: request to Cancel ignored
}
void wxWizard::OnBackOrNext(wxCommandEvent& event)
{
wxASSERT_MSG( (event.GetEventObject() == m_btnNext) ||
(event.GetEventObject() == m_btnPrev),
wxT("unknown button") );
wxCHECK_RET( m_page, wxT("should have a valid current page") );
// ask the current page first: notice that we do it before calling
// GetNext/Prev() because the data transferred from the controls of the page
// may change the value returned by these methods
if ( !m_page->Validate() || !m_page->TransferDataFromWindow() )
{
// the page data is incorrect, don't do anything
return;
}
bool forward = event.GetEventObject() == m_btnNext;
// Give the application a chance to set state which may influence GetNext()/GetPrev()
wxWizardEvent eventPreChanged(wxEVT_WIZARD_BEFORE_PAGE_CHANGED, GetId(), forward, m_page);
(void)m_page->GetEventHandler()->ProcessEvent(eventPreChanged);
if (!eventPreChanged.IsAllowed())
return;
wxWizardPage *page;
if ( forward )
{
page = m_page->GetNext();
}
else // back
{
page = m_page->GetPrev();
wxASSERT_MSG( page, wxT("\"<Back\" button should have been disabled") );
}
// just pass to the new page (or maybe not - but we don't care here)
(void)ShowPage(page, forward);
}
void wxWizard::OnHelp(wxCommandEvent& WXUNUSED(event))
{
// this function probably can never be called when we don't have an active
// page, but a small extra check won't hurt
if(m_page != NULL)
{
// Create and send the help event to the specific page handler
// event data contains the active page so that context-sensitive
// help is possible
wxWizardEvent eventHelp(wxEVT_WIZARD_HELP, GetId(), true, m_page);
(void)m_page->GetEventHandler()->ProcessEvent(eventHelp);
}
}
void wxWizard::OnWizEvent(wxWizardEvent& event)
{
// the dialogs have wxWS_EX_BLOCK_EVENTS style on by default but we want to
// propagate wxEVT_WIZARD_XXX to the parent (if any), so do it manually
if ( !(GetExtraStyle() & wxWS_EX_BLOCK_EVENTS) )
{
// the event will be propagated anyhow
event.Skip();
}
else
{
wxWindow *parent = GetParent();
if ( !parent || !parent->GetEventHandler()->ProcessEvent(event) )
{
event.Skip();
}
}
if ( ( !m_wasModal ) &&
event.IsAllowed() &&
( event.GetEventType() == wxEVT_WIZARD_FINISHED ||
event.GetEventType() == wxEVT_WIZARD_CANCEL
)
)
{
Destroy();
}
}
void wxWizard::SetBitmap(const wxBitmap& bitmap)
{
m_bitmap = bitmap;
if (m_statbmp)
m_statbmp->SetBitmap(m_bitmap);
}
// ----------------------------------------------------------------------------
// wxWizardEvent
// ----------------------------------------------------------------------------
wxWizardEvent::wxWizardEvent(wxEventType type, int id, bool direction, wxWizardPage* page)
: wxNotifyEvent(type, id)
{
// Modified 10-20-2001 Robert Cavanaugh
// add the active page to the event data
m_direction = direction;
m_page = page;
}
/// Do the adaptation
bool wxWizard::DoLayoutAdaptation()
{
wxWindowList windows;
wxWindowList pages;
// Make all the pages (that use sizers) scrollable
for ( wxSizerItemList::compatibility_iterator node = m_sizerPage->GetChildren().GetFirst(); node; node = node->GetNext() )
{
wxSizerItem * const item = node->GetData();
if ( item->IsWindow() )
{
wxWizardPage* page = wxDynamicCast(item->GetWindow(), wxWizardPage);
if (page)
{
while (page)
{
if (!pages.Find(page) && page->GetSizer())
{
// Create a scrolled window and reparent
wxScrolledWindow* scrolledWindow = new wxScrolledWindow(page, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL|wxVSCROLL|wxHSCROLL|wxBORDER_NONE);
wxSizer* oldSizer = page->GetSizer();
wxSizer* newSizer = new wxBoxSizer(wxVERTICAL);
newSizer->Add(scrolledWindow,1, wxEXPAND, 0);
page->SetSizer(newSizer, false /* don't delete the old sizer */);
scrolledWindow->SetSizer(oldSizer);
wxStandardDialogLayoutAdapter::DoReparentControls(page, scrolledWindow);
pages.Append(page);
windows.Append(scrolledWindow);
}
page = page->GetNext();
}
}
}
}
wxStandardDialogLayoutAdapter::DoFitWithScrolling(this, windows);
// Size event doesn't get sent soon enough on wxGTK
Layout();
SetLayoutAdaptationDone(true);
return true;
}
bool wxWizard::ResizeBitmap(wxBitmap& bmp)
{
if (!GetBitmapPlacement())
return false;
if (bmp.IsOk())
{
wxSize pageSize = m_sizerPage->GetSize();
if (pageSize == wxSize(0,0))
pageSize = GetPageSize();
int bitmapWidth = wxMax(bmp.GetScaledWidth(), GetMinimumBitmapWidth());
int bitmapHeight = pageSize.y;
if (!m_statbmp->GetBitmap().IsOk() || m_statbmp->GetBitmap().GetScaledHeight() != bitmapHeight)
{
wxBitmap bitmap(bitmapWidth, bitmapHeight);
{
wxMemoryDC dc;
dc.SelectObject(bitmap);
dc.SetBackground(wxBrush(m_bitmapBackgroundColour));
dc.Clear();
if (GetBitmapPlacement() & wxWIZARD_TILE)
{
TileBitmap(wxRect(0, 0, bitmapWidth, bitmapHeight), dc, bmp);
}
else
{
int x, y;
if (GetBitmapPlacement() & wxWIZARD_HALIGN_LEFT)
x = 0;
else if (GetBitmapPlacement() & wxWIZARD_HALIGN_RIGHT)
x = bitmapWidth - bmp.GetScaledWidth();
else
x = (bitmapWidth - bmp.GetScaledWidth())/2;
if (GetBitmapPlacement() & wxWIZARD_VALIGN_TOP)
y = 0;
else if (GetBitmapPlacement() & wxWIZARD_VALIGN_BOTTOM)
y = bitmapHeight - bmp.GetScaledHeight();
else
y = (bitmapHeight - bmp.GetScaledHeight())/2;
dc.DrawBitmap(bmp, x, y, true);
dc.SelectObject(wxNullBitmap);
}
}
bmp = bitmap;
}
}
return true;
}
bool wxWizard::TileBitmap(const wxRect& rect, wxDC& dc, const wxBitmap& bitmap)
{
int w = bitmap.GetScaledWidth();
int h = bitmap.GetScaledHeight();
wxMemoryDC dcMem;
dcMem.SelectObjectAsSource(bitmap);
int i, j;
for (i = rect.x; i < rect.x + rect.width; i += w)
{
for (j = rect.y; j < rect.y + rect.height; j+= h)
dc.Blit(i, j, bitmap.GetScaledWidth(), bitmap.GetScaledHeight(), & dcMem, 0, 0);
}
dcMem.SelectObject(wxNullBitmap);
return true;
}
#endif // wxUSE_WIZARDDLG