From 1d89da8a5c9e12fd21cdffce1a922d5122af9128 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sat, 22 Dec 2007 16:52:31 +0000 Subject: [PATCH] allow centering wxMessageDialog on its parent window (patch 1836072) git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@50904 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- docs/changes.txt | 3 +- include/wx/msw/msgdlg.h | 7 +++- samples/dialogs/dialogs.cpp | 4 +-- src/msw/msgdlg.cpp | 69 +++++++++++++++++++++++++++++++++++++ 4 files changed, 79 insertions(+), 4 deletions(-) diff --git a/docs/changes.txt b/docs/changes.txt index 8a29459d4f..0a05c3f33e 100644 --- a/docs/changes.txt +++ b/docs/changes.txt @@ -280,7 +280,8 @@ wxMSW: - Return the restored window size from GetSize() when window is minimized. - wxCheckListBox now looks more native, especially under XP (Marcin Malich). - Allow tooltips longer than 64 (up to 128) characters in wxTaskBarIcon -- Fix centering wxFileDialog +- Fix centering wxFileDialog and allow positioning it +- Allow centering wxMessageDialog on its parent window (troelsk) wxX11: diff --git a/include/wx/msw/msgdlg.h b/include/wx/msw/msgdlg.h index 95c61af4e3..29ae1be0b3 100644 --- a/include/wx/msw/msgdlg.h +++ b/include/wx/msw/msgdlg.h @@ -22,12 +22,17 @@ public: const wxPoint& WXUNUSED(pos) = wxDefaultPosition) : wxMessageDialogBase(parent, message, caption, style) { + m_hook = NULL; } virtual int ShowModal(); -protected: +private: + static WXLRESULT wxCALLBACK HookFunction(int code, WXWPARAM, WXLPARAM); + + WXHANDLE m_hook; // HHOOK used to position the message box + DECLARE_DYNAMIC_CLASS(wxMessageDialog) DECLARE_NO_COPY_CLASS(wxMessageDialog) }; diff --git a/samples/dialogs/dialogs.cpp b/samples/dialogs/dialogs.cpp index 29195ad6df..ffd6d9d424 100644 --- a/samples/dialogs/dialogs.cpp +++ b/samples/dialogs/dialogs.cpp @@ -650,10 +650,10 @@ void MyFrame::LogDialog(wxCommandEvent& WXUNUSED(event)) #if wxUSE_MSGDLG void MyFrame::MessageBox(wxCommandEvent& WXUNUSED(event) ) { - wxMessageDialog dialog(NULL, + wxMessageDialog dialog(this, _T("This is a message box\nA long, long string to test out the message box properly"), _T("Message box text"), - wxNO_DEFAULT | wxYES_NO | wxCANCEL | wxICON_INFORMATION); + wxCENTER | wxNO_DEFAULT | wxYES_NO | wxCANCEL | wxICON_INFORMATION); if ( dialog.SetYesNoLabels(_T("Answer &Yes"),_T("Answer &No")) ) { diff --git a/src/msw/msgdlg.cpp b/src/msw/msgdlg.cpp index 061b9211a2..177da7d522 100644 --- a/src/msw/msgdlg.cpp +++ b/src/msw/msgdlg.cpp @@ -24,6 +24,7 @@ #include "wx/app.h" #include "wx/utils.h" #include "wx/dialog.h" + #include "wx/hashmap.h" #endif #include "wx/msw/private.h" @@ -35,6 +36,65 @@ IMPLEMENT_CLASS(wxMessageDialog, wxDialog) +// there can potentially be one message box per thread so we use a hash map +// with thread ids as keys and (currently shown) message boxes as values +// +// TODO: replace this with wxTLS once it's available +WX_DECLARE_HASH_MAP(unsigned long, wxMessageDialog *, + wxIntegerHash, wxIntegerEqual, + wxMessageDialogMap); + +namespace +{ + +wxMessageDialogMap& HookMap() +{ + static wxMessageDialogMap s_Map; + + return s_Map; +} + +} // anonymous namespace + +/* static */ +WXLRESULT wxCALLBACK +wxMessageDialog::HookFunction(int code, WXWPARAM wParam, WXLPARAM lParam) +{ + // Find the thread-local instance of wxMessageDialog + const DWORD tid = ::GetCurrentThreadId(); + wxMessageDialogMap::iterator node = HookMap().find(tid); + wxCHECK_MSG( node != HookMap().end(), false, + wxT("bogus thread id in wxMessageDialog::Hook") ); + + wxMessageDialog * const wnd = node->second; + + const HHOOK hhook = (HHOOK)wnd->m_hook; + const LRESULT rc = ::CallNextHookEx(hhook, code, wParam, lParam); + + if ( code == HC_ACTION && lParam ) + { + const CWPRETSTRUCT * const s = (CWPRETSTRUCT *)lParam; + + if ( s->message == HCBT_ACTIVATE ) + { + // we won't need this hook any longer + ::UnhookWindowsHookEx(hhook); + wnd->m_hook = NULL; + HookMap().erase(tid); + + if ( wnd->GetMessageDialogStyle() & wxCENTER ) + { + wnd->SetHWND(s->hwnd); + wnd->Center(); // center on parent + wnd->SetHWND(NULL); + } + //else: default behaviour, center on screen + } + } + + return rc; +} + int wxMessageDialog::ShowModal() { if ( !wxTheApp->GetTopWindow() ) @@ -110,6 +170,15 @@ int wxMessageDialog::ShowModal() } #endif // wxUSE_UNICODE + // install the hook if we need to position the dialog in a non-default way + if ( wxStyle & wxCENTER ) + { + const DWORD tid = ::GetCurrentThreadId(); + m_hook = ::SetWindowsHookEx(WH_CALLWNDPROCRET, + &wxMessageDialog::HookFunction, NULL, tid); + HookMap()[tid] = this; + } + // do show the dialog int msAns = MessageBox(hWnd, message.wx_str(), m_caption.wx_str(), msStyle); int ans; -- 2.45.2