]> git.saurik.com Git - wxWidgets.git/blob - src/os2/dialog.cpp
Fix some bugs
[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 #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 EVT_CLOSE(wxDialog::OnCloseWindow)
45 END_EVENT_TABLE()
46
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
53 class wxDialogModalData
54 {
55 public:
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
68 private:
69 wxModalEventLoop m_evtLoop;
70 };
71
72 wxDEFINE_TIED_SCOPED_PTR_TYPE(wxDialogModalData);
73
74 // ============================================================================
75 // implementation
76 // ============================================================================
77
78 // ----------------------------------------------------------------------------
79 // wxDialog construction
80 // ----------------------------------------------------------------------------
81
82 void wxDialog::Init()
83 {
84 m_pOldFocus = (wxWindow *)NULL;
85 m_isShown = FALSE;
86 m_pWindowDisabler = (wxWindowDisabler *)NULL;
87 m_modalData = NULL;
88 SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE));
89 } // end of wxDialog::Init
90
91 bool 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 )
100 {
101 Init();
102 SetExtraStyle(GetExtraStyle() | wxTOPLEVEL_EX_DIALOG);
103
104 //
105 // Save focus before doing anything which can potentially change it
106 //
107 m_pOldFocus = FindFocus();
108
109 //
110 // All dialogs should really have this style
111 //
112 lStyle |= wxTAB_TRAVERSAL;
113
114 if (!wxTopLevelWindow::Create( pParent
115 ,vId
116 ,rsTitle
117 ,rPos
118 ,rSize
119 ,lStyle
120 ,rsName
121 ))
122 return FALSE;
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 void wxDialog::SetModal(
134 bool bFlag
135 )
136 {
137 if (bFlag)
138 {
139 m_windowStyle |= wxDIALOG_MODAL ;
140 wxModelessWindows.DeleteObject(this);
141 }
142 else
143 {
144 m_windowStyle &= ~wxDIALOG_MODAL ;
145 wxModelessWindows.Append(this);
146 }
147 } // end of wxDialog::SetModal
148
149 wxDialog::~wxDialog()
150 {
151 m_isBeingDeleted = TRUE;
152 Show(FALSE);
153 } // end of wxDialog::~wxDialog
154
155 //
156 // By default, pressing escape cancels the dialog
157 //
158 void wxDialog::OnCharHook(
159 wxKeyEvent& rEvent
160 )
161 {
162 if (GetHWND())
163 {
164 if (rEvent.m_keyCode == WXK_ESCAPE)
165 {
166 //
167 // Behaviour changed in 2.0: we'll send a Cancel message
168 // to the dialog instead of Close.
169 //
170 wxCommandEvent vCancelEvent( wxEVT_COMMAND_BUTTON_CLICKED
171 ,wxID_CANCEL
172 );
173
174 vCancelEvent.SetEventObject( this );
175 GetEventHandler()->ProcessEvent(vCancelEvent);
176
177 //
178 // Ensure that there is another message for this window so the
179 // ShowModal loop will exit and won't get stuck in GetMessage().
180 //
181 ::WinPostMsg(GetHwnd(), WM_NULL, 0, 0);
182 return;
183 }
184 }
185 // We didn't process this event.
186 rEvent.Skip();
187 }
188
189 // ----------------------------------------------------------------------------
190 // showing the dialogs
191 // ----------------------------------------------------------------------------
192
193 bool wxDialog::IsModal() const
194 {
195 return (GetWindowStyleFlag() & wxDIALOG_MODAL) != 0;
196 } // end of wxDialog::IsModal
197
198 bool wxDialog::IsModalShowing() const
199 {
200 return m_modalData != NULL; // const_cast
201 } // end of wxDialog::IsModalShowing
202
203 void wxDialog::DoShowModal()
204 {
205 wxWindow* pParent = GetParent();
206 wxWindow* pOldFocus = m_pOldFocus;
207 HWND hWndOldFocus = 0;
208
209 wxCHECK_RET( !IsModalShowing(), _T("DoShowModal() called twice") );
210 wxCHECK_RET( IsModal(), _T("can't DoShowModal() modeless dialog") );
211
212 if (pOldFocus)
213 hWndOldFocus = (HWND)pOldFocus->GetHWND();
214
215 //
216 // Remember where the focus was
217 //
218 if (!pOldFocus)
219 {
220 pOldFocus = pParent;
221 if (pParent)
222 hWndOldFocus = GetHwndOf(pParent);
223 }
224
225 //
226 // Disable all other app windows
227 //
228 wxASSERT_MSG(!m_pWindowDisabler, _T("disabling windows twice?"));
229
230 //
231 // Before entering the modal loop, reset the "is in OnIdle()" flag (see
232 // comment in app.cpp)
233 //
234 extern bool gbInOnIdle;
235 bool bWasInOnIdle = gbInOnIdle;
236
237 gbInOnIdle = FALSE;
238
239 // enter the modal loop
240 {
241 wxDialogModalDataTiedPtr modalData(&m_modalData,
242 new wxDialogModalData(this));
243 modalData->RunLoop();
244 }
245 gbInOnIdle = bWasInOnIdle;
246
247 //
248 // and restore focus
249 // Note that this code MUST NOT access the dialog object's data
250 // in case the object has been deleted (which will be the case
251 // for a modal dialog that has been destroyed before calling EndModal).
252 //
253 if (pOldFocus && (pOldFocus != this) && ::WinIsWindow(vHabmain, hWndOldFocus))
254 {
255 //
256 // This is likely to prove that the object still exists
257 //
258 if (wxFindWinFromHandle((WXHWND) hWndOldFocus) == pOldFocus)
259 pOldFocus->SetFocus();
260 }
261 } // end of wxDialog::DoShowModal
262
263 bool wxDialog::Show(
264 bool bShow
265 )
266 {
267 if (!bShow)
268 {
269 //
270 // If we had disabled other app windows, reenable them back now because
271 // if they stay disabled Windows will activate another window (one
272 // which is enabled, anyhow) and we will lose activation. We really don't
273 // do this in OS/2 since PM does this for us.
274 //
275 if (m_pWindowDisabler)
276 {
277 delete m_pWindowDisabler;
278 m_pWindowDisabler = NULL;
279 }
280 if ( m_modalData )
281 m_modalData->ExitLoop();
282 }
283
284 //
285 // ShowModal() may be called for already shown dialog
286 //
287 if (!wxDialogBase::Show(bShow) && !(bShow && IsModal()))
288 {
289 //
290 // Nothing to do
291 //
292 return FALSE;
293 }
294
295 if (bShow)
296 {
297 // dialogs don't get WM_SIZE message after creation unlike most (all?)
298 // other windows and so could start their life non laid out correctly
299 // if we didn't call Layout() from here
300 //
301 // NB: normally we should call it just the first time but doing it
302 // every time is simpler than keeping a flag
303 // Layout();
304
305 //
306 // Usually will result in TransferDataToWindow() being called
307 //
308 InitDialog();
309 }
310
311 if (GetTitle().c_str())
312 ::WinSetWindowText((HWND)GetHwnd(), GetTitle().c_str());
313 if (IsModal())
314 {
315 if (bShow)
316 {
317 //
318 // Modal dialog needs a parent window, so try to find one
319 //
320 if (!GetParent())
321 {
322 wxWindow* pParent = wxTheApp->GetTopWindow();
323
324 if ( pParent && pParent != this && pParent->IsShown() )
325 {
326 //
327 // Use it
328 //
329 m_parent = pParent;
330
331 }
332 }
333 DoShowModal();
334 }
335 }
336 return TRUE;
337 } // end of wxDialog::Show
338
339 //
340 // Replacement for Show(TRUE) for modal dialogs - returns return code
341 //
342 int wxDialog::ShowModal()
343 {
344 if (!IsModal())
345 {
346 SetModal(TRUE);
347 }
348 Show(TRUE);
349 return GetReturnCode();
350 } // end of wxDialog::ShowModal
351
352 void wxDialog::EndModal(
353 int nRetCode
354 )
355 {
356 SetReturnCode(nRetCode);
357 Show(FALSE);
358 } // end of wxDialog::EndModal
359
360 // ----------------------------------------------------------------------------
361 // wxWin event handlers
362 // ----------------------------------------------------------------------------
363
364 void wxDialog::OnApply(
365 wxCommandEvent& rEvent
366 )
367 {
368 if (Validate())
369 TransferDataFromWindow();
370 } // end of wxDialog::OnApply
371
372 // Standard buttons
373 void wxDialog::OnOK(
374 wxCommandEvent& rEvent
375 )
376 {
377 if ( Validate() && TransferDataFromWindow() )
378 {
379 EndModal(wxID_OK);
380 }
381 } // end of wxDialog::OnOK
382
383 void wxDialog::OnCancel(
384 wxCommandEvent& rEvent
385 )
386 {
387 EndModal(wxID_CANCEL);
388 } // end of wxDialog::OnCancel
389
390 void wxDialog::OnCloseWindow(
391 wxCloseEvent& rEvent
392 )
393 {
394 //
395 // We'll send a Cancel message by default,
396 // 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(
429 wxSysColourChangedEvent& rEvent
430 )
431 {
432 SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE));
433 Refresh();
434 } // end of wxDialog::OnSysColourChanged
435
436 MRESULT wxDialog::OS2WindowProc(
437 WXUINT uMessage
438 , WXWPARAM wParam
439 , WXLPARAM lParam
440 )
441 {
442 MRESULT rc = 0;
443 bool bProcessed = FALSE;
444
445 switch (uMessage)
446 {
447 case WM_CLOSE:
448 //
449 // If we can't close, tell the system that we processed the
450 // message - otherwise it would close us
451 //
452 bProcessed = !Close();
453 break;
454 }
455
456 if (!bProcessed)
457 rc = wxWindow::OS2WindowProc( uMessage
458 ,wParam
459 ,lParam
460 );
461 return rc;
462 } // end of wxDialog::OS2WindowProc
463