mirror of
https://github.com/wxWidgets/wxWidgets.git
synced 2026-10-06 07:00:16 +08:00
Add support for "Do not show this again" checkbox to wxInfoBar
Closes #25394.
This commit is contained in:
committed by
Vadim Zeitlin
parent
ce7273b3ba
commit
cd07eabd54
@@ -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).
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
|
||||
@@ -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
@@ -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.
|
||||
|
||||
|
||||
@@ -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 }? &
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user