1 ///////////////////////////////////////////////////////////////////////////// 
   2 // Name:        src/msw/dialog.cpp 
   3 // Purpose:     wxDialog class 
   4 // Author:      Julian Smart 
   8 // Copyright:   (c) Julian Smart 
   9 // Licence:     wxWindows licence 
  10 ///////////////////////////////////////////////////////////////////////////// 
  12 // ============================================================================ 
  14 // ============================================================================ 
  16 // ---------------------------------------------------------------------------- 
  18 // ---------------------------------------------------------------------------- 
  20 // For compilers that support precompilation, includes "wx.h". 
  21 #include "wx/wxprec.h" 
  27 #include "wx/dialog.h" 
  30     #include "wx/msw/wrapcdlg.h" 
  34     #include "wx/button.h" 
  35     #include "wx/settings.h" 
  38     #include "wx/toolbar.h" 
  41 #include "wx/msw/private.h" 
  42 #include "wx/evtloop.h" 
  43 #include "wx/scopedptr.h" 
  45 #if defined(__SMARTPHONE__) && defined(__WXWINCE__) 
  46     #include "wx/msw/wince/resources.h" 
  47 #endif // __SMARTPHONE__ && __WXWINCE__ 
  49 // ---------------------------------------------------------------------------- 
  51 // ---------------------------------------------------------------------------- 
  53 #if wxUSE_EXTENDED_RTTI 
  54 WX_DEFINE_FLAGS( wxDialogStyle 
) 
  56 wxBEGIN_FLAGS( wxDialogStyle 
) 
  57     // new style border flags, we put them first to 
  58     // use them for streaming out 
  59     wxFLAGS_MEMBER(wxBORDER_SIMPLE
) 
  60     wxFLAGS_MEMBER(wxBORDER_SUNKEN
) 
  61     wxFLAGS_MEMBER(wxBORDER_DOUBLE
) 
  62     wxFLAGS_MEMBER(wxBORDER_RAISED
) 
  63     wxFLAGS_MEMBER(wxBORDER_STATIC
) 
  64     wxFLAGS_MEMBER(wxBORDER_NONE
) 
  66     // old style border flags 
  67     wxFLAGS_MEMBER(wxSIMPLE_BORDER
) 
  68     wxFLAGS_MEMBER(wxSUNKEN_BORDER
) 
  69     wxFLAGS_MEMBER(wxDOUBLE_BORDER
) 
  70     wxFLAGS_MEMBER(wxRAISED_BORDER
) 
  71     wxFLAGS_MEMBER(wxSTATIC_BORDER
) 
  72     wxFLAGS_MEMBER(wxNO_BORDER
) 
  74     // standard window styles 
  75     wxFLAGS_MEMBER(wxTAB_TRAVERSAL
) 
  76     wxFLAGS_MEMBER(wxCLIP_CHILDREN
) 
  79     wxFLAGS_MEMBER(wxWS_EX_VALIDATE_RECURSIVELY
) 
  80     wxFLAGS_MEMBER(wxSTAY_ON_TOP
) 
  81     wxFLAGS_MEMBER(wxCAPTION
) 
  82 #if WXWIN_COMPATIBILITY_2_6 
  83     wxFLAGS_MEMBER(wxTHICK_FRAME
) 
  84 #endif // WXWIN_COMPATIBILITY_2_6 
  85     wxFLAGS_MEMBER(wxSYSTEM_MENU
) 
  86     wxFLAGS_MEMBER(wxRESIZE_BORDER
) 
  87 #if WXWIN_COMPATIBILITY_2_6 
  88     wxFLAGS_MEMBER(wxRESIZE_BOX
) 
  89 #endif // WXWIN_COMPATIBILITY_2_6 
  90     wxFLAGS_MEMBER(wxCLOSE_BOX
) 
  91     wxFLAGS_MEMBER(wxMAXIMIZE_BOX
) 
  92     wxFLAGS_MEMBER(wxMINIMIZE_BOX
) 
  93 wxEND_FLAGS( wxDialogStyle 
) 
  95 IMPLEMENT_DYNAMIC_CLASS_XTI(wxDialog
, wxTopLevelWindow
,"wx/dialog.h") 
  97 wxBEGIN_PROPERTIES_TABLE(wxDialog
) 
  98     wxPROPERTY( Title
, wxString
, SetTitle
, GetTitle
, wxString() , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) 
  99     wxPROPERTY_FLAGS( WindowStyle 
, wxDialogStyle 
, long , SetWindowStyleFlag 
, GetWindowStyleFlag 
, EMPTY_MACROVALUE 
, 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // style 
 100 wxEND_PROPERTIES_TABLE() 
 102 wxBEGIN_HANDLERS_TABLE(wxDialog
) 
 103 wxEND_HANDLERS_TABLE() 
 105 wxCONSTRUCTOR_6( wxDialog 
, wxWindow
* , Parent 
, wxWindowID 
, Id 
, wxString 
, Title 
, wxPoint 
, Position 
, wxSize 
, Size 
, long , WindowStyle
) 
 108 IMPLEMENT_DYNAMIC_CLASS(wxDialog
, wxTopLevelWindow
) 
 111 // ---------------------------------------------------------------------------- 
 113 // ---------------------------------------------------------------------------- 
 115 // this is simply a container for any data we need to implement modality which 
 116 // allows us to avoid changing wxDialog each time the implementation changes 
 117 class wxDialogModalData
 
 120     wxDialogModalData(wxDialog 
*dialog
) : m_evtLoop(dialog
) { } 
 133     wxModalEventLoop m_evtLoop
; 
 136 wxDEFINE_TIED_SCOPED_PTR_TYPE(wxDialogModalData
) 
 138 // ============================================================================ 
 140 // ============================================================================ 
 142 // ---------------------------------------------------------------------------- 
 143 // wxDialog construction 
 144 // ---------------------------------------------------------------------------- 
 146 void wxDialog::Init() 
 150 #if wxUSE_TOOLBAR && defined(__POCKETPC__) 
 151     m_dialogToolBar 
= NULL
; 
 153 #if wxUSE_DIALOG_SIZEGRIP 
 155 #endif // wxUSE_DIALOG_SIZEGRIP 
 158 bool wxDialog::Create(wxWindow 
*parent
, 
 160                       const wxString
& title
, 
 164                       const wxString
& name
) 
 166     SetExtraStyle(GetExtraStyle() | wxTOPLEVEL_EX_DIALOG
); 
 168     // All dialogs should really have this style 
 169     style 
|= wxTAB_TRAVERSAL
; 
 171     if ( !wxTopLevelWindow::Create(parent
, id
, title
, pos
, size
, style
, name
) ) 
 175         SetFont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT
)); 
 177 #if defined(__SMARTPHONE__) && defined(__WXWINCE__) 
 178     SetLeftMenu(wxID_OK
, _("OK")); 
 180 #if wxUSE_TOOLBAR && defined(__POCKETPC__) 
 184 #if wxUSE_DIALOG_SIZEGRIP 
 185     if ( HasFlag(wxRESIZE_BORDER
) ) 
 189         Connect(wxEVT_CREATE
, 
 190                 wxWindowCreateEventHandler(wxDialog::OnWindowCreate
)); 
 192 #endif // wxUSE_DIALOG_SIZEGRIP 
 197 wxDialog::~wxDialog() 
 199     // this will also reenable all the other windows for a modal dialog 
 202 #if wxUSE_DIALOG_SIZEGRIP 
 204 #endif // wxUSE_DIALOG_SIZEGRIP 
 207 // ---------------------------------------------------------------------------- 
 208 // showing the dialogs 
 209 // ---------------------------------------------------------------------------- 
 211 wxWindow 
