1 /////////////////////////////////////////////////////////////////////////////
3 // Purpose: wxDialog class
4 // Author: Julian Smart
8 // Copyright: (c) Julian Smart and Markus Holzem
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
13 #pragma implementation "dialog.h"
16 // For compilers that support precompilation, includes "wx.h".
17 #include "wx/wxprec.h"
24 #include "wx/dialog.h"
28 #include "wx/settings.h"
31 #include "wx/msw/private.h"
33 #if USE_COMMON_DIALOGS
37 #define wxDIALOG_DEFAULT_X 300
38 #define wxDIALOG_DEFAULT_Y 300
40 // Lists to keep track of windows, so we can disable/enable them
42 wxList wxModalDialogs
;
43 wxList wxModelessWindows
; // Frames and modeless dialogs
44 extern wxList wxPendingDelete
;
46 #if !USE_SHARED_LIBRARY
47 IMPLEMENT_DYNAMIC_CLASS(wxDialog
, wxPanel
)
49 BEGIN_EVENT_TABLE(wxDialog
, wxPanel
)
50 EVT_BUTTON(wxID_OK
, wxDialog::OnOK
)
51 EVT_BUTTON(wxID_APPLY
, wxDialog::OnApply
)
52 EVT_BUTTON(wxID_CANCEL
, wxDialog::OnCancel
)
53 EVT_CHAR_HOOK(wxDialog::OnCharHook
)
54 EVT_SYS_COLOUR_CHANGED(wxDialog::OnSysColourChanged
)
55 EVT_CLOSE(wxDialog::OnCloseWindow
)
60 long wxDialog::MSWDefWindowProc(WXUINT nMsg
, WXWPARAM wParam
, WXLPARAM lParam
)
62 return ::CallWindowProc(CASTWNDPROC m_oldWndProc
, (HWND
) GetHWND(), (UINT
) nMsg
, (WPARAM
) wParam
, (LPARAM
) lParam
);
65 bool wxDialog::MSWProcessMessage(WXMSG
* pMsg
)
67 return (::IsDialogMessage((HWND
) GetHWND(), (MSG
*)pMsg
) != 0);
70 bool wxDialog::MSWOnClose(void)
75 wxDialog::wxDialog(void)
78 m_modalShowing
= FALSE
;
80 SetBackgroundColour(wxSystemSettings::GetSystemColour(wxSYS_COLOUR_3DFACE
));
81 SetDefaultBackgroundColour(wxSystemSettings::GetSystemColour(wxSYS_COLOUR_3DFACE
));
84 bool wxDialog::Create(wxWindow
*parent
, wxWindowID id
,
85 const wxString
& title
,
91 SetBackgroundColour(wxSystemSettings::GetSystemColour(wxSYS_COLOUR_3DFACE
));
92 SetDefaultBackgroundColour(wxSystemSettings::GetSystemColour(wxSYS_COLOUR_3DFACE
));
96 wxTopLevelWindows
.Append(this);
98 // windowFont = wxTheFontList->FindOrCreateFont(11, wxSWISS, wxNORMAL, wxNORMAL);
100 if (parent
) parent
->AddChild(this);
103 m_windowId
= (int)NewControlId();
112 if (x
< 0) x
= wxDIALOG_DEFAULT_X
;
113 if (y
< 0) y
= wxDIALOG_DEFAULT_Y
;
115 m_windowStyle
= style
;
118 m_modalShowing
= FALSE
;
125 WXDWORD extendedStyle
= MakeExtendedStyle(m_windowStyle
);
126 if (m_windowStyle
& wxSTAY_ON_TOP
)
127 extendedStyle
|= WS_EX_TOPMOST
;
129 // Allows creation of dialogs with & without captions under MSWindows
130 if(style
& wxCAPTION
){
131 MSWCreate(m_windowId
, (wxWindow
*)parent
, NULL
, this, NULL
, x
, y
, width
, height
, 0, "wxCaptionDialog",
135 MSWCreate(m_windowId
, (wxWindow
*)parent
, NULL
, this, NULL
, x
, y
, width
, height
, 0, "wxNoCaptionDialog",
139 SubclassWin(GetHWND());
141 SetWindowText((HWND
) GetHWND(), (const char *)title
);
142 SetFont(wxSystemSettings::GetSystemFont(wxSYS_DEFAULT_GUI_FONT
));
147 void wxDialog::SetModal(bool flag
)
150 m_windowStyle
|= wxDIALOG_MODAL
;
152 if ( m_windowStyle
& wxDIALOG_MODAL
)
153 m_windowStyle
-= wxDIALOG_MODAL
;
155 wxModelessWindows
.DeleteObject(this);
157 wxModelessWindows
.Append(this);
160 wxDialog::~wxDialog()
162 m_isBeingDeleted
= TRUE
;
164 wxTopLevelWindows
.DeleteObject(this);
169 // For some reason, wxWindows can activate another task altogether
170 // when a frame is destroyed after a modal dialog has been invoked.
171 // Try to bring the parent to the top.
172 // dfgg: I moved this following line from end of function -
173 // must not call if another window is on top!!
174 // This can often happen with Close() and delayed deleting
175 if (GetParent() && GetParent()->GetHWND())
176 ::BringWindowToTop((HWND
) GetParent()->GetHWND());
179 m_modalShowing
= FALSE
;
181 ShowWindow((HWND
) GetHWND(), SW_HIDE
);
183 if ( (GetWindowStyleFlag() & wxDIALOG_MODAL
) != wxDIALOG_MODAL
)
184 wxModelessWindows
.DeleteObject(this);
188 // If this is the last top-level window, exit.
189 if (wxTheApp
&& (wxTopLevelWindows
.Number() == 0))
191 wxTheApp
->SetTopWindow(NULL
);
193 if (wxTheApp
->GetExitOnFrameDelete())
200 // By default, pressing escape cancels the dialog
201 void wxDialog::OnCharHook(wxKeyEvent
& event
)
205 if (event
.m_keyCode
== WXK_ESCAPE
)
207 // Behaviour changed in 2.0: we'll send a Cancel message
208 // to the dialog instead of Close.
209 wxCommandEvent
cancelEvent(wxEVT_COMMAND_BUTTON_CLICKED
, wxID_CANCEL
);
210 cancelEvent
.SetEventObject( this );
211 GetEventHandler()->ProcessEvent(cancelEvent
);
216 // We didn't process this event.
220 void wxDialog::OnPaint(wxPaintEvent
& event
)
222 // No: if you call the default procedure, it makes
223 // the following painting code not work.
224 // wxWindow::OnPaint(event);
227 void wxDialog::Fit(void)
232 void wxDialog::Iconize(bool WXUNUSED(iconize
))
234 // Windows dialog boxes can't be iconized
237 bool wxDialog::IsIconized(void) const
242 void wxDialog::SetSize(int x
, int y
, int width
, int height
, int WXUNUSED(sizeFlags
))
244 wxWindow::SetSize(x
, y
, width
, height
);
247 void wxDialog::SetClientSize(int width
, int height
)
249 HWND hWnd
= (HWND
) GetHWND();
251 GetClientRect(hWnd
, &rect
);
254 GetWindowRect(hWnd
, &rect2
);
256 // Find the difference between the entire window (title bar and all)
257 // and the client area; add this to the new client size to move the
259 int actual_width
= rect2
.right
- rect2
.left
- rect
.right
+ width
;
260 int actual_height
= rect2
.bottom
- rect2
.top
- rect
.bottom
+ height
;
262 MoveWindow(hWnd
, rect2
.left
, rect2
.top
, actual_width
, actual_height
, TRUE
);
264 wxSizeEvent
event(wxSize(actual_width
, actual_height
), m_windowId
);
265 event
.SetEventObject( this );
266 GetEventHandler()->ProcessEvent(event
);
269 void wxDialog::GetPosition(int *x
, int *y
) const
271 HWND hWnd
= (HWND
) GetHWND();
273 GetWindowRect(hWnd
, &rect
);
279 bool wxDialog::IsShown(void) const
284 bool wxDialog::Show(bool show
)
291 bool modal
= ((GetWindowStyleFlag() & wxDIALOG_MODAL
) == wxDIALOG_MODAL
) ;
293 #if WXGARBAGE_COLLECTION_ON /* MATTHEW: GC */
296 if (!wxModelessWindows
.Member(this))
297 wxModelessWindows
.Append(this);
299 wxModelessWindows
.DeleteObject(this);
302 if (!wxTopLevelWindows
.Member(this))
303 wxTopLevelWindows
.Append(this);
305 wxTopLevelWindows
.DeleteObject(this);
312 m_hwndOldFocus
= (WXHWND
)::GetFocus();
314 wxList DisabledWindows
;
317 BringWindowToTop((HWND
) GetHWND());
321 m_modalShowing
= TRUE
;
322 wxNode
*node
= wxModalDialogs
.First();
325 wxDialog
*box
= (wxDialog
*)node
->Data();
327 ::EnableWindow((HWND
) box
->GetHWND(), FALSE
);
330 node
= wxModelessWindows
.First();
333 wxWindow
*win
= (wxWindow
*)node
->Data();
334 if (::IsWindowEnabled((HWND
) win
->GetHWND()))
336 ::EnableWindow((HWND
) win
->GetHWND(), FALSE
);
337 DisabledWindows
.Append(win
);
342 ShowWindow((HWND
) GetHWND(), SW_SHOW
);
343 EnableWindow((HWND
) GetHWND(), TRUE
);
344 BringWindowToTop((HWND
) GetHWND());
346 if (!wxModalDialogs
.Member(this))
347 wxModalDialogs
.Append(this);
350 // Must test whether this dialog still exists: we may not process
351 // a message before the deletion.
352 while (wxModalDialogs
.Member(this) && m_modalShowing
&& GetMessage(&msg
, NULL
, 0, 0))
354 if (m_acceleratorTable
.Ok() &&
355 ::TranslateAccelerator((HWND
) GetHWND(), (HACCEL
) m_acceleratorTable
.GetHACCEL(), &msg
))
357 // Have processed the message
359 else if (!IsDialogMessage((HWND
) GetHWND(), &msg
))
361 TranslateMessage(&msg
);
362 DispatchMessage(&msg
);
364 if (m_modalShowing
&& !::PeekMessage(&msg
, 0, 0, 0, PM_NOREMOVE
))
365 // dfgg: NB MUST test m_modalShowing again as the message loop could have triggered
366 // a Show(FALSE) in the mean time!!!
367 // Without the test, we might delete the dialog before the end of modal showing.
369 while (wxTheApp
->ProcessIdle() && m_modalShowing
)
371 // Keep going until we decide we've done enough
375 // dfgg: now must specifically re-enable all other app windows that we disabled earlier
376 node
=DisabledWindows
.First();
378 wxWindow
* win
= (wxWindow
*) node
->Data();
379 HWND hWnd
= (HWND
) win
->GetHWND();
380 if (::IsWindow(hWnd
) && (wxModalDialogs
.Member(win
) || wxModelessWindows
.Member(win
) ))
381 ::EnableWindow(hWnd
,TRUE
);
387 ::SetFocus((HWND
)m_hwndOldFocus
);
389 wxModalDialogs
.DeleteObject(this);
391 wxNode
*last
= wxModalDialogs
.Last();
393 // If there's still a modal dialog active, we
394 // enable it, else we enable all modeless windows
397 wxDialog
*box
= (wxDialog
*)last
->Data();
398 HWND hwnd
= (HWND
) box
->GetHWND();
399 if (box
->m_winEnabled
)
400 EnableWindow(hwnd
, TRUE
);
401 BringWindowToTop(hwnd
);
405 wxNode
*node
= wxModelessWindows
.First();
408 wxWindow
*win
= (wxWindow
*)node
->Data();
409 HWND hwnd
= (HWND
) win
->GetHWND();
410 // Only enable again if not user-disabled.
411 if (win
->IsUserEnabled())
412 EnableWindow(hwnd
, TRUE
);
416 // Try to highlight the correct window (the parent)
420 hWndParent
= (HWND
) GetParent()->GetHWND();
422 ::BringWindowToTop(hWndParent
);
424 ShowWindow((HWND
) GetHWND(), SW_HIDE
);
425 m_modalShowing
= FALSE
;
432 ShowWindow((HWND
) GetHWND(), SW_SHOW
);
433 BringWindowToTop((HWND
) GetHWND());
437 // Try to highlight the correct window (the parent)
441 hWndParent
= (HWND
) GetParent()->GetHWND();
443 ::BringWindowToTop(hWndParent
);
445 ShowWindow((HWND
) GetHWND(), SW_HIDE
);
451 void wxDialog::SetTitle(const wxString
& title
)
453 SetWindowText((HWND
) GetHWND(), (const char *)title
);
456 wxString
wxDialog::GetTitle(void) const
458 GetWindowText((HWND
) GetHWND(), wxBuffer
, 1000);
459 return wxString(wxBuffer
);
462 void wxDialog::Centre(int direction
)
464 int x_offset
,y_offset
;
465 int display_width
, display_height
;
466 int width
, height
, x
, y
;
467 wxWindow
*parent
= GetParent();
468 if ((direction
& wxCENTER_FRAME
) && parent
)
470 parent
->GetPosition(&x_offset
,&y_offset
) ;
471 parent
->GetSize(&display_width
,&display_height
) ;
475 wxDisplaySize(&display_width
, &display_height
);
480 GetSize(&width
, &height
);
483 if (direction
& wxHORIZONTAL
)
484 x
= (int)((display_width
- width
)/2);
485 if (direction
& wxVERTICAL
)
486 y
= (int)((display_height
- height
)/2);
488 SetSize(x
+x_offset
, y
+y_offset
, width
, height
);
491 // Replacement for Show(TRUE) for modal dialogs - returns return code
492 int wxDialog::ShowModal(void)
494 m_windowStyle
|= wxDIALOG_MODAL
;
496 return GetReturnCode();
499 void wxDialog::EndModal(int retCode
)
501 SetReturnCode(retCode
);
505 // Define for each class of dialog and control
506 WXHBRUSH
wxDialog::OnCtlColor(WXHDC pDC
, WXHWND pWnd
, WXUINT nCtlColor
,
507 WXUINT message
, WXWPARAM wParam
, WXLPARAM lParam
)
510 HBRUSH hbrush
= Ctl3dCtlColorEx(message
, wParam
, lParam
);
511 return (WXHBRUSH
) hbrush
;
518 void wxDialog::OnOK(wxCommandEvent
& event
)
520 if ( Validate() && TransferDataFromWindow() )
526 SetReturnCode(wxID_OK
);
532 void wxDialog::OnApply(wxCommandEvent
& event
)
535 TransferDataFromWindow();
536 // TODO probably need to disable the Apply button until things change again
539 void wxDialog::OnCancel(wxCommandEvent
& event
)
542 EndModal(wxID_CANCEL
);
545 SetReturnCode(wxID_CANCEL
);
550 bool wxDialog::OnClose(void)
552 // Behaviour changed in 2.0: we'll send a Cancel message by default,
553 // which may close the dialog.
554 // Check for looping if the Cancel event handler calls Close()
556 static wxList closing
;
558 if ( closing
.Member(this) )
561 closing
.Append(this);
563 wxCommandEvent
cancelEvent(wxEVT_COMMAND_BUTTON_CLICKED
, wxID_CANCEL
);
564 cancelEvent
.SetEventObject( this );
565 GetEventHandler()->ProcessEvent(cancelEvent
);
567 closing
.DeleteObject(this);
572 void wxDialog::OnCloseWindow(wxCloseEvent
& event
)
575 if ( GetEventHandler()->OnClose() || event
.GetForce())
581 // Destroy the window (delayed, if a managed window)
582 bool wxDialog::Destroy(void)
584 if (!wxPendingDelete
.Member(this))
585 wxPendingDelete
.Append(this);
589 void wxDialog::OnSysColourChanged(wxSysColourChangedEvent
& event
)
594 SetBackgroundColour(wxSystemSettings::GetSystemColour(wxSYS_COLOUR_3DFACE
));
595 SetDefaultBackgroundColour(wxSystemSettings::GetSystemColour(wxSYS_COLOUR_3DFACE
));
600 long wxDialog::MSWWindowProc(WXUINT message
, WXWPARAM wParam
, WXLPARAM lParam
)
602 return wxWindow::MSWWindowProc(message
, wParam
, lParam
);