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