Add support for "Do not show this again" checkbox to wxInfoBar

Closes #25394.
This commit is contained in:
Blake-Madden
2025-05-26 17:54:07 +02:00
committed by Vadim Zeitlin
parent ce7273b3ba
commit cd07eabd54
10 changed files with 198 additions and 34 deletions
+1
View File
@@ -314,6 +314,7 @@ All (GUI):
- Add wxApp::SetAppearance() to explicitly set dark or light mode (#24461).
- Add wxAuiManager::{Save,Load}Layout() (#24235).
- Add wxGrid::CopySelection() (Blake Madden, #24124).
- Add wxInfoBar::ShowCheckBox() (Blake Madden, #25394).
- Add wxRadioButton group support to wxGenericValidator (Bill Su, #24264).
- Add wxRibbonBar::GetPageById() (Blake Madden, #24211).
- Add wxStatusBar::AddFieldControl() (AliKet, #24092).
+10
View File
@@ -1394,11 +1394,21 @@ page.
this property is of class "button" has name (can be one of standard
button ID) and has optional label property. If no buttons are added
to the info bar, the default "Close" button will be shown.}
@row3col{checkboxlabel, @ref overview_xrcformat_type_text,
Shows a checkbox at the bottom of the infobar with the specified label.
Note that specifying this attribute automatically turns on @c
wxINFOBAR_CHECKBOX style (optional). @since 3.3.0.}
@row3col{checked, @ref overview_xrcformat_type_bool,
If showing the checkbox, indicates whether it should be checked by
default (optional). @since 3.3.0.}
@endTable
Example:
@code
<object class="wxInfoBar">
<style>wxINFOBAR_CHECKBOX</style>
<checkboxlabel>Do not show this again</checkboxlabel>
<checked>1</checked>
<effectduration>1000</effectduration>
<showeffect>wxSHOW_EFFECT_EXPAND</showeffect>
<hideeffect>wxSHOW_EFFECT_SLIDE_TO_RIGHT</hideeffect>
+25 -6
View File
@@ -13,11 +13,17 @@
class WXDLLIMPEXP_FWD_CORE wxBitmapButton;
class WXDLLIMPEXP_FWD_CORE wxStaticBitmap;
class WXDLLIMPEXP_FWD_CORE wxStaticText;
class WXDLLIMPEXP_FWD_CORE wxCheckBox;
// ----------------------------------------------------------------------------
// wxInfoBar
// ----------------------------------------------------------------------------
enum
{
wxINFOBAR_CHECKBOX = 0x0010
};
class WXDLLIMPEXP_CORE wxInfoBarGeneric : public wxInfoBarBase
{
public:
@@ -25,13 +31,13 @@ public:
// hidden
wxInfoBarGeneric() { Init(); }
wxInfoBarGeneric(wxWindow *parent, wxWindowID winid = wxID_ANY)
wxInfoBarGeneric(wxWindow *parent, wxWindowID winid = wxID_ANY, long style = 0)
{
Init();
Create(parent, winid);
Create(parent, winid, style);
}
bool Create(wxWindow *parent, wxWindowID winid = wxID_ANY);
bool Create(wxWindow *parent, wxWindowID winid = wxID_ANY, long style = 0);
// implement base class methods
@@ -75,6 +81,14 @@ public:
// get the currently used effect animation duration
int GetEffectDuration() const { return m_effectDuration; }
// Whether the checkbox was checked at the time of the window
// being closed.
// This should be called in a client's handler for the
// wxID_CLOSE button being clicked.
bool IsCheckBoxChecked() const { return m_checked; }
// Sets whether the checkbox should be shown.
void ShowCheckBox(const wxString& checkBoxText, bool checked);
// overridden base class methods
// -----------------------------
@@ -100,6 +114,8 @@ private:
// common part of all ctors
void Init();
virtual bool UseNative() const { return false; }
// handler for the close button
void OnButton(wxCommandEvent& event);
@@ -120,9 +136,10 @@ private:
// different controls making up the bar
wxStaticBitmap *m_icon;
wxStaticText *m_text;
wxBitmapButton *m_button;
wxStaticBitmap *m_icon = nullptr;
wxStaticText *m_text = nullptr;
wxBitmapButton *m_button = nullptr;
wxCheckBox *m_checkbox = nullptr;
// the effects to use when showing/hiding and duration for them: by default
// the effect is determined by the info bar automatically depending on its
@@ -131,6 +148,8 @@ private:
m_hideEffect;
int m_effectDuration;
bool m_checked = false;
wxDECLARE_EVENT_TABLE();
wxDECLARE_NO_COPY_CLASS(wxInfoBarGeneric);
};
+7 -5
View File
@@ -16,21 +16,21 @@
// wxInfoBar for GTK+
// ----------------------------------------------------------------------------
// notice that the native GTK+ implementation is only available since
// (relatively recent) 2.18 so we inherit from the generic one to be able to
// notice that the native GTK+ implementation is only available since 2.18,
// so we inherit from the generic one to be able to
// fall back to it if GTK+ version is determined to be too old during run-time
class WXDLLIMPEXP_CORE wxInfoBar : public wxInfoBarGeneric
{
public:
wxInfoBar() { Init(); }
wxInfoBar(wxWindow *parent, wxWindowID winid = wxID_ANY)
wxInfoBar(wxWindow *parent, wxWindowID winid = wxID_ANY, long style = 0)
{
Init();
Create(parent, winid);
Create(parent, winid, style);
}
bool Create(wxWindow *parent, wxWindowID winid = wxID_ANY);
bool Create(wxWindow *parent, wxWindowID winid = wxID_ANY, long style = 0);
virtual ~wxInfoBar();
@@ -62,6 +62,8 @@ protected:
private:
void Init() { m_impl = nullptr; }
virtual bool UseNative() const override;
// add a button with the given id/label and return its widget
GtkWidget *GTKAddButton(wxWindowID btnid,
const wxString& label = wxString());
+43 -2
View File
@@ -6,6 +6,18 @@
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
/**
Styles to pass to the constructor or Create().
@since 3.3.0
*/
enum
{
/// Include support for showing a customizable checkbox()
/// at the bottom of a wxInfoBar.
wxINFOBAR_CHECKBOX = 0x0080
};
/**
An info bar is a transient window shown at top or bottom of its parent
window to display non-critical information to the user.
@@ -86,7 +98,7 @@ public:
@see Create()
*/
wxInfoBar(wxWindow *parent, wxWindowID winid = wxID_ANY);
wxInfoBar(wxWindow *parent, wxWindowID winid = wxID_ANY, long style = 0);
/**
Create the info bar window.
@@ -106,8 +118,10 @@ public:
@param winid
The id of the info bar window, usually unused as currently no
events are generated by this class.
@param style
Optional styles to apply to the control.
*/
bool Create(wxWindow *parent, wxWindowID winid = wxID_ANY);
bool Create(wxWindow *parent, wxWindowID winid = wxID_ANY, long style = 0);
/**
Add a button to be shown in the info bar.
@@ -272,6 +286,33 @@ public:
/// Return the effect animation duration currently used.
int GetEffectDuration() const;
/**
Return whether the checkbox was checked at the time of the window being
closed.
This function is typically used in the button handler for the @c
wxEVT_BUTTON message for @c wxID_CLOSE, which would typically call
Dismiss() to hide the info bar and then call this function to see if
the checkbox was checked and save its value to reuse it the next time
(e.g. to avoid showing the same message again in a common use case).
See the dialogs sample for an example.
@since 3.3.0
*/
bool IsCheckBoxChecked() const;
/**
Sets whether the checkbox should be shown, its label, and whether it is
checked by default.
@note The wxINFOBAR_CHECKBOX style must be used for this control
if calling this function.
@since 3.3.0
*/
void ShowCheckBox(const wxString& checkBoxText, bool checked);
/**
Overridden base class methods changes the font of the text message.
+2
View File
@@ -1083,6 +1083,8 @@ wxInfoBar =
[xrc:p="o"] element effectduration {_, t_integer }* &
[xrc:p="o"] element showeffect {_, t_showeffect }* &
[xrc:p="o"] element hideeffect {_, t_showeffect }* &
[xrc:p="o"] element checkboxlabel {_, t_text }* &
[xrc:p="o"] element checked {_, t_bool }* &
element object {
attribute class { "button" } &
attribute name { t_identifier }? &
+22 -1
View File
@@ -721,7 +721,7 @@ MyFrame::MyFrame(const wxString& title)
#if wxUSE_INFOBAR
// an info bar can be created very simply and used without any extra effort
m_infoBarSimple = new wxInfoBar(this);
m_infoBarSimple = new wxInfoBar(this, wxID_ANY, wxINFOBAR_CHECKBOX);
// or it can also be customized by
m_infoBarAdvanced = new wxInfoBar(this);
@@ -942,6 +942,13 @@ void MyFrame::LogDialog(wxCommandEvent& WXUNUSED(event))
void MyFrame::InfoBarSimple(wxCommandEvent& WXUNUSED(event))
{
static int s_count = 0;
static bool s_dontShowAgain = false;
if (s_dontShowAgain)
{
wxMessageBox("You asked to not see this again. Remember?");
return;
}
wxString msg;
if ( ++s_count % 2 )
@@ -959,7 +966,21 @@ void MyFrame::InfoBarSimple(wxCommandEvent& WXUNUSED(event))
s_count);
}
m_infoBarSimple->ShowCheckBox(_("Do not show this again"), false);
m_infoBarSimple->ShowMessage(msg);
// intercept the close button being clicked
m_infoBarSimple->Bind(wxEVT_BUTTON,
[this](wxCommandEvent& WXUNUSED(event))
{
// dismiss the message and (if a generic control)
// see if the "don't show this again" checkbox
// was checked and handle that for next time
m_infoBarSimple->Dismiss();
if (m_infoBarSimple->IsCheckBoxChecked())
{
s_dontShowAgain = true;
};
}, wxID_CLOSE);
}
void MyFrame::InfoBarAdvanced(wxCommandEvent& WXUNUSED(event))
+44 -6
View File
@@ -35,6 +35,8 @@
#include "wx/artprov.h"
#include "wx/scopeguard.h"
#include "wx/valgen.h"
#include "wx/checkbox.h"
#ifdef __WXGTK3__
#include "wx/gtk/private/wrapgtk.h"
@@ -45,6 +47,7 @@
wxBEGIN_EVENT_TABLE(wxInfoBarGeneric, wxInfoBarBase)
EVT_BUTTON(wxID_ANY, wxInfoBarGeneric::OnButton)
EVT_BUTTON(wxID_CLOSE, wxInfoBarGeneric::OnButton)
wxEND_EVENT_TABLE()
// ============================================================================
@@ -64,11 +67,12 @@ void wxInfoBarGeneric::Init()
m_effectDuration = 0;
}
bool wxInfoBarGeneric::Create(wxWindow *parent, wxWindowID winid)
bool wxInfoBarGeneric::Create(wxWindow *parent, wxWindowID winid, long style)
{
// calling Hide() before Create() ensures that we're created initially
// hidden
Hide();
SetWindowStyle(style);
if ( !wxWindow::Create(parent, winid) )
return false;
@@ -115,19 +119,37 @@ bool wxInfoBarGeneric::Create(wxWindow *parent, wxWindowID winid)
if(!m_hasFgCol)
m_text->SetForegroundColour(colFg);
m_button = wxBitmapButton::NewCloseButton(this, wxID_ANY);
m_button = wxBitmapButton::NewCloseButton(this, wxID_CLOSE);
m_button->SetToolTip(_("Hide this notification message."));
m_checkbox =
new wxCheckBox(this, wxID_ANY, wxEmptyString, wxDefaultPosition,
wxDefaultSize, 0, wxGenericValidator(&m_checked));
m_checkbox->SetForegroundColour(
wxSystemSettings::GetColour(wxSYS_COLOUR_INFOTEXT));
// center the text inside the sizer with an icon to the left of it and a
// button at the very right
//
// NB: AddButton() relies on the button being the last control in the sizer
// and being preceded by a spacer
wxSizer * const sizer = new wxBoxSizer(wxHORIZONTAL);
sizer->Add(m_icon, wxSizerFlags().Centre().Border());
sizer->Add(m_text, wxSizerFlags().Proportion(1).Centre());
sizer->AddSpacer(0); // This spacer only exists for compatibility.
sizer->Add(m_button, wxSizerFlags().Centre().Border());
wxSizer * const defaultControlSizer = new wxBoxSizer(wxVERTICAL);
wxBoxSizer* const firstRowSizer = new wxBoxSizer(wxHORIZONTAL);
firstRowSizer->Add(m_icon, wxSizerFlags{}.Centre().Border());
firstRowSizer->Add(m_text, wxSizerFlags{}.Proportion(1).Centre());
firstRowSizer->AddSpacer(0); // This spacer only exists for compatibility.
firstRowSizer->Add(m_button, wxSizerFlags{}.Centre().Border());
wxBoxSizer* const secondRowSizer = new wxBoxSizer(wxHORIZONTAL);
secondRowSizer->Add(m_checkbox, wxSizerFlags{}.CentreVertical().Border());
defaultControlSizer->Add(firstRowSizer, wxSizerFlags{ 1 }.Expand());
defaultControlSizer->Add(secondRowSizer);
defaultControlSizer->Show(m_checkbox, !m_checkbox->GetLabel().empty(), true);
sizer->Add(defaultControlSizer, wxSizerFlags{ 1 }.Expand());
SetSizer(sizer);
return true;
@@ -223,6 +245,8 @@ void wxInfoBarGeneric::UpdateParent()
void wxInfoBarGeneric::DoHide()
{
TransferDataFromWindow();
HideWithEffect(GetHideEffect(), GetEffectDuration());
UpdateParent();
@@ -230,6 +254,8 @@ void wxInfoBarGeneric::DoHide()
void wxInfoBarGeneric::DoShow()
{
TransferDataToWindow();
// re-layout the parent first so that the window expands into an already
// unoccupied by the other controls area: for this we need to change our
// internal visibility flag to force Layout() to take us into account (an
@@ -466,4 +492,16 @@ void wxInfoBarGeneric::OnButton(wxCommandEvent& WXUNUSED(event))
DoHide();
}
void wxInfoBarGeneric::ShowCheckBox(const wxString& checkBoxText, bool checked)
{
wxASSERT_MSG( HasFlag(wxINFOBAR_CHECKBOX),
"wxINFOBAR_CHECKBOX style should be set if calling ShowCheckBox()!");
m_checked = checked;
if (m_checkbox != nullptr)
{
m_checkbox->SetLabel(checkBoxText);
GetSizer()->Show(m_checkbox, !checkBoxText.empty(), true);
}
}
#endif // wxUSE_INFOBAR
+11 -13
View File
@@ -75,17 +75,6 @@ public:
// local functions
// ----------------------------------------------------------------------------
namespace
{
inline bool UseNative()
{
// native GtkInfoBar widget is only available in GTK+ 2.18 and later
return wx_is_at_least_gtk2(18);
}
} // anonymous namespace
extern "C"
{
@@ -108,10 +97,19 @@ static void wxgtk_infobar_close(GtkInfoBar * WXUNUSED(infobar),
// wxInfoBar implementation
// ============================================================================
bool wxInfoBar::Create(wxWindow *parent, wxWindowID winid)
bool wxInfoBar::UseNative() const
{
// Native GtkInfoBar widget is only available in GTK+ 2.18 and later.
// Also, if the checkbox is included, then we need to use
// the generic version.
return wx_is_at_least_gtk2(18) && !HasFlag(wxINFOBAR_CHECKBOX);
}
bool wxInfoBar::Create(wxWindow *parent, wxWindowID winid, long style)
{
SetWindowStyle(style);
if ( !UseNative() )
return wxInfoBarGeneric::Create(parent, winid);
return wxInfoBarGeneric::Create(parent, winid, style);
m_impl = new wxInfoBarGTKImpl;
+33 -1
View File
@@ -36,6 +36,9 @@ wxInfoBarXmlHandler::wxInfoBarXmlHandler()
XRC_ADD_SHOW_EFFECT(wxSHOW_EFFECT_SLIDE_TO_BOTTOM);
XRC_ADD_SHOW_EFFECT(wxSHOW_EFFECT_BLEND);
XRC_ADD_SHOW_EFFECT(wxSHOW_EFFECT_EXPAND);
XRC_ADD_STYLE(wxINFOBAR_CHECKBOX);
AddWindowStyles();
}
wxObject *wxInfoBarXmlHandler::DoCreateResource()
@@ -44,7 +47,18 @@ wxObject *wxInfoBarXmlHandler::DoCreateResource()
{
XRC_MAKE_INSTANCE(control, wxInfoBar)
control->Create(m_parentAsWindow, GetID());
const wxString& checkboxLabel = GetText("checkboxlabel");
const bool hasCheckbox = !checkboxLabel.empty();
long style = GetStyle();
if ( hasCheckbox )
{
// If we have a checkbox, we need to add the wxINFOBAR_CHECKBOX
// style to allow using it.
style |= wxINFOBAR_CHECKBOX;
}
control->Create(m_parentAsWindow, GetID(), style);
SetupWindow(control);
@@ -57,6 +71,24 @@ wxObject *wxInfoBarXmlHandler::DoCreateResource()
if ( HasParam("effectduration") )
control->SetEffectDuration(GetLong("effectduration"));
bool checked = false;
if ( HasParam("checked") )
{
if ( !hasCheckbox )
{
ReportError
(
R"(The "checked" parameter can only be specified when )"
R"(the "checkboxlabel" parameter is set.)"
);
}
checked = GetBool("checked");
}
if ( hasCheckbox )
control->ShowCheckBox(checkboxLabel, checked);
m_insideBar = true;
CreateChildrenPrivately(control);
m_insideBar = false;