Provide a task-dialog based wxMSW wxMessageDialog implementation.

Use the task dialog instead of the legacy message box for wxMessageDialog
implementation under wxMSW on recent (Vista and later) Windows versions.

As part of this change, remove wxMessageDialogWithCustomLabels and integrate
its functionality in wxMessageDialogBase itself as it's now used by all
platforms.

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@65348 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Vadim Zeitlin
2010-08-18 22:48:28 +00:00
parent 5a607f8b23
commit ede7b01760
13 changed files with 364 additions and 118 deletions

View File

@@ -18,7 +18,7 @@
#if wxUSE_MSGDLG
#include "wx/msgdlg.h"
#include "wx/ptr_scpd.h"
// there is no hook support under CE so we can't use the code for message box
// positioning there
@@ -38,9 +38,12 @@
#endif
#endif
#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"
@@ -53,6 +56,8 @@
#include "wx/msw/wince/missing.h"
#endif
using namespace wxMSWMessageDialog;
IMPLEMENT_CLASS(wxMessageDialog, wxDialog)
#if wxUSE_MSGBOX_HOOK
@@ -430,7 +435,7 @@ wxFont wxMessageDialog::GetMessageFont()
return wxNativeFontInfo(ncm.lfMessageFont);
}
int wxMessageDialog::ShowModal()
int wxMessageDialog::ShowMessageBox()
{
if ( !wxTheApp->GetTopWindow() )
{
@@ -564,11 +569,194 @@ int wxMessageDialog::ShowModal()
// do show the dialog
int msAns = MessageBox(hWnd, message.wx_str(), m_caption.wx_str(), msStyle);
return MSWTranslateReturnCode(msAns);
}
int wxMessageDialog::ShowTaskDialog()
{
#ifdef wxHAS_MSW_TASKDIALOG
TaskDialogIndirect_t taskDialogIndirect = GetTaskDialogIndirectFunc();
if ( !taskDialogIndirect )
return wxID_CANCEL;
WinStruct<TASKDIALOGCONFIG> 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;
}
return MSWTranslateReturnCode( msAns );
#else
wxFAIL_MSG( "Task dialogs are unavailable." );
return wxID_CANCEL;
#endif // wxHAS_MSW_TASKDIALOG
}
int wxMessageDialog::ShowModal()
{
if ( HasNativeTaskDialog() )
return ShowTaskDialog();
return ShowMessageBox();
}
// ----------------------------------------------------------------------------
// Helpers of the wxMSWMessageDialog namespace
// ----------------------------------------------------------------------------
#ifdef wxHAS_MSW_TASKDIALOG
wxMSWTaskDialogConfig::wxMSWTaskDialogConfig(const wxMessageDialogBase& dlg)
: buttons(new TASKDIALOG_BUTTON[3])
{
parent = dlg.GetParentForModalDialog();
caption = dlg.GetCaption();
message = dlg.GetMessage();
extendedMessage = dlg.GetExtendedMessage();
iconId = dlg.GetEffectiveIcon();
style = dlg.GetMessageDialogStyle();
useCustomLabels = dlg.HasCustomLabels();
btnYesLabel = dlg.GetYesLabel();
btnNoLabel = dlg.GetNoLabel();
btnOKLabel = dlg.GetOKLabel();
btnCancelLabel = dlg.GetCancelLabel();
}
void wxMSWTaskDialogConfig::MSWCommonTaskDialogInit(TASKDIALOGCONFIG &tdc)
{
tdc.dwFlags = TDF_EXPAND_FOOTER_AREA | TDF_POSITION_RELATIVE_TO_WINDOW;
tdc.hInstance = wxGetInstance();
tdc.pszWindowTitle = caption.wx_str();
// use the top level window as parent if none specified
tdc.hwndParent = parent ? GetHwndOf(parent) : NULL;
if ( wxTheApp->GetLayoutDirection() == wxLayout_RightToLeft )
tdc.dwFlags |= TDF_RTL_LAYOUT;
tdc.pszMainInstruction = message.wx_str();
tdc.pszContent = extendedMessage.wx_str();
// set an icon to be used, if possible
switch ( iconId )
{
case wxICON_ERROR:
tdc.pszMainIcon = TD_ERROR_ICON;
break;
case wxICON_WARNING:
tdc.pszMainIcon = TD_WARNING_ICON;
break;
case wxICON_INFORMATION:
tdc.pszMainIcon = TD_INFORMATION_ICON;
break;
}
// custom label button array that can hold all buttons in use
tdc.pButtons = buttons.get();
if ( style & wxYES_NO )
{
AddTaskDialogButton(tdc, IDYES, TDCBF_YES_BUTTON, btnYesLabel);
AddTaskDialogButton(tdc, IDNO, TDCBF_NO_BUTTON, btnNoLabel);
if (style & wxCANCEL)
AddTaskDialogButton(tdc, IDCANCEL,
TDCBF_CANCEL_BUTTON, btnCancelLabel);
if ( style & wxNO_DEFAULT )
tdc.nDefaultButton = IDNO;
else if ( style & wxCANCEL_DEFAULT )
tdc.nDefaultButton = IDCANCEL;
}
else // without Yes/No we're going to have an OK button
{
AddTaskDialogButton(tdc, IDOK, TDCBF_OK_BUTTON, btnOKLabel);
if ( style & wxCANCEL )
{
AddTaskDialogButton(tdc, IDCANCEL,
TDCBF_CANCEL_BUTTON, btnCancelLabel);
if ( style & wxCANCEL_DEFAULT )
tdc.nDefaultButton = IDCANCEL;
}
}
}
void wxMSWTaskDialogConfig::AddTaskDialogButton(TASKDIALOGCONFIG &tdc,
int btnCustomId,
int btnCommonId,
const wxString& customLabel)
{
if ( useCustomLabels )
{
// use custom buttons to implement custom labels
TASKDIALOG_BUTTON &tdBtn = buttons[tdc.cButtons];
tdBtn.nButtonID = btnCustomId;
tdBtn.pszButtonText = customLabel.wx_str();
tdc.cButtons++;
}
else
{
tdc.dwCommonButtons |= btnCommonId;
}
}
// Task dialog can be used from different threads (and wxProgressDialog always
// uses it from another thread in fact) so protect access to the static
// variable below with a critical section.
wxCRIT_SECT_DECLARE(gs_csTaskDialogIndirect);
TaskDialogIndirect_t wxMSWMessageDialog::GetTaskDialogIndirectFunc()
{
static TaskDialogIndirect_t s_TaskDialogIndirect = NULL;
wxCRIT_SECT_LOCKER(lock, gs_csTaskDialogIndirect);
if ( !s_TaskDialogIndirect )
{
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;
}
#endif // wxHAS_MSW_TASKDIALOG
bool wxMSWMessageDialog::HasNativeTaskDialog()
{
#ifdef wxHAS_MSW_TASKDIALOG
return wxGetWinVersion() >= wxWinVersion_6;
#else
return false;
#endif
}
int wxMSWMessageDialog::MSWTranslateReturnCode(int msAns)
{
int ans;
switch (msAns)
{
default:
wxFAIL_MSG(wxT("unexpected ::MessageBox() return code"));
wxFAIL_MSG(wxT("unexpected return code"));
// fall through
case IDCANCEL:
@@ -584,6 +772,7 @@ int wxMessageDialog::ShowModal()
ans = wxID_NO;
break;
}
return ans;
}