Added automatic dialog scrolling ability

Added ability to resize wizard bitmaps automatically
Made it easier to derive from wxWizard and override behaviour,
mainly by making members protected instead of private



git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@50942 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Julian Smart
2007-12-29 16:35:39 +00:00
parent 85136e3bf5
commit 3aa8e4ea6d
25 changed files with 1234 additions and 29 deletions

View File

@@ -39,8 +39,13 @@
#include "wx/statline.h"
#include "wx/sysopt.h"
#include "wx/module.h"
#include "wx/private/stattext.h"
#include "wx/bookctrl.h"
#if wxUSE_DISPLAY
#include "wx/display.h"
#endif
// ----------------------------------------------------------------------------
// wxDialogBase
@@ -54,11 +59,17 @@ BEGIN_EVENT_TABLE(wxDialogBase, wxTopLevelWindow)
EVT_CHAR_HOOK(wxDialogBase::OnCharHook)
END_EVENT_TABLE()
wxDialogLayoutAdapter* wxDialogBase::sm_layoutAdapter = NULL;
bool wxDialogBase::sm_layoutAdaptation = false;
void wxDialogBase::Init()
{
m_returnCode = 0;
m_affirmativeId = wxID_OK;
m_escapeId = wxID_ANY;
m_layoutAdaptationLevel = 3;
m_layoutAdaptationDone = FALSE;
m_layoutAdaptationMode = wxDIALOG_ADAPTATION_MODE_DEFAULT;
// the dialogs have this flag on by default to prevent the events from the
// dialog controls from reaching the parent frame which is usually
@@ -459,3 +470,407 @@ void wxDialogBase::OnSysColourChanged(wxSysColourChangedEvent& event)
event.Skip();
}
/// Do the adaptation
bool wxDialogBase::DoLayoutAdaptation()
{
if (GetLayoutAdapter())
return GetLayoutAdapter()->DoLayoutAdaptation((wxDialog*) this);
else
return false;
}
/// Can we do the adaptation?
bool wxDialogBase::CanDoLayoutAdaptation()
{
// Check if local setting overrides the global setting
bool layoutEnabled = (GetLayoutAdaptationMode() == wxDIALOG_ADAPTATION_MODE_ENABLED) || (IsLayoutAdaptationEnabled() && (GetLayoutAdaptationMode() != wxDIALOG_ADAPTATION_MODE_DISABLED));
return (layoutEnabled && !m_layoutAdaptationDone && GetLayoutAdaptationLevel() != 0 && GetLayoutAdapter() != NULL && GetLayoutAdapter()->CanDoLayoutAdaptation((wxDialog*) this));
}
/// Set scrolling adapter class, returning old adapter
wxDialogLayoutAdapter* wxDialogBase::SetLayoutAdapter(wxDialogLayoutAdapter* adapter)
{
wxDialogLayoutAdapter* oldLayoutAdapter = sm_layoutAdapter;
sm_layoutAdapter = adapter;
return oldLayoutAdapter;
}
/*!
* Standard adapter
*/
IMPLEMENT_CLASS(wxDialogLayoutAdapter, wxObject)
IMPLEMENT_CLASS(wxStandardDialogLayoutAdapter, wxDialogLayoutAdapter)
// Allow for caption size on wxWidgets < 2.9
#if defined(__WXGTK__) && !wxCHECK_VERSION(2,9,0)
#define wxEXTRA_DIALOG_HEIGHT 30
#else
#define wxEXTRA_DIALOG_HEIGHT 0
#endif
/// Indicate that adaptation should be done
bool wxStandardDialogLayoutAdapter::CanDoLayoutAdaptation(wxDialog* dialog)
{
if (dialog->GetSizer())
{
wxSize windowSize, displaySize;
return MustScroll(dialog, windowSize, displaySize) != 0;
}
else
return false;
}
bool wxStandardDialogLayoutAdapter::DoLayoutAdaptation(wxDialog* dialog)
{
if (dialog->GetSizer())
{
wxBookCtrlBase* bookContentWindow = wxDynamicCast(dialog->GetContentWindow(), wxBookCtrlBase);
if (bookContentWindow)
{
// If we have a book control, make all the pages (that use sizers) scrollable
wxWindowList windows;
for (size_t i = 0; i < bookContentWindow->GetPageCount(); i++)
{
wxWindow* page = bookContentWindow->GetPage(i);
wxScrolledWindow* scrolledWindow = wxDynamicCast(page, wxScrolledWindow);
if (scrolledWindow)
windows.Append(scrolledWindow);
else if (!scrolledWindow && page->GetSizer())
{
// Create a scrolled window and reparent
scrolledWindow = CreateScrolledWindow(page);
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);
ReparentControls(page, scrolledWindow);
windows.Append(scrolledWindow);
}
}
FitWithScrolling(dialog, windows);
}
else
{
// If we have an arbitrary dialog, create a scrolling area for the main content, and a button sizer
// for the main buttons.
wxScrolledWindow* scrolledWindow = CreateScrolledWindow(dialog);
int buttonSizerBorder = 0;
// First try to find a wxStdDialogButtonSizer
wxSizer* buttonSizer = FindButtonSizer(true /* find std button sizer */, dialog, dialog->GetSizer(), buttonSizerBorder);
// Next try to find a wxBoxSizer containing the controls
if (!buttonSizer && dialog->GetLayoutAdaptationLevel() > wxDIALOG_ADAPTATION_STANDARD_SIZER)
buttonSizer = FindButtonSizer(false /* find ordinary sizer */, dialog, dialog->GetSizer(), buttonSizerBorder);
// If we still don't have a button sizer, collect any 'loose' buttons in the layout
if (!buttonSizer && dialog->GetLayoutAdaptationLevel() > wxDIALOG_ADAPTATION_ANY_SIZER)
{
int count = 0;
wxStdDialogButtonSizer* stdButtonSizer = new wxStdDialogButtonSizer;
buttonSizer = stdButtonSizer;
FindLooseButtons(dialog, stdButtonSizer, dialog->GetSizer(), count);
if (count > 0)
stdButtonSizer->Realize();
else
{
delete buttonSizer;
buttonSizer = NULL;
}
}
if (buttonSizerBorder == 0)
buttonSizerBorder = 5;
ReparentControls(dialog, scrolledWindow, buttonSizer);
wxBoxSizer* newTopSizer = new wxBoxSizer(wxVERTICAL);
wxSizer* oldSizer = dialog->GetSizer();
dialog->SetSizer(newTopSizer, false /* don't delete old sizer */);
newTopSizer->Add(scrolledWindow, 1, wxEXPAND|wxALL, 0);
if (buttonSizer)
newTopSizer->Add(buttonSizer, 0, wxEXPAND|wxALL, buttonSizerBorder);
scrolledWindow->SetSizer(oldSizer);
FitWithScrolling(dialog, scrolledWindow);
}
}
dialog->SetLayoutAdaptationDone(true);
return true;
}
// Create the scrolled window
wxScrolledWindow* wxStandardDialogLayoutAdapter::CreateScrolledWindow(wxWindow* parent)
{
wxScrolledWindow* scrolledWindow = new wxScrolledWindow(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL|wxVSCROLL|wxHSCROLL|wxBORDER_NONE);
return scrolledWindow;
}
/// Find and remove the button sizer, if any
wxSizer* wxStandardDialogLayoutAdapter::FindButtonSizer(bool stdButtonSizer, wxDialog* dialog, wxSizer* sizer, int& retBorder, int accumlatedBorder)
{
for ( wxSizerItemList::compatibility_iterator node = sizer->GetChildren().GetFirst();
node; node = node->GetNext() )
{
wxSizerItem *item = node->GetData();
wxSizer *childSizer = item->GetSizer();
if ( childSizer )
{
int newBorder = accumlatedBorder;
if (item->GetFlag() & wxALL)
newBorder += item->GetBorder();
if (stdButtonSizer) // find wxStdDialogButtonSizer
{
wxStdDialogButtonSizer* buttonSizer = wxDynamicCast(childSizer, wxStdDialogButtonSizer);
if (buttonSizer)
{
sizer->Detach(childSizer);
retBorder = newBorder;
return buttonSizer;
}
}
else // find a horizontal box sizer containing standard buttons
{
wxBoxSizer* buttonSizer = wxDynamicCast(childSizer, wxBoxSizer);
if (buttonSizer && IsOrdinaryButtonSizer(dialog, buttonSizer))
{
sizer->Detach(childSizer);
retBorder = newBorder;
return buttonSizer;
}
}
wxSizer* s = FindButtonSizer(stdButtonSizer, dialog, childSizer, retBorder, newBorder);
if (s)
return s;
}
}
return NULL;
}
/// Check if this sizer contains standard buttons, and so can be repositioned in the dialog
bool wxStandardDialogLayoutAdapter::IsOrdinaryButtonSizer(wxDialog* dialog, wxBoxSizer* sizer)
{
if (sizer->GetOrientation() != wxHORIZONTAL)
return false;
for ( wxSizerItemList::compatibility_iterator node = sizer->GetChildren().GetFirst();
node; node = node->GetNext() )
{
wxSizerItem *item = node->GetData();
wxButton *childButton = wxDynamicCast(item->GetWindow(), wxButton);
if (childButton && IsStandardButton(dialog, childButton))
return true;
}
return false;
}
/// Check if this is a standard button
bool wxStandardDialogLayoutAdapter::IsStandardButton(wxDialog* dialog, wxButton* button)
{
wxWindowID id = button->GetId();
return (id == wxID_OK || id == wxID_CANCEL || id == wxID_YES || id == wxID_NO || id == wxID_SAVE ||
id == wxID_APPLY || id == wxID_HELP || id == wxID_CONTEXT_HELP || dialog->IsMainButtonId(id));
}
/// Find 'loose' main buttons in the existing layout and add them to the standard dialog sizer
bool wxStandardDialogLayoutAdapter::FindLooseButtons(wxDialog* dialog, wxStdDialogButtonSizer* buttonSizer, wxSizer* sizer, int& count)
{
wxSizerItemList::compatibility_iterator node = sizer->GetChildren().GetFirst();
while (node)
{
wxSizerItemList::compatibility_iterator next = node->GetNext();
wxSizerItem *item = node->GetData();
wxSizer *childSizer = item->GetSizer();
wxButton *childButton = wxDynamicCast(item->GetWindow(), wxButton);
if (childButton && IsStandardButton(dialog, childButton))
{
sizer->Detach(childButton);
buttonSizer->AddButton(childButton);
count ++;
}
if (childSizer)
FindLooseButtons(dialog, buttonSizer, childSizer, count);
node = next;
}
return true;
}
/// Reparent the controls to the scrolled window
void wxStandardDialogLayoutAdapter::ReparentControls(wxWindow* parent, wxWindow* reparentTo, wxSizer* buttonSizer)
{
DoReparentControls(parent, reparentTo, buttonSizer);
}
void wxStandardDialogLayoutAdapter::DoReparentControls(wxWindow* parent, wxWindow* reparentTo, wxSizer* buttonSizer)
{
wxWindowList::compatibility_iterator node = parent->GetChildren().GetFirst();
while (node)
{
wxWindowList::compatibility_iterator next = node->GetNext();
wxWindow *win = node->GetData();
// Don't reparent the scrolled window or buttons in the button sizer
if (win != reparentTo && (!buttonSizer || !buttonSizer->GetItem(win)))
{
win->Reparent(reparentTo);
#ifdef __WXMSW__
// Restore correct tab order
::SetWindowPos((HWND) win->GetHWND(), HWND_BOTTOM, -1, -1, -1, -1, SWP_NOMOVE|SWP_NOSIZE);
#endif
}
node = next;
}
}
/// Find whether scrolling will be necessary for the dialog, returning wxVERTICAL, wxHORIZONTAL or both
int wxStandardDialogLayoutAdapter::MustScroll(wxDialog* dialog, wxSize& windowSize, wxSize& displaySize)
{
return DoMustScroll(dialog, windowSize, displaySize);
}
/// Find whether scrolling will be necessary for the dialog, returning wxVERTICAL, wxHORIZONTAL or both
int wxStandardDialogLayoutAdapter::DoMustScroll(wxDialog* dialog, wxSize& windowSize, wxSize& displaySize)
{
wxSize minWindowSize = dialog->GetSizer()->GetMinSize();
windowSize = dialog->GetSize();
windowSize = wxSize(wxMax(windowSize.x, minWindowSize.x), wxMax(windowSize.y, minWindowSize.y));
#if wxUSE_DISPLAY
displaySize = wxDisplay(wxDisplay::GetFromWindow(dialog)).GetClientArea().GetSize();
#else
displaySize = wxGetClientDisplayRect();
#endif
int flags = 0;
if (windowSize.y >= (displaySize.y - wxEXTRA_DIALOG_HEIGHT))
flags |= wxVERTICAL;
if (windowSize.x >= displaySize.x)
flags |= wxHORIZONTAL;
return flags;
}
// A function to fit the dialog around its contents, and then adjust for screen size.
// If scrolled windows are passed, scrolling is enabled in the required orientation(s).
bool wxStandardDialogLayoutAdapter::FitWithScrolling(wxDialog* dialog, wxWindowList& windows)
{
return DoFitWithScrolling(dialog, windows);
}
// A function to fit the dialog around its contents, and then adjust for screen size.
// If a scrolled window is passed, scrolling is enabled in the required orientation(s).
bool wxStandardDialogLayoutAdapter::FitWithScrolling(wxDialog* dialog, wxScrolledWindow* scrolledWindow)
{
return DoFitWithScrolling(dialog, scrolledWindow);
}
// A function to fit the dialog around its contents, and then adjust for screen size.
// If a scrolled window is passed, scrolling is enabled in the required orientation(s).
bool wxStandardDialogLayoutAdapter::DoFitWithScrolling(wxDialog* dialog, wxScrolledWindow* scrolledWindow)
{
wxWindowList windows;
windows.Append(scrolledWindow);
return DoFitWithScrolling(dialog, windows);
}
bool wxStandardDialogLayoutAdapter::DoFitWithScrolling(wxDialog* dialog, wxWindowList& windows)
{
wxSizer* sizer = dialog->GetSizer();
if (!sizer)
return false;
sizer->SetSizeHints(dialog);
wxSize windowSize, displaySize;
int scrollFlags = DoMustScroll(dialog, windowSize, displaySize);
int scrollBarSize = 20;
if (scrollFlags)
{
int scrollBarExtraX = 0, scrollBarExtraY = 0;
bool resizeHorizontally = (scrollFlags & wxHORIZONTAL) != 0;
bool resizeVertically = (scrollFlags & wxVERTICAL) != 0;
if (windows.GetCount() != 0)
{
// Allow extra for a scrollbar, assuming we resizing in one direction only.
if ((resizeVertically && !resizeHorizontally) && (windowSize.x < (displaySize.x - scrollBarSize)))
scrollBarExtraX = scrollBarSize;
if ((resizeHorizontally && !resizeVertically) && (windowSize.y < (displaySize.y - scrollBarSize)))
scrollBarExtraY = scrollBarSize;
}
wxWindowList::compatibility_iterator node = windows.GetFirst();
while (node)
{
wxWindow *win = node->GetData();
wxScrolledWindow* scrolledWindow = wxDynamicCast(win, wxScrolledWindow);
if (scrolledWindow)
{
scrolledWindow->SetScrollRate(resizeHorizontally ? 10 : 0, resizeVertically ? 10 : 0);
if (scrolledWindow->GetSizer())
scrolledWindow->GetSizer()->Fit(scrolledWindow);
}
node = node->GetNext();
}
wxSize limitTo = windowSize + wxSize(scrollBarExtraX, scrollBarExtraY);
if (resizeVertically)
limitTo.y = displaySize.y - wxEXTRA_DIALOG_HEIGHT;
if (resizeHorizontally)
limitTo.x = displaySize.x;
dialog->SetMinSize(limitTo);
dialog->SetSize(limitTo);
dialog->SetSizeHints( limitTo.x, limitTo.y, dialog->GetMaxWidth(), dialog->GetMaxHeight() );
}
return true;
}
/*!
* Module to initialise standard adapter
*/
class wxDialogLayoutAdapterModule: public wxModule
{
DECLARE_DYNAMIC_CLASS(wxDialogLayoutAdapterModule)
public:
wxDialogLayoutAdapterModule() {}
virtual void OnExit() { delete wxDialogBase::SetLayoutAdapter(NULL); }
virtual bool OnInit() { wxDialogBase::SetLayoutAdapter(new wxStandardDialogLayoutAdapter); return true; }
};
IMPLEMENT_DYNAMIC_CLASS(wxDialogLayoutAdapterModule, wxModule)