Switched over to using wxEventLoop.
[wxWidgets.git] / src / os2 / dialog.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: dialog.cpp
3 // Purpose: wxDialog class
4 // Author: David Webster
5 // Modified by:
6 // Created: 10/14/99
7 // RCS-ID: $Id$
8 // Copyright: (c) David Webster
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 // For compilers that support precompilation, includes "wx.h".
13 #include "wx/wxprec.h"
14
15 #ifndef WX_PRECOMP
16 #include "wx/dialog.h"
17 #include "wx/utils.h"
18 #include "wx/frame.h"
19 #include "wx/app.h"
20 #include "wx/settings.h"
21 #include "wx/intl.h"
22 #include "wx/log.h"
23 #endif
24
25 #include "wx/os2/private.h"
26 #include "wx/log.h"
27 #include "wx/evtloop.h"
28 #include "wx/ptr_scpd.h"
29
30 #define wxDIALOG_DEFAULT_X 300
31 #define wxDIALOG_DEFAULT_Y 300
32
33 #define wxDIALOG_DEFAULT_WIDTH 500
34 #define wxDIALOG_DEFAULT_HEIGHT 500
35
36 wxWindowList wxModalDialogs;
37
38 IMPLEMENT_DYNAMIC_CLASS(wxDialog, wxTopLevelWindow)
39
40 BEGIN_EVENT_TABLE(wxDialog, wxDialogBase)
41 EVT_BUTTON(wxID_OK, wxDialog::OnOK)
42 EVT_BUTTON(wxID_APPLY, wxDialog::OnApply)
43 EVT_BUTTON(wxID_CANCEL, wxDialog::OnCancel)
44 EVT_CHAR_HOOK(wxDialog::OnCharHook)
45 EVT_SYS_COLOUR_CHANGED(wxDialog::OnSysColourChanged)
46 EVT_CLOSE(wxDialog::OnCloseWindow)
47 END_EVENT_TABLE()
48
49 // ----------------------------------------------------------------------------
50 // wxDialogModalData
51 // ----------------------------------------------------------------------------
52
53 // this is simply a container for any data we need to implement modality which
54 // allows us to avoid changing wxDialog each time the implementation changes
55 class wxDialogModalData
56 {
57 public:
58 wxDialogModalData(wxDialog *dialog) : m_evtLoop(dialog) { }
59
60 void RunLoop()
61 {
62 m_evtLoop.Run();
63 }
64
65 void ExitLoop()
66 {
67 m_evtLoop.Exit();
68 }
69
70 private:
71 wxModalEventLoop m_evtLoop;
72 };
73
74 wxDEFINE_TIED_SCOPED_PTR_TYPE(wxDialogModalData);
75
76 // ============================================================================
77 // implementation
78 // ============================================================================
79
80 // ----------------------------------------------------------------------------
81 // wxDialog construction
82 // ----------------------------------------------------------------------------
83
84 void wxDialog::Init()
85 {
86 m_pOldFocus = (wxWindow *)NULL;
87 m_isShown = FALSE;
88 m_pWindowDisabler = (wxWindowDisabler *)NULL;
89 SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE));
90 } // end of wxDialog::Init
91
92 bool wxDialog::Create(
93 wxWindow* pParent
94 , wxWindowID vId
95 , const wxString& rsTitle
96 , const wxPoint& rPos
97 , const wxSize& rSize
98 , long lStyle
99 , const wxString& rsName
100 )
101 {
102 long lX = rPos.x;
103 long lY = rPos.y;
104 long lWidth = rSize.x;
105 long lHeight = rSize.y;
106 const char* zDlg;
107 WXDWORD dwExtendedStyle = 0L;
108 HWND hWnd;
109
110 Init();
111 SetExtraStyle(GetExtraStyle() | wxTOPLEVEL_EX_DIALOG);
112
113 //
114 // Save focus before doing anything which can potentially change it
115 //
116 m_pOldFocus = FindFocus();
117
118 //
119 // All dialogs should really have this style
120 //
121 lStyle |= wxTAB_TRAVERSAL;
122
123 if (!wxTopLevelWindow::Create( pParent
124 ,vId
125 ,rsTitle
126 ,rPos
127 ,rSize
128 ,lStyle
129 ,rsName
130 ))
131 return FALSE;
132 SetFont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT));
133
134 //
135 // Must defer setting the title until after dialog is created and sized
136 //
137 if (!rsTitle.IsNull())
138 SetTitle(rsTitle);
139 return TRUE;
140 } // end of wxDialog::Create
141
142 void wxDialog::SetModal(
143 bool bFlag
144 )
145 {
146 if (bFlag)
147 {
148 m_windowStyle |= wxDIALOG_MODAL ;
149 wxModelessWindows.DeleteObject(this);
150 }
151 else
152 {
153 m_windowStyle &= ~wxDIALOG_MODAL ;
154 wxModelessWindows.Append(this);
155 }
156 } // end of wxDialog::SetModal
157
158 wxDialog::~wxDialog()
159 {
160 m_isBeingDeleted = TRUE;
161 Show(FALSE);
162 } // end of wxDialog::~wxDialog
163
164 //
165 // By default, pressing escape cancels the dialog
166 //
167 void wxDialog::OnCharHook(
168 wxKeyEvent& rEvent
169 )
170 {
171 if (GetHWND())
172 {
173 if (rEvent.m_keyCode == WXK_ESCAPE)
174 {
175 //
176 // Behaviour changed in 2.0: we'll send a Cancel message
177 // to the dialog instead of Close.
178 //
179 wxCommandEvent vCancelEvent( wxEVT_COMMAND_BUTTON_CLICKED
180 ,wxID_CANCEL
181 );
182
183 vCancelEvent.SetEventObject( this );
184 GetEventHandler()->ProcessEvent(vCancelEvent);
185
186 //
187 // Ensure that there is another message for this window so the
188 // ShowModal loop will exit and won't get stuck in GetMessage().
189 //
190 ::WinPostMsg(GetHwnd(), WM_NULL, 0, 0);
191 return;
192 }
193 }
194 // We didn't process this event.
195 rEvent.Skip();
196 }
197
198 // ----------------------------------------------------------------------------
199 // showing the dialogs
200 // ----------------------------------------------------------------------------
201
202 bool wxDialog::IsModal() const
203 {
204 return (GetWindowStyleFlag() & wxDIALOG_MODAL) != 0;
205 } // end of wxDialog::IsModal
206
207 bool wxDialog::IsModalShowing() const
208 {
209 return wxModalDialogs.Find((wxDialog *)this) != NULL; // const_cast
210 } // end of wxDialog::IsModalShowing
211
212 void wxDialog::DoShowModal()
213 {
214 wxWindow* pParent = GetParent();
215 wxWindow* pOldFocus = m_pOldFocus;
216 HWND hWndOldFocus = 0;
217
218 wxCHECK_RET( !IsModalShowing(), _T("DoShowModal() called twice") );
219 wxCHECK_RET( IsModal(), _T("can't DoShowModal() modeless dialog") );
220
221 wxModalDialogs.Append(this);
222 if (pOldFocus)
223 hWndOldFocus = (HWND)pOldFocus->GetHWND();
224
225 //
226 // Remember where the focus was
227 //
228 if (!pOldFocus)
229 {
230 pOldFocus = pParent;
231 if (pParent)
232 hWndOldFocus = GetHwndOf(pParent);
233 }
234
235 //
236 // Disable all other app windows
237 //
238 wxASSERT_MSG(!m_pWindowDisabler, _T("disabling windows twice?"));
239
240 //
241 // Disables other app windows and window proc message processing
242 // until WinDismissDlg called
243 //
244 ::WinProcessDlg((HWND)GetHwnd());
245
246 //
247 // Before entering the modal loop, reset the "is in OnIdle()" flag (see
248 // comment in app.cpp)
249 //
250 extern bool gbInOnIdle;
251 bool bWasInOnIdle = gbInOnIdle;
252
253 gbInOnIdle = FALSE;
254
255 // enter the modal loop
256 {
257 wxDialogModalDataTiedPtr modalData(&m_modalData,
258 new wxDialogModalData(this));
259 modalData->RunLoop();
260 }
261 gbInOnIdle = bWasInOnIdle;
262
263 //
264 // and restore focus
265 // Note that this code MUST NOT access the dialog object's data
266 // in case the object has been deleted (which will be the case
267 // for a modal dialog that has been destroyed before calling EndModal).
268 //
269 if (pOldFocus && (pOldFocus != this) && ::WinIsWindow(vHabmain, hWndOldFocus))
270 {
271 //
272 // This is likely to prove that the object still exists
273 //
274 if (wxFindWinFromHandle((WXHWND) hWndOldFocus) == pOldFocus)
275 pOldFocus->SetFocus();
276 }
277 } // end of wxDialog::DoShowModal
278
279 bool wxDialog::Show(
280 bool bShow
281 )
282 {
283 if (!bShow)
284 {
285 //
286 // If we had disabled other app windows, reenable them back now because
287 // if they stay disabled Windows will activate another window (one
288 // which is enabled, anyhow) and we will lose activation. We really don't
289 // do this in OS/2 since PM does this for us.
290 //
291 if (m_pWindowDisabler)
292 {
293 delete m_pWindowDisabler;
294 m_pWindowDisabler = NULL;
295 }
296 }
297
298 //
299 // ShowModal() may be called for already shown dialog
300 //
301 if (!wxDialogBase::Show(bShow) && !(bShow && IsModal()))
302 {
303 //
304 // Nothing to do
305 //
306 return FALSE;
307 }
308
309 if (bShow)
310 {
311 //
312 // Usually will result in TransferDataToWindow() being called
313 //
314 InitDialog();
315 }
316
317 if (GetTitle().c_str())
318 ::WinSetWindowText((HWND)GetHwnd(), GetTitle().c_str());
319 if (IsModal())
320 {
321 if (bShow)
322 {
323 //
324 // Modal dialog needs a parent window, so try to find one
325 //
326 if (!GetParent())
327 {
328 wxWindow* pParent = wxTheApp->GetTopWindow();
329
330 if ( pParent && pParent != this && pParent->IsShown() )
331 {
332 //
333 // Use it
334 //
335 m_parent = pParent;
336
337 }
338 }
339 DoShowModal();
340 }
341 else // end of modal dialog
342 {
343 //
344 // This will cause IsModalShowing() return FALSE and our local
345 // message loop will terminate
346 //
347 wxModalDialogs.DeleteObject(this);
348 }
349 }
350 return TRUE;
351 } // end of wxDialog::Show
352
353 //
354 // Replacement for Show(TRUE) for modal dialogs - returns return code
355 //
356 int wxDialog::ShowModal()
357 {
358 if (!IsModal())
359 {
360 SetModal(TRUE);
361 }
362 Show(TRUE);
363 return GetReturnCode();
364 } // end of wxDialog::ShowModal
365
366 void wxDialog::EndModal(
367 int nRetCode
368 )
369 {
370 SetReturnCode(nRetCode);
371 Show(FALSE);
372 ::WinDismissDlg((HWND)GetHwnd(), nRetCode);
373 } // end of wxDialog::EndModal
374
375 // ----------------------------------------------------------------------------
376 // wxWin event handlers
377 // ----------------------------------------------------------------------------
378
379 void wxDialog::OnApply(
380 wxCommandEvent& rEvent
381 )
382 {
383 if (Validate())
384 TransferDataFromWindow();
385 } // end of wxDialog::OnApply
386
387 // Standard buttons
388 void wxDialog::OnOK(
389 wxCommandEvent& rEvent
390 )
391 {
392 if ( Validate() && TransferDataFromWindow() )
393 {
394 EndModal(wxID_OK);
395 }
396 } // end of wxDialog::OnOK
397
398 void wxDialog::OnCancel(
399 wxCommandEvent& rEvent
400 )
401 {
402 EndModal(wxID_CANCEL);
403 } // end of wxDialog::OnCancel
404
405 void wxDialog::OnCloseWindow(
406 wxCloseEvent& rEvent
407 )
408 {
409 //
410 // We'll send a Cancel message by default,
411 // which may close the dialog.
412 // Check for looping if the Cancel event handler calls Close().
413 //
414 // Note that if a cancel button and handler aren't present in the dialog,
415 // nothing will happen when you close the dialog via the window manager, or
416 // via Close().
417 // We wouldn't want to destroy the dialog by default, since the dialog may have been
418 // created on the stack.
419 // However, this does mean that calling dialog->Close() won't delete the dialog
420 // unless the handler for wxID_CANCEL does so. So use Destroy() if you want to be
421 // sure to destroy the dialog.
422 // The default OnCancel (above) simply ends a modal dialog, and hides a modeless dialog.
423 //
424
425 //
426 // Ugh??? This is not good but until I figure out a global list it'll have to do
427 //
428 static wxList closing;
429
430 if ( closing.Member(this) )
431 return;
432
433 closing.Append(this);
434
435 wxCommandEvent vCancelEvent(wxEVT_COMMAND_BUTTON_CLICKED, wxID_CANCEL);
436
437 vCancelEvent.SetEventObject( this );
438 GetEventHandler()->ProcessEvent(vCancelEvent); // This may close the dialog
439
440 closing.DeleteObject(this);
441 } // end of wxDialog::OnCloseWindow
442
443 void wxDialog::OnSysColourChanged(
444 wxSysColourChangedEvent& rEvent
445 )
446 {
447 SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE));
448 Refresh();
449 } // end of wxDialog::OnSysColourChanged
450
451 MRESULT wxDialog::OS2WindowProc(
452 WXUINT uMessage
453 , WXWPARAM wParam
454 , WXLPARAM lParam
455 )
456 {
457 MRESULT rc = 0;
458 bool bProcessed = FALSE;
459
460 switch (uMessage)
461 {
462 case WM_CLOSE:
463 //
464 // If we can't close, tell the system that we processed the
465 // message - otherwise it would close us
466 //
467 bProcessed = !Close();
468 break;
469 }
470
471 if (!bProcessed)
472 rc = wxWindow::OS2WindowProc( uMessage
473 ,wParam
474 ,lParam
475 );
476 return rc;
477 } // end of wxDialog::OS2WindowProc
478