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