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"
30 #include "wx/button.h"
31 #include "wx/dcclient.h"
33 #include "wx/settings.h"
34 #include "wx/stattext.h"
36 #include "wx/containr.h"
39 #include "wx/statline.h"
40 #include "wx/sysopt.h"
44 // ----------------------------------------------------------------------------
46 // ----------------------------------------------------------------------------
48 // this class is used to wrap the text on word boundary: wrapping is done by
49 // calling OnStartLine() and OnOutputLine() functions
53 wxTextWrapper() { m_eol
= false; }
55 // win is used for getting the font, text is the text to wrap, width is the
56 // max line width or -1 to disable wrapping
57 void Wrap(wxWindow
*win
, const wxString
& text
, int widthMax
);
59 // we don't need it, but just to avoid compiler warnings
60 virtual ~wxTextWrapper() { }
64 virtual void OnOutputLine(const wxString
& line
) = 0;
66 // called at the start of every new line (except the very first one)
67 virtual void OnNewLine() { }
70 // call OnOutputLine() and set m_eol to true
71 void DoOutputLine(const wxString
& line
)
78 // this function is a destructive inspector: when it returns true it also
79 // resets the flag to false so calling it again woulnd't return true any
81 bool IsStartOfNewLine()
95 #endif // wxUSE_STATTEXT
97 // ----------------------------------------------------------------------------
99 // ----------------------------------------------------------------------------
101 BEGIN_EVENT_TABLE(wxDialogBase
, wxTopLevelWindow
)
102 EVT_CHAR_HOOK(wxDialogBase::OnCharHook
)
103 WX_EVENT_TABLE_CONTROL_CONTAINER(wxDialogBase
)
106 WX_DELEGATE_TO_CONTROL_CONTAINER(wxDialogBase
, wxTopLevelWindow
)
108 void wxDialogBase::Init()
111 m_affirmativeId
= wxID_OK
;
112 m_escapeId
= wxID_ANY
;
114 // the dialogs have this flag on by default to prevent the events from the
115 // dialog controls from reaching the parent frame which is usually
116 // undesirable and can lead to unexpected and hard to find bugs
117 SetExtraStyle(GetExtraStyle() | wxWS_EX_BLOCK_EVENTS
);
119 m_container
.SetContainerWindow(this);
124 void wxTextWrapper::Wrap(wxWindow
*win
, const wxString
& text
, int widthMax
)
126 const wxChar
*lastSpace
= NULL
;
129 const wxChar
*lineStart
= text
.c_str();
130 for ( const wxChar
*p
= lineStart
; ; p
++ )
132 if ( IsStartOfNewLine() )
141 if ( *p
== _T('\n') || *p
== _T('\0') )
145 if ( *p
== _T('\0') )
155 if ( widthMax
>= 0 && lastSpace
)
158 win
->GetTextExtent(line
, &width
, NULL
);
160 if ( width
> widthMax
)
162 // remove the last word from this line
163 line
.erase(lastSpace
- lineStart
, p
+ 1 - lineStart
);
166 // go back to the last word of this line which we didn't
171 //else: no wrapping at all or impossible to wrap
176 class wxTextSizerWrapper
: public wxTextWrapper
179 wxTextSizerWrapper(wxWindow
*win
)
185 wxSizer
*CreateSizer(const wxString
& text
, int widthMax
)
187 m_sizer
= new wxBoxSizer(wxVERTICAL
);
188 Wrap(m_win
, text
, widthMax
);
193 virtual void OnOutputLine(const wxString
& line
)
197 m_sizer
->Add(new wxStaticText(m_win
, wxID_ANY
, line
));
199 else // empty line, no need to create a control for it
202 m_hLine
= m_win
->GetCharHeight();
204 m_sizer
->Add(5, m_hLine
);
214 wxSizer
*wxDialogBase::CreateTextSizer(const wxString
& message
)
216 // I admit that this is complete bogus, but it makes
217 // message boxes work for pda screens temporarily..
219 const bool is_pda
= wxSystemSettings::GetScreenType() <= wxSYS_SCREEN_PDA
;
222 widthMax
= wxSystemSettings::GetMetric( wxSYS_SCREEN_X
) - 25;
225 // '&' is used as accel mnemonic prefix in the wxWidgets controls but in
226 // the static messages created by CreateTextSizer() (used by wxMessageBox,
227 // for example), we don't want this special meaning, so we need to quote it
228 wxString
text(message
);
229 text
.Replace(_T("&"), _T("&&"));
231 wxTextSizerWrapper
wrapper(this);
233 return wrapper
.CreateSizer(text
, widthMax
);
236 class wxLabelWrapper
: public wxTextWrapper
239 void WrapLabel(wxWindow
*text
, int widthMax
)
242 Wrap(text
, text
->GetLabel(), widthMax
);
243 text
->SetLabel(m_text
);
247 virtual void OnOutputLine(const wxString
& line
)
252 virtual void OnNewLine()
261 // NB: don't "factor out" the scope operator, SGI MIPSpro 7.3 (but not 7.4)
262 // gets confused if it doesn't immediately follow the class name
264 #if defined(__WXGTK__) && !defined(__WXUNIVERSAL__)
271 wxLabelWrapper wrapper
;
272 wrapper
.WrapLabel(this, width
);
275 #endif // wxUSE_STATTEXT
277 wxSizer
*wxDialogBase::CreateButtonSizer( long flags
, bool separated
, wxCoord distance
)
279 #ifdef __SMARTPHONE__
280 wxUnusedVar(separated
);
281 wxUnusedVar(distance
);
283 wxDialog
* dialog
= (wxDialog
*) this;
285 dialog
->SetLeftMenu(wxID_OK
);
288 if (flags
& wxCANCEL
){
289 dialog
->SetRightMenu(wxID_CANCEL
);
293 dialog
->SetLeftMenu(wxID_YES
);
297 dialog
->SetLeftMenu(wxID_NO
);
299 wxBoxSizer
* sizer
= new wxBoxSizer(wxHORIZONTAL
);
302 #else // !__SMARTPHONE__
305 // PocketPC guidelines recommend for Ok/Cancel dialogs to use
306 // OK button located inside caption bar and implement Cancel functionality
307 // through Undo outside dialog. As native behaviour this will be default
308 // here but can be easily replaced with real wxButtons
309 // with "wince.dialog.real-ok-cancel" option set to 1
310 if ( ((flags
& ~(wxCANCEL
|wxNO_DEFAULT
))== wxOK
) &&
311 (wxSystemOptions::GetOptionInt(wxT("wince.dialog.real-ok-cancel"))==0)
314 wxBoxSizer
* sizer
= new wxBoxSizer(wxHORIZONTAL
);
317 #endif // __POCKETPC__
321 wxSizer
* buttonSizer
= CreateStdDialogButtonSizer( flags
);
323 // Mac Human Interface Guidelines recommend not to use static lines as grouping elements
324 #if wxUSE_STATLINE && !defined(__WXMAC__)
328 wxBoxSizer
*topsizer
= new wxBoxSizer( wxVERTICAL
);
329 topsizer
->Add( new wxStaticLine( this, wxID_ANY
), 0, wxEXPAND
| wxBOTTOM
, distance
);
330 topsizer
->Add( buttonSizer
, 0, wxEXPAND
);
333 #else // !wxUSE_STATLINE
335 wxUnusedVar(separated
);
336 wxUnusedVar(distance
);
339 #endif // wxUSE_STATLINE/!wxUSE_STATLINE
341 #else // !wxUSE_BUTTON
343 wxUnusedVar(separated
);
344 wxUnusedVar(distance
);
345 wxBoxSizer
* sizer
= new wxBoxSizer(wxHORIZONTAL
);
348 #endif // wxUSE_BUTTON/!wxUSE_BUTTON
350 #endif // __SMARTPHONE__/!__SMARTPHONE__
355 wxStdDialogButtonSizer
*wxDialogBase::CreateStdDialogButtonSizer( long flags
)
357 wxStdDialogButtonSizer
*sizer
= new wxStdDialogButtonSizer();
360 wxButton
*yes
= NULL
;
364 ok
= new wxButton(this, wxID_OK
);
365 sizer
->AddButton(ok
);
368 if (flags
& wxCANCEL
){
369 wxButton
*cancel
= new wxButton(this, wxID_CANCEL
);
370 sizer
->AddButton(cancel
);
374 yes
= new wxButton(this, wxID_YES
);
375 sizer
->AddButton(yes
);
379 no
= new wxButton(this, wxID_NO
);
380 sizer
->AddButton(no
);
384 wxButton
*help
= new wxButton(this, wxID_HELP
);
385 sizer
->AddButton(help
);
388 if (flags
& wxNO_DEFAULT
)
411 SetAffirmativeId(wxID_OK
);
412 else if (flags
& wxYES
)
413 SetAffirmativeId(wxID_YES
);
420 #endif // wxUSE_BUTTON
422 // ----------------------------------------------------------------------------
423 // event handling stuff
424 // ----------------------------------------------------------------------------
426 bool wxDialogBase::EmulateButtonClickIfPresent(int id
)
428 wxButton
*btn
= wxDynamicCast(FindWindow(id
), wxButton
);
430 if ( !btn
|| !btn
->IsEnabled() || !btn
->IsShown() )
433 wxCommandEvent
event(wxEVT_COMMAND_BUTTON_CLICKED
, id
);
434 event
.SetEventObject(btn
);
435 btn
->GetEventHandler()->ProcessEvent(event
);
440 bool wxDialogBase::IsEscapeKey(const wxKeyEvent
& event
)
442 // for most platforms, Esc key is used to close the dialogs
443 return event
.GetKeyCode() == WXK_ESCAPE
&&
444 event
.GetModifiers() == wxMOD_NONE
;
447 void wxDialogBase::OnCharHook(wxKeyEvent
& event
)
449 if ( event
.GetKeyCode() == WXK_ESCAPE
)
451 int idCancel
= GetEscapeId();
455 // don't handle Esc specially at all
459 // this value is special: it means translate Esc to wxID_CANCEL
460 // but if there is no such button, then fall back to wxID_OK
461 if ( EmulateButtonClickIfPresent(wxID_CANCEL
) )
467 // translate Esc to button press for the button with given id
468 if ( EmulateButtonClickIfPresent(idCancel
) )