]> git.saurik.com Git - wxWidgets.git/blame - src/os2/dialog.cpp
better focus handling (blind fix)
[wxWidgets.git] / src / os2 / dialog.cpp
CommitLineData
0e320a79
DW
1/////////////////////////////////////////////////////////////////////////////
2// Name: dialog.cpp
3// Purpose: wxDialog class
fb46a9a6 4// Author: David Webster
0e320a79 5// Modified by:
fb46a9a6 6// Created: 10/14/99
0e320a79 7// RCS-ID: $Id$
fb46a9a6
DW
8// Copyright: (c) David Webster
9// Licence: wxWindows licence
0e320a79
DW
10/////////////////////////////////////////////////////////////////////////////
11
27476f73
DW
12// For compilers that support precompilation, includes "wx.h".
13#include "wx/wxprec.h"
0e320a79 14
27476f73 15#ifndef WX_PRECOMP
0e320a79
DW
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"
27476f73
DW
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
27476f73
DW
28#define wxDIALOG_DEFAULT_X 300
29#define wxDIALOG_DEFAULT_Y 300
0e320a79 30
c9cb56f7
DW
31#define wxDIALOG_DEFAULT_WIDTH 500
32#define wxDIALOG_DEFAULT_HEIGHT 500
33
0e320a79
DW
34// Lists to keep track of windows, so we can disable/enable them
35// for modal dialogs
27476f73
DW
36wxWindowList wxModalDialogs;
37wxWindowList wxModelessWindows; // Frames and modeless dialogs
38extern wxList WXDLLEXPORT wxPendingDelete;
0e320a79 39
27476f73
DW
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()
0e320a79 51
c9cb56f7 52void wxDialog::Init()
0e320a79 53{
c9cb56f7 54 m_pOldFocus = (wxWindow *)NULL;
27476f73 55 m_isShown = FALSE;
c9cb56f7 56 m_pWindowDisabler = (wxWindowDisabler *)NULL;
0e320a79 57 SetBackgroundColour(wxSystemSettings::GetSystemColour(wxSYS_COLOUR_3DFACE));
c9cb56f7
DW
58} // end of wxDialog::Init
59
60bool 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)
0e320a79 69{
c9cb56f7
DW
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();
27476f73 86 else
c9cb56f7
DW
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 //
27476f73 99 // All dialogs should really have this style
c9cb56f7
DW
100 //
101 m_windowStyle |= wxTAB_TRAVERSAL;
102
103 //
27476f73
DW
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)
c9cb56f7
DW
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));
27476f73 138 return TRUE;
c9cb56f7 139} // end of wxDialog::Create
0e320a79 140
c9cb56f7
DW
141void wxDialog::SetModal(
142 bool bFlag
143)
0e320a79 144{
c9cb56f7 145 if (bFlag)
27476f73
DW
146 m_windowStyle |= wxDIALOG_MODAL ;
147 else if ( m_windowStyle & wxDIALOG_MODAL )
148 m_windowStyle -= wxDIALOG_MODAL ;
149
150 wxModelessWindows.DeleteObject(this);
c9cb56f7 151 if (!bFlag)
27476f73 152 wxModelessWindows.Append(this);
c9cb56f7 153} // end of wxDialog::SetModal
0e320a79
DW
154
155wxDialog::~wxDialog()
156{
27476f73 157 m_isBeingDeleted = TRUE;
0e320a79 158 wxTopLevelWindows.DeleteObject(this);
27476f73 159 Show(FALSE);
c9cb56f7 160 if (!IsModal)
27476f73
DW
161 wxModelessWindows.DeleteObject(this);
162
c9cb56f7 163 //
0e320a79 164 // If this is the last top-level window, exit.
c9cb56f7 165 //
0e320a79
DW
166 if (wxTheApp && (wxTopLevelWindows.Number() == 0))
167 {
c9cb56f7 168 wxTheApp->SetTopWindow(NULL);
0e320a79 169
c9cb56f7
DW
170 if (wxTheApp->GetExitOnFrameDelete())
171 {
172 ::WinPostMsg(GetHwnd(), WM_QUIT, 0, 0);
173 }
0e320a79 174 }
c9cb56f7 175} // end of wxDialog::~wxDialog
0e320a79 176
c9cb56f7 177//
0e320a79 178// By default, pressing escape cancels the dialog
c9cb56f7
DW
179//
180void wxDialog::OnCharHook(
181 wxKeyEvent& rEvent
182)
0e320a79 183{
27476f73
DW
184 if (GetHWND())
185 {
c9cb56f7 186 if (rEvent.m_keyCode == WXK_ESCAPE)
27476f73 187 {
c9cb56f7 188 //
27476f73
DW
189 // Behaviour changed in 2.0: we'll send a Cancel message
190 // to the dialog instead of Close.
c9cb56f7
DW
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);
27476f73
DW
204 return;
205 }
206 }
207 // We didn't process this event.
c9cb56f7 208 rEvent.Skip();
27476f73
DW
209}
210
c9cb56f7
DW
211void wxDialog::Iconize(
212 bool WXUNUSED(bIconize)
213)
27476f73 214{
c9cb56f7 215} // end of wxDialog::Iconize
0e320a79
DW
216
217bool wxDialog::IsIconized() const
218{
0e320a79 219 return FALSE;
c9cb56f7 220} // end of wxDialog::IsIconized
0e320a79 221
c9cb56f7
DW
222void wxDialog::DoSetClientSize(
223 int nWidth
224, int nHeight
225)
27476f73 226{
c9cb56f7
DW
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
256void wxDialog::DoGetPosition(
257 int* pnX
258, int* pnY
259) const
0e320a79 260{
c9cb56f7 261 RECTL vRect;
27476f73 262
c9cb56f7
DW
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
27476f73
DW
269
270bool wxDialog::IsModal() const
271{
c9cb56f7
DW
272 return (GetWindowStyleFlag() & wxDIALOG_MODAL) != 0;
273} // end of wxDialog::IsModal
0e320a79 274
c9cb56f7 275bool wxDialog::IsModalShowing() const
0e320a79 276{
c9cb56f7
DW
277 return wxModalDialogs.Find((wxDialog *)this) != NULL; // const_cast
278} // end of wxDialog::IsModalShowing
0e320a79 279
c9cb56f7 280void wxDialog::DoShowModal()
0e320a79 281{
c9cb56f7
DW
282 wxWindow* pParent = GetParent();
283 wxWindow* pOldFocus = m_pOldFocus;
284 HWND hWndOldFocus = 0;
0e320a79 285
c9cb56f7
DW
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();
0e320a79 292
c9cb56f7
DW
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
342bool wxDialog::Show(
343 bool bShow
344)
0e320a79 345{
c9cb56f7
DW
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 }
0e320a79 359
c9cb56f7
DW
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//
0e320a79 414// Replacement for Show(TRUE) for modal dialogs - returns return code
c9cb56f7 415//
0e320a79
DW
416int wxDialog::ShowModal()
417{
c9cb56f7
DW
418 if (!IsModal())
419 {
420 SetModal(TRUE);
421 }
27476f73
DW
422 Show(TRUE);
423 return GetReturnCode();
c9cb56f7 424} // end of wxDialog::ShowModal
0e320a79 425
c9cb56f7
DW
426void wxDialog::EndModal(
427 int nRetCode
428)
0e320a79 429{
c9cb56f7 430 SetReturnCode(nRetCode);
27476f73 431 Show(FALSE);
c9cb56f7 432} // end of wxDialog::EndModal
0e320a79 433
c9cb56f7
DW
434void wxDialog::OnApply(
435 wxCommandEvent& rEvent
436)
27476f73 437{
c9cb56f7
DW
438 if (Validate())
439 TransferDataFromWindow();
440} // end of wxDialog::OnApply
441
0e320a79 442// Standard buttons
c9cb56f7
DW
443void wxDialog::OnOK(
444 wxCommandEvent& rEvent
445)
0e320a79 446{
27476f73
DW
447 if ( Validate() && TransferDataFromWindow() )
448 {
c9cb56f7 449 EndModal(wxID_OK);
27476f73 450 }
c9cb56f7 451} // end of wxDialog::OnOK
0e320a79 452
c9cb56f7
DW
453void wxDialog::OnCancel(
454 wxCommandEvent& rEvent
455)
0e320a79 456{
c9cb56f7
DW
457 EndModal(wxID_CANCEL);
458} // end of wxDialog::OnCancel
0e320a79 459
c9cb56f7
DW
460void wxDialog::OnCloseWindow(
461 wxCloseEvent& rEvent
462)
0e320a79 463{
c9cb56f7 464 //
0e320a79
DW
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().
c9cb56f7 468 //
0e320a79
DW
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.
c9cb56f7 478 //
0e320a79 479
c9cb56f7
DW
480 //
481 // Ugh??? This is not good but until I figure out a global list it'll have to do
482 //
0e320a79 483 static wxList closing;
c3d43472 484
0e320a79
DW
485 if ( closing.Member(this) )
486 return;
c3d43472 487
0e320a79 488 closing.Append(this);
c3d43472 489
c9cb56f7
DW
490 wxCommandEvent vCancelEvent(wxEVT_COMMAND_BUTTON_CLICKED, wxID_CANCEL);
491
492 vCancelEvent.SetEventObject( this );
493 GetEventHandler()->ProcessEvent(vCancelEvent); // This may close the dialog
0e320a79
DW
494
495 closing.DeleteObject(this);
c9cb56f7 496} // end of wxDialog::OnCloseWindow
0e320a79 497
c9cb56f7 498//
0e320a79 499// Destroy the window (delayed, if a managed window)
c9cb56f7 500//
0e320a79
DW
501bool wxDialog::Destroy()
502{
c9cb56f7
DW
503 wxCHECK_MSG( !wxPendingDelete.Member(this), FALSE,
504 _T("wxDialog destroyed twice") );
505 wxPendingDelete.Append(this);
27476f73 506 return TRUE;
c9cb56f7 507} // end of wxDialog::Destroy
27476f73 508
c9cb56f7
DW
509void wxDialog::OnSysColourChanged(
510 wxSysColourChangedEvent& rEvent
511)
27476f73 512{
c9cb56f7
DW
513 SetBackgroundColour(wxSystemSettings::GetSystemColour(wxSYS_COLOUR_3DFACE));
514 Refresh();
515} // end of wxDialog::OnSysColourChanged
516
517MRESULT wxDialog::OS2WindowProc(
518 WXUINT uMessage
519, WXWPARAM wParam
520, WXLPARAM lParam
521)
0e320a79 522{
c9cb56f7
DW
523 MRESULT rc = 0;
524 bool bProcessed = FALSE;
27476f73 525
c9cb56f7 526 switch (uMessage)
27476f73
DW
527 {
528 case WM_CLOSE:
c9cb56f7
DW
529 //
530 // If we can't close, tell the system that we processed the
27476f73 531 // message - otherwise it would close us
c9cb56f7
DW
532 //
533 bProcessed = !Close();
27476f73
DW
534 break;
535 }
536
c9cb56f7
DW
537 if (!bProcessed)
538 rc = wxWindow::OS2WindowProc( uMessage
539 ,wParam
540 ,lParam
541 );
27476f73 542 return rc;
c9cb56f7 543} // end of wxDialog::OS2WindowProc
27476f73 544