X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/ede7b01760e920b31520b15c919445db882a8012..eea4d01c65f9b29baa1193db762b4c6b8144af24:/src/msw/msgdlg.cpp?ds=sidebyside diff --git a/src/msw/msgdlg.cpp b/src/msw/msgdlg.cpp index 50191c6f77..b0118ae243 100644 --- a/src/msw/msgdlg.cpp +++ b/src/msw/msgdlg.cpp @@ -18,8 +18,6 @@ #if wxUSE_MSGDLG -#include "wx/ptr_scpd.h" - // there is no hook support under CE so we can't use the code for message box // positioning there #ifndef __WXWINCE__ @@ -29,21 +27,21 @@ #endif #ifndef WX_PRECOMP + #include "wx/msgdlg.h" #include "wx/app.h" #include "wx/intl.h" #include "wx/utils.h" - #include "wx/dialog.h" + #include "wx/msw/private.h" #if wxUSE_MSGBOX_HOOK #include "wx/hashmap.h" #endif #endif +#include "wx/ptr_scpd.h" #include "wx/dynlib.h" -#include "wx/msw/private.h" #include "wx/msw/private/button.h" #include "wx/msw/private/metrics.h" #include "wx/msw/private/msgdlg.h" -#include "wx/msgdlg.h" #if wxUSE_MSGBOX_HOOK #include "wx/fontutil.h" @@ -255,8 +253,10 @@ void wxMessageDialog::ReplaceStaticWithEdit() { if ( *i != '\n' ) { - // found last non-newline char, remove everything after it and stop - text.erase(i.base() + 1, text.end()); + // found last non-newline char, remove anything after it if + // necessary and stop in any case + if ( i != text.rbegin() ) + text.erase(i.base() + 1, text.end()); break; } } @@ -511,6 +511,11 @@ int wxMessageDialog::ShowMessageBox() } } + if ( wxStyle & wxHELP ) + { + msStyle |= MB_HELP; + } + // set the icon style switch ( GetEffectiveIcon() ) { @@ -573,41 +578,54 @@ int wxMessageDialog::ShowMessageBox() return MSWTranslateReturnCode(msAns); } -int wxMessageDialog::ShowTaskDialog() +int wxMessageDialog::ShowModal() { #ifdef wxHAS_MSW_TASKDIALOG - TaskDialogIndirect_t taskDialogIndirect = GetTaskDialogIndirectFunc(); - if ( !taskDialogIndirect ) - return wxID_CANCEL; + if ( HasNativeTaskDialog() ) + { + TaskDialogIndirect_t taskDialogIndirect = GetTaskDialogIndirectFunc(); + wxCHECK_MSG( taskDialogIndirect, wxID_CANCEL, wxS("no task dialog?") ); - WinStruct tdc; - wxMSWTaskDialogConfig wxTdc( *this ); - wxTdc.MSWCommonTaskDialogInit( tdc ); + WinStruct tdc; + wxMSWTaskDialogConfig wxTdc( *this ); + wxTdc.MSWCommonTaskDialogInit( tdc ); - int msAns; - HRESULT hr = taskDialogIndirect( &tdc, &msAns, NULL, NULL ); - if ( FAILED(hr) ) - { - wxLogApiError( "TaskDialogIndirect", hr ); - return wxID_CANCEL; - } + int msAns; + HRESULT hr = taskDialogIndirect( &tdc, &msAns, NULL, NULL ); + if ( FAILED(hr) ) + { + wxLogApiError( "TaskDialogIndirect", hr ); + return wxID_CANCEL; + } - return MSWTranslateReturnCode( msAns ); -#else - wxFAIL_MSG( "Task dialogs are unavailable." ); + // In case only an "OK" button was specified we actually created a + // "Cancel" button (see comment in MSWCommonTaskDialogInit). This + // results in msAns being IDCANCEL while we want IDOK (just like + // how the native MessageBox function does with only an "OK" button). + if ( (msAns == IDCANCEL) + && !(GetMessageDialogStyle() & (wxYES_NO|wxCANCEL)) ) + { + msAns = IDOK; + } - return wxID_CANCEL; + return MSWTranslateReturnCode( msAns ); + } #endif // wxHAS_MSW_TASKDIALOG -} - + return ShowMessageBox(); +} -int wxMessageDialog::ShowModal() +void wxMessageDialog::DoCentre(int dir) { +#ifdef wxHAS_MSW_TASKDIALOG + // Task dialog is always centered on its parent window and trying to center + // it manually doesn't work because its HWND is not created yet so don't + // even try as this would only result in (debug) error messages. if ( HasNativeTaskDialog() ) - return ShowTaskDialog(); + return; +#endif // wxHAS_MSW_TASKDIALOG - return ShowMessageBox(); + wxMessageDialogBase::DoCentre(dir); } // ---------------------------------------------------------------------------- @@ -617,12 +635,34 @@ int wxMessageDialog::ShowModal() #ifdef wxHAS_MSW_TASKDIALOG wxMSWTaskDialogConfig::wxMSWTaskDialogConfig(const wxMessageDialogBase& dlg) - : buttons(new TASKDIALOG_BUTTON[3]) + : buttons(new TASKDIALOG_BUTTON[MAX_BUTTONS]) { parent = dlg.GetParentForModalDialog(); caption = dlg.GetCaption(); message = dlg.GetMessage(); extendedMessage = dlg.GetExtendedMessage(); + + // Before wxMessageDialog added support for extended message it was common + // practice to have long multiline texts in the message box with the first + // line playing the role of the main message and the rest of the extended + // one. Try to detect such usage automatically here by synthesizing the + // extended message on our own if it wasn't given. + if ( extendedMessage.empty() ) + { + // Check if there is a blank separating line after the first line (this + // is not the same as searching for "\n\n" as we want the automatically + // recognized main message be single line to avoid embarrassing false + // positives). + const size_t posNL = message.find('\n'); + if ( posNL != wxString::npos && + posNL < message.length() - 1 && + message[posNL + 1 ] == '\n' ) + { + extendedMessage.assign(message, posNL + 2, wxString::npos); + message.erase(posNL); + } + } + iconId = dlg.GetEffectiveIcon(); style = dlg.GetMessageDialogStyle(); useCustomLabels = dlg.HasCustomLabels(); @@ -630,6 +670,7 @@ wxMSWTaskDialogConfig::wxMSWTaskDialogConfig(const wxMessageDialogBase& dlg) btnNoLabel = dlg.GetNoLabel(); btnOKLabel = dlg.GetOKLabel(); btnCancelLabel = dlg.GetCancelLabel(); + btnHelpLabel = dlg.GetHelpLabel(); } void wxMSWTaskDialogConfig::MSWCommonTaskDialogInit(TASKDIALOGCONFIG &tdc) @@ -643,8 +684,23 @@ void wxMSWTaskDialogConfig::MSWCommonTaskDialogInit(TASKDIALOGCONFIG &tdc) if ( wxTheApp->GetLayoutDirection() == wxLayout_RightToLeft ) tdc.dwFlags |= TDF_RTL_LAYOUT; - tdc.pszMainInstruction = message.wx_str(); - tdc.pszContent = extendedMessage.wx_str(); + + // If we have both the main and extended messages, just use them as + // intended. However if only one message is given we normally use it as the + // content and not as the main instruction because the latter is supposed + // to stand out compared to the former and doesn't look good if there is + // nothing for it to contrast with. Finally, notice that the extended + // message we use here might be automatically extracted from the main + // message in our ctor, see comment there. + if ( !extendedMessage.empty() ) + { + tdc.pszMainInstruction = message.wx_str(); + tdc.pszContent = extendedMessage.wx_str(); + } + else + { + tdc.pszContent = message.wx_str(); + } // set an icon to be used, if possible switch ( iconId ) @@ -681,16 +737,38 @@ void wxMSWTaskDialogConfig::MSWCommonTaskDialogInit(TASKDIALOGCONFIG &tdc) } else // without Yes/No we're going to have an OK button { - AddTaskDialogButton(tdc, IDOK, TDCBF_OK_BUTTON, btnOKLabel); - if ( style & wxCANCEL ) { + AddTaskDialogButton(tdc, IDOK, TDCBF_OK_BUTTON, btnOKLabel); AddTaskDialogButton(tdc, IDCANCEL, TDCBF_CANCEL_BUTTON, btnCancelLabel); if ( style & wxCANCEL_DEFAULT ) tdc.nDefaultButton = IDCANCEL; } + else // Only "OK" + { + // We actually create a "Cancel" button instead because we want to + // allow closing the dialog box with Escape (and also Alt-F4 or + // clicking the close button in the title bar) which wouldn't work + // without a Cancel button. + if ( !useCustomLabels ) + { + useCustomLabels = true; + btnOKLabel = _("OK"); + } + + AddTaskDialogButton(tdc, IDCANCEL, TDCBF_CANCEL_BUTTON, btnOKLabel); + } + } + + if ( style & wxHELP ) + { + // There is no support for "Help" button in the task dialog, it can + // only show "Retry" or "Close" ones. + useCustomLabels = true; + + AddTaskDialogButton(tdc, IDHELP, 0 /* not used */, btnHelpLabel); } } @@ -707,6 +785,10 @@ void wxMSWTaskDialogConfig::AddTaskDialogButton(TASKDIALOGCONFIG &tdc, tdBtn.nButtonID = btnCustomId; tdBtn.pszButtonText = customLabel.wx_str(); tdc.cButtons++; + + // We should never have more than 4 buttons currently as this is the + // maximal number of buttons supported by the message dialog. + wxASSERT_MSG( tdc.cButtons <= MAX_BUTTONS, wxT("Too many buttons") ); } else { @@ -721,19 +803,20 @@ wxCRIT_SECT_DECLARE(gs_csTaskDialogIndirect); TaskDialogIndirect_t wxMSWMessageDialog::GetTaskDialogIndirectFunc() { - static TaskDialogIndirect_t s_TaskDialogIndirect = NULL; + // Initialize the function pointer to an invalid value different from NULL + // to avoid reloading comctl32.dll and trying to resolve it every time + // we're called if task dialog is not available (notice that this may + // happen even under Vista+ if we don't use comctl32.dll v6). + static const TaskDialogIndirect_t + INVALID_TASKDIALOG_FUNC = reinterpret_cast(-1); + static TaskDialogIndirect_t s_TaskDialogIndirect = INVALID_TASKDIALOG_FUNC; wxCRIT_SECT_LOCKER(lock, gs_csTaskDialogIndirect); - if ( !s_TaskDialogIndirect ) + if ( s_TaskDialogIndirect == INVALID_TASKDIALOG_FUNC ) { wxLoadedDLL dllComCtl32("comctl32.dll"); wxDL_INIT_FUNC(s_, TaskDialogIndirect, dllComCtl32); - - // We must always succeed as this code is only executed under Vista and - // later which must have task dialog support. - wxASSERT_MSG( s_TaskDialogIndirect, - "Task dialog support unexpectedly not available" ); } return s_TaskDialogIndirect; @@ -744,10 +827,14 @@ TaskDialogIndirect_t wxMSWMessageDialog::GetTaskDialogIndirectFunc() bool wxMSWMessageDialog::HasNativeTaskDialog() { #ifdef wxHAS_MSW_TASKDIALOG - return wxGetWinVersion() >= wxWinVersion_6; -#else + if ( wxGetWinVersion() >= wxWinVersion_6 ) + { + if ( wxMSWMessageDialog::GetTaskDialogIndirectFunc() ) + return true; + } +#endif // wxHAS_MSW_TASKDIALOG + return false; -#endif } int wxMSWMessageDialog::MSWTranslateReturnCode(int msAns) @@ -771,6 +858,9 @@ int wxMSWMessageDialog::MSWTranslateReturnCode(int msAns) case IDNO: ans = wxID_NO; break; + case IDHELP: + ans = wxID_HELP; + break; } return ans;