*wxDialog::FindSuitableParent() const 
 213     // first try to use the currently active window 
 214     HWND hwndFg 
= ::GetForegroundWindow(); 
 215     wxWindow 
*parent 
= hwndFg 
? wxFindWinFromHandle((WXHWND
)hwndFg
) 
 219         // next try the main app window 
 220         parent 
= wxTheApp
->GetTopWindow(); 
 223     // finally, check if the parent we found is really suitable 
 224     if ( !parent 
|| parent 
== (wxWindow 
*)this || !parent
->IsShown() ) 
 226         // don't use this one 
 233 bool wxDialog::Show(bool show
) 
 235     if ( show 
== IsShown() ) 
 238     if ( !show 
&& 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(); 
 250         if (CanDoLayoutAdaptation()) 
 251             DoLayoutAdaptation(); 
 253         // this usually will result in TransferDataToWindow() being called 
 254         // which will change the controls values so do it before showing as 
 255         // otherwise we could have some flicker 
 259     wxDialogBase::Show(show
); 
 263         // dialogs don't get WM_SIZE message from ::ShowWindow() for some 
 264         // reason so generate it ourselves for consistency with frames and 
 265         // dialogs in other ports 
 267         // NB: normally we should call it just the first time but doing it 
 268         //     every time is simpler than keeping a flag 
 269         const wxSize size 
= GetClientSize(); 
 270         ::SendMessage(GetHwnd(), WM_SIZE
, 
 271                       SIZE_RESTORED
, MAKELPARAM(size
.x
, size
.y
)); 
 277 void wxDialog::Raise() 
 279     ::SetForegroundWindow(GetHwnd()); 
 282 // show dialog modally 
 283 int wxDialog::ShowModal() 
 285     wxASSERT_MSG( !IsModal(), _T("ShowModal() can't be called twice") ); 
 289     // EndModal may have been called from InitDialog handler (called from 
 290     // inside Show()) and hidden the dialog back again 
 293         // enter and run the modal loop 
 294         wxDialogModalDataTiedPtr 
modalData(&m_modalData
, 
 295                                            new wxDialogModalData(this)); 
 296         modalData
->RunLoop(); 
 299     return GetReturnCode(); 
 302 void wxDialog::EndModal(int retCode
) 
 304     wxASSERT_MSG( IsModal(), _T("EndModal() called for non modal dialog") ); 
 306     SetReturnCode(retCode
); 
 311 // ---------------------------------------------------------------------------- 
 312 // wxDialog gripper handling 
 313 // ---------------------------------------------------------------------------- 
 315 #if wxUSE_DIALOG_SIZEGRIP 
 317 void wxDialog::SetWindowStyleFlag(long style
) 
 319     wxDialogBase::SetWindowStyleFlag(style
); 
 321     if ( HasFlag(wxRESIZE_BORDER
) ) 
 327 void wxDialog::CreateGripper() 
 331         // just create it here, it will be positioned and shown later 
 332         m_hGripper 
= (WXHWND
)::CreateWindow
 
 340                                     SBS_SIZEBOXBOTTOMRIGHTALIGN
, 
 350 void wxDialog::DestroyGripper() 
 354         // we used to have trouble with gripper appearing on top (and hence 
 355         // overdrawing) the other, real, dialog children -- check that this 
 356         // isn't the case automatically (but notice that this could be false if 
 357         // we're not shown at all as in this case ResizeGripper() might not 
 358         // have been called yet) 
 359         wxASSERT_MSG( !IsShown() || 
 360                       ::GetWindow((HWND
)m_hGripper
, GW_HWNDNEXT
) == 0, 
 361             _T("Bug in wxWidgets: gripper should be at the bottom of Z-order") ); 
 362         ::DestroyWindow((HWND
) m_hGripper
); 
 367 void wxDialog::ShowGripper(bool show
) 
 369     wxASSERT_MSG( m_hGripper
, _T("shouldn't be called if we have no gripper") ); 
 374     ::ShowWindow((HWND
)m_hGripper
, show 
? SW_SHOW 
: SW_HIDE
); 
 377 void wxDialog::ResizeGripper() 
 379     wxASSERT_MSG( m_hGripper
, _T("shouldn't be called if we have no gripper") ); 
 381     HWND hwndGripper 
= (HWND
)m_hGripper
; 
 383     const wxRect rectGripper 
= wxRectFromRECT(wxGetWindowRect(hwndGripper
)); 
 384     const wxSize size 
= GetClientSize() - rectGripper
.GetSize(); 
 386     ::SetWindowPos(hwndGripper
, HWND_BOTTOM
, 
 388                    rectGripper
.width
, rectGripper
.height
, 
 392 void wxDialog::OnWindowCreate(wxWindowCreateEvent
& event
) 
 394     if ( m_hGripper 
&& IsShown() && 
 395             event
.GetWindow() && event
.GetWindow()->GetParent() == this ) 
 397         // Put gripper below the newly created child window 
 398         ::SetWindowPos((HWND
)m_hGripper
, HWND_BOTTOM
, 0, 0, 0, 0, 
 399                        SWP_NOSIZE 
| SWP_NOMOVE 
| SWP_NOACTIVATE
); 
 405 #endif // wxUSE_DIALOG_SIZEGRIP 
 407 // ---------------------------------------------------------------------------- 
 408 // wxWin event handlers 
 409 // ---------------------------------------------------------------------------- 
 412 // Responds to the OK button in a PocketPC titlebar. This 
 413 // can be overridden, or you can change the id used for 
 414 // sending the event, by calling SetAffirmativeId. 
 415 bool wxDialog::DoOK() 
 417     const int idOk 
= GetAffirmativeId(); 
 418     if ( EmulateButtonClickIfPresent(idOk
) ) 
 421     wxCommandEvent 
event(wxEVT_COMMAND_BUTTON_CLICKED
, GetAffirmativeId()); 
 422     event
.SetEventObject(this); 
 424     return HandleWindowEvent(event
); 
 426 #endif // __POCKETPC__ 
 428 #if wxUSE_TOOLBAR && defined(__POCKETPC__) 
 429 // create main toolbar by calling OnCreateToolBar() 
 430 wxToolBar
* wxDialog::CreateToolBar(long style
, wxWindowID winid
, const wxString
& name
) 
 432     m_dialogToolBar 
= OnCreateToolBar(style
, winid
, name
); 
 434     return m_dialogToolBar
; 
 437 // return a new toolbar 
 438 wxToolBar 
*wxDialog::OnCreateToolBar(long style
, 
 440                                        const wxString
& name
) 
 442     return new wxToolMenuBar(this, winid
, 
 443                          wxDefaultPosition
, wxDefaultSize
, 
 448 // --------------------------------------------------------------------------- 
 449 // dialog Windows messages processing 
 450 // --------------------------------------------------------------------------- 
 452 WXLRESULT 
wxDialog::MSWWindowProc(WXUINT message
, WXWPARAM wParam
, WXLPARAM lParam
) 
 455     bool processed 
= false; 
 460         // react to pressing the OK button in the title 
 463             switch ( LOWORD(wParam
) ) 
 469                         processed 
= !Close(); 
 471 #ifdef __SMARTPHONE__ 
 474                     processed 
= HandleCommand( LOWORD(wParam
) , 0 , NULL 
); 
 476 #endif // __SMARTPHONE__ 
 482             // if we can't close, tell the system that we processed the 
 483             // message - otherwise it would close us 
 484             processed 
= !Close(); 
 488 #if wxUSE_DIALOG_SIZEGRIP 
 501 #endif // wxUSE_DIALOG_SIZEGRIP 
 503             // the Windows dialogs unfortunately are not meant to be resizeable 
 504             // at all and their standard class doesn't include CS_[VH]REDRAW 
 505             // styles which means that the window is not refreshed properly 
 506             // after the resize and no amount of WS_CLIPCHILDREN/SIBLINGS can 
 507             // help with it - so we have to refresh it manually which certainly 
 508             // creates flicker but at least doesn't show garbage on the screen 
 509             rc 
= wxWindow::MSWWindowProc(message
, wParam
, lParam
); 
 511             if ( HasFlag(wxFULL_REPAINT_ON_RESIZE
) ) 
 513                 ::InvalidateRect(GetHwnd(), NULL
, false /* erase bg */); 
 517 #ifndef __WXMICROWIN__ 
 519             // we want to override the busy cursor for modal dialogs: 
 520             // typically, wxBeginBusyCursor() is called and then a modal dialog 
 521             // is shown, but the modal dialog shouldn't have hourglass cursor 
 522             if ( IsModal() && wxIsBusy() ) 
 524                 // set our cursor for all windows (but see below) 
 525                 wxCursor cursor 
= m_cursor
; 
 527                     cursor 
= wxCURSOR_ARROW
; 
 529                 ::SetCursor(GetHcursorOf(cursor
)); 
 531                 // in any case, stop here and don't let wxWindow process this 
 532                 // message (it would set the busy cursor) 
 535                 // but return false to tell the child window (if the event 
 536                 // comes from one of them and not from ourselves) that it can 
 537                 // set its own cursor if it has one: thus, standard controls 
 538                 // (e.g. text ctrl) still have correct cursors in a dialog 
 539                 // invoked while wxIsBusy() 
 543 #endif // __WXMICROWIN__ 
 547         rc 
= wxWindow::MSWWindowProc(message
, wParam
, lParam
);