Add wxDataViewToggleRenderer::ShowAsRadio()

This allows showing radio buttons in wxDataViewCtrl easily and natively.

Notice that this approach, adding an extra function to the existing
renderer class instead of creating some new wxDataViewRadioRenderer (see
https://github.com/wxWidgets/wxWidgets/pull/809), was finally chosen
because it is simpler to implement and, more importantly, because it
will be more natural to generalize if/when we also add a 3-state
check/radio renderer.

Closes https://github.com/wxWidgets/wxWidgets/pull/853
This commit is contained in:
Vadim Zeitlin
2018-07-11 01:13:22 +02:00
parent 58832ce8d7
commit 03a13591b9
9 changed files with 111 additions and 5 deletions

View File

@@ -94,6 +94,7 @@ All:
All (GUI):
- Add wxDataViewToggleRenderer::ShowAsRadio().
- Improve stock items consistency and aesthetics (dhowland).
- Fix bug with missing items in overflowing AUI toolbar (Maarten Bent).
- Revert to left-aligning wxSpinCtrl contents by default.

View File

@@ -132,6 +132,8 @@ public:
wxDataViewCellMode mode = wxDATAVIEW_CELL_INERT,
int align = wxDVR_DEFAULT_ALIGNMENT );
void ShowAsRadio() { m_radio = true; }
virtual bool SetValue( const wxVariant &value ) wxOVERRIDE;
virtual bool GetValue( wxVariant &value ) const wxOVERRIDE;
#if wxUSE_ACCESSIBILITY
@@ -149,6 +151,7 @@ public:
const wxMouseEvent *mouseEvent) wxOVERRIDE;
private:
bool m_toggle;
bool m_radio;
protected:
wxDECLARE_DYNAMIC_CLASS_NO_COPY(wxDataViewToggleRenderer);

View File

@@ -107,6 +107,8 @@ public:
wxDataViewCellMode mode = wxDATAVIEW_CELL_INERT,
int align = wxDVR_DEFAULT_ALIGNMENT );
void ShowAsRadio();
bool SetValue( const wxVariant &value ) wxOVERRIDE;
bool GetValue( wxVariant &value ) const wxOVERRIDE;

View File

@@ -198,6 +198,8 @@ public:
wxDataViewCellMode mode = wxDATAVIEW_CELL_INERT,
int align = wxDVR_DEFAULT_ALIGNMENT);
void ShowAsRadio();
virtual bool MacRender();
virtual void OSXOnCellChanged(NSObject *value,

View File

@@ -2272,6 +2272,9 @@ public:
This class is used by wxDataViewCtrl to render toggle controls.
Note that "toggles" can be represented either by check boxes (default) or
radio buttons.
@see wxDataViewCheckIconTextRenderer
@library{wxadv}
@category{dvc}
@@ -2292,6 +2295,24 @@ public:
wxDataViewToggleRenderer(const wxString& varianttype = GetDefaultType(),
wxDataViewCellMode mode = wxDATAVIEW_CELL_INERT,
int align = wxDVR_DEFAULT_ALIGNMENT);
/**
Switch to using radiobutton-like appearance instead of the default
checkbox-like one.
By default, this renderer uses checkboxes to represent the boolean
values, but using this method its appearance can be changed to use
radio buttons instead.
Notice that only the appearance is changed, the cells don't really
start behaving as radio buttons after a call to ShowAsRadio(), i.e. the
application code also needs to react to selecting one of the cells
shown by this renderer and clearing all the other ones in the same row
or column to actually implement radio button-like behaviour.
@since 3.1.2
*/
void ShowAsRadio();
};

View File

