diff --git a/docs/changes.txt b/docs/changes.txt index 4023793277..7e7620bf75 100644 --- a/docs/changes.txt +++ b/docs/changes.txt @@ -446,6 +446,7 @@ All (GUI): - Added documented, public wxNavigationEnabled<> class. - Added wxTextCtrl::PositionToCoords() (Navaneeth). +- Added support for wxHELP button to wxMessageDialog. - Support float, double and file name values in wxGenericValidator (troelsk). - Fix keyboard navigation in wxGrid with hidden columns (ivan_14_32). - Add wxDataViewEvent::IsEditCancelled() (Allonii). diff --git a/include/wx/generic/msgdlgg.h b/include/wx/generic/msgdlgg.h index f6583bd351..21db4aa32b 100644 --- a/include/wx/generic/msgdlgg.h +++ b/include/wx/generic/msgdlgg.h @@ -32,6 +32,7 @@ protected: void OnYes(wxCommandEvent& event); void OnNo(wxCommandEvent& event); + void OnHelp(wxCommandEvent& event); void OnCancel(wxCommandEvent& event); // can be overridden to provide more contents to the dialog diff --git a/include/wx/gtk/msgdlg.h b/include/wx/gtk/msgdlg.h index daab4caac9..8c0a7b095c 100644 --- a/include/wx/gtk/msgdlg.h +++ b/include/wx/gtk/msgdlg.h @@ -40,6 +40,7 @@ private: virtual wxString GetDefaultNoLabel() const; virtual wxString GetDefaultOKLabel() const; virtual wxString GetDefaultCancelLabel() const; + virtual wxString GetDefaultHelpLabel() const; // create the real GTK+ dialog: this is done from ShowModal() to allow // changing the message between constructing the dialog and showing it diff --git a/include/wx/msgdlg.h b/include/wx/msgdlg.h index ca96fc7ff9..c3e8d9af4f 100644 --- a/include/wx/msgdlg.h +++ b/include/wx/msgdlg.h @@ -177,10 +177,16 @@ public: return true; } + virtual bool SetHelpLabel(const ButtonLabel& help) + { + DoSetCustomLabel(m_help, help); + return true; + } + // test if any custom labels were set bool HasCustomLabels() const { - return !(m_ok.empty() && m_cancel.empty() && + return !(m_ok.empty() && m_cancel.empty() && m_help.empty() && m_yes.empty() && m_no.empty()); } @@ -195,6 +201,8 @@ public: { return m_ok.empty() ? GetDefaultOKLabel() : m_ok; } wxString GetCancelLabel() const { return m_cancel.empty() ? GetDefaultCancelLabel() : m_cancel; } + wxString GetHelpLabel() const + { return m_help.empty() ? GetDefaultHelpLabel() : m_help; } // based on message dialog style, returns exactly one of: wxICON_NONE, // wxICON_ERROR, wxICON_WARNING, wxICON_QUESTION, wxICON_INFORMATION @@ -250,6 +258,7 @@ protected: const wxString& GetCustomYesLabel() const { return m_yes; } const wxString& GetCustomNoLabel() const { return m_no; } const wxString& GetCustomOKLabel() const { return m_ok; } + const wxString& GetCustomHelpLabel() const { return m_help; } const wxString& GetCustomCancelLabel() const { return m_cancel; } private: @@ -259,13 +268,15 @@ private: virtual wxString GetDefaultNoLabel() const { return wxGetTranslation("No"); } virtual wxString GetDefaultOKLabel() const { return wxGetTranslation("OK"); } virtual wxString GetDefaultCancelLabel() const { return wxGetTranslation("Cancel"); } + virtual wxString GetDefaultHelpLabel() const { return wxGetTranslation("Help"); } // labels for the buttons, initially empty meaning that the defaults should // be used, use GetYes/No/OK/CancelLabel() to access them wxString m_yes, m_no, m_ok, - m_cancel; + m_cancel, + m_help; wxDECLARE_NO_COPY_CLASS(wxMessageDialogBase); }; diff --git a/include/wx/msw/private/msgdlg.h b/include/wx/msw/private/msgdlg.h index 5df01fc10d..45db8702e7 100644 --- a/include/wx/msw/private/msgdlg.h +++ b/include/wx/msw/private/msgdlg.h @@ -30,8 +30,10 @@ namespace wxMSWMessageDialog class wxMSWTaskDialogConfig { public: + enum { MAX_BUTTONS = 4 }; + wxMSWTaskDialogConfig() - : buttons(new TASKDIALOG_BUTTON[3]), + : buttons(new TASKDIALOG_BUTTON[MAX_BUTTONS]), parent(NULL), iconId(0), style(0), @@ -53,6 +55,7 @@ namespace wxMSWMessageDialog wxString btnNoLabel; wxString btnOKLabel; wxString btnCancelLabel; + wxString btnHelpLabel; // Will create a task dialog with it's paremeters for it's creation // stored in the provided TASKDIALOGCONFIG parameter. diff --git a/include/wx/osx/msgdlg.h b/include/wx/osx/msgdlg.h index cad3de35b7..9c3d38067d 100644 --- a/include/wx/osx/msgdlg.h +++ b/include/wx/osx/msgdlg.h @@ -43,7 +43,7 @@ protected: void* ConstructNSAlert(); #endif - int m_buttonId[3]; + int m_buttonId[4]; int m_buttonCount; #if wxOSX_USE_COCOA diff --git a/interface/wx/msgdlg.h b/interface/wx/msgdlg.h index 0448b04366..70aba8cca1 100644 --- a/interface/wx/msgdlg.h +++ b/interface/wx/msgdlg.h @@ -22,6 +22,12 @@ Puts Yes and No buttons in the message box. It is recommended to always use @c wxCANCEL with this style as otherwise the message box won't have a close button under wxMSW and the user will be forced to answer it. + @style{wxHELP} + Puts a Help button to the message box. This button can have special + appearance or be specially positioned if its label is not changed from + the default one. Notice that using this button is not supported when + showing a message box from non-main thread in wxOSX/Cocoa and it is not + supported in wxOSX/Carbon at all. @since 2.9.3. @style{wxNO_DEFAULT} Makes the "No" button default, can only be used with @c wxYES_NO. @style{wxCANCEL_DEFAULT} @@ -116,6 +122,19 @@ public: */ virtual void SetExtendedMessage(const wxString& extendedMessage); + /** + Sets the label for the Help button. + + Please see the remarks in SetYesNoLabels() documentation. + + Notice that changing the label of the help button resets its special + status (if any, this depends on the platform) and it will be treated + just like another button in this case. + + @since 2.9.3 + */ + virtual bool SetHelpLabel(const ButtonLabel& help); + /** Sets the message shown by the dialog. @@ -190,7 +209,8 @@ public: virtual bool SetYesNoLabels(const ButtonLabel& yes, const ButtonLabel& no); /** - Shows the dialog, returning one of wxID_OK, wxID_CANCEL, wxID_YES, wxID_NO. + Shows the dialog, returning one of wxID_OK, wxID_CANCEL, wxID_YES, + wxID_NO or wxID_HELP. Notice that this method returns the identifier of the button which was clicked unlike wxMessageBox() function. @@ -215,9 +235,9 @@ public: extended text and custom labels for the message box buttons, are not provided by this function but only by wxMessageDialog. - The return value is one of: @c wxYES, @c wxNO, @c wxCANCEL or @c wxOK - (notice that this return value is @b different from the return value of - wxMessageDialog::ShowModal()). + The return value is one of: @c wxYES, @c wxNO, @c wxCANCEL, @c wxOK or @c + wxHELP (notice that this return value is @b different from the return value + of wxMessageDialog::ShowModal()). For example: @code diff --git a/samples/dialogs/dialogs.cpp b/samples/dialogs/dialogs.cpp index 335cc16ca2..14f1a80318 100644 --- a/samples/dialogs/dialogs.cpp +++ b/samples/dialogs/dialogs.cpp @@ -2669,6 +2669,7 @@ const TestMessageBoxDialog::BtnInfo TestMessageBoxDialog::ms_btnInfo[] = { wxNO, "&No" }, { wxOK, "&Ok" }, { wxCANCEL, "&Cancel" }, + { wxHELP, "&Help" }, }; BEGIN_EVENT_TABLE(TestMessageBoxDialog, wxDialog) @@ -2889,6 +2890,11 @@ void TestMessageBoxDialog::PrepareMessageDialog(wxMessageDialogBase &dlg) dlg.SetOKLabel(m_labels[Btn_Ok]->GetValue()); } } + + if ( style & wxHELP ) + { + dlg.SetHelpLabel(m_labels[Btn_Help]->GetValue()); + } } void TestMessageBoxDialog::OnApply(wxCommandEvent& WXUNUSED(event)) @@ -2896,7 +2902,34 @@ void TestMessageBoxDialog::OnApply(wxCommandEvent& WXUNUSED(event)) wxMessageDialog dlg(this, GetMessage(), "Test Message Box", GetStyle()); PrepareMessageDialog(dlg); - dlg.ShowModal(); + wxString btnName; + switch ( dlg.ShowModal() ) + { + case wxID_OK: + btnName = "OK"; + break; + + case wxID_CANCEL: + // Avoid the extra message box if the dialog was cancelled. + return; + + case wxID_YES: + btnName = "Yes"; + break; + + case wxID_NO: + btnName = "No"; + break; + + case wxID_HELP: + btnName = "Help"; + break; + + default: + btnName = "Unknown"; + } + + wxLogMessage("Dialog was closed with the \"%s\" button.", btnName); } void TestMessageBoxDialog::OnClose(wxCommandEvent& WXUNUSED(event)) diff --git a/samples/dialogs/dialogs.h b/samples/dialogs/dialogs.h index fbad49919a..61dd0f85aa 100644 --- a/samples/dialogs/dialogs.h +++ b/samples/dialogs/dialogs.h @@ -228,6 +228,7 @@ private: Btn_No, Btn_Ok, Btn_Cancel, + Btn_Help, Btn_Max }; diff --git a/src/common/utilscmn.cpp b/src/common/utilscmn.cpp index 6e9a224e9d..4ff8dade7a 100644 --- a/src/common/utilscmn.cpp +++ b/src/common/utilscmn.cpp @@ -1361,6 +1361,8 @@ int wxMessageBox(const wxString& message, const wxString& caption, long style, return wxNO; case wxID_CANCEL: return wxCANCEL; + case wxID_HELP: + return wxHELP; } wxFAIL_MSG( wxT("unexpected return code from wxMessageDialog") ); diff --git a/src/generic/msgdlgg.cpp b/src/generic/msgdlgg.cpp index 3fd78a7269..c3dd7a8067 100644 --- a/src/generic/msgdlgg.cpp +++ b/src/generic/msgdlgg.cpp @@ -74,6 +74,7 @@ protected: BEGIN_EVENT_TABLE(wxGenericMessageDialog, wxDialog) EVT_BUTTON(wxID_YES, wxGenericMessageDialog::OnYes) EVT_BUTTON(wxID_NO, wxGenericMessageDialog::OnNo) + EVT_BUTTON(wxID_HELP, wxGenericMessageDialog::OnHelp) EVT_BUTTON(wxID_CANCEL, wxGenericMessageDialog::OnCancel) END_EVENT_TABLE() @@ -133,6 +134,13 @@ wxSizer *wxGenericMessageDialog::CreateMsgDlgButtonSizer() btnDef = yes; } + if ( m_dialogStyle & wxHELP ) + { + wxButton * const + help = new wxButton(this, wxID_HELP, GetCustomHelpLabel()); + sizerStd->AddButton(help); + } + if ( btnDef ) { btnDef->SetDefault(); @@ -148,7 +156,7 @@ wxSizer *wxGenericMessageDialog::CreateMsgDlgButtonSizer() // Use standard labels for all buttons return CreateSeparatedButtonSizer ( - m_dialogStyle & (wxOK | wxCANCEL | wxYES_NO | + m_dialogStyle & (wxOK | wxCANCEL | wxHELP | wxYES_NO | wxNO_DEFAULT | wxCANCEL_DEFAULT) ); } @@ -242,6 +250,11 @@ void wxGenericMessageDialog::OnNo(wxCommandEvent& WXUNUSED(event)) EndModal( wxID_NO ); } +void wxGenericMessageDialog::OnHelp(wxCommandEvent& WXUNUSED(event)) +{ + EndModal( wxID_HELP ); +} + void wxGenericMessageDialog::OnCancel(wxCommandEvent& WXUNUSED(event)) { // Allow cancellation via ESC/Close button except if diff --git a/src/gtk/msgdlg.cpp b/src/gtk/msgdlg.cpp index d459602f0b..2b47ac27ef 100644 --- a/src/gtk/msgdlg.cpp +++ b/src/gtk/msgdlg.cpp @@ -74,6 +74,11 @@ wxString wxMessageDialog::GetDefaultCancelLabel() const return GTK_STOCK_CANCEL; } +wxString wxMessageDialog::GetDefaultHelpLabel() const +{ + return GTK_STOCK_HELP; +} + void wxMessageDialog::DoSetCustomLabel(wxString& var, const ButtonLabel& label) { int stockId = label.GetStockId(); @@ -135,16 +140,21 @@ void wxMessageDialog::GTKCreateMsgDialog() // when using custom labels, we have to add all the buttons ourselves if ( !HasCustomLabels() ) { - if ( m_dialogStyle & wxYES_NO ) + // "Help" button is not supported by predefined combinations so we + // always need to create the buttons manually when it's used. + if ( !(m_dialogStyle & wxHELP) ) { - if ( !(m_dialogStyle & wxCANCEL) ) - buttons = GTK_BUTTONS_YES_NO; - //else: no standard GTK_BUTTONS_YES_NO_CANCEL so leave as NONE - } - else if ( m_dialogStyle & wxOK ) - { - buttons = m_dialogStyle & wxCANCEL ? GTK_BUTTONS_OK_CANCEL - : GTK_BUTTONS_OK; + if ( m_dialogStyle & wxYES_NO ) + { + if ( !(m_dialogStyle & wxCANCEL) ) + buttons = GTK_BUTTONS_YES_NO; + //else: no standard GTK_BUTTONS_YES_NO_CANCEL so leave as NONE + } + else if ( m_dialogStyle & wxOK ) + { + buttons = m_dialogStyle & wxCANCEL ? GTK_BUTTONS_OK_CANCEL + : GTK_BUTTONS_OK; + } } } @@ -211,9 +221,16 @@ void wxMessageDialog::GTKCreateMsgDialog() const bool addButtons = buttons == GTK_BUTTONS_NONE; #endif // wxUSE_LIBHILDON/!wxUSE_LIBHILDON - if ( m_dialogStyle & wxYES_NO ) // Yes/No or Yes/No/Cancel dialog + + if ( addButtons ) { - if ( addButtons ) + if ( m_dialogStyle & wxHELP ) + { + gtk_dialog_add_button(dlg, wxGTK_CONV(GetHelpLabel()), + GTK_RESPONSE_HELP); + } + + if ( m_dialogStyle & wxYES_NO ) // Yes/No or Yes/No/Cancel dialog { // Add the buttons in the correct order which is, according to // http://library.gnome.org/devel/hig-book/stable/windows-alert.html.en @@ -233,32 +250,29 @@ void wxMessageDialog::GTKCreateMsgDialog() gtk_dialog_add_button(dlg, wxGTK_CONV(GetYesLabel()), GTK_RESPONSE_YES); } - - // it'd probably be harmless to call gtk_dialog_set_default_response() - // twice but why do it if we're going to change the default below - // anyhow - if ( !(m_dialogStyle & wxCANCEL_DEFAULT) ) + else // Ok or Ok/Cancel dialog { - gtk_dialog_set_default_response(dlg, - m_dialogStyle & wxNO_DEFAULT - ? GTK_RESPONSE_NO - : GTK_RESPONSE_YES); - } - } - else if ( addButtons ) // Ok or Ok/Cancel dialog - { - gtk_dialog_add_button(dlg, wxGTK_CONV(GetOKLabel()), GTK_RESPONSE_OK); - if ( m_dialogStyle & wxCANCEL ) - { - gtk_dialog_add_button(dlg, wxGTK_CONV(GetCancelLabel()), - GTK_RESPONSE_CANCEL); + gtk_dialog_add_button(dlg, wxGTK_CONV(GetOKLabel()), GTK_RESPONSE_OK); + if ( m_dialogStyle & wxCANCEL ) + { + gtk_dialog_add_button(dlg, wxGTK_CONV(GetCancelLabel()), + GTK_RESPONSE_CANCEL); + } } } + gint defaultButton; if ( m_dialogStyle & wxCANCEL_DEFAULT ) - { - gtk_dialog_set_default_response(dlg, GTK_RESPONSE_CANCEL); - } + defaultButton = GTK_RESPONSE_CANCEL; + else if ( m_dialogStyle & wxNO_DEFAULT ) + defaultButton = GTK_RESPONSE_NO; + else if ( m_dialogStyle & wxYES_NO ) + defaultButton = GTK_RESPONSE_YES; + else // No need to change the default value, whatever it is. + defaultButton = GTK_RESPONSE_NONE; + + if ( defaultButton != GTK_RESPONSE_NONE ) + gtk_dialog_set_default_response(dlg, defaultButton); } int wxMessageDialog::ShowModal() @@ -302,6 +316,8 @@ int wxMessageDialog::ShowModal() return wxID_YES; case GTK_RESPONSE_NO: return wxID_NO; + case GTK_RESPONSE_HELP: + return wxID_HELP; } } diff --git a/src/msw/msgdlg.cpp b/src/msw/msgdlg.cpp index 7c786e5141..b0118ae243 100644 --- a/src/msw/msgdlg.cpp +++ b/src/msw/msgdlg.cpp @@ -511,6 +511,11 @@ int wxMessageDialog::ShowMessageBox() } } + if ( wxStyle & wxHELP ) + { + msStyle |= MB_HELP; + } + // set the icon style switch ( GetEffectiveIcon() ) { @@ -630,7 +635,7 @@ void wxMessageDialog::DoCentre(int dir) #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(); @@ -665,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) @@ -755,6 +761,15 @@ void wxMSWTaskDialogConfig::MSWCommonTaskDialogInit(TASKDIALOGCONFIG &tdc) 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); + } } void wxMSWTaskDialogConfig::AddTaskDialogButton(TASKDIALOGCONFIG &tdc, @@ -770,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 { @@ -839,6 +858,9 @@ int wxMSWMessageDialog::MSWTranslateReturnCode(int msAns) case IDNO: ans = wxID_NO; break; + case IDHELP: + ans = wxID_HELP; + break; } return ans; diff --git a/src/osx/cocoa/msgdlg.mm b/src/osx/cocoa/msgdlg.mm index ad44f55600..445a097caa 100644 --- a/src/osx/cocoa/msgdlg.mm +++ b/src/osx/cocoa/msgdlg.mm @@ -138,6 +138,8 @@ int wxMessageDialog::ShowModal() } } + wxASSERT_MSG( !(style & wxHELP), "wxHELP not supported in non-GUI thread" ); + CFOptionFlags exitButton; OSStatus err = CFUserNotificationDisplayAlert( 0, alertType, NULL, NULL, NULL, cfTitle, cfText, @@ -285,5 +287,15 @@ void* wxMessageDialog::ConstructNSAlert() } } + + if ( style & wxHELP ) + { + wxCFStringRef cfHelpString( GetHelpLabel(), GetFont().GetEncoding() ); + [alert addButtonWithTitle:cfHelpString.AsNSString()]; + m_buttonId[ m_buttonCount++ ] = wxID_HELP; + } + + wxASSERT_MSG( m_buttonCount <= WXSIZEOF(m_buttonId), "Too many buttons" ); + return alert; }