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:
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user