1 ///////////////////////////////////////////////////////////////////////////// 
   3 // Purpose:     wxDialog class 
   4 // Author:      David Webster 
   8 // Copyright:   (c) David Webster 
   9 // Licence:     wxWindows licence 
  10 ///////////////////////////////////////////////////////////////////////////// 
  12 // For compilers that support precompilation, includes "wx.h". 
  13 #include "wx/wxprec.h" 
  16 #include "wx/dialog.h" 
  20 #include "wx/settings.h" 
  25 #include "wx/os2/private.h" 
  27 #include "wx/evtloop.h" 
  28 #include "wx/ptr_scpd.h" 
  30 #define wxDIALOG_DEFAULT_X 300 
  31 #define wxDIALOG_DEFAULT_Y 300 
  33 #define wxDIALOG_DEFAULT_WIDTH 500 
  34 #define wxDIALOG_DEFAULT_HEIGHT 500 
  36 IMPLEMENT_DYNAMIC_CLASS(wxDialog
, wxTopLevelWindow
) 
  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
) 
  45     EVT_CLOSE(wxDialog::OnCloseWindow
) 
  48 // ---------------------------------------------------------------------------- 
  50 // ---------------------------------------------------------------------------- 
  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
 
  57     wxDialogModalData(wxDialog 
*dialog
) : m_evtLoop(dialog
) { } 
  70     wxModalEventLoop m_evtLoop
; 
  73 wxDEFINE_TIED_SCOPED_PTR_TYPE(wxDialogModalData
); 
  75 // ============================================================================ 
  77 // ============================================================================ 
  79 // ---------------------------------------------------------------------------- 
  80 // wxDialog construction 
  81 // ---------------------------------------------------------------------------- 
  85     m_pOldFocus 
= (wxWindow 
*)NULL
; 
  87     m_pWindowDisabler 
= (wxWindowDisabler 
*)NULL
; 
  89     SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE
)); 
  90 } // end of wxDialog::Init 
  92 bool wxDialog::Create( 
  95 , const wxString
&                   rsTitle
 
  99 , const wxString
&                   rsName
 
 103     SetExtraStyle(GetExtraStyle() | wxTOPLEVEL_EX_DIALOG
); 
 106     // Save focus before doing anything which can potentially change it 
 108     m_pOldFocus 
= FindFocus(); 
 111     // All dialogs should really have this style 
 113     lStyle 
|= wxTAB_TRAVERSAL
; 
 115     if (!wxTopLevelWindow::Create( pParent
 
 124     SetFont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT
)); 
 127     // Must defer setting the title until after dialog is created and sized 
 129     if (!rsTitle
.IsNull()) 
 132 } // end of wxDialog::Create 
 135 wxDialog::wxDialog(wxWindow 
*parent
, 
 136                    const wxString
& title
, 
 137                    bool WXUNUSED(modal
), 
 143                    const wxString
& name
) 
 147     Create(parent
, wxID_ANY
, title
, wxPoint(x
, y
), wxSize(w
, h
), style
, name
); 
 150 void wxDialog::SetModal( 
 154     // nothing to do, obsolete method 
 155 } // end of wxDialog::SetModal 
 157 wxDialog::~wxDialog() 
 159     m_isBeingDeleted 
= TRUE
; 
 161     // this will also reenable all the other windows for a modal dialog 
 163 } // end of wxDialog::~wxDialog 
 166 // By default, pressing escape cancels the dialog 
 168 void wxDialog::OnCharHook( 
 174         if (rEvent
.m_keyCode 
== WXK_ESCAPE
) 
 177             // Behaviour changed in 2.0: we'll send a Cancel message 
 178             // to the dialog instead of Close. 
 180             wxCommandEvent          
vCancelEvent( wxEVT_COMMAND_BUTTON_CLICKED
 
 184             vCancelEvent
.SetEventObject( this ); 
 185             GetEventHandler()->ProcessEvent(vCancelEvent
); 
 188             // Ensure that there is another message for this window so the 
 189             // ShowModal loop will exit and won't get stuck in GetMessage(). 
 191             ::WinPostMsg(GetHwnd(), WM_NULL
, 0, 0); 
 195     // We didn't process this event. 
 199 // ---------------------------------------------------------------------------- 
 200 // showing the dialogs 
 201 // ---------------------------------------------------------------------------- 
 203 bool wxDialog::IsModalShowing() const 
 206 } // end of wxDialog::IsModalShowing 
 209 wxWindow 
*wxDialog::FindSuitableParent() const 
 211     // first try to use the currently active window 
 212     HWND hwndFg 
= ::WinQueryActiveWindow(HWND_DESKTOP
); 
 213     wxWindow 
*parent 
= hwndFg 
? wxFindWinFromHandle((WXHWND
)hwndFg
) 
 217         // next try the main app window 
 218         parent 
= wxTheApp
->GetTopWindow(); 
 221     // finally, check if the parent we found is really suitable 
 222     if ( !parent 
|| parent 
== (wxWindow 
*)this || !parent
->IsShown() ) 
 224         // don't use this one 
 235     if ( bShow 
== IsShown() ) 
 238     if (!bShow 
&& m_modalData 
) 
 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(); 
 247         if (m_pWindowDisabler
) 
 249             delete m_pWindowDisabler
; 
 250             m_pWindowDisabler 
= NULL
; 
 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 
 263     wxDialogBase::Show(bShow
); 
 265     if (GetTitle().c_str()) 
 266         ::WinSetWindowText((HWND
)GetHwnd(), GetTitle().c_str()); 
 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 
 274         // NB: normally we should call it just the first time but doing it 
 275         //     every time is simpler than keeping a flag 
 280 } // end of wxDialog::Show 
 283 // Replacement for Show(TRUE) for modal dialogs - returns return code 
 285 int wxDialog::ShowModal() 
 287     wxASSERT_MSG( !IsModal(), _T("wxDialog::ShowModal() reentered?") ); 
 289     m_endModalCalled 
