Add support for using arbitrary windows as wxStaticBox labels

This commit implements the new feature in wxGTK and updates the sample
and the documentation.
This commit is contained in:
Vadim Zeitlin
2017-12-19 21:29:32 +01:00
parent 29bd25b757
commit 7c849276f8
6 changed files with 226 additions and 17 deletions

View File

@@ -113,6 +113,7 @@ All (GUI):
- Allow wxWebView::RunScript() return values (Jose Lorenzo, GSoC 2017). - Allow wxWebView::RunScript() return values (Jose Lorenzo, GSoC 2017).
- Allow using fractional pen widths with wxGraphicsContext (Adrien Tétar). - Allow using fractional pen widths with wxGraphicsContext (Adrien Tétar).
- Add support for loading fonts from external files (Arthur Norman). - Add support for loading fonts from external files (Arthur Norman).
- Add support for using arbitrary windows as wxStaticBox labels.
- Improve wxSVGFileDC to support more of wxDC API (Maarten Bent). - Improve wxSVGFileDC to support more of wxDC API (Maarten Bent).
- Add support for wxAuiManager and wxAuiPaneInfo to XRC (Andrea Zanellato). - Add support for wxAuiManager and wxAuiPaneInfo to XRC (Andrea Zanellato).
- Add support for wxSL_MIN_MAX_LABELS and wxSL_VALUE_LABEL to XRC (ousnius). - Add support for wxSL_MIN_MAX_LABELS and wxSL_VALUE_LABEL to XRC (ousnius).

View File

