Mutiple updates from SciTech for wxWindows including the following:
[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 // Lists to keep track of windows, so we can disable/enable them
35 // for modal dialogs
36 wxWindowList wxModalDialogs;
37 wxWindowList wxModelessWindows; // Frames and modeless dialogs
38 extern wxList WXDLLEXPORT wxPendingDelete;
39
40 IMPLEMENT_DYNAMIC_CLASS(wxDialog, wxPanel)
41
42 BEGIN_EVENT_TABLE(wxDialog, wxPanel)
43 EVT_SIZE(wxDialog::OnSize)
44 EVT_BUTTON(wxID_OK, wxDialog::OnOK)
45 EVT_BUTTON(wxID_APPLY, wxDialog::OnApply)
46 EVT_BUTTON(wxID_CANCEL, wxDialog::OnCancel)
47 EVT_CHAR_HOOK(wxDialog::OnCharHook)
48 EVT_SYS_COLOUR_CHANGED(wxDialog::OnSysColourChanged)
49 EVT_CLOSE(wxDialog::OnCloseWindow)
50 END_EVENT_TABLE()
51
52 void wxDialog::Init()
53 {
54 m_pOldFocus = (wxWindow *)NULL;
55 m_isShown = FALSE;
56 m_pWindowDisabler = (wxWindowDisabler *)NULL;
57 SetBackgroundColour(wxSystemSettings::GetSystemColour(wxSYS_COLOUR_3DFACE));
58 } // end of wxDialog::Init
59
60 bool wxDialog::Create(
61 wxWindow* pParent
62 , wxWindowID vId
63 , const wxString& rsTitle
64 , const wxPoint& rPos
65 , const wxSize& rSize
66 , long lStyle
67 , const wxString& rsName
68 )
69 {
70 long lX = rPos.x;
71 long lY = rPos.y;
72 long lWidth = rSize.x;
73 long lHeight = rSize.y;
74 const char* zDlg;
75 WXDWORD dwExtendedStyle = 0L;
76 HWND hWnd;
77
78 Init();
79 m_pOldFocus = (wxWindow*)FindFocus();
80 SetName(rsName);
81 wxTopLevelWindows.Append(this);
82 if (pParent)
83 pParent->AddChild(this);
84 if (vId == -1)
85 m_windowId = NewControlId();
86 else
87 m_windowId = vId;
88 if (lX < 0)
89 lX = wxDIALOG_DEFAULT_X;
90 if (lY < 0)
91 lY = wxDIALOG_DEFAULT_Y;
92 m_windowStyle = lStyle;
93 if (lWidth < 0)
94 lWidth = wxDIALOG_DEFAULT_WIDTH;
95 if (lHeight < 0)
96 lHeight = wxDIALOG_DEFAULT_HEIGHT;
97
98 //
99 // All dialogs should really have this style
100 //
101 m_windowStyle |= wxTAB_TRAVERSAL;
102
103 //
104 // Allows creation of dialogs with & without captions under MSWindows,
105 // resizeable or not (but a resizeable dialog always has caption -
106 // otherwise it would look too strange)
107 //
108 if (lStyle & wxRESIZE_BORDER )
109 zDlg = "wxResizeableDialog";
110 else if (lStyle & wxCAPTION )
111 zDlg = "wxCaptionDialog";
112 else
113 zDlg = "wxNoCaptionDialog";
114 OS2Create( GetWinHwnd(pParent)
115 ,NULL
116 ,rsTitle.c_str()
117 ,0L
118 ,lX
119 ,lY
120 ,lWidth
121 ,lHeight
122 ,GetWinHwnd(pParent)
123 ,HWND_TOP
124 ,(long)m_windowId
125 ,NULL
126 ,NULL
127 );
128 hWnd = (HWND)GetHWND();
129 if (!hWnd)
130 {
131 return FALSE;
132 }
133 SubclassWin(GetHWND());
134 ::WinSetWindowText( hWnd
135 ,(PSZ)rsTitle.c_str()
136 );
137 SetFont(wxSystemSettings::GetSystemFont(wxSYS_DEFAULT_GUI_FONT));
138 return TRUE;
139 } // end of wxDialog::Create
140
141 void wxDialog::SetModal(
142 bool bFlag
143 )
144 {
145 if (bFlag)
146 m_windowStyle |= wxDIALOG_MODAL ;
147 else if ( m_windowStyle & wxDIALOG_MODAL )
148 m_windowStyle -= wxDIALOG_MODAL ;
149
150 wxModelessWindows.DeleteObject(this);
151 if (!bFlag)
152 wxModelessWindows.Append(this);
153 } // end of wxDialog::SetModal
154
155 wxDialog::~wxDialog()
156 {
157 m_isBeingDeleted = TRUE;
158 wxTopLevelWindows.DeleteObject(this);
159 Show(FALSE);
160 if (!IsModal())
161 wxModelessWindows.DeleteObject(this);
162
163 //
164 // If this is the last top-level window, exit.
165 //
166 if (wxTheApp && (wxTopLevelWindows.Number() == 0))
167 {
168 wxTheApp->SetTopWindow(NULL);
169
170 if (wxTheApp->GetExitOnFrameDelete())
171 {
172 ::WinPostMsg(GetHwnd(), WM_QUIT, 0, 0);
173 }
174 }
175 } // end of wxDialog::~wxDialog
176
177 //
178 // By default, pressing escape cancels the dialog
179 //
180 void wxDialog::OnCharHook(
181 wxKeyEvent& rEvent
182 )
183 {
184 if (GetHWND())
185 {
186 if (rEvent.m_keyCode == WXK_ESCAPE)
187 {
188 //
189 // Behaviour changed in 2.0: we'll send a Cancel message
190 // to the dialog instead of Close.
191 //
192 wxCommandEvent vCancelEvent( wxEVT_COMMAND_BUTTON_CLICKED
193 ,wxID_CANCEL
194 );
195
196 vCancelEvent.SetEventObject( this );
197 GetEventHandler()->ProcessEvent(vCancelEvent);
198
199 //
200 // Ensure that there is another message for this window so the
201 // ShowModal loop will exit and won't get stuck in GetMessage().
202 //
203 ::WinPostMsg(GetHwnd(), WM_NULL, 0, 0);
204 return;
205 }
206 }
207 // We didn't process this event.
208 rEvent.Skip();
209 }
210
211 void wxDialog::Iconize(
212 bool WXUNUSED(bIconize)
213 )
214 {
215 } // end of wxDialog::Iconize
216
217 bool wxDialog::IsIconized() const
218 {
219 return FALSE;
220 } // end of wxDialog::IsIconized
221
222 void wxDialog::DoSetClientSize(
223 int nWidth
224 , int nHeight
225 )
226 {
227 HWND hWnd = (HWND) GetHWND();
228 RECTL vRect;
229 RECTL vRect2;
230
231 ::WinQueryWindowRect(hWnd, &vRect);
232 ::WinQueryWindowRect(hWnd, &vRect2);
233
234 LONG lActualWidth = vRect2.xRight - vRect2.xLeft - vRect.xRight + nWidth;
235 LONG lActualHeight = vRect2.yTop + vRect2.yTop - vRect.yTop + nHeight;
236
237 ::WinSetWindowPos( GetHwnd()
238 ,HWND_TOP
239 ,(LONG)vRect2.xLeft
240 ,(LONG)vRect2.yTop
241 ,(LONG)lActualWidth
242 ,(LONG)lActualHeight
243 ,SWP_SIZE | SWP_MOVE
244 );
245
246 wxSizeEvent vEvent( wxSize( lActualWidth
247 ,lActualHeight
248 )
249 ,m_windowId
250 );
251
252 vEvent.SetEventObject( this );
253 GetEventHandler()->ProcessEvent(vEvent);
254 } // end of wxDialog::DoSetClientSize
255
256 void wxDialog::DoGetPosition(
257 int* pnX
258 , int* pnY
259 ) const
260 {
261 RECTL vRect;
262
263 ::WinQueryWindowRect(GetHwnd(), &vRect);
264 if (pnX)
265 *pnX = vRect.xLeft;
266 if (pnY)
267 *pnY = vRect.yBottom; // OS/2's bottom is windows' top???
268 } // end of wxDialog::DoGetPosition
269
270 bool wxDialog::IsModal() const
271 {
272 return (GetWindowStyleFlag() & wxDIALOG_MODAL) != 0;
273 } // end of wxDialog::IsModal
274
275 bool wxDialog::IsModalShowing() const
276 {
277 return wxModalDialogs.Find((wxDialog *)this) != NULL; // const_cast
278 } // end of wxDialog::IsModalShowing
279
280 void wxDialog::DoShowModal()
281 {
282 wxWindow* pParent = GetParent();
283 wxWindow* pOldFocus = m_pOldFocus;
284 HWND hWndOldFocus = 0;
285
286 wxCHECK_RET( !IsModalShowing(), _T("DoShowModal() called twice") );
287 wxCHECK_RET( IsModal(), _T("can't DoShowModal() modeless dialog") );
288
289 wxModalDialogs.Append(this);
290 if (pOldFocus)
291 hWndOldFocus = (HWND)pOldFocus->GetHWND();
292
293 //
294 // Remember where the focus was
295 //
296 if (!pOldFocus)
297 {
298 pOldFocus = pParent;
299 if (pParent)
300 hWndOldFocus = GetHwndOf(pParent);
301 }
302
303 //
304 // Disable all other app windows
305 //
306 wxASSERT_MSG(!m_pWindowDisabler, _T("disabling windows twice?"));
307
308 m_pWindowDisabler = new wxWindowDisabler(this);
309
310 //
311 // Enter the modal loop
312 //
313 while ( IsModalShowing() )
314 {
315 #if wxUSE_THREADS
316 wxMutexGuiLeaveOrEnter();
317 #endif // wxUSE_THREADS
318
319 while ( !wxTheApp->Pending() && wxTheApp->ProcessIdle() )
320 ;
321
322 // a message came or no more idle processing to do
323 wxTheApp->DoMessage();
324 }
325
326 //
327 // Snd restore focus
328 // Note that this code MUST NOT access the dialog object's data
329 // in case the object has been deleted (which will be the case
330 // for a modal dialog that has been destroyed before calling EndModal).
331 //
332 if (pOldFocus && (pOldFocus != this) && ::WinIsWindow(vHabmain, hWndOldFocus))
333 {
334 //
335 // This is likely to prove that the object still exists
336 //
337 if (wxFindWinFromHandle((WXHWND) hWndOldFocus) == pOldFocus)
338 pOldFocus->SetFocus();
339 }
340 } // end of wxDialog::DoShowModal
341
342 bool wxDialog::Show(
343 bool bShow
344 )
345 {
346 if (!bShow)
347 {
348 //
349 // If we had disabled other app windows, reenable them back now because
350 // if they stay disabled Windows will activate another window (one
351 // which is enabled, anyhow) and we will lose activation
352 //
353 if (m_pWindowDisabler)
354 {
355 delete m_pWindowDisabler;
356 m_pWindowDisabler = NULL;
357 }
358 }
359
360 //
361 // ShowModal() may be called for already shown dialog
362 //
363 if (!wxDialogBase::Show(bShow) && !(bShow && IsModal()))
364 {
365 //
366 // Nothing to do
367 //
368 return FALSE;
369 }
370
371 if (bShow)
372 {
373 //
374 // Usually will result in TransferDataToWindow() being called
375 //
376 InitDialog();
377 }
378
379 if (IsModal())
380 {
381 if (bShow)
382 {
383 //
384 // Modal dialog needs a parent window, so try to find one
385 //
386 if (!GetParent())
387 {
388 wxWindow* pParent = wxTheApp->GetTopWindow();
389
390 if ( pParent && pParent != this && pParent->IsShown() )
391 {
392 //
393 // Use it
394 //
395 m_parent = pParent;
396
397 }
398 }
399 DoShowModal();
400 }
401 else // end of modal dialog
402 {
403 //
404 // This will cause IsModalShowing() return FALSE and our local
405 // message loop will terminate
406 //
407 wxModalDialogs.DeleteObject(this);
408 }
409 }
410 return FALSE;
411 } // end of wxDialog::Show
412
413 //
414 // Replacement for Show(TRUE) for modal dialogs - returns return code
415 //
416 int wxDialog::ShowModal()
417 {
418 if (!IsModal())
419 {
420 SetModal(TRUE);
421 }
422 Show(TRUE);
423 return GetReturnCode();
424 } // end of wxDialog::ShowModal
425
426 void wxDialog::EndModal(
427 int nRetCode
428 )
429 {
430 SetReturnCode(nRetCode);
431 Show(FALSE);
432 } // end of wxDialog::EndModal
433
434 void wxDialog::OnApply(
435 wxCommandEvent& rEvent
436 )
437 {
438 if (Validate())
439 TransferDataFromWindow();
440 } // end of wxDialog::OnApply
441
442 // Standard buttons
443 void wxDialog::OnOK(
444 wxCommandEvent& rEvent
445 )
446 {
447 if ( Validate() && TransferDataFromWindow() )
448 {
449 EndModal(wxID_OK);
450 }
451 } // end of wxDialog::OnOK
452
453 void wxDialog::OnCancel(
454 wxCommandEvent& rEvent
455 )
456 {
457 EndModal(wxID_CANCEL);
458 } // end of wxDialog::OnCancel
459
460 void wxDialog::OnCloseWindow(
461 wxCloseEvent& rEvent
462 )
463 {
464 //
465 // We'll send a Cancel message by default,
466 // which may close the dialog.
467 // Check for looping if the Cancel event handler calls Close().
468 //
469 // Note that if a cancel button and handler aren't present in the dialog,
470 // nothing will happen when you close the dialog via the window manager, or
471 // via Close().
472 // We wouldn't want to destroy the dialog by default, since the dialog may have been
473 // created on the stack.
474 // However, this does mean that calling dialog->Close() won't delete the dialog
475 // unless the handler for wxID_CANCEL does so. So use Destroy() if you want to be
476 // sure to destroy the dialog.
477 // The default OnCancel (above) simply ends a modal dialog, and hides a modeless dialog.
478 //
479
480 //
481 // Ugh??? This is not good but until I figure out a global list it'll have to do
482 //
483 static wxList closing;
484
485 if ( closing.Member(this) )
486 return;
487
488 closing.Append(this);
489
490 wxCommandEvent vCancelEvent(wxEVT_COMMAND_BUTTON_CLICKED, wxID_CANCEL);
491
492 vCancelEvent.SetEventObject( this );
493 GetEventHandler()->ProcessEvent(vCancelEvent); // This may close the dialog
494
495 closing.DeleteObject(this);
496 } // end of wxDialog::OnCloseWindow
497
498 //
499 // Destroy the window (delayed, if a managed window)
500 //
501 bool wxDialog::Destroy()
502 {
503 wxCHECK_MSG( !wxPendingDelete.Member(this), FALSE,
504 _T("wxDialog destroyed twice") );
505 wxPendingDelete.Append(this);
506 return TRUE;
507 } // end of wxDialog::Destroy
508
509 void wxDialog::OnSysColourChanged(
510 wxSysColourChangedEvent& rEvent
511 )
512 {
513 SetBackgroundColour(wxSystemSettings::GetSystemColour(wxSYS_COLOUR_3DFACE));
514 Refresh();
515 } // end of wxDialog::OnSysColourChanged
516
517 MRESULT wxDialog::OS2WindowProc(
518 WXUINT uMessage
519 , WXWPARAM wParam
520 , WXLPARAM lParam
521 )
522 {
523 MRESULT rc = 0;
524 bool bProcessed = FALSE;
525
526 switch (uMessage)
527 {
528 case WM_CLOSE:
529 //
530 // If we can't close, tell the system that we processed the
531 // message - otherwise it would close us
532 //
533 bProcessed = !Close();
534 break;
535 }
536
537 if (!bProcessed)
538 rc = wxWindow::OS2WindowProc( uMessage
539 ,wParam
540 ,lParam
541 );
542 return rc;
543 } // end of wxDialog::OS2WindowProc
544