= false; 
 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 
 296     if ( !m_endModalCalled 
) 
 298         // modal dialog needs a parent window, so try to find one 
 299         wxWindow 
*parent 
= GetParent(); 
 302             parent 
= FindSuitableParent(); 
 305         // remember where the focus was 
 306         wxWindow 
*oldFocus 
= m_pOldFocus
; 
 309             // VZ: do we really want to do this? 
 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
; 
 320         // Before entering the modal loop, reset the "is in OnIdle()" flag (see 
 321         // comment in app.cpp) 
 323         extern bool                     gbInOnIdle
; 
 324         bool                            bWasInOnIdle 
= gbInOnIdle
; 
 328         // enter and run the modal loop 
 330             wxDialogModalDataTiedPtr 
modalData(&m_modalData
, 
 331                                                new wxDialogModalData(this)); 
 332             modalData
->RunLoop(); 
 334         gbInOnIdle 
= bWasInOnIdle
; 
 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
)) 
 342             // This is likely to prove that the object still exists 
 343             if (wxFindWinFromHandle((WXHWND
) hwndOldFocus
) == oldFocus
) 
 344                 oldFocus
->SetFocus(); 
 348     return GetReturnCode(); 
 349 } // end of wxDialog::ShowModal 
 351 void wxDialog::EndModal( 
 355     wxASSERT_MSG( IsModal(), _T("EndModal() called for non modal dialog") ); 
 357     m_endModalCalled 
= true; 
 358     SetReturnCode(nRetCode
); 
 361 } // end of wxDialog::EndModal 
 363 void wxDialog::EndDialog(int rc
) 
 371 // ---------------------------------------------------------------------------- 
 372 // wxWin event handlers 
 373 // ---------------------------------------------------------------------------- 
 375 void wxDialog::OnApply( 
 376   wxCommandEvent
&                   rEvent
 
 380         TransferDataFromWindow(); 
 381 } // end of wxDialog::OnApply 
 385   wxCommandEvent
&                   rEvent
 
 388     if ( Validate() && TransferDataFromWindow() ) 
 392 } // end of wxDialog::OnOK 
 394 void wxDialog::OnCancel( 
 395   wxCommandEvent
&                   rEvent
 
 398     EndDialog(wxID_CANCEL
); 
 399 } // end of wxDialog::OnCancel 
 401 void wxDialog::OnCloseWindow( 
 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(). 
 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 
 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. 
 421     // Ugh???  This is not good but until I figure out a global list it'll have to do 
 423     static wxList closing
; 
 425     if ( closing
.Member(this) ) 
 428     closing
.Append(this); 
 430     wxCommandEvent                  
vCancelEvent(wxEVT_COMMAND_BUTTON_CLICKED
, wxID_CANCEL
); 
 432     vCancelEvent
.SetEventObject( this ); 
 433     GetEventHandler()->ProcessEvent(vCancelEvent
); // This may close the dialog 
 435     closing
.DeleteObject(this); 
 436 } // end of wxDialog::OnCloseWindow 
 438 void wxDialog::OnSysColourChanged( 
 439   wxSysColourChangedEvent
&          rEvent
 
 442     SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE
)); 
 444 } // end of wxDialog::OnSysColourChanged 
 446 MRESULT 
wxDialog::OS2WindowProc( 
 453     bool                            bProcessed 
= FALSE
; 
 459             // If we can't close, tell the system that we processed the 
 460             // message - otherwise it would close us 
 462             bProcessed 
= !Close(); 
 467         rc 
= wxWindow::OS2WindowProc( uMessage
 
 472 } // end of wxDialog::OS2WindowProc