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