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