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