1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/common/dlgcmn.cpp
3 // Purpose: common (to all ports) wxDialog functions
4 // Author: Vadim Zeitlin
8 // Copyright: (c) Vadim Zeitlin
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
12 // ============================================================================
14 // ============================================================================
16 // ----------------------------------------------------------------------------
18 // ----------------------------------------------------------------------------
20 // For compilers that support precompilation, includes "wx.h".
21 #include "wx/wxprec.h"
27 #include "wx/dialog.h"
31 #include "wx/button.h"
32 #include "wx/dcclient.h"
34 #include "wx/settings.h"
35 #include "wx/stattext.h"
37 #include "wx/containr.h"
40 #include "wx/statline.h"
41 #include "wx/sysopt.h"
42 #include "wx/module.h"
43 #include "wx/bookctrl.h"
44 #include "wx/scrolwin.h"
45 #include "wx/textwrapper.h"
46 #include "wx/testing.h"
49 #include "wx/display.h"
52 extern WXDLLEXPORT_DATA(const char) wxDialogNameStr
[] = "dialog";
54 wxModalDialogHook
*wxModalDialogHook::ms_instance
= NULL
;
56 // ----------------------------------------------------------------------------
58 // ----------------------------------------------------------------------------
60 wxDEFINE_FLAGS( wxDialogStyle
)
61 wxBEGIN_FLAGS( wxDialogStyle
)
62 // new style border flags, we put them first to
63 // use them for streaming out
64 wxFLAGS_MEMBER(wxBORDER_SIMPLE
)
65 wxFLAGS_MEMBER(wxBORDER_SUNKEN
)
66 wxFLAGS_MEMBER(wxBORDER_DOUBLE
)
67 wxFLAGS_MEMBER(wxBORDER_RAISED
)
68 wxFLAGS_MEMBER(wxBORDER_STATIC
)
69 wxFLAGS_MEMBER(wxBORDER_NONE
)
71 // old style border flags
72 wxFLAGS_MEMBER(wxSIMPLE_BORDER
)
73 wxFLAGS_MEMBER(wxSUNKEN_BORDER
)
74 wxFLAGS_MEMBER(wxDOUBLE_BORDER
)
75 wxFLAGS_MEMBER(wxRAISED_BORDER
)
76 wxFLAGS_MEMBER(wxSTATIC_BORDER
)
77 wxFLAGS_MEMBER(wxNO_BORDER
)
79 // standard window styles
80 wxFLAGS_MEMBER(wxTAB_TRAVERSAL
)
81 wxFLAGS_MEMBER(wxCLIP_CHILDREN
)
84 wxFLAGS_MEMBER(wxWS_EX_VALIDATE_RECURSIVELY
)
85 wxFLAGS_MEMBER(wxSTAY_ON_TOP
)
86 wxFLAGS_MEMBER(wxCAPTION
)
87 #if WXWIN_COMPATIBILITY_2_6
88 wxFLAGS_MEMBER(wxTHICK_FRAME
)
89 #endif // WXWIN_COMPATIBILITY_2_6
90 wxFLAGS_MEMBER(wxSYSTEM_MENU
)
91 wxFLAGS_MEMBER(wxRESIZE_BORDER
)
92 #if WXWIN_COMPATIBILITY_2_6
93 wxFLAGS_MEMBER(wxRESIZE_BOX
)
94 #endif // WXWIN_COMPATIBILITY_2_6
95 wxFLAGS_MEMBER(wxCLOSE_BOX
)
96 wxFLAGS_MEMBER(wxMAXIMIZE_BOX
)
97 wxFLAGS_MEMBER(wxMINIMIZE_BOX
)
98 wxEND_FLAGS( wxDialogStyle
)
100 wxIMPLEMENT_DYNAMIC_CLASS_XTI(wxDialog
, wxTopLevelWindow
, "wx/dialog.h")
102 wxBEGIN_PROPERTIES_TABLE(wxDialog
)
103 wxPROPERTY( Title
, wxString
, SetTitle
, GetTitle
, wxString(), \
104 0 /*flags*/, wxT("Helpstring"), wxT("group"))
106 wxPROPERTY_FLAGS( WindowStyle
, wxDialogStyle
, long, SetWindowStyleFlag
, \
107 GetWindowStyleFlag
, wxEMPTY_PARAMETER_VALUE
, 0 /*flags*/, \
108 wxT("Helpstring"), wxT("group")) // style
109 wxEND_PROPERTIES_TABLE()
111 wxEMPTY_HANDLERS_TABLE(wxDialog
)
113 wxCONSTRUCTOR_6( wxDialog
, wxWindow
*, Parent
, wxWindowID
, Id
, \
114 wxString
, Title
, wxPoint
, Position
, wxSize
, Size
, long, WindowStyle
)
116 // ----------------------------------------------------------------------------
118 // ----------------------------------------------------------------------------
120 BEGIN_EVENT_TABLE(wxDialogBase
, wxTopLevelWindow
)
121 EVT_BUTTON(wxID_ANY
, wxDialogBase::OnButton
)
123 EVT_CLOSE(wxDialogBase::OnCloseWindow
)
125 EVT_CHAR_HOOK(wxDialogBase::OnCharHook
)
128 wxDialogLayoutAdapter
* wxDialogBase::sm_layoutAdapter
= NULL
;
129 bool wxDialogBase::sm_layoutAdaptation
= false;
131 void wxDialogBase::Init()
134 m_affirmativeId
= wxID_OK
;
135 m_escapeId
= wxID_ANY
;
136 m_layoutAdaptationLevel
= 3;
137 m_layoutAdaptationDone
= FALSE
;
138 m_layoutAdaptationMode
= wxDIALOG_ADAPTATION_MODE_DEFAULT
;
140 // the dialogs have this flag on by default to prevent the events from the
141 // dialog controls from reaching the parent frame which is usually
142 // undesirable and can lead to unexpected and hard to find bugs
143 SetExtraStyle(GetExtraStyle() | wxWS_EX_BLOCK_EVENTS
);
146 wxWindow
*wxDialogBase::CheckIfCanBeUsedAsParent(wxWindow
*parent
) const
151 extern WXDLLIMPEXP_DATA_BASE(wxList
) wxPendingDelete
;
152 if ( wxPendingDelete
.Member(parent
) || parent
->IsBeingDeleted() )
154 // this window is being deleted and we shouldn't create any children
159 if ( parent
->HasExtraStyle(wxWS_EX_TRANSIENT
) )
161 // this window is not being deleted yet but it's going to disappear
162 // soon so still don't parent this window under it
166 if ( !parent
->IsShownOnScreen() )
168 // using hidden parent won't work correctly neither
172 // FIXME-VC6: this compiler requires an explicit const cast or it fails
174 if ( const_cast<const wxWindow
*>(parent
) == this )
176 // not sure if this can really happen but it doesn't hurt to guard
177 // against this clearly invalid situation
185 wxDialogBase::GetParentForModalDialog(wxWindow
*parent
, long style
) const
187 // creating a parent-less modal dialog will result (under e.g. wxGTK2)
188 // in an unfocused dialog, so try to find a valid parent for it unless we
189 // were explicitly asked not to
190 if ( style
& wxDIALOG_NO_PARENT
)
193 // first try the given parent
195 parent
= CheckIfCanBeUsedAsParent(wxGetTopLevelParent(parent
));
197 // then the currently active window
199 parent
= CheckIfCanBeUsedAsParent(
200 wxGetTopLevelParent(wxGetActiveWindow()));
202 // and finally the application main window
204 parent
= CheckIfCanBeUsedAsParent(wxTheApp
->GetTopWindow());
211 wxSizer
*wxDialogBase::CreateTextSizer(const wxString
& message
)
213 wxTextSizerWrapper
wrapper(this);
215 return CreateTextSizer(message
, wrapper
);
218 wxSizer
*wxDialogBase::CreateTextSizer(const wxString
& message
,
219 wxTextSizerWrapper
& wrapper
)
221 // I admit that this is complete bogus, but it makes
222 // message boxes work for pda screens temporarily..
224 const bool is_pda
= wxSystemSettings::GetScreenType() <= wxSYS_SCREEN_PDA
;
227 widthMax
= wxSystemSettings::GetMetric( wxSYS_SCREEN_X
) - 25;
230 return wrapper
.CreateSizer(message
, widthMax
);
233 #endif // wxUSE_STATTEXT
235 wxSizer
*wxDialogBase::CreateButtonSizer(long flags
)
237 #ifdef __SMARTPHONE__
238 wxDialog
* dialog
= (wxDialog
*) this;
240 dialog
->SetLeftMenu(wxID_OK
);
242 if ( flags
& wxCANCEL
)
243 dialog
->SetRightMenu(wxID_CANCEL
);
246 dialog
->SetLeftMenu(wxID_YES
);
249 dialog
->SetRightMenu(wxID_NO
);
252 #else // !__SMARTPHONE__
257 // PocketPC guidelines recommend for Ok/Cancel dialogs to use OK button
258 // located inside caption bar and implement Cancel functionality through
259 // Undo outside dialog. As native behaviour this will be default here but
260 // can be replaced with real wxButtons by setting the option below to 1
261 if ( (flags
& ~(wxCANCEL
|wxNO_DEFAULT
)) != wxOK
||
262 wxSystemOptions::GetOptionInt(wxT("wince.dialog.real-ok-cancel")) )
263 #endif // __POCKETPC__
265 return CreateStdDialogButtonSizer(flags
);
269 #endif // __POCKETPC__
271 #else // !wxUSE_BUTTON
275 #endif // wxUSE_BUTTON/!wxUSE_BUTTON
277 #endif // __SMARTPHONE__/!__SMARTPHONE__
280 wxSizer
*wxDialogBase::CreateSeparatedSizer(wxSizer
*sizer
)
282 // Mac Human Interface Guidelines recommend not to use static lines as
284 #if wxUSE_STATLINE && !defined(__WXMAC__)
285 wxBoxSizer
*topsizer
= new wxBoxSizer(wxVERTICAL
);
286 topsizer
->Add(new wxStaticLine(this),
287 wxSizerFlags().Expand().DoubleBorder(wxBOTTOM
));
288 topsizer
->Add(sizer
, wxSizerFlags().Expand());
290 #endif // wxUSE_STATLINE
295 wxSizer
*wxDialogBase::CreateSeparatedButtonSizer(long flags
)
297 wxSizer
*sizer
= CreateButtonSizer(flags
);
301 return CreateSeparatedSizer(sizer
);
306 wxStdDialogButtonSizer
*wxDialogBase::CreateStdDialogButtonSizer( long flags
)
308 wxStdDialogButtonSizer
*sizer
= new wxStdDialogButtonSizer();
311 wxButton
*yes
= NULL
;
316 ok
= new wxButton(this, wxID_OK
);
317 sizer
->AddButton(ok
);
320 if (flags
& wxCANCEL
)
322 wxButton
*cancel
= new wxButton(this, wxID_CANCEL
);
323 sizer
->AddButton(cancel
);
328 yes
= new wxButton(this, wxID_YES
);
329 sizer
->AddButton(yes
);
334 no
= new wxButton(this, wxID_NO
);
335 sizer
->AddButton(no
);
340 wxButton
*apply
= new wxButton(this, wxID_APPLY
);
341 sizer
->AddButton(apply
);
346 wxButton
*close
= new wxButton(this, wxID_CLOSE
);
347 sizer
->AddButton(close
);
352 wxButton
*help
= new wxButton(this, wxID_HELP
);
353 sizer
->AddButton(help
);
356 if (flags
& wxNO_DEFAULT
)
379 SetAffirmativeId(wxID_OK
);
380 else if (flags
& wxYES
)
381 SetAffirmativeId(wxID_YES
);
388 #endif // wxUSE_BUTTON
390 // ----------------------------------------------------------------------------
391 // standard buttons handling
392 // ----------------------------------------------------------------------------
394 void wxDialogBase::EndDialog(int rc
)
402 void wxDialogBase::AcceptAndClose()
404 if ( Validate() && TransferDataFromWindow() )
406 EndDialog(m_affirmativeId
);
410 void wxDialogBase::SetAffirmativeId(int affirmativeId
)
412 m_affirmativeId
= affirmativeId
;
415 void wxDialogBase::SetEscapeId(int escapeId
)
417 m_escapeId
= escapeId
;
420 bool wxDialogBase::EmulateButtonClickIfPresent(int id
)
423 wxButton
*btn
= wxDynamicCast(FindWindow(id
), wxButton
);
425 if ( !btn
|| !btn
->IsEnabled() || !btn
->IsShown() )
428 wxCommandEvent
event(wxEVT_BUTTON
, id
);
429 event
.SetEventObject(btn
);
430 btn
->GetEventHandler()->ProcessEvent(event
);
433 #else // !wxUSE_BUTTON
436 #endif // wxUSE_BUTTON/!wxUSE_BUTTON
439 bool wxDialogBase::SendCloseButtonClickEvent()
441 int idCancel
= GetEscapeId();
445 // The user doesn't want this dialog to close "implicitly".
449 // this value is special: it means translate Esc to wxID_CANCEL
450 // but if there is no such button, then fall back to wxID_OK
451 if ( EmulateButtonClickIfPresent(wxID_CANCEL
) )
453 idCancel
= GetAffirmativeId();
457 // translate Esc to button press for the button with given id
458 if ( EmulateButtonClickIfPresent(idCancel
) )
465 bool wxDialogBase::IsEscapeKey(const wxKeyEvent
& event
)
467 // For most platforms, Esc key is used to close the dialogs.
469 // Notice that we intentionally don't check for modifiers here, Shift-Esc,
470 // Alt-Esc and so on still close the dialog, typically.
471 return event
.GetKeyCode() == WXK_ESCAPE
;
474 void wxDialogBase::OnCharHook(wxKeyEvent
& event
)
476 if ( IsEscapeKey(event
) )
478 if ( SendCloseButtonClickEvent() )
480 // Skip the call to event.Skip() below, we did handle this key.
488 void wxDialogBase::OnButton(wxCommandEvent
& event
)
490 const int id
= event
.GetId();
491 if ( id
== GetAffirmativeId() )
495 else if ( id
== wxID_APPLY
)
498 TransferDataFromWindow();
500 // TODO: disable the Apply button until things change again
502 else if ( id
== GetEscapeId() ||
503 (id
== wxID_CANCEL
&& GetEscapeId() == wxID_ANY
) )
505 EndDialog(wxID_CANCEL
);
507 else // not a standard button
513 // ----------------------------------------------------------------------------
514 // compatibility methods for supporting the modality API
515 // ----------------------------------------------------------------------------
517 wxDEFINE_EVENT( wxEVT_WINDOW_MODAL_DIALOG_CLOSED
, wxWindowModalDialogEvent
);
519 IMPLEMENT_DYNAMIC_CLASS(wxWindowModalDialogEvent
, wxCommandEvent
)
521 void wxDialogBase::ShowWindowModal ()
524 SendWindowModalDialogEvent ( wxEVT_WINDOW_MODAL_DIALOG_CLOSED
);
527 void wxDialogBase::SendWindowModalDialogEvent ( wxEventType type
)
529 wxWindowModalDialogEvent
event ( type
, GetId());
530 event
.SetEventObject(this);
532 if ( !GetEventHandler()->ProcessEvent(event
) )
534 // the event is not propagated upwards to the parent automatically
535 // because the dialog is a top level window, so do it manually as
536 // in 9 cases of 10 the message must be processed by the dialog
537 // owner and not the dialog itself
538 (void)GetParent()->GetEventHandler()->ProcessEvent(event
);
543 wxDialogModality
wxDialogBase::GetModality() const
545 return IsModal() ? wxDIALOG_MODALITY_APP_MODAL
: wxDIALOG_MODALITY_NONE
;
548 // ----------------------------------------------------------------------------
549 // other event handlers
550 // ----------------------------------------------------------------------------
552 void wxDialogBase::OnCloseWindow(wxCloseEvent
& WXUNUSED(event
))
554 // We'll send a Cancel message by default, which may close the dialog.
556 // Check for looping if the Cancel event handler calls Close().
558 // VZ: this is horrible and MT-unsafe. Can't we reuse some of these global
559 // lists here? don't dare to change it now, but should be done later!
560 static wxList closing
;
562 if ( closing
.Member(this) )
565 closing
.Append(this);
567 if ( !SendCloseButtonClickEvent() )
569 // If the handler didn't close the dialog (e.g. because there is no
570 // button with matching id) we still want to close it when the user
571 // clicks the "x" button in the title bar, otherwise we shouldn't even
572 // have put it there.
574 // Notice that using wxID_CLOSE might have been a better choice but we
575 // use wxID_CANCEL for compatibility reasons.
576 EndDialog(wxID_CANCEL
);
579 closing
.DeleteObject(this);
582 void wxDialogBase::OnSysColourChanged(wxSysColourChangedEvent
& event
)
585 SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE
));
592 /// Do the adaptation
593 bool wxDialogBase::DoLayoutAdaptation()
595 if (GetLayoutAdapter())
597 wxWindow
* focusWindow
= wxFindFocusDescendant(this); // from event.h
598 if (GetLayoutAdapter()->DoLayoutAdaptation((wxDialog
*) this))
601 focusWindow
->SetFocus();
611 /// Can we do the adaptation?
612 bool wxDialogBase::CanDoLayoutAdaptation()
614 // Check if local setting overrides the global setting
615 bool layoutEnabled
= (GetLayoutAdaptationMode() == wxDIALOG_ADAPTATION_MODE_ENABLED
) || (IsLayoutAdaptationEnabled() && (GetLayoutAdaptationMode() != wxDIALOG_ADAPTATION_MODE_DISABLED
));
617 return (layoutEnabled
&& !m_layoutAdaptationDone
&& GetLayoutAdaptationLevel() != 0 && GetLayoutAdapter() != NULL
&& GetLayoutAdapter()->CanDoLayoutAdaptation((wxDialog
*) this));
620 /// Set scrolling adapter class, returning old adapter
621 wxDialogLayoutAdapter
* wxDialogBase::SetLayoutAdapter(wxDialogLayoutAdapter
* adapter
)
623 wxDialogLayoutAdapter
* oldLayoutAdapter
= sm_layoutAdapter
;
624 sm_layoutAdapter
= adapter
;
625 return oldLayoutAdapter
;
632 IMPLEMENT_CLASS(wxDialogLayoutAdapter
, wxObject
)
634 IMPLEMENT_CLASS(wxStandardDialogLayoutAdapter
, wxDialogLayoutAdapter
)
636 // Allow for caption size on wxWidgets < 2.9
637 #if defined(__WXGTK__) && !wxCHECK_VERSION(2,9,0)
638 #define wxEXTRA_DIALOG_HEIGHT 30
640 #define wxEXTRA_DIALOG_HEIGHT 0
643 /// Indicate that adaptation should be done
644 bool wxStandardDialogLayoutAdapter::CanDoLayoutAdaptation(wxDialog
* dialog
)
646 if (dialog
->GetSizer())
648 wxSize windowSize
, displaySize
;
649 return MustScroll(dialog
, windowSize
, displaySize
) != 0;
655 bool wxStandardDialogLayoutAdapter::DoLayoutAdaptation(wxDialog
* dialog
)
657 if (dialog
->GetSizer())
660 wxBookCtrlBase
* bookContentWindow
= wxDynamicCast(dialog
->GetContentWindow(), wxBookCtrlBase
);
662 if (bookContentWindow
)
664 // If we have a book control, make all the pages (that use sizers) scrollable
665 wxWindowList windows
;
666 for (size_t i
= 0; i
< bookContentWindow
->GetPageCount(); i
++)
668 wxWindow
* page
= bookContentWindow
->GetPage(i
);
670 wxScrolledWindow
* scrolledWindow
= wxDynamicCast(page
, wxScrolledWindow
);
672 windows
.Append(scrolledWindow
);
673 else if (!scrolledWindow
&& page
->GetSizer())
675 // Create a scrolled window and reparent
676 scrolledWindow
= CreateScrolledWindow(page
);
677 wxSizer
* oldSizer
= page
->GetSizer();
679 wxSizer
* newSizer
= new wxBoxSizer(wxVERTICAL
);
680 newSizer
->Add(scrolledWindow
,1, wxEXPAND
, 0);
682 page
->SetSizer(newSizer
, false /* don't delete the old sizer */);
684 scrolledWindow
->SetSizer(oldSizer
);
686 ReparentControls(page
, scrolledWindow
);
688 windows
.Append(scrolledWindow
);
692 FitWithScrolling(dialog
, windows
);
695 #endif // wxUSE_BOOKCTRL
698 // If we have an arbitrary dialog, create a scrolling area for the main content, and a button sizer
699 // for the main buttons.
700 wxScrolledWindow
* scrolledWindow
= CreateScrolledWindow(dialog
);
702 int buttonSizerBorder
= 0;
704 // First try to find a wxStdDialogButtonSizer
705 wxSizer
* buttonSizer
= FindButtonSizer(true /* find std button sizer */, dialog
, dialog
->GetSizer(), buttonSizerBorder
);
707 // Next try to find a wxBoxSizer containing the controls
708 if (!buttonSizer
&& dialog
->GetLayoutAdaptationLevel() > wxDIALOG_ADAPTATION_STANDARD_SIZER
)
709 buttonSizer
= FindButtonSizer(false /* find ordinary sizer */, dialog
, dialog
->GetSizer(), buttonSizerBorder
);
711 // If we still don't have a button sizer, collect any 'loose' buttons in the layout
712 if (!buttonSizer
&& dialog
->GetLayoutAdaptationLevel() > wxDIALOG_ADAPTATION_ANY_SIZER
)
715 wxStdDialogButtonSizer
* stdButtonSizer
= new wxStdDialogButtonSizer
;
716 buttonSizer
= stdButtonSizer
;
718 FindLooseButtons(dialog
, stdButtonSizer
, dialog
->GetSizer(), count
);
720 stdButtonSizer
->Realize();
723 wxDELETE(buttonSizer
);
727 if (buttonSizerBorder
== 0)
728 buttonSizerBorder
= 5;
730 ReparentControls(dialog
, scrolledWindow
, buttonSizer
);
732 wxBoxSizer
* newTopSizer
= new wxBoxSizer(wxVERTICAL
);
733 wxSizer
* oldSizer
= dialog
->GetSizer();
735 dialog
->SetSizer(newTopSizer
, false /* don't delete old sizer */);
737 newTopSizer
->Add(scrolledWindow
, 1, wxEXPAND
|wxALL
, 0);
739 newTopSizer
->Add(buttonSizer
, 0, wxEXPAND
|wxALL
, buttonSizerBorder
);
741 scrolledWindow
->SetSizer(oldSizer
);
743 FitWithScrolling(dialog
, scrolledWindow
);
744 #endif // wxUSE_BUTTON
748 dialog
->SetLayoutAdaptationDone(true);
752 // Create the scrolled window
753 wxScrolledWindow
* wxStandardDialogLayoutAdapter::CreateScrolledWindow(wxWindow
* parent
)
755 wxScrolledWindow
* scrolledWindow
= new wxScrolledWindow(parent
, wxID_ANY
, wxDefaultPosition
, wxDefaultSize
, wxTAB_TRAVERSAL
|wxVSCROLL
|wxHSCROLL
|wxBORDER_NONE
);
756 return scrolledWindow
;
761 /// Find and remove the button sizer, if any
762 wxSizer
* wxStandardDialogLayoutAdapter::FindButtonSizer(bool stdButtonSizer
, wxDialog
* dialog
, wxSizer
* sizer
, int& retBorder
, int accumlatedBorder
)
764 for ( wxSizerItemList::compatibility_iterator node
= sizer
->GetChildren().GetFirst();
765 node
; node
= node
->GetNext() )
767 wxSizerItem
*item
= node
->GetData();
768 wxSizer
*childSizer
= item
->GetSizer();
772 int newBorder
= accumlatedBorder
;
773 if (item
->GetFlag() & wxALL
)
774 newBorder
+= item
->GetBorder();
776 if (stdButtonSizer
) // find wxStdDialogButtonSizer
778 wxStdDialogButtonSizer
* buttonSizer
= wxDynamicCast(childSizer
, wxStdDialogButtonSizer
);
781 sizer
->Detach(childSizer
);
782 retBorder
= newBorder
;
786 else // find a horizontal box sizer containing standard buttons
788 wxBoxSizer
* buttonSizer
= wxDynamicCast(childSizer
, wxBoxSizer
);
789 if (buttonSizer
&& IsOrdinaryButtonSizer(dialog
, buttonSizer
))
791 sizer
->Detach(childSizer
);
792 retBorder
= newBorder
;
797 wxSizer
* s
= FindButtonSizer(stdButtonSizer
, dialog
, childSizer
, retBorder
, newBorder
);
805 /// Check if this sizer contains standard buttons, and so can be repositioned in the dialog
806 bool wxStandardDialogLayoutAdapter::IsOrdinaryButtonSizer(wxDialog
* dialog
, wxBoxSizer
* sizer
)
808 if (sizer
->GetOrientation() != wxHORIZONTAL
)
811 for ( wxSizerItemList::compatibility_iterator node
= sizer
->GetChildren().GetFirst();
812 node
; node
= node
->GetNext() )
814 wxSizerItem
*item
= node
->GetData();
815 wxButton
*childButton
= wxDynamicCast(item
->GetWindow(), wxButton
);
817 if (childButton
&& IsStandardButton(dialog
, childButton
))
823 /// Check if this is a standard button
824 bool wxStandardDialogLayoutAdapter::IsStandardButton(wxDialog
* dialog
, wxButton
* button
)
826 wxWindowID id
= button
->GetId();
828 return (id
== wxID_OK
|| id
== wxID_CANCEL
|| id
== wxID_YES
|| id
== wxID_NO
|| id
== wxID_SAVE
||
829 id
== wxID_APPLY
|| id
== wxID_HELP
|| id
== wxID_CONTEXT_HELP
|| dialog
->IsMainButtonId(id
));
832 /// Find 'loose' main buttons in the existing layout and add them to the standard dialog sizer
833 bool wxStandardDialogLayoutAdapter::FindLooseButtons(wxDialog
* dialog
, wxStdDialogButtonSizer
* buttonSizer
, wxSizer
* sizer
, int& count
)
835 wxSizerItemList::compatibility_iterator node
= sizer
->GetChildren().GetFirst();
838 wxSizerItemList::compatibility_iterator next
= node
->GetNext();
839 wxSizerItem
*item
= node
->GetData();
840 wxSizer
*childSizer
= item
->GetSizer();
841 wxButton
*childButton
= wxDynamicCast(item
->GetWindow(), wxButton
);
843 if (childButton
&& IsStandardButton(dialog
, childButton
))
845 sizer
->Detach(childButton
);
846 buttonSizer
->AddButton(childButton
);
851 FindLooseButtons(dialog
, buttonSizer
, childSizer
, count
);
858 #endif // wxUSE_BUTTON
860 /// Reparent the controls to the scrolled window
861 void wxStandardDialogLayoutAdapter::ReparentControls(wxWindow
* parent
, wxWindow
* reparentTo
, wxSizer
* buttonSizer
)
863 DoReparentControls(parent
, reparentTo
, buttonSizer
);
866 void wxStandardDialogLayoutAdapter::DoReparentControls(wxWindow
* parent
, wxWindow
* reparentTo
, wxSizer
* buttonSizer
)
868 wxWindowList::compatibility_iterator node
= parent
->GetChildren().GetFirst();
871 wxWindowList::compatibility_iterator next
= node
->GetNext();
873 wxWindow
*win
= node
->GetData();
875 // Don't reparent the scrolled window or buttons in the button sizer
876 if (win
!= reparentTo
&& (!buttonSizer
|| !buttonSizer
->GetItem(win
)))
878 win
->Reparent(reparentTo
);
880 // Restore correct tab order
881 ::SetWindowPos((HWND
) win
->GetHWND(), HWND_BOTTOM
, -1, -1, -1, -1, SWP_NOMOVE
|SWP_NOSIZE
);
889 /// Find whether scrolling will be necessary for the dialog, returning wxVERTICAL, wxHORIZONTAL or both
890 int wxStandardDialogLayoutAdapter::MustScroll(wxDialog
* dialog
, wxSize
& windowSize
, wxSize
& displaySize
)
892 return DoMustScroll(dialog
, windowSize
, displaySize
);
895 /// Find whether scrolling will be necessary for the dialog, returning wxVERTICAL, wxHORIZONTAL or both
896 int wxStandardDialogLayoutAdapter::DoMustScroll(wxDialog
* dialog
, wxSize
& windowSize
, wxSize
& displaySize
)
898 wxSize minWindowSize
= dialog
->GetSizer()->GetMinSize();
899 windowSize
= dialog
->GetSize();
900 windowSize
= wxSize(wxMax(windowSize
.x
, minWindowSize
.x
), wxMax(windowSize
.y
, minWindowSize
.y
));
902 displaySize
= wxDisplay(wxDisplay::GetFromWindow(dialog
)).GetClientArea().GetSize();
904 displaySize
= wxGetClientDisplayRect().GetSize();
909 if (windowSize
.y
>= (displaySize
.y
- wxEXTRA_DIALOG_HEIGHT
))
911 if (windowSize
.x
>= displaySize
.x
)
912 flags
|= wxHORIZONTAL
;
917 // A function to fit the dialog around its contents, and then adjust for screen size.
918 // If scrolled windows are passed, scrolling is enabled in the required orientation(s).
919 bool wxStandardDialogLayoutAdapter::FitWithScrolling(wxDialog
* dialog
, wxWindowList
& windows
)
921 return DoFitWithScrolling(dialog
, windows
);
924 // A function to fit the dialog around its contents, and then adjust for screen size.
925 // If a scrolled window is passed, scrolling is enabled in the required orientation(s).
926 bool wxStandardDialogLayoutAdapter::FitWithScrolling(wxDialog
* dialog
, wxScrolledWindow
* scrolledWindow
)
928 return DoFitWithScrolling(dialog
, scrolledWindow
);
931 // A function to fit the dialog around its contents, and then adjust for screen size.
932 // If a scrolled window is passed, scrolling is enabled in the required orientation(s).
933 bool wxStandardDialogLayoutAdapter::DoFitWithScrolling(wxDialog
* dialog
, wxScrolledWindow
* scrolledWindow
)
935 wxWindowList windows
;
936 windows
.Append(scrolledWindow
);
937 return DoFitWithScrolling(dialog
, windows
);
940 bool wxStandardDialogLayoutAdapter::DoFitWithScrolling(wxDialog
* dialog
, wxWindowList
& windows
)
942 wxSizer
* sizer
= dialog
->GetSizer();
946 sizer
->SetSizeHints(dialog
);
948 wxSize windowSize
, displaySize
;
949 int scrollFlags
= DoMustScroll(dialog
, windowSize
, displaySize
);
950 int scrollBarSize
= 20;
954 int scrollBarExtraX
= 0, scrollBarExtraY
= 0;
955 bool resizeHorizontally
= (scrollFlags
& wxHORIZONTAL
) != 0;
956 bool resizeVertically
= (scrollFlags
& wxVERTICAL
) != 0;
958 if (windows
.GetCount() != 0)
960 // Allow extra for a scrollbar, assuming we resizing in one direction only.
961 if ((resizeVertically
&& !resizeHorizontally
) && (windowSize
.x
< (displaySize
.x
- scrollBarSize
)))
962 scrollBarExtraX
= scrollBarSize
;
963 if ((resizeHorizontally
&& !resizeVertically
) && (windowSize
.y
< (displaySize
.y
- scrollBarSize
)))
964 scrollBarExtraY
= scrollBarSize
;
967 wxWindowList::compatibility_iterator node
= windows
.GetFirst();
970 wxWindow
*win
= node
->GetData();
971 wxScrolledWindow
* scrolledWindow
= wxDynamicCast(win
, wxScrolledWindow
);
974 scrolledWindow
->SetScrollRate(resizeHorizontally
? 10 : 0, resizeVertically
? 10 : 0);
976 if (scrolledWindow
->GetSizer())
977 scrolledWindow
->GetSizer()->Fit(scrolledWindow
);
980 node
= node
->GetNext();
983 wxSize limitTo
= windowSize
+ wxSize(scrollBarExtraX
, scrollBarExtraY
);
984 if (resizeVertically
)
985 limitTo
.y
= displaySize
.y
- wxEXTRA_DIALOG_HEIGHT
;
986 if (resizeHorizontally
)
987 limitTo
.x
= displaySize
.x
;
989 dialog
->SetMinSize(limitTo
);
990 dialog
->SetSize(limitTo
);
992 dialog
->SetSizeHints( limitTo
.x
, limitTo
.y
, dialog
->GetMaxWidth(), dialog
->GetMaxHeight() );
999 * Module to initialise standard adapter
1002 class wxDialogLayoutAdapterModule
: public wxModule
1004 DECLARE_DYNAMIC_CLASS(wxDialogLayoutAdapterModule
)
1006 wxDialogLayoutAdapterModule() {}
1007 virtual void OnExit() { delete wxDialogBase::SetLayoutAdapter(NULL
); }
1008 virtual bool OnInit() { wxDialogBase::SetLayoutAdapter(new wxStandardDialogLayoutAdapter
); return true; }
1011 IMPLEMENT_DYNAMIC_CLASS(wxDialogLayoutAdapterModule
, wxModule
)