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/private/stattext.h"
45 // ----------------------------------------------------------------------------
47 // ----------------------------------------------------------------------------
49 BEGIN_EVENT_TABLE(wxDialogBase
, wxTopLevelWindow
)
50 EVT_BUTTON(wxID_ANY
, wxDialogBase::OnButton
)
52 EVT_CLOSE(wxDialogBase::OnCloseWindow
)
54 EVT_CHAR_HOOK(wxDialogBase::OnCharHook
)
56 WX_EVENT_TABLE_CONTROL_CONTAINER(wxDialogBase
)
59 WX_DELEGATE_TO_CONTROL_CONTAINER(wxDialogBase
, wxTopLevelWindow
)
61 void wxDialogBase::Init()
64 m_affirmativeId
= wxID_OK
;
65 m_escapeId
= wxID_ANY
;
67 // the dialogs have this flag on by default to prevent the events from the
68 // dialog controls from reaching the parent frame which is usually
69 // undesirable and can lead to unexpected and hard to find bugs
70 SetExtraStyle(GetExtraStyle() | wxWS_EX_BLOCK_EVENTS
);
72 WX_INIT_CONTROL_CONTAINER();
75 // helper of GetParentForModalDialog()
76 static bool CanBeUsedAsParent(wxWindow
*parent
)
78 extern WXDLLIMPEXP_DATA_CORE(wxList
) wxPendingDelete
;
80 return !parent
->HasExtraStyle(wxWS_EX_TRANSIENT
) &&
81 parent
->IsShownOnScreen() &&
82 !wxPendingDelete
.Member(parent
) &&
83 !parent
->IsBeingDeleted();
86 wxWindow
*wxDialogBase::GetParentForModalDialog(wxWindow
*parent
) const
88 // creating a parent-less modal dialog will result (under e.g. wxGTK2)
89 // in an unfocused dialog, so try to find a valid parent for it:
91 parent
= wxGetTopLevelParent(parent
);
93 if ( !parent
|| !CanBeUsedAsParent(parent
) )
94 parent
= wxTheApp
->GetTopWindow();
96 if ( parent
&& !CanBeUsedAsParent(parent
) )
98 // can't use this one, it's going to disappear
107 class wxTextSizerWrapper
: public wxTextWrapper
110 wxTextSizerWrapper(wxWindow
*win
)
116 wxSizer
*CreateSizer(const wxString
& text
, int widthMax
)
118 m_sizer
= new wxBoxSizer(wxVERTICAL
);
119 Wrap(m_win
, text
, widthMax
);
124 virtual void OnOutputLine(const wxString
& line
)
128 m_sizer
->Add(new wxStaticText(m_win
, wxID_ANY
, line
));
130 else // empty line, no need to create a control for it
133 m_hLine
= m_win
->GetCharHeight();
135 m_sizer
->Add(5, m_hLine
);
145 wxSizer
*wxDialogBase::CreateTextSizer(const wxString
& message
)
147 // I admit that this is complete bogus, but it makes
148 // message boxes work for pda screens temporarily..
150 const bool is_pda
= wxSystemSettings::GetScreenType() <= wxSYS_SCREEN_PDA
;
153 widthMax
= wxSystemSettings::GetMetric( wxSYS_SCREEN_X
) - 25;
156 // '&' is used as accel mnemonic prefix in the wxWidgets controls but in
157 // the static messages created by CreateTextSizer() (used by wxMessageBox,
158 // for example), we don't want this special meaning, so we need to quote it
159 wxString
text(message
);
160 text
.Replace(_T("&"), _T("&&"));
162 wxTextSizerWrapper
wrapper(this);
164 return wrapper
.CreateSizer(text
, widthMax
);
167 #endif // wxUSE_STATTEXT
169 wxSizer
*wxDialogBase::CreateButtonSizer(long flags
)
171 wxSizer
*sizer
= NULL
;
173 #ifdef __SMARTPHONE__
174 wxDialog
* dialog
= (wxDialog
*) this;
176 dialog
->SetLeftMenu(wxID_OK
);
178 if ( flags
& wxCANCEL
)
179 dialog
->SetRightMenu(wxID_CANCEL
);
182 dialog
->SetLeftMenu(wxID_YES
);
185 dialog
->SetRightMenu(wxID_NO
);
186 #else // !__SMARTPHONE__
191 // PocketPC guidelines recommend for Ok/Cancel dialogs to use OK button
192 // located inside caption bar and implement Cancel functionality through
193 // Undo outside dialog. As native behaviour this will be default here but
194 // can be replaced with real wxButtons by setting the option below to 1
195 if ( (flags
& ~(wxCANCEL
|wxNO_DEFAULT
)) != wxOK
||
196 wxSystemOptions::GetOptionInt(wxT("wince.dialog.real-ok-cancel")) )
197 #endif // __POCKETPC__
199 sizer
= CreateStdDialogButtonSizer(flags
);
201 #endif // wxUSE_BUTTON
203 #endif // __SMARTPHONE__/!__SMARTPHONE__
208 wxSizer
*wxDialogBase::CreateSeparatedButtonSizer(long flags
)
210 wxSizer
*sizer
= CreateButtonSizer(flags
);
214 // Mac Human Interface Guidelines recommend not to use static lines as
216 #if wxUSE_STATLINE && !defined(__WXMAC__)
217 wxBoxSizer
*topsizer
= new wxBoxSizer(wxVERTICAL
);
218 topsizer
->Add(new wxStaticLine(this),
219 wxSizerFlags().Expand().DoubleBorder(wxBOTTOM
));
220 topsizer
->Add(sizer
, wxSizerFlags().Expand());
222 #endif // wxUSE_STATLINE
229 wxStdDialogButtonSizer
*wxDialogBase::CreateStdDialogButtonSizer( long flags
)
231 wxStdDialogButtonSizer
*sizer
= new wxStdDialogButtonSizer();
234 wxButton
*yes
= NULL
;
239 ok
= new wxButton(this, wxID_OK
);
240 sizer
->AddButton(ok
);
243 if (flags
& wxCANCEL
)
245 wxButton
*cancel
= new wxButton(this, wxID_CANCEL
);
246 sizer
->AddButton(cancel
);
251 yes
= new wxButton(this, wxID_YES
);
252 sizer
->AddButton(yes
);
257 no
= new wxButton(this, wxID_NO
);
258 sizer
->AddButton(no
);
263 wxButton
*apply
= new wxButton(this, wxID_APPLY
);
264 sizer
->AddButton(apply
);
269 wxButton
*close
= new wxButton(this, wxID_CLOSE
);
270 sizer
->AddButton(close
);
275 wxButton
*help
= new wxButton(this, wxID_HELP
);
276 sizer
->AddButton(help
);
279 if (flags
& wxNO_DEFAULT
)
302 SetAffirmativeId(wxID_OK
);
303 else if (flags
& wxYES
)
304 SetAffirmativeId(wxID_YES
);
311 #endif // wxUSE_BUTTON
313 // ----------------------------------------------------------------------------
314 // standard buttons handling
315 // ----------------------------------------------------------------------------
317 void wxDialogBase::EndDialog(int rc
)
325 void wxDialogBase::AcceptAndClose()
327 if ( Validate() && TransferDataFromWindow() )
329 EndDialog(m_affirmativeId
);
333 void wxDialogBase::SetAffirmativeId(int affirmativeId
)
335 m_affirmativeId
= affirmativeId
;
338 void wxDialogBase::SetEscapeId(int escapeId
)
340 m_escapeId
= escapeId
;
343 bool wxDialogBase::EmulateButtonClickIfPresent(int id
)
346 wxButton
*btn
= wxDynamicCast(FindWindow(id
), wxButton
);
348 if ( !btn
|| !btn
->IsEnabled() || !btn
->IsShown() )
351 wxCommandEvent
event(wxEVT_COMMAND_BUTTON_CLICKED
, id
);
352 event
.SetEventObject(btn
);
353 btn
->GetEventHandler()->ProcessEvent(event
);
356 #else // !wxUSE_BUTTON
359 #endif // wxUSE_BUTTON/!wxUSE_BUTTON
362 bool wxDialogBase::IsEscapeKey(const wxKeyEvent
& event
)
364 // for most platforms, Esc key is used to close the dialogs
365 return event
.GetKeyCode() == WXK_ESCAPE
&&
366 event
.GetModifiers() == wxMOD_NONE
;
369 void wxDialogBase::OnCharHook(wxKeyEvent
& event
)
371 if ( event
.GetKeyCode() == WXK_ESCAPE
)
373 int idCancel
= GetEscapeId();
377 // don't handle Esc specially at all
381 // this value is special: it means translate Esc to wxID_CANCEL
382 // but if there is no such button, then fall back to wxID_OK
383 if ( EmulateButtonClickIfPresent(wxID_CANCEL
) )
385 idCancel
= GetAffirmativeId();
389 // translate Esc to button press for the button with given id
390 if ( EmulateButtonClickIfPresent(idCancel
) )
398 void wxDialogBase::OnButton(wxCommandEvent
& event
)
400 const int id
= event
.GetId();
401 if ( id
== GetAffirmativeId() )
405 else if ( id
== wxID_APPLY
)
408 TransferDataFromWindow();
410 // TODO: disable the Apply button until things change again
412 else if ( id
== GetEscapeId() ||
413 (id
== wxID_CANCEL
&& GetEscapeId() == wxID_ANY
) )
415 EndDialog(wxID_CANCEL
);
417 else // not a standard button
423 // ----------------------------------------------------------------------------
424 // other event handlers
425 // ----------------------------------------------------------------------------
427 void wxDialogBase::OnCloseWindow(wxCloseEvent
& WXUNUSED(event
))
429 // We'll send a Cancel message by default, which may close the dialog.
430 // Check for looping if the Cancel event handler calls Close().
432 // Note that if a cancel button and handler aren't present in the dialog,
433 // nothing will happen when you close the dialog via the window manager, or
434 // via Close(). We wouldn't want to destroy the dialog by default, since
435 // the dialog may have been created on the stack. However, this does mean
436 // that calling dialog->Close() won't delete the dialog unless the handler
437 // for wxID_CANCEL does so. So use Destroy() if you want to be sure to
438 // destroy the dialog. The default OnCancel (above) simply ends a modal
439 // dialog, and hides a modeless dialog.
441 // VZ: this is horrible and MT-unsafe. Can't we reuse some of these global
442 // lists here? don't dare to change it now, but should be done later!
443 static wxList closing
;
445 if ( closing
.Member(this) )
448 closing
.Append(this);
450 wxCommandEvent
cancelEvent(wxEVT_COMMAND_BUTTON_CLICKED
, wxID_CANCEL
);
451 cancelEvent
.SetEventObject( this );
452 GetEventHandler()->ProcessEvent(cancelEvent
); // This may close the dialog
454 closing
.DeleteObject(this);
457 void wxDialogBase::OnSysColourChanged(wxSysColourChangedEvent
& WXUNUSED(event
))
459 SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE
));