@@ -194,6 +194,8 @@ Currently the following symbols exist:
@itemdef{wxHAS_RAW_KEY_CODES, Defined if raw key codes (see wxKeyEvent::GetRawKeyCode are supported.} @itemdef{wxHAS_RAW_KEY_CODES, Defined if raw key codes (see wxKeyEvent::GetRawKeyCode are supported.}
@itemdef{wxHAS_REGEX_ADVANCED, Defined if advanced syntax is available in wxRegEx.} @itemdef{wxHAS_REGEX_ADVANCED, Defined if advanced syntax is available in wxRegEx.}
@itemdef{wxHAS_TASK_BAR_ICON, Defined if wxTaskBarIcon is available on the current platform.} @itemdef{wxHAS_TASK_BAR_ICON, Defined if wxTaskBarIcon is available on the current platform.}
@itemdef{wxHAS_WINDOW_LABEL_IN_STATIC_BOX, Defined if wxStaticBox::Create()
overload taking @c wxWindow* instead of the text label is available on the current platform.}
@itemdef{wxHAS_MODE_T, Defined when wxWidgets defines @c mode_t typedef for the @itemdef{wxHAS_MODE_T, Defined when wxWidgets defines @c mode_t typedef for the
compilers not providing it. If another library used in a wxWidgets compilers not providing it. If another library used in a wxWidgets
application, such as ACE (http://www.cs.wustl.edu/~schmidt/ACE.html), also application, such as ACE (http://www.cs.wustl.edu/~schmidt/ACE.html), also

View File

@@ -18,6 +18,7 @@ class WXDLLIMPEXP_CORE wxStaticBox : public wxStaticBoxBase
public: public:
wxStaticBox() wxStaticBox()
{ {
Init();
} }
wxStaticBox( wxWindow *parent, wxStaticBox( wxWindow *parent,
@@ -28,6 +29,21 @@ public:
long style = 0, long style = 0,
const wxString &name = wxStaticBoxNameStr ) const wxString &name = wxStaticBoxNameStr )
{ {
Init();
Create( parent, id, label, pos, size, style, name );
}
wxStaticBox( wxWindow *parent,
wxWindowID id,
wxWindow* label,
const wxPoint &pos = wxDefaultPosition,
const wxSize &size = wxDefaultSize,
long style = 0,
const wxString &name = wxStaticBoxNameStr )
{
Init();
Create( parent, id, label, pos, size, style, name ); Create( parent, id, label, pos, size, style, name );
} }
@@ -37,7 +53,21 @@ public:
const wxPoint &pos = wxDefaultPosition, const wxPoint &pos = wxDefaultPosition,
const wxSize &size = wxDefaultSize, const wxSize &size = wxDefaultSize,
long style = 0, long style = 0,
const wxString &name = wxStaticBoxNameStr ); const wxString &name = wxStaticBoxNameStr )
{
return DoCreate( parent, id, &label, NULL, pos, size, style, name );
}
bool Create( wxWindow *parent,
wxWindowID id,
wxWindow* label,
const wxPoint &pos = wxDefaultPosition,
const wxSize &size = wxDefaultSize,
long style = 0,
const wxString &name = wxStaticBoxNameStr )
{
return DoCreate( parent, id, NULL, label, pos, size, style, name );
}
virtual void SetLabel( const wxString &label ) wxOVERRIDE; virtual void SetLabel( const wxString &label ) wxOVERRIDE;
@@ -52,13 +82,39 @@ public:
virtual void AddChild( wxWindowBase *child ) wxOVERRIDE; virtual void AddChild( wxWindowBase *child ) wxOVERRIDE;
virtual void WXDestroyWithoutChildren() wxOVERRIDE;
protected: protected:
// Common part of all ctors.
void Init()
{
m_labelWin = NULL;
}
// Common implementation of both Create() overloads: exactly one of
// labelStr and labelWin parameters must be non-null.
bool DoCreate(wxWindow *parent,
wxWindowID id,
const wxString* labelStr,
wxWindow* labelWin,
const wxPoint& pos,
const wxSize& size,
long style,
const wxString& name);
virtual bool GTKWidgetNeedsMnemonic() const wxOVERRIDE; virtual bool GTKWidgetNeedsMnemonic() const wxOVERRIDE;
virtual void GTKWidgetDoSetMnemonic(GtkWidget* w) wxOVERRIDE; virtual void GTKWidgetDoSetMnemonic(GtkWidget* w) wxOVERRIDE;
void DoApplyWidgetStyle(GtkRcStyle *style) wxOVERRIDE; void DoApplyWidgetStyle(GtkRcStyle *style) wxOVERRIDE;
// If non-null, the window used as our label. This window is owned by the
// static box and will be deleted when it is.
wxWindow* m_labelWin;
wxDECLARE_DYNAMIC_CLASS(wxStaticBox); wxDECLARE_DYNAMIC_CLASS(wxStaticBox);
}; };
// Indicate that we have the ctor overload taking wxWindow as label.
#define wxHAS_WINDOW_LABEL_IN_STATIC_BOX
#endif // _WX_GTKSTATICBOX_H_ #endif // _WX_GTKSTATICBOX_H_

View File

@@ -84,6 +84,42 @@ public:
long style = 0, long style = 0,
const wxString& name = wxStaticBoxNameStr); const wxString& name = wxStaticBoxNameStr);
/**
Constructor for a static box using the given window as label.
This constructor takes a pointer to an arbitrary window (although
usually a wxCheckBox or a wxRadioButton) instead of just the usual text
label and puts this window at the top of the box at the place where the
label would be shown.
The @a label window must be a non-null, fully created window and will
become a child of this wxStaticBox, i.e. it will be owned by this
control and will be deleted when the wxStaticBox itself is deleted.
An example of creating a wxStaticBox with window as a label:
@code
void MyFrame::CreateControls()
{
wxPanel* panel = new wxPanel(this);
wxCheckBox* checkbox = new wxCheckBox(panel, wxID_ANY, "Box checkbox");
wxStaticBox* box = new wxStaticBox(panel, wxID_ANY, checkbox);
...
}
@endcode
Currently this constructor is only available in wxGTK, use
@c wxHAS_WINDOW_LABEL_IN_STATIC_BOX to check whether it can be used at
compile-time.
@since 3.1.1
*/
wxStaticBox(wxWindow* parent, wxWindowID id,
wxWindow* label,
const wxPoint& pos = wxDefaultPosition,
const wxSize& size = wxDefaultSize,
long style = 0,
const wxString& name = wxStaticBoxNameStr);
/** /**
Destructor, destroying the group box. Destructor, destroying the group box.
*/ */
@@ -97,5 +133,25 @@ public:
const wxPoint& pos = wxDefaultPosition, const wxPoint& pos = wxDefaultPosition,
const wxSize& size = wxDefaultSize, long style = 0, const wxSize& size = wxDefaultSize, long style = 0,
const wxString& name = wxStaticBoxNameStr); const wxString& name = wxStaticBoxNameStr);
};
/**
Creates the static box with the window as a label.
This method can only be called for an object created using its default
constructor.
See the constructor documentation for more details.
Currently this overload is only available in wxGTK, use
@c wxHAS_WINDOW_LABEL_IN_STATIC_BOX to check whether it can be used at
compile-time.
@since 3.1.1
*/
wxStaticBox(wxWindow* parent, wxWindowID id,
wxWindow* label,
const wxPoint& pos = wxDefaultPosition,
const wxSize& size = wxDefaultSize,
long style = 0,
const wxString& name = wxStaticBoxNameStr);
};