@@ -108,6 +108,10 @@ private:
void OnPrependList(wxCommandEvent& event);
void OnDeleteList(wxCommandEvent& event);
// Third (wxDataViewListCtrl) page.
void OnListValueChanged(wxDataViewEvent& event);
// Fourth page.
void OnDeleteTreeItem(wxCommandEvent& event);
void OnDeleteAllTreeItems(wxCommandEvent& event);
@@ -176,6 +180,9 @@ private:
wxLog *m_logOld;
private:
// Flag used by OnListValueChanged(), see there.
bool m_eventFromProgram;
wxDECLARE_EVENT_TABLE();
};
@@ -450,6 +457,8 @@ MyFrame::MyFrame(wxFrame *frame, const wxString &title, int x, int y, int w, int
m_ctrl[2] = NULL;
m_ctrl[3] = NULL;
m_eventFromProgram = false;
SetIcon(wxICON(sample));
@@ -759,6 +768,17 @@ void MyFrame::BuildDataViewCtrl(wxPanel* parent, unsigned int nPanel, unsigned l
page2_model->DecRef();
lc->AppendToggleColumn( "Toggle" );
// We're not limited to convenience column-appending functions, it
// can also be done fully manually, which allows us to customize
// the renderer being used.
wxDataViewToggleRenderer* const rendererRadio =
new wxDataViewToggleRenderer("bool", wxDATAVIEW_CELL_ACTIVATABLE);
rendererRadio->ShowAsRadio();
wxDataViewColumn* const colRadio =
new wxDataViewColumn("Radio", rendererRadio, 1);
lc->AppendColumn(colRadio, "bool");
lc->AppendTextColumn( "Text" );
lc->AppendProgressColumn( "Progress" );
@@ -767,11 +787,14 @@ void MyFrame::BuildDataViewCtrl(wxPanel* parent, unsigned int nPanel, unsigned l
{
data.clear();
data.push_back( (i%3) == 0 );
data.push_back( i == 7 ); // select a single (random) radio item
data.push_back( wxString::Format("row %d", i) );
data.push_back( long(5*i) );
lc->AppendItem( data );
}
lc->Bind(wxEVT_DATAVIEW_ITEM_VALUE_CHANGED, &MyFrame::OnListValueChanged, this);
}
break;
@@ -1390,6 +1413,48 @@ void MyFrame::OnShowAttributes(wxCommandEvent& WXUNUSED(event))
m_attributes->SetHidden(false);
}
// ----------------------------------------------------------------------------
// MyFrame - event handlers for the third (wxDataViewListCtrl) page
// ----------------------------------------------------------------------------
void MyFrame::OnListValueChanged(wxDataViewEvent& event)
{
// Ignore changes coming from our own SetToggleValue() calls below.
if ( m_eventFromProgram )
{
m_eventFromProgram = false;
return;
}
wxDataViewListCtrl* const lc = static_cast<wxDataViewListCtrl*>(m_ctrl[2]);
const int columnToggle = 1;
// Handle selecting a radio button by unselecting all the other ones.
if ( event.GetColumn() == columnToggle )
{
const int rowChanged = lc->ItemToRow(event.GetItem());
if ( lc->GetToggleValue(rowChanged, columnToggle) )
{
for ( int row = 0; row < lc->GetItemCount(); ++row )
{
if ( row != rowChanged )
{
m_eventFromProgram = true;
lc->SetToggleValue(false, row, columnToggle);
}
}
}
else // The item was cleared.
{
// Explicitly check it back, we want to always have exactly one
// checked radio item in this column.
m_eventFromProgram = true;
lc->SetToggleValue(true, rowChanged, columnToggle);
}
}
}
// ----------------------------------------------------------------------------
// MyFrame - event handlers for the fourth page
// ----------------------------------------------------------------------------

View File

@@ -1260,6 +1260,7 @@ wxDataViewToggleRenderer::wxDataViewToggleRenderer( const wxString &varianttype,
wxDataViewRenderer( varianttype, mode, align )
{
m_toggle = false;
m_radio = false;
}
bool wxDataViewToggleRenderer::SetValue( const wxVariant &value )
@@ -1301,11 +1302,12 @@ bool wxDataViewToggleRenderer::Render( wxRect cell, wxDC *dc, int WXUNUSED(state
size.IncTo(GetSize());
cell.SetSize(size);
wxRendererNative::Get().DrawCheckBox(
GetOwner()->GetOwner(),
*dc,
cell,
flags );
wxRendererNative& renderer = wxRendererNative::Get();
wxWindow* const win = GetOwner()->GetOwner();
if ( m_radio )
renderer.DrawRadioBitmap(win, *dc, cell, flags);
else
renderer.DrawCheckBox(win, *dc, cell, flags);
return true;
}

View File

@@ -2539,6 +2539,11 @@ wxDataViewToggleRenderer::wxDataViewToggleRenderer( const wxString &varianttype,
SetAlignment(align);
}
void wxDataViewToggleRenderer::ShowAsRadio()
{
gtk_cell_renderer_toggle_set_radio(GTK_CELL_RENDERER_TOGGLE(m_renderer), TRUE);
}
bool wxDataViewToggleRenderer::SetValue( const wxVariant &value )
{
bool tmp = value;

View File

@@ -3326,6 +3326,11 @@ wxDataViewToggleRenderer::wxDataViewToggleRenderer(const wxString& varianttype,
[cell release];
}
void wxDataViewToggleRenderer::ShowAsRadio()
{
[GetNativeData()->GetItemCell() setButtonType:NSRadioButton];
}
bool wxDataViewToggleRenderer::MacRender()
{
[GetNativeData()->GetItemCell() setIntValue:GetValue().GetLong()];