View Issue Details
ID | Project | Category | View Status | Date Submitted | Last Update |
---|---|---|---|---|---|
0001408 | OpenMPT | User Interface | public | 2021-01-16 15:16 | 2025-08-27 19:28 |
Reporter | Saga Musix | Assigned To | |||
Priority | normal | Severity | feature | Reproducibility | N/A |
Status | new | Resolution | open | ||
Target Version | OpenMPT 1.33 / libopenmpt 0.9 (goals) | ||||
Summary | 0001408: Migrate MessageBoxes to Vista TaskDialog | ||||
Description | It's well known that Yes/No/Cancel style dialogs are bad UX, as action buttons should make it clear which action they are actually going to carry out. As OpenMPT no longer supports Windows XP, it would be considerably easier to migrate existing | ||||
Tags | No tags attached. | ||||
Has the bug occurred in previous versions? | |||||
Tested code revision (in case you know it) | |||||
related to | 0001687 | resolved | Saga Musix | Use modern folder picker dialog on Windows Vista and later |
MFC has a wrapper, |
|
This is the first meaningful TaskDialog implementation in Wine that supports more than just plain old Yes/No/Cancel buttons: This would raise the required Wine version to at least 2.5 (2.11 for custom buttons). We appear to have no Wine 2.x users according to update statistics, but a handful of people are still on 1.8. |
|
Requiring Wine 3.0 should be trivial by now, however, we still do have Windows XP builds. We could still use Vista dialogs and fallback to even worse UX for Windows XP: "click Yes for $ACTION, click No for $OTHERACTION". |
|
For those messages currently supported by the |
|
That would be OK, I think. RETRO builds can have reduced functionality. |
|
Technically only |
|
r22143 reimplements the |
|
A first stab at a wrapper class for TaskDialog.patch (20,882 bytes)
Index: mptrack/dlg_misc.cpp =================================================================== --- mptrack/dlg_misc.cpp (revision 24083) +++ mptrack/dlg_misc.cpp (working copy) @@ -1573,27 +1573,29 @@ if((TrackerSettings::Instance().gnMsgBoxVisiblityFlags & msg.mask) == 0) return; -#if MPT_WINNT_AT_LEAST(MPT_WIN_VISTA) && defined(UNICODE) - if(CTaskDialog::IsSupported() - && !(mpt::OS::Windows::IsWine() && theApp.GetWineVersion()->Version().IsBefore(mpt::OS::Wine::Version(3, 13, 0)))) + TaskDlg dlg = TaskDlg{} + .WindowTitle(msg.mainTitle) + .Icon(MB_ICONINFORMATION); + + bool dontShowAgain; + if(TaskDlg::ModernTaskDialogSupported()) { - CTaskDialog taskDialog(msg.message, msg.mainTitle ? CString{msg.mainTitle} : CString{}, AfxGetAppName(), TDCBF_OK_BUTTON); - taskDialog.SetVerificationCheckboxText(_T("Do not show this message again")); - taskDialog.SetVerificationCheckbox(msg.defaultDontShowAgainStatus); - taskDialog.DoModal(); - - if(taskDialog.GetVerificationCheckboxState()) - TrackerSettings::Instance().gnMsgBoxVisiblityFlags &= ~msg.mask; - else - TrackerSettings::Instance().gnMsgBoxVisiblityFlags |= msg.mask; + dlg.Description(msg.message) + .VerificationText(_T("Do not show this message again")) + .VerificationChecked(msg.defaultDontShowAgainStatus); + dontShowAgain = dlg.DoModal().verificationChecked; } else -#endif { - if(Reporting::Confirm(msg.message + CString(_T("\n\nShow this message again?")), msg.mainTitle ? CString{msg.mainTitle} : CString{}, msg.defaultDontShowAgainStatus) == cnfNo) - TrackerSettings::Instance().gnMsgBoxVisiblityFlags &= ~msg.mask; - else - TrackerSettings::Instance().gnMsgBoxVisiblityFlags |= msg.mask; + dlg.Description(CString{msg.message} + _T("\n\nShow this message again?")) + .Buttons({{_T("Yes"), IDYES}, {_T("No"), IDNO} }) + .DefaultButton(msg.defaultDontShowAgainStatus ? IDNO : IDYES); + dontShowAgain = dlg.DoModal().buttonId == IDNO; } + + if(dontShowAgain) + TrackerSettings::Instance().gnMsgBoxVisiblityFlags &= ~msg.mask; + else + TrackerSettings::Instance().gnMsgBoxVisiblityFlags |= msg.mask; } Index: mptrack/Reporting.cpp =================================================================== --- mptrack/Reporting.cpp (revision 24083) +++ mptrack/Reporting.cpp (working copy) @@ -10,23 +10,27 @@ #include "stdafx.h" #include "Reporting.h" -#include "../mptrack/Mainfrm.h" +#include "Mainfrm.h" +#if MPT_WINNT_AT_LEAST(MPT_WIN_VISTA) && defined(UNICODE) +#include "Mptrack.h" +#include <afxtaskdialog.h> +#endif OPENMPT_NAMESPACE_BEGIN -static inline UINT LogLevelToFlags(LogLevel level) +static inline UINT LogLevelToIcon(LogLevel level) { switch(level) { - case LogDebug: return MB_OK; break; - case LogNotification: return MB_OK; break; - case LogInformation: return MB_OK | MB_ICONINFORMATION; break; - case LogWarning: return MB_OK | MB_ICONWARNING; break; - case LogError: return MB_OK | MB_ICONERROR; break; + case LogDebug: return 0; + case LogNotification: return 0; + case LogInformation: return MB_ICONINFORMATION; + case LogWarning: return MB_ICONWARNING; + case LogError: return MB_ICONERROR; } - return MB_OK; + return 0; } @@ -80,70 +84,264 @@ text.SetAt(uint16_max - 2, _T('.')); text.SetAt(uint16_max - 3, _T('.')); } - UINT result = ::MessageBox(parent->GetSafeHwnd(), text, caption.IsEmpty() ? CString(MAINFRAME_TITLE) : caption, flags); + UINT result = ::MessageBox(parent->GetSafeHwnd(), text, caption.IsEmpty() ? CString{MAINFRAME_TITLE} : caption, flags); return result; } +static const TCHAR *GetButtonString(UINT id) +{ + mpt::Library user32{mpt::LibraryPath::System(P_("user32"))}; + using PMB_GETSTRING = LPCWSTR(WINAPI *)(UINT); + PMB_GETSTRING MB_GetString = nullptr; + user32.Bind(MB_GetString, "MB_GetString"); + if(MB_GetString) + return MB_GetString(id - 1); + + switch(id) + { + case IDOK: return _T("&OK"); + case IDCANCEL: return _T("&Cancel"); + case IDABORT: return _T("&Abort"); + case IDRETRY: return _T("&Retry"); + case IDIGNORE: return _T("&Ignore"); + case IDYES: return _T("&Yes"); + case IDNO: return _T("&No"); + case IDCLOSE: return _T("&Close"); + case IDHELP: return _T("Help"); + case IDTRYAGAIN: return _T("&Try Again"); + case IDCONTINUE: return _T("&Continue"); + default: return _T(""); + } +} + + +bool TaskDlg::ModernTaskDialogSupported() +{ +#if MPT_WINNT_AT_LEAST(MPT_WIN_VISTA) && defined(UNICODE) + return CTaskDialog::IsSupported() + && !(mpt::OS::Windows::IsWine() && theApp.GetWineVersion()->Version().IsBefore(mpt::OS::Wine::Version(3, 13, 0))); +#else + return false; +#endif +} + + +TaskDlg::Result TaskDlg::DoModal(const CWnd *parent) const +{ + if(!parent) + parent = CMainFrame::GetActiveWindow(); + +#if MPT_WINNT_AT_LEAST(MPT_WIN_VISTA) && defined(UNICODE) + if(ModernTaskDialogSupported()) + { + CTaskDialog taskDialog{ + description, + headline, + windowTitle.IsEmpty() ? GetTitle() : windowTitle, + buttons.empty() ? TDCBF_OK_BUTTON : 0, + bigButtons ? TDF_ENABLE_HYPERLINKS | TDF_USE_COMMAND_LINKS : 0}; + + if(icon == MB_ICONINFORMATION) + taskDialog.SetMainIcon(TD_INFORMATION_ICON); + else if(icon == MB_ICONWARNING) + taskDialog.SetMainIcon(TD_WARNING_ICON); + else if(icon == MB_ICONERROR) + taskDialog.SetMainIcon(TD_ERROR_ICON); + else if(icon == MB_ICONQUESTION) + taskDialog.SetMainIcon(TD_INFORMATION_ICON); // theApp.LoadStandardIcon(IDI_QUESTION) - this icon hasn't been updated since Vista, and shouldn't be used according to guidelines anyway... + + for(const auto &button : buttons) + { + taskDialog.AddCommandControl(button.commandId, button.text); + } + + if(!verificationText.IsEmpty()) + { + taskDialog.SetVerificationCheckboxText(verificationText); + taskDialog.SetVerificationCheckbox(verificationChecked); + } + + if(defaultButton) + taskDialog.SetDefaultCommandControl(defaultButton); + + UINT result = static_cast<UINT>(taskDialog.DoModal(parent->GetSafeHwnd())); + return {result, !verificationText.IsEmpty() ? !!taskDialog.GetVerificationCheckboxState() : false}; + } +#endif + + // Fallback using regular MessageBox + UINT flags = MB_OK; + if(buttons.size() <= 1) + { + flags = MB_OK; + } else if(buttons.size() == 2) + { + uint32 hasButton = 0; + for(const auto &button : buttons) + { + hasButton |= (1 << button.commandId); + } + if(hasButton == ((1 << IDOK) | (1 << IDCANCEL))) + flags = MB_OKCANCEL; + else if(hasButton == ((1 << IDYES) | (1 << IDNO))) + flags = MB_YESNO; + else if(hasButton == ((1 << IDRETRY) | (1 << IDCANCEL))) + flags = MB_RETRYCANCEL; + else + flags = MB_OKCANCEL; + } else if(buttons.size() == 3) + { + flags = MB_YESNOCANCEL; + } + + if(defaultButton != IDOK) + { + if(defaultButton == IDCANCEL) + flags |= MB_DEFBUTTON3; + else if(defaultButton == IDNO) + flags |= MB_DEFBUTTON2; + } + + CString messageText = description; + if(!headline.IsEmpty()) + messageText = headline + _T("\n\n") + messageText; + + // Workaround MessageBox text length limitation: Better show a truncated string than no message at all. + if(messageText.GetLength() > uint16_max) + { + messageText.Truncate(uint16_max); + messageText.SetAt(uint16_max - 1, _T('.')); + messageText.SetAt(uint16_max - 2, _T('.')); + messageText.SetAt(uint16_max - 3, _T('.')); + } + UINT result = ::MessageBox(parent->GetSafeHwnd(), messageText, windowTitle.IsEmpty() ? GetTitle() : windowTitle, flags | icon); + return {result, false}; +} + + void Reporting::Notification(const AnyStringLocale &text, const CWnd *parent) { - ShowNotificationImpl(mpt::ToCString(text), FillEmptyCaption(CString(), LogNotification), LogLevelToFlags(LogNotification), parent); + TaskDlg{} + .Description(mpt::ToCString(text)) + .WindowTitle(FillEmptyCaption({}, LogNotification)) + .AddButton(GetButtonString(IDOK), IDOK) + .DoModal(parent); } void Reporting::Notification(const AnyStringLocale &text, const AnyStringLocale &caption, const CWnd *parent) { - ShowNotificationImpl(mpt::ToCString(text), FillEmptyCaption(mpt::ToCString(caption), LogNotification), LogLevelToFlags(LogNotification), parent); + TaskDlg{} + .Description(mpt::ToCString(text)) + .WindowTitle(FillEmptyCaption(mpt::ToCString(caption), LogNotification)) + .AddButton(GetButtonString(IDOK), IDOK) + .DoModal(parent); } void Reporting::Information(const AnyStringLocale &text, const CWnd *parent) { - ShowNotificationImpl(mpt::ToCString(text), FillEmptyCaption(CString(), LogInformation), LogLevelToFlags(LogInformation), parent); + TaskDlg{} + .Description(mpt::ToCString(text)) + .WindowTitle(FillEmptyCaption({}, LogInformation)) + .AddButton(GetButtonString(IDOK), IDOK) + .Icon(MB_ICONINFORMATION) + .DoModal(parent); } void Reporting::Information(const AnyStringLocale &text, const AnyStringLocale &caption, const CWnd *parent) { - ShowNotificationImpl(mpt::ToCString(text), FillEmptyCaption(mpt::ToCString(caption), LogInformation), LogLevelToFlags(LogInformation), parent); + TaskDlg{} + .Description(mpt::ToCString(text)) + .WindowTitle(FillEmptyCaption(mpt::ToCString(caption), LogInformation)) + .AddButton(GetButtonString(IDOK), IDOK) + .Icon(MB_ICONINFORMATION) + .DoModal(parent); } void Reporting::Warning(const AnyStringLocale &text, const CWnd *parent) { - ShowNotificationImpl(mpt::ToCString(text), FillEmptyCaption(CString(), LogWarning), LogLevelToFlags(LogWarning), parent); + TaskDlg{} + .Description(mpt::ToCString(text)) + .WindowTitle(FillEmptyCaption({}, LogWarning)) + .AddButton(GetButtonString(IDOK), IDOK) + .Icon(MB_ICONWARNING) + .DoModal(parent); } void Reporting::Warning(const AnyStringLocale &text, const AnyStringLocale &caption, const CWnd *parent) { - ShowNotificationImpl(mpt::ToCString(text), FillEmptyCaption(mpt::ToCString(caption), LogWarning), LogLevelToFlags(LogWarning), parent); + TaskDlg{} + .Description(mpt::ToCString(text)) + .WindowTitle(FillEmptyCaption(mpt::ToCString(caption), LogWarning)) + .AddButton(GetButtonString(IDOK), IDOK) + .Icon(MB_ICONWARNING) + .DoModal(parent); } void Reporting::Error(const AnyStringLocale &text, const CWnd *parent) { - ShowNotificationImpl(mpt::ToCString(text), FillEmptyCaption(CString(), LogError), LogLevelToFlags(LogError), parent); + TaskDlg{} + .Description(mpt::ToCString(text)) + .WindowTitle(FillEmptyCaption({}, LogError)) + .AddButton(GetButtonString(IDOK), IDOK) + .Icon(MB_ICONERROR) + .DoModal(parent); } void Reporting::Error(const AnyStringLocale &text, const AnyStringLocale &caption, const CWnd *parent) { - ShowNotificationImpl(mpt::ToCString(text), FillEmptyCaption(mpt::ToCString(caption), LogError), LogLevelToFlags(LogError), parent); + TaskDlg{} + .Description(mpt::ToCString(text)) + .WindowTitle(FillEmptyCaption(mpt::ToCString(caption), LogError)) + .AddButton(GetButtonString(IDOK), IDOK) + .Icon(MB_ICONERROR) + .DoModal(parent); } void Reporting::Message(LogLevel level, const AnyStringLocale &text, const CWnd *parent) { - ShowNotificationImpl(mpt::ToCString(text), FillEmptyCaption(CString(), level), LogLevelToFlags(level), parent); + TaskDlg{} + .Description(mpt::ToCString(text)) + .WindowTitle(FillEmptyCaption({}, level)) + .AddButton(GetButtonString(IDOK), IDOK) + .Icon(LogLevelToIcon(level)) + .DoModal(parent); } void Reporting::Message(LogLevel level, const AnyStringLocale &text, const AnyStringLocale &caption, const CWnd *parent) { - ShowNotificationImpl(mpt::ToCString(text), FillEmptyCaption(mpt::ToCString(caption), level), LogLevelToFlags(level), parent); + TaskDlg{} + .Description(mpt::ToCString(text)) + .WindowTitle(FillEmptyCaption(mpt::ToCString(caption), level)) + .AddButton(GetButtonString(IDOK), IDOK) + .Icon(LogLevelToIcon(level)) + .DoModal(parent); } ConfirmAnswer Reporting::Confirm(const AnyStringLocale &text, bool showCancel, bool defaultNo, const CWnd *parent) { - return Confirm(mpt::ToCString(text), GetTitle() + _T(" - Confirmation"), showCancel, defaultNo, parent); + return Confirm(text, GetTitle() + _T(" - Confirmation"), showCancel, defaultNo, parent); } +ConfirmAnswer Reporting::Confirm(const AnyStringLocale &text, const AnyStringLocale &caption, bool showCancel, bool defaultNo, const CWnd *parent) +{ + std::vector<TaskDlg::Button> buttonList = + { + {GetButtonString(IDYES), IDYES}, + {GetButtonString(IDNO), IDNO} + }; + if(showCancel) + buttonList.push_back({GetButtonString(IDCANCEL), IDCANCEL}); + TaskDlg params = TaskDlg{} + .Description(mpt::ToCString(text)) + .WindowTitle(FillEmptyCaption(mpt::ToCString(caption))) + .Buttons(buttonList) + .Icon(MB_ICONQUESTION); -ConfirmAnswer Reporting::Confirm(const AnyStringLocale &text, const AnyStringLocale &caption, bool showCancel, bool defaultNo, const CWnd *parent) -{ - UINT result = ShowNotificationImpl(mpt::ToCString(text), FillEmptyCaption(mpt::ToCString(caption)), (showCancel ? MB_YESNOCANCEL : MB_YESNO) | MB_ICONQUESTION | (defaultNo ? MB_DEFBUTTON2 : 0), parent); + if(defaultNo) + params.DefaultButton(IDNO); + + auto result = params.DoModal(parent).buttonId; switch(result) { case IDYES: @@ -155,25 +353,18 @@ return cnfCancel; } } - - RetryAnswer Reporting::RetryCancel(const AnyStringLocale &text, const CWnd *parent) { - return RetryCancel(mpt::ToCString(text), GetTitle(), parent); + return RetryCancel(text, GetTitle(), parent); } - - RetryAnswer Reporting::RetryCancel(const AnyStringLocale &text, const AnyStringLocale &caption, const CWnd *parent) { - UINT result = ShowNotificationImpl(mpt::ToCString(text), FillEmptyCaption(mpt::ToCString(caption)), MB_RETRYCANCEL, parent); - switch(result) - { - case IDRETRY: - return rtyRetry; - default: - case IDCANCEL: - return rtyCancel; - } + auto result = TaskDlg{} + .Description(mpt::ToCString(text)) + .WindowTitle(FillEmptyCaption(mpt::ToCString(caption))) + .Buttons({{GetButtonString(IDRETRY), IDRETRY}, {GetButtonString(IDCANCEL), IDCANCEL}}) + .DoModal(parent).buttonId; + return (result == IDRETRY) ? rtyRetry : rtyCancel; } Index: mptrack/Reporting.h =================================================================== --- mptrack/Reporting.h (revision 24083) +++ mptrack/Reporting.h (working copy) @@ -12,10 +12,55 @@ #include "openmpt/all/BuildSettings.hpp" +#include <vector> OPENMPT_NAMESPACE_BEGIN +struct TaskDlg +{ + // When assigning a custom command ID instead of IDOK/IDCANCEL/..., use this base offset + static constexpr int CUSTOM_ID_BASE = 200; + + struct Button + { + CString text; + UINT commandId; + }; + + struct Result + { + UINT buttonId; + bool verificationChecked; + }; + + Result DoModal(const CWnd *parent = nullptr) const; + + static bool ModernTaskDialogSupported(); + + TaskDlg &WindowTitle(CString title) { windowTitle = std::move(title); return *this; } + TaskDlg &Headline(CString text) { headline = std::move(text); return *this; } + TaskDlg &Description(CString text) { description = std::move(text); return *this; } + TaskDlg &AddButton(CString text, UINT commandID) { buttons.push_back({std::move(text), commandID}); return *this; } + TaskDlg &Buttons(std::vector<Button> buttonList) { buttons = std::move(buttonList); return *this; } + TaskDlg &DefaultButton(int commandID) { defaultButton = commandID; return *this; } + TaskDlg &Icon(UINT iconType) { icon = iconType; return *this; } + TaskDlg &VerificationText(CString text) { verificationText = std::move(text); return *this; } + TaskDlg &VerificationChecked(bool checked) { verificationChecked = checked; return *this; } + TaskDlg &UseBigButtons(bool useBigButtons) { bigButtons = useBigButtons; return *this; } + +protected: + CString windowTitle; + CString headline; + CString description; + CString verificationText; + std::vector<Button> buttons; + int defaultButton = 0; + UINT icon = 0; + bool verificationChecked = false; + bool bigButtons = false; +}; + enum ConfirmAnswer { cnfYes, @@ -31,42 +76,39 @@ }; -class Reporting +namespace Reporting { - -public: // Show a simple notification - static void Notification(const AnyStringLocale &text, const CWnd *parent = nullptr); - static void Notification(const AnyStringLocale &text, const AnyStringLocale &caption, const CWnd *parent = nullptr); + void Notification(const AnyStringLocale &text, const CWnd *parent = nullptr); + void Notification(const AnyStringLocale &text, const AnyStringLocale &caption, const CWnd *parent = nullptr); // Show a simple information - static void Information(const AnyStringLocale &text, const CWnd *parent = nullptr); - static void Information(const AnyStringLocale &text, const AnyStringLocale &caption, const CWnd *parent = nullptr); + void Information(const AnyStringLocale &text, const CWnd *parent = nullptr); + void Information(const AnyStringLocale &text, const AnyStringLocale &caption, const CWnd *parent = nullptr); // Show a simple warning - static void Warning(const AnyStringLocale &text, const CWnd *parent = nullptr); - static void Warning(const AnyStringLocale &text, const AnyStringLocale &caption, const CWnd *parent = nullptr); + void Warning(const AnyStringLocale &text, const CWnd *parent = nullptr); + void Warning(const AnyStringLocale &text, const AnyStringLocale &caption, const CWnd *parent = nullptr); // Show an error box. - static void Error(const AnyStringLocale &text, const CWnd *parent = nullptr); - static void Error(const AnyStringLocale &text, const AnyStringLocale &caption, const CWnd *parent = nullptr); + void Error(const AnyStringLocale &text, const CWnd *parent = nullptr); + void Error(const AnyStringLocale &text, const AnyStringLocale &caption, const CWnd *parent = nullptr); // Simplified version of the above - static void Message(LogLevel level, const AnyStringLocale &text, const CWnd *parent = nullptr); - static void Message(LogLevel level, const AnyStringLocale &text, const AnyStringLocale &caption, const CWnd *parent = nullptr); + void Message(LogLevel level, const AnyStringLocale &text, const CWnd *parent = nullptr); + void Message(LogLevel level, const AnyStringLocale &text, const AnyStringLocale &caption, const CWnd *parent = nullptr); // Show a confirmation dialog. - static ConfirmAnswer Confirm(const AnyStringLocale &text, bool showCancel = false, bool defaultNo = false, const CWnd *parent = nullptr); - static ConfirmAnswer Confirm(const AnyStringLocale &text, const AnyStringLocale &caption, bool showCancel = false, bool defaultNo = false, const CWnd *parent = nullptr); + ConfirmAnswer Confirm(const AnyStringLocale &text, bool showCancel = false, bool defaultNo = false, const CWnd *parent = nullptr); + ConfirmAnswer Confirm(const AnyStringLocale &text, const AnyStringLocale &caption, bool showCancel = false, bool defaultNo = false, const CWnd *parent = nullptr); // work-around string literals for caption decaying to bool and catching the wrong overload instead of converting to a string. - static ConfirmAnswer Confirm(const AnyStringLocale &text, const char *caption, bool showCancel = false, bool defaultNo = false, const CWnd *parent = nullptr) { return Confirm(text, AnyStringLocale(caption), showCancel, defaultNo, parent); } - static ConfirmAnswer Confirm(const AnyStringLocale &text, const wchar_t *caption, bool showCancel = false, bool defaultNo = false, const CWnd *parent = nullptr) { return Confirm(text, AnyStringLocale(caption), showCancel, defaultNo, parent); } - static ConfirmAnswer Confirm(const AnyStringLocale &text, const CString &caption, bool showCancel = false, bool defaultNo = false, const CWnd *parent = nullptr) { return Confirm(text, AnyStringLocale(caption), showCancel, defaultNo, parent); } + inline ConfirmAnswer Confirm(const AnyStringLocale &text, const char *caption, bool showCancel = false, bool defaultNo = false, const CWnd *parent = nullptr) { return Confirm(text, AnyStringLocale(caption), showCancel, defaultNo, parent); } + inline ConfirmAnswer Confirm(const AnyStringLocale &text, const wchar_t *caption, bool showCancel = false, bool defaultNo = false, const CWnd *parent = nullptr) { return Confirm(text, AnyStringLocale(caption), showCancel, defaultNo, parent); } + inline ConfirmAnswer Confirm(const AnyStringLocale &text, const CString &caption, bool showCancel = false, bool defaultNo = false, const CWnd *parent = nullptr) { return Confirm(text, AnyStringLocale(caption), showCancel, defaultNo, parent); } // Show a confirmation dialog. - static RetryAnswer RetryCancel(const AnyStringLocale &text, const CWnd *parent = nullptr); - static RetryAnswer RetryCancel(const AnyStringLocale &text, const AnyStringLocale &caption, const CWnd *parent = nullptr); - + RetryAnswer RetryCancel(const AnyStringLocale &text, const CWnd *parent = nullptr); + RetryAnswer RetryCancel(const AnyStringLocale &text, const AnyStringLocale &caption, const CWnd *parent = nullptr); }; |
|
Date Modified | Username | Field | Change |
---|---|---|---|
2021-01-16 15:16 | Saga Musix | New Issue | |
2021-01-16 15:17 | Saga Musix | Note Added: 0004612 | |
2021-01-16 15:56 | Saga Musix | Note Added: 0004613 | |
2021-01-16 15:58 | Saga Musix | Note Edited: 0004613 | |
2021-01-20 09:34 | manx | Target Version | => OpenMPT 1.31.01.00 / libopenmpt 0.7.0 (upgrade first) |
2022-02-16 17:36 | manx | Note Added: 0005097 | |
2022-02-16 17:57 | Saga Musix | Note Added: 0005098 | |
2022-02-16 18:06 | manx | Note Added: 0005099 | |
2022-02-18 23:12 | Saga Musix | Note Added: 0005103 | |
2023-03-19 16:12 | Saga Musix | Target Version | OpenMPT 1.31.01.00 / libopenmpt 0.7.0 (upgrade first) => OpenMPT 1.32.01.00 / libopenmpt 0.8.0 (upgrade first) |
2023-04-07 19:46 | manx | Relationship added | related to 0001687 |
2024-11-10 16:10 | Saga Musix | Note Added: 0006166 | |
2025-03-23 16:22 | Saga Musix | Target Version | OpenMPT 1.32.01.00 / libopenmpt 0.8.0 (upgrade first) => OpenMPT 1.33 / libopenmpt 0.9 (goals) |
2025-08-27 19:28 | Saga Musix | Note Added: 0006453 | |
2025-08-27 19:28 | Saga Musix | File Added: TaskDialog.patch |