View File

@@ -116,6 +116,9 @@ public:
protected: protected:
// event handlers // event handlers
void OnCheckOrRadioBox(wxCommandEvent& event); void OnCheckOrRadioBox(wxCommandEvent& event);
#ifdef wxHAS_WINDOW_LABEL_IN_STATIC_BOX
void OnBoxCheckBox(wxCommandEvent& event);
#endif // wxHAS_WINDOW_LABEL_IN_STATIC_BOX
void OnButtonReset(wxCommandEvent& event); void OnButtonReset(wxCommandEvent& event);
void OnButtonBoxText(wxCommandEvent& event); void OnButtonBoxText(wxCommandEvent& event);
@@ -137,6 +140,9 @@ protected:
// the check/radio boxes for styles // the check/radio boxes for styles
wxCheckBox *m_chkVert, wxCheckBox *m_chkVert,
*m_chkGeneric, *m_chkGeneric,
#ifdef wxHAS_WINDOW_LABEL_IN_STATIC_BOX
*m_chkBoxWithCheck,
#endif // wxHAS_WINDOW_LABEL_IN_STATIC_BOX
*m_chkAutoResize, *m_chkAutoResize,
*m_chkEllipsize; *m_chkEllipsize;
@@ -207,6 +213,9 @@ StaticWidgetsPage::StaticWidgetsPage(WidgetsBookCtrl *book,
m_chkVert = m_chkVert =
m_chkAutoResize = m_chkAutoResize =
m_chkGeneric = m_chkGeneric =
#ifdef wxHAS_WINDOW_LABEL_IN_STATIC_BOX
m_chkBoxWithCheck =
#endif // wxHAS_WINDOW_LABEL_IN_STATIC_BOX
#if wxUSE_MARKUP #if wxUSE_MARKUP
m_chkGreen = m_chkGreen =
#endif // wxUSE_MARKUP #endif // wxUSE_MARKUP
@@ -243,6 +252,9 @@ void StaticWidgetsPage::CreateContent()
m_chkGeneric = CreateCheckBoxAndAddToSizer(sizerLeft, m_chkGeneric = CreateCheckBoxAndAddToSizer(sizerLeft,
"&Generic wxStaticText"); "&Generic wxStaticText");
#ifdef wxHAS_WINDOW_LABEL_IN_STATIC_BOX
m_chkBoxWithCheck = CreateCheckBoxAndAddToSizer(sizerLeft, "Checkable &box");
#endif // wxHAS_WINDOW_LABEL_IN_STATIC_BOX
m_chkVert = CreateCheckBoxAndAddToSizer(sizerLeft, "&Vertical line"); m_chkVert = CreateCheckBoxAndAddToSizer(sizerLeft, "&Vertical line");
m_chkAutoResize = CreateCheckBoxAndAddToSizer(sizerLeft, "&Fit to text"); m_chkAutoResize = CreateCheckBoxAndAddToSizer(sizerLeft, "&Fit to text");
sizerLeft->Add(5, 5, 0, wxGROW | wxALL, 5); // spacer sizerLeft->Add(5, 5, 0, wxGROW | wxALL, 5); // spacer
@@ -367,6 +379,9 @@ void StaticWidgetsPage::CreateContent()
void StaticWidgetsPage::Reset() void StaticWidgetsPage::Reset()
{ {
m_chkGeneric->SetValue(false); m_chkGeneric->SetValue(false);
#ifdef wxHAS_WINDOW_LABEL_IN_STATIC_BOX
m_chkBoxWithCheck->SetValue(false);
#endif // wxHAS_WINDOW_LABEL_IN_STATIC_BOX
m_chkVert->SetValue(false); m_chkVert->SetValue(false);
m_chkAutoResize->SetValue(true); m_chkAutoResize->SetValue(true);
m_chkEllipsize->SetValue(true); m_chkEllipsize->SetValue(true);
@@ -469,10 +484,28 @@ void StaticWidgetsPage::CreateStatic()
flagsText |= align; flagsText |= align;
flagsBox |= align; flagsBox |= align;
wxStaticBox *staticBox = new wxStaticBox(this, wxID_ANY, wxStaticBox *staticBox;
m_textBox->GetValue(), #ifdef wxHAS_WINDOW_LABEL_IN_STATIC_BOX
wxDefaultPosition, wxDefaultSize, if ( m_chkBoxWithCheck->GetValue() )
flagsBox); {
wxCheckBox* const label = new wxCheckBox(this, wxID_ANY,
m_textBox->GetValue());
label->Bind(wxEVT_CHECKBOX, &StaticWidgetsPage::OnBoxCheckBox, this);
staticBox = new wxStaticBox(this, wxID_ANY,
label,
wxDefaultPosition, wxDefaultSize,
flagsBox);
}
else // normal static box
#endif // wxHAS_WINDOW_LABEL_IN_STATIC_BOX
{
staticBox = new wxStaticBox(this, wxID_ANY,
m_textBox->GetValue(),
wxDefaultPosition, wxDefaultSize,
flagsBox);
}
m_sizerStatBox = new wxStaticBoxSizer(staticBox, isVert ? wxHORIZONTAL m_sizerStatBox = new wxStaticBoxSizer(staticBox, isVert ? wxHORIZONTAL
: wxVERTICAL); : wxVERTICAL);
@@ -559,6 +592,14 @@ void StaticWidgetsPage::OnCheckOrRadioBox(wxCommandEvent& event)
CreateStatic(); CreateStatic();
} }
#ifdef wxHAS_WINDOW_LABEL_IN_STATIC_BOX
void StaticWidgetsPage::OnBoxCheckBox(wxCommandEvent& event)
{
wxLogMessage("Box check box has been %schecked",
event.IsChecked() ? "": "un");
}
#endif // wxHAS_WINDOW_LABEL_IN_STATIC_BOX
void StaticWidgetsPage::OnButtonBoxText(wxCommandEvent& WXUNUSED(event)) void StaticWidgetsPage::OnButtonBoxText(wxCommandEvent& WXUNUSED(event))
{ {
m_sizerStatBox->GetStaticBox()->SetLabel(m_textBox->GetValue()); m_sizerStatBox->GetStaticBox()->SetLabel(m_textBox->GetValue());

View File

@@ -59,13 +59,14 @@ static gboolean expose_event(GtkWidget* widget, GdkEventExpose*, wxWindow*)
// wxStaticBox // wxStaticBox
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
bool wxStaticBox::Create( wxWindow *parent, bool wxStaticBox::DoCreate(wxWindow *parent,
wxWindowID id, wxWindowID id,
const wxString& label, const wxString* labelStr,
const wxPoint& pos, wxWindow* labelWin,
const wxSize& size, const wxPoint& pos,
long style, const wxSize& size,
const wxString& name ) long style,
const wxString& name)
{ {
if (!PreCreation( parent, pos, size ) || if (!PreCreation( parent, pos, size ) ||
!CreateBase( parent, id, pos, size, style, wxDefaultValidator, name )) !CreateBase( parent, id, pos, size, style, wxDefaultValidator, name ))
@@ -74,11 +75,41 @@ bool wxStaticBox::Create( wxWindow *parent,
return false; return false;
} }
m_widget = GTKCreateFrame(label); if ( labelStr )
g_object_ref(m_widget); {
m_widget = GTKCreateFrame(*labelStr);
// only base SetLabel needs to be called after GTKCreateFrame // only base SetLabel needs to be called after GTKCreateFrame
wxControl::SetLabel(label); wxControl::SetLabel(*labelStr);
}
else // Use the given window as the label.
{
wxCHECK_MSG( labelWin, false, wxS("Label window can't be null") );
GtkWidget* const labelWidget = labelWin->m_widget;
wxCHECK_MSG( labelWidget, false, wxS("Label window must be created") );
// The widget must not have any parent at GTK+ level or setting it as
// label widget would fail.
GtkWidget* const oldParent = gtk_widget_get_parent(labelWidget);
gtk_container_remove(GTK_CONTAINER(oldParent), labelWidget);
gtk_widget_unparent(labelWidget);
// It also should be our child at wx API level, but without being our
// child in wxGTK, i.e. it must not be added to the GtkFrame container,
// so we can't call Reparent() here (not even wxWindowBase version, as
// it still would end up in our overridden AddChild()), nor the normal
// AddChild() for the same reason.
labelWin->GetParent()->RemoveChild(labelWin);
wxWindowBase::AddChild(labelWin);
m_labelWin = labelWin;
m_widget = gtk_frame_new(NULL);
gtk_frame_set_label_widget(GTK_FRAME(m_widget), labelWidget);
}
g_object_ref(m_widget);
m_parent->DoAddChild( this ); m_parent->DoAddChild( this );
@@ -121,16 +152,38 @@ void wxStaticBox::AddChild( wxWindowBase *child )
wxStaticBoxBase::AddChild(child); wxStaticBoxBase::AddChild(child);
} }
void wxStaticBox::WXDestroyWithoutChildren()
{
// The label window doesn't count as our child, it's really a part of
// static box itself and it makes no sense to leave it alive when the box
// is destroyed, so do it even when it's supposed to be destroyed without
// destroying its children.
if ( m_labelWin )
{
// By deleting it here, we indirectly remove this window from the list
// of our children and hence prevent the base class version of this
// method from reparenting it and thus keeping it alive.
delete m_labelWin;
m_labelWin = NULL;
}
wxStaticBoxBase::WXDestroyWithoutChildren();
}
void wxStaticBox::SetLabel( const wxString& label ) void wxStaticBox::SetLabel( const wxString& label )
{ {
wxCHECK_RET( m_widget != NULL, wxT("invalid staticbox") ); wxCHECK_RET( m_widget != NULL, wxT("invalid staticbox") );
wxCHECK_RET( !m_labelWin, wxS("Doesn't make sense when using label window") );
GTKSetLabelForFrame(GTK_FRAME(m_widget), label); GTKSetLabelForFrame(GTK_FRAME(m_widget), label);
} }
void wxStaticBox::DoApplyWidgetStyle(GtkRcStyle *style) void wxStaticBox::DoApplyWidgetStyle(GtkRcStyle *style)
{ {
GTKFrameApplyWidgetStyle(GTK_FRAME(m_widget), style); GTKFrameApplyWidgetStyle(GTK_FRAME(m_widget), style);
if ( m_labelWin )
GTKDoApplyWidgetStyle(m_labelWin, style);
if (m_wxwindow) if (m_wxwindow)
GTKApplyStyle(m_wxwindow, style); GTKApplyStyle(m_wxwindow, style);