]> git.saurik.com Git - wxWidgets.git/blob - src/common/dlgcmn.cpp
3b4bb1e4608e3de3c7d8377f415a3df25455c0df
[wxWidgets.git] / src / common / dlgcmn.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/common/dlgcmn.cpp
3 // Purpose: common (to all ports) wxDialog functions
4 // Author: Vadim Zeitlin
5 // Modified by:
6 // Created: 28.06.99
7 // RCS-ID: $Id$
8 // Copyright: (c) Vadim Zeitlin
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 // ============================================================================
13 // declarations
14 // ============================================================================
15
16 // ----------------------------------------------------------------------------
17 // headers
18 // ----------------------------------------------------------------------------
19
20 // For compilers that support precompilation, includes "wx.h".
21 #include "wx/wxprec.h"
22
23 #ifdef __BORLANDC__
24 #pragma hdrstop
25 #endif
26
27 #include "wx/dialog.h"
28
29 #ifndef WX_PRECOMP
30 #include "wx/button.h"
31 #include "wx/dcclient.h"
32 #include "wx/intl.h"
33 #include "wx/settings.h"
34 #include "wx/stattext.h"
35 #include "wx/sizer.h"
36 #include "wx/containr.h"
37 #endif
38
39 #include "wx/statline.h"
40 #include "wx/sysopt.h"
41
42 #if wxUSE_STATTEXT
43
44 // ----------------------------------------------------------------------------
45 // wxTextWrapper
46 // ----------------------------------------------------------------------------
47
48 // this class is used to wrap the text on word boundary: wrapping is done by
49 // calling OnStartLine() and OnOutputLine() functions
50 class wxTextWrapper
51 {
52 public:
53 wxTextWrapper() { m_eol = false; }
54
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);
58
59 // we don't need it, but just to avoid compiler warnings
60 virtual ~wxTextWrapper() { }
61
62 protected:
63 // line may be empty
64 virtual void OnOutputLine(const wxString& line) = 0;
65
66 // called at the start of every new line (except the very first one)
67 virtual void OnNewLine() { }
68
69 private:
70 // call OnOutputLine() and set m_eol to true
71 void DoOutputLine(const wxString& line)
72 {
73 OnOutputLine(line);
74
75 m_eol = true;
76 }
77
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
80 // more
81 bool IsStartOfNewLine()
82 {
83 if ( !m_eol )
84 return false;
85
86 m_eol = false;
87
88 return true;
89 }
90
91
92 bool m_eol;
93 };
94
95 #endif // wxUSE_STATTEXT
96
97 // ----------------------------------------------------------------------------
98 // wxDialogBase
99 // ----------------------------------------------------------------------------
100
101 BEGIN_EVENT_TABLE(wxDialogBase, wxTopLevelWindow)
102 EVT_CHAR_HOOK(wxDialogBase::OnCharHook)
103 WX_EVENT_TABLE_CONTROL_CONTAINER(wxDialogBase)
104 END_EVENT_TABLE()
105
106 WX_DELEGATE_TO_CONTROL_CONTAINER(wxDialogBase, wxTopLevelWindow)
107
108 void wxDialogBase::Init()
109 {
110 m_returnCode = 0;
111 m_affirmativeId = wxID_OK;
112 m_escapeId = wxID_ANY;
113
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);
118
119 m_container.SetContainerWindow(this);
120 }
121
122 #if wxUSE_STATTEXT
123
124 void wxTextWrapper::Wrap(wxWindow *win, const wxString& text, int widthMax)
125 {
126 const wxChar *lastSpace = NULL;
127 wxString line;
128
129 const wxChar *lineStart = text.c_str();
130 for ( const wxChar *p = lineStart; ; p++ )
131 {
132 if ( IsStartOfNewLine() )
133 {
134 OnNewLine();
135
136 lastSpace = NULL;
137 line.clear();
138 lineStart = p;
139 }
140
141 if ( *p == _T('\n') || *p == _T('\0') )
142 {
143 DoOutputLine(line);
144
145 if ( *p == _T('\0') )
146 break;
147 }
148 else // not EOL
149 {
150 if ( *p == _T(' ') )
151 lastSpace = p;
152
153 line += *p;
154
155 if ( widthMax >= 0 && lastSpace )
156 {
157 int width;
158 win->GetTextExtent(line, &width, NULL);
159
160 if ( width > widthMax )
161 {
162 // remove the last word from this line
163 line.erase(lastSpace - lineStart, p + 1 - lineStart);
164 DoOutputLine(line);
165
166 // go back to the last word of this line which we didn't
167 // output yet
168 p = lastSpace;
169 }
170 }
171 //else: no wrapping at all or impossible to wrap
172 }
173 }
174 }
175
176 class wxTextSizerWrapper : public wxTextWrapper
177 {
178 public:
179 wxTextSizerWrapper(wxWindow *win)
180 {
181 m_win = win;
182 m_hLine = 0;
183 }
184
185 wxSizer *CreateSizer(const wxString& text, int widthMax)
186 {
187 m_sizer = new wxBoxSizer(wxVERTICAL);
188 Wrap(m_win, text, widthMax);
189 return m_sizer;
190 }
191
192 protected:
193 virtual void OnOutputLine(const wxString& line)
194 {
195 if ( !line.empty() )
196 {
197 m_sizer->Add(new wxStaticText(m_win, wxID_ANY, line));
198 }
199 else // empty line, no need to create a control for it
200 {
201 if ( !m_hLine )
202 m_hLine = m_win->GetCharHeight();
203
204 m_sizer->Add(5, m_hLine);
205 }
206 }
207
208 private:
209 wxWindow *m_win;
210 wxSizer *m_sizer;
211 int m_hLine;
212 };
213
214 wxSizer *wxDialogBase::CreateTextSizer(const wxString& message)
215 {
216 // I admit that this is complete bogus, but it makes
217 // message boxes work for pda screens temporarily..
218 int widthMax = -1;
219 const bool is_pda = wxSystemSettings::GetScreenType() <= wxSYS_SCREEN_PDA;
220 if (is_pda)
221 {
222 widthMax = wxSystemSettings::GetMetric( wxSYS_SCREEN_X ) - 25;
223 }
224
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("&&"));
230
231 wxTextSizerWrapper wrapper(this);
232
233 return wrapper.CreateSizer(text, widthMax);
234 }
235
236 class wxLabelWrapper : public wxTextWrapper
237 {
238 public:
239 void WrapLabel(wxWindow *text, int widthMax)
240 {
241 m_text.clear();
242 Wrap(text, text->GetLabel(), widthMax);
243 text->SetLabel(m_text);
244 }
245
246 protected:
247 virtual void OnOutputLine(const wxString& line)
248 {
249 m_text += line;
250 }
251
252 virtual void OnNewLine()
253 {
254 m_text += _T('\n');
255 }
256
257 private:
258 wxString m_text;
259 };
260
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
263 void
264 #if defined(__WXGTK__) && !defined(__WXUNIVERSAL__)
265 wxStaticText::
266 #else
267 wxStaticTextBase::
268 #endif
269 Wrap(int width)
270 {
271 wxLabelWrapper wrapper;
272 wrapper.WrapLabel(this, width);
273 }
274
275 #endif // wxUSE_STATTEXT
276
277 wxSizer *wxDialogBase::CreateButtonSizer( long flags, bool separated, wxCoord distance )
278 {
279 #ifdef __SMARTPHONE__
280 wxUnusedVar(separated);
281 wxUnusedVar(distance);
282
283 wxDialog* dialog = (wxDialog*) this;
284 if (flags & wxOK){
285 dialog->SetLeftMenu(wxID_OK);
286 }
287
288 if (flags & wxCANCEL){
289 dialog->SetRightMenu(wxID_CANCEL);
290 }
291
292 if (flags & wxYES){
293 dialog->SetLeftMenu(wxID_YES);
294 }
295
296 if (flags & wxNO){
297 dialog->SetLeftMenu(wxID_NO);
298 }
299 wxBoxSizer* sizer = new wxBoxSizer(wxHORIZONTAL);
300 return sizer;
301
302 #else // !__SMARTPHONE__
303
304 #ifdef __POCKETPC__
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)
312 )
313 {
314 wxBoxSizer* sizer = new wxBoxSizer(wxHORIZONTAL);
315 return sizer;
316 }
317 #endif // __POCKETPC__
318
319 #if wxUSE_BUTTON
320
321 wxSizer* buttonSizer = CreateStdDialogButtonSizer( flags );
322
323 // Mac Human Interface Guidelines recommend not to use static lines as grouping elements
324 #if wxUSE_STATLINE && !defined(__WXMAC__)
325 if(!separated)
326 return buttonSizer;
327
328 wxBoxSizer *topsizer = new wxBoxSizer( wxVERTICAL );
329 topsizer->Add( new wxStaticLine( this, wxID_ANY ), 0, wxEXPAND | wxBOTTOM, distance );
330 topsizer->Add( buttonSizer, 0, wxEXPAND );
331 return topsizer;
332
333 #else // !wxUSE_STATLINE
334
335 wxUnusedVar(separated);
336 wxUnusedVar(distance);
337 return buttonSizer;
338
339 #endif // wxUSE_STATLINE/!wxUSE_STATLINE
340
341 #else // !wxUSE_BUTTON
342
343 wxUnusedVar(separated);
344 wxUnusedVar(distance);
345 wxBoxSizer* sizer = new wxBoxSizer(wxHORIZONTAL);
346 return sizer;
347
348 #endif // wxUSE_BUTTON/!wxUSE_BUTTON
349
350 #endif // __SMARTPHONE__/!__SMARTPHONE__
351 }
352
353 #if wxUSE_BUTTON
354
355 wxStdDialogButtonSizer *wxDialogBase::CreateStdDialogButtonSizer( long flags )
356 {
357 wxStdDialogButtonSizer *sizer = new wxStdDialogButtonSizer();
358
359 wxButton *ok = NULL;
360 wxButton *yes = NULL;
361 wxButton *no = NULL;
362
363 if (flags & wxOK){
364 ok = new wxButton(this, wxID_OK);
365 sizer->AddButton(ok);
366 }
367
368 if (flags & wxCANCEL){
369 wxButton *cancel = new wxButton(this, wxID_CANCEL);
370 sizer->AddButton(cancel);
371 }
372
373 if (flags & wxYES){
374 yes = new wxButton(this, wxID_YES);
375 sizer->AddButton(yes);
376 }
377
378 if (flags & wxNO){
379 no = new wxButton(this, wxID_NO);
380 sizer->AddButton(no);
381 }
382
383 if (flags & wxHELP){
384 wxButton *help = new wxButton(this, wxID_HELP);
385 sizer->AddButton(help);
386 }
387
388 if (flags & wxNO_DEFAULT)
389 {
390 if (no)
391 {
392 no->SetDefault();
393 no->SetFocus();
394 }
395 }
396 else
397 {
398 if (ok)
399 {
400 ok->SetDefault();
401 ok->SetFocus();
402 }
403 else if (yes)
404 {
405 yes->SetDefault();
406 yes->SetFocus();
407 }
408 }
409
410 if (flags & wxOK)
411 SetAffirmativeId(wxID_OK);
412 else if (flags & wxYES)
413 SetAffirmativeId(wxID_YES);
414
415 sizer->Realize();
416
417 return sizer;
418 }
419
420 #endif // wxUSE_BUTTON
421
422 // ----------------------------------------------------------------------------
423 // event handling stuff
424 // ----------------------------------------------------------------------------
425
426 bool wxDialogBase::EmulateButtonClickIfPresent(int id)
427 {
428 wxButton *btn = wxDynamicCast(FindWindow(id), wxButton);
429
430 if ( !btn || !btn->IsEnabled() || !btn->IsShown() )
431 return false;
432
433 wxCommandEvent event(wxEVT_COMMAND_BUTTON_CLICKED, id);
434 event.SetEventObject(btn);
435 btn->GetEventHandler()->ProcessEvent(event);
436
437 return true;
438 }
439
440 bool wxDialogBase::IsEscapeKey(const wxKeyEvent& event)
441 {
442 // for most platforms, Esc key is used to close the dialogs
443 return event.GetKeyCode() == WXK_ESCAPE &&
444 event.GetModifiers() == wxMOD_NONE;
445 }
446
447 void wxDialogBase::OnCharHook(wxKeyEvent& event)
448 {
449 if ( event.GetKeyCode() == WXK_ESCAPE )
450 {
451 int idCancel = GetEscapeId();
452 switch ( idCancel )
453 {
454 case wxID_NONE:
455 // don't handle Esc specially at all
456 break;
457
458 case wxID_ANY:
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) )
462 return;
463 idCancel = wxID_OK;
464 // fall through
465
466 default:
467 // translate Esc to button press for the button with given id
468 if ( EmulateButtonClickIfPresent(idCancel) )
469 return;
470 }
471 }
472
473 event.Skip();
474 }
475