Make wxDataViewCheckIconTextRenderer class public

Export this class, which was only used internally by wxTreeListCtrl
before, so that user code can use it for its own columns with custom
wxDataViewCtrl models.
This commit is contained in:
Vadim Zeitlin
2017-10-02 22:28:28 +02:00
parent 9662be097d
commit f0de65fb98
5 changed files with 357 additions and 250 deletions

View File

@@ -136,6 +136,7 @@ All (GUI):
- Fix calculating point position in wxDataViewCtrl::HitTest(). - Fix calculating point position in wxDataViewCtrl::HitTest().
- Fix position of the rectangle returned by wxDataViewCtrl::GetItemRect(). - Fix position of the rectangle returned by wxDataViewCtrl::GetItemRect().
- Add wxDataViewRenderer::GetAccessibleDescription(). - Add wxDataViewRenderer::GetAccessibleDescription().
- Add wxDataViewCheckIconTextRenderer class.
- Improve wxImage::Scale() handling of pixels with alpha channel (Tim Kosse). - Improve wxImage::Scale() handling of pixels with alpha channel (Tim Kosse).
- Fix parsing of RGBA strings in wxColour (Laurent Poujoulat). - Fix parsing of RGBA strings in wxColour (Laurent Poujoulat).
- Refactor code in wxQuantize() for MSVC to avoid crash. - Refactor code in wxQuantize() for MSVC to avoid crash.

View File

@@ -77,6 +77,32 @@ private:
DECLARE_VARIANT_OBJECT_EXPORTED(wxDataViewIconText, WXDLLIMPEXP_ADV) DECLARE_VARIANT_OBJECT_EXPORTED(wxDataViewIconText, WXDLLIMPEXP_ADV)
// ----------------------------------------------------------------------------
// wxDataViewCheckIconText: value class used by wxDataViewCheckIconTextRenderer
// ----------------------------------------------------------------------------
class wxDataViewCheckIconText : public wxDataViewIconText
{
public:
wxDataViewCheckIconText(const wxString& text = wxString(),
const wxIcon& icon = wxNullIcon,
wxCheckBoxState checkedState = wxCHK_UNDETERMINED)
: wxDataViewIconText(text, icon),
m_checkedState(checkedState)
{
}
wxCheckBoxState GetCheckedState() const { return m_checkedState; }
void SetCheckedState(wxCheckBoxState state) { m_checkedState = state; }
private:
wxCheckBoxState m_checkedState;
wxDECLARE_DYNAMIC_CLASS(wxDataViewCheckIconText);
};
DECLARE_VARIANT_OBJECT_EXPORTED(wxDataViewCheckIconText, WXDLLIMPEXP_ADV)
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// wxDataViewRendererBase // wxDataViewRendererBase
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
@@ -509,6 +535,61 @@ typedef wxDataViewTextRenderer wxDataViewDateRenderer;
#endif // generic or GTK+ versions #endif // generic or GTK+ versions
// ----------------------------------------------------------------------------
// wxDataViewCheckIconTextRenderer: 3-state checkbox + text + optional icon
// ----------------------------------------------------------------------------
class WXDLLIMPEXP_ADV wxDataViewCheckIconTextRenderer
: public wxDataViewCustomRenderer
{
public:
static wxString GetDefaultType() { return wxS("wxDataViewCheckIconText"); }
explicit wxDataViewCheckIconTextRenderer
(
wxDataViewCellMode mode = wxDATAVIEW_CELL_ACTIVATABLE,
int align = wxDVR_DEFAULT_ALIGNMENT
);
// This renderer can always display the 3rd ("indeterminate") checkbox
// state if the model contains cells with wxCHK_UNDETERMINED value, but it
// doesn't allow the user to set it by default. Call this method to allow
// this to happen.
void Allow3rdStateForUser(bool allow = true);
virtual bool SetValue(const wxVariant& value) wxOVERRIDE;
virtual bool GetValue(wxVariant& value) const wxOVERRIDE;
#if wxUSE_ACCESSIBILITY
virtual wxString GetAccessibleDescription() const wxOVERRIDE;
#endif // wxUSE_ACCESSIBILITY
virtual wxSize GetSize() const wxOVERRIDE;
virtual bool Render(wxRect cell, wxDC* dc, int state) wxOVERRIDE;
virtual bool ActivateCell(const wxRect& cell,
wxDataViewModel *model,
const wxDataViewItem & item,
unsigned int col,
const wxMouseEvent *mouseEvent) wxOVERRIDE;
private:
wxSize GetCheckSize() const;
// Just some arbitrary constants defining margins, in pixels.
enum
{
MARGIN_CHECK_ICON = 3,
MARGIN_ICON_TEXT = 4
};
wxDataViewCheckIconText m_value;
bool m_allow3rdStateForUser;
wxDECLARE_DYNAMIC_CLASS_NO_COPY(wxDataViewCheckIconTextRenderer);
};
// this class is obsolete, its functionality was merged in // this class is obsolete, its functionality was merged in
// wxDataViewTextRenderer itself now, don't use it any more // wxDataViewTextRenderer itself now, don't use it any more
#define wxDataViewTextRendererAttr wxDataViewTextRenderer #define wxDataViewTextRendererAttr wxDataViewTextRenderer

View File

@@ -1797,6 +1797,7 @@ enum wxDataViewCellRenderState
There is a number of ready-to-use renderers provided: There is a number of ready-to-use renderers provided:
- wxDataViewTextRenderer, - wxDataViewTextRenderer,
- wxDataViewIconTextRenderer, - wxDataViewIconTextRenderer,
- wxDataViewCheckIconTextRenderer,
- wxDataViewToggleRenderer, - wxDataViewToggleRenderer,
- wxDataViewProgressRenderer, - wxDataViewProgressRenderer,
- wxDataViewBitmapRenderer, - wxDataViewBitmapRenderer,
@@ -2059,6 +2060,7 @@ public:
wxDataViewIconText can be converted to and from a wxVariant using the left wxDataViewIconText can be converted to and from a wxVariant using the left
shift operator. shift operator.
@see wxDataViewCheckIconTextRenderer
@library{wxadv} @library{wxadv}
@category{dvc} @category{dvc}
*/ */
@@ -2081,6 +2083,58 @@ public:
}; };
/**
This renderer class shows a checkbox in addition to the icon and text shown
by the base class and also allows the user to toggle this checkbox.
By default this class doesn't allow the user to put the checkbox into the
third, i.e. indeterminate, state, even though it can display the state if
the program returns the corresponding value from the associated model. Call
Allow3rdStateForUser() explicitly if the user should be able to select the
3rd state interactively too.
This class is used internally by wxTreeListCtrl, and can be seen in action
in the corresponding sample.
@see wxDataViewIconTextRenderer, wxDataViewToggleRenderer
@library{wxadv}
@category{dvc}
@since 3.1.1
*/
class wxDataViewCheckIconTextRenderer : public wxDataViewRenderer
{
public:
static wxString GetDefaultType() { return wxS("wxDataViewCheckIconText"); }
/**
Create a new renderer.
By default the renderer is activatable, i.e. allows the user to toggle
the checkbox.
*/
explicit wxDataViewCheckIconTextRenderer
(
wxDataViewCellMode mode = wxDATAVIEW_CELL_ACTIVATABLE,
int align = wxDVR_DEFAULT_ALIGNMENT
);
/**
Allow the user to interactively select the 3rd state for the items
rendered by this object.
As described in the class overview, this renderer can always display
the 3rd ("indeterminate") checkbox state if the model contains cells
with wxCHK_UNDETERMINED value, but it doesn't allow the user to set it
by default. Call this method to allow this to happen.
@param allow If @true, interactively clicking a checked cell switches
it to the indeterminate value and clicking it again unchecks it.
If @false, clicking a checked cell switches to the unchecked value,
skipping the indeterminate one.
*/
void Allow3rdStateForUser(bool allow = true);
};
/** /**
@class wxDataViewProgressRenderer @class wxDataViewProgressRenderer
@@ -2140,6 +2194,7 @@ public:
This class is used by wxDataViewCtrl to render toggle controls. This class is used by wxDataViewCtrl to render toggle controls.
@see wxDataViewCheckIconTextRenderer
@library{wxadv} @library{wxadv}
@category{dvc} @category{dvc}
*/ */

View File

@@ -1929,6 +1929,200 @@ wxSize wxDataViewDateRenderer::GetSize() const
#endif // (defined(wxHAS_GENERIC_DATAVIEWCTRL) || defined(__WXGTK__)) && wxUSE_DATEPICKCTRL #endif // (defined(wxHAS_GENERIC_DATAVIEWCTRL) || defined(__WXGTK__)) && wxUSE_DATEPICKCTRL
// ----------------------------------------------------------------------------
// wxDataViewCheckIconTextRenderer implementation
// ----------------------------------------------------------------------------
IMPLEMENT_VARIANT_OBJECT_EXPORTED(wxDataViewCheckIconText, WXDLLIMPEXP_ADV)
wxIMPLEMENT_CLASS(wxDataViewCheckIconText, wxDataViewIconText);
wxIMPLEMENT_CLASS(wxDataViewCheckIconTextRenderer, wxDataViewRenderer);
wxDataViewCheckIconTextRenderer::wxDataViewCheckIconTextRenderer
(
wxDataViewCellMode mode,
int align
)
: wxDataViewCustomRenderer(GetDefaultType(), mode, align)
{
m_allow3rdStateForUser = false;
}
void wxDataViewCheckIconTextRenderer::Allow3rdStateForUser(bool allow)
{
m_allow3rdStateForUser = allow;
}
bool wxDataViewCheckIconTextRenderer::SetValue(const wxVariant& value)
{
m_value << value;
return true;
}
bool wxDataViewCheckIconTextRenderer::GetValue(wxVariant& value) const
{
value << m_value;
return true;
}
#if wxUSE_ACCESSIBILITY
wxString wxDataViewCheckIconTextRenderer::GetAccessibleDescription() const
{
wxString text = m_value.GetText();
if ( !text.empty() )
{
text += wxS(" ");
}
switch ( m_value.GetCheckedState() )
{
case wxCHK_CHECKED:
/* TRANSLATORS: Checkbox state name */
text += _("checked");
break;
case wxCHK_UNCHECKED:
/* TRANSLATORS: Checkbox state name */
text += _("unchecked");
break;
case wxCHK_UNDETERMINED:
/* TRANSLATORS: Checkbox state name */
text += _("undetermined");
break;
}
return text;
}
#endif // wxUSE_ACCESSIBILITY
wxSize wxDataViewCheckIconTextRenderer::GetSize() const
{
wxSize size = GetCheckSize();
size.x += MARGIN_CHECK_ICON;
if ( m_value.GetIcon().IsOk() )
{
const wxSize sizeIcon = m_value.GetIcon().GetSize();
if ( sizeIcon.y > size.y )
size.y = sizeIcon.y;
size.x += sizeIcon.x + MARGIN_ICON_TEXT;
}
wxString text = m_value.GetText();
if ( text.empty() )
text = "Dummy";
const wxSize sizeText = GetTextExtent(text);
if ( sizeText.y > size.y )
size.y = sizeText.y;
size.x += sizeText.x;
return size;
}
bool wxDataViewCheckIconTextRenderer::Render(wxRect cell, wxDC* dc, int state)
{
// Draw the checkbox first.
int renderFlags = 0;
switch ( m_value.GetCheckedState() )
{
case wxCHK_UNCHECKED:
break;
case wxCHK_CHECKED:
renderFlags |= wxCONTROL_CHECKED;
break;
case wxCHK_UNDETERMINED:
renderFlags |= wxCONTROL_UNDETERMINED;
break;
}
if ( state & wxDATAVIEW_CELL_PRELIT )
renderFlags |= wxCONTROL_CURRENT;
const wxSize sizeCheck = GetCheckSize();
wxRect rectCheck(cell.GetPosition(), sizeCheck);
rectCheck = rectCheck.CentreIn(cell, wxVERTICAL);
wxRendererNative::Get().DrawCheckBox
(
GetView(), *dc, rectCheck, renderFlags
);
// Then the icon, if any.
int xoffset = sizeCheck.x + MARGIN_CHECK_ICON;
const wxIcon& icon = m_value.GetIcon();
if ( icon.IsOk() )
{
const wxSize sizeIcon = icon.GetSize();
wxRect rectIcon(cell.GetPosition(), sizeIcon);
rectIcon.x += xoffset;
rectIcon = rectIcon.CentreIn(cell, wxVERTICAL);
dc->DrawIcon(icon, rectIcon.GetPosition());
xoffset += sizeIcon.x + MARGIN_ICON_TEXT;
}
// Finally the text.
RenderText(m_value.GetText(), xoffset, cell, dc, state);
return true;
}
bool
wxDataViewCheckIconTextRenderer::ActivateCell(const wxRect& WXUNUSED(cell),
wxDataViewModel *model,
const wxDataViewItem & item,
unsigned int col,
const wxMouseEvent *mouseEvent)
{
if ( mouseEvent )
{
if ( !wxRect(GetCheckSize()).Contains(mouseEvent->GetPosition()) )
return false;
}
// If the 3rd state is user-settable then the cycle is
// unchecked->checked->undetermined.
wxCheckBoxState checkedState = m_value.GetCheckedState();
switch ( checkedState )
{
case wxCHK_CHECKED:
checkedState = m_allow3rdStateForUser ? wxCHK_UNDETERMINED
: wxCHK_UNCHECKED;
break;
case wxCHK_UNDETERMINED:
// Whether 3rd state is user-settable or not, the next state is
// unchecked.
checkedState = wxCHK_UNCHECKED;
break;
case wxCHK_UNCHECKED:
checkedState = wxCHK_CHECKED;
break;
}
m_value.SetCheckedState(checkedState);
wxVariant value;
value << m_value;
model->ChangeValue(value, item, col);
return true;
}
wxSize wxDataViewCheckIconTextRenderer::GetCheckSize() const
{
return wxRendererNative::Get().GetCheckBoxSize(GetView());
}
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// wxDataViewListStore // wxDataViewListStore
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------

View File

@@ -364,7 +364,6 @@ public:
void SetItemData(Node* item, wxClientData* data); void SetItemData(Node* item, wxClientData* data);
void CheckItem(Node* item, wxCheckBoxState checkedState); void CheckItem(Node* item, wxCheckBoxState checkedState);
void ToggleItem(wxDataViewItem item);
// Implement the base class pure virtual methods. // Implement the base class pure virtual methods.
@@ -403,214 +402,6 @@ private:
bool m_isFlat; bool m_isFlat;
}; };
// ============================================================================
// wxDataViewCheckIconText[Renderer]: special renderer for our first column.
// ============================================================================
// Currently this class is private but it could be extracted and made part of
// public API later as could be used directly with wxDataViewCtrl as well.
namespace
{
const char* CHECK_ICON_TEXT_TYPE = "wxDataViewCheckIconText";
// The value used by wxDataViewCheckIconTextRenderer
class wxDataViewCheckIconText : public wxDataViewIconText
{
public:
wxDataViewCheckIconText(const wxString& text = wxString(),
const wxIcon& icon = wxNullIcon,
wxCheckBoxState checkedState = wxCHK_UNDETERMINED)
: wxDataViewIconText(text, icon),
m_checkedState(checkedState)
{
}
wxDataViewCheckIconText(const wxDataViewCheckIconText& other)
: wxDataViewIconText(other),
m_checkedState(other.m_checkedState)
{
}
// There is no encapsulation anyhow, so just expose this field directly.
wxCheckBoxState m_checkedState;
private:
wxDECLARE_DYNAMIC_CLASS(wxDataViewCheckIconText);
};
wxIMPLEMENT_DYNAMIC_CLASS(wxDataViewCheckIconText, wxDataViewIconText);
DECLARE_VARIANT_OBJECT(wxDataViewCheckIconText)
IMPLEMENT_VARIANT_OBJECT(wxDataViewCheckIconText)
class wxDataViewCheckIconTextRenderer : public wxDataViewCustomRenderer
{
public:
wxDataViewCheckIconTextRenderer()
: wxDataViewCustomRenderer(CHECK_ICON_TEXT_TYPE,
wxDATAVIEW_CELL_ACTIVATABLE)
{
}
virtual bool SetValue(const wxVariant& value) wxOVERRIDE
{
m_value << value;
return true;
}
virtual bool GetValue(wxVariant& WXUNUSED(value)) const wxOVERRIDE
{
return false;
}
#if wxUSE_ACCESSIBILITY
virtual wxString GetAccessibleDescription() const wxOVERRIDE
{
wxString text = m_value.GetText();
if ( !text.empty() )
{
text += wxS(" ");
}
switch ( m_value.m_checkedState )
{
case wxCHK_CHECKED:
/* TRANSLATORS: Checkbox state name */
text += _("checked");
break;
case wxCHK_UNCHECKED:
/* TRANSLATORS: Checkbox state name */
text += _("unchecked");
break;
case wxCHK_UNDETERMINED:
/* TRANSLATORS: Checkbox state name */
text += _("undetermined");
break;
}
return text;
}
#endif // wxUSE_ACCESSIBILITY
wxSize GetSize() const wxOVERRIDE
{
wxSize size = GetCheckSize();
size.x += MARGIN_CHECK_ICON;
if ( m_value.GetIcon().IsOk() )
{
const wxSize sizeIcon = m_value.GetIcon().GetSize();
if ( sizeIcon.y > size.y )
size.y = sizeIcon.y;
size.x += sizeIcon.x + MARGIN_ICON_TEXT;
}
wxString text = m_value.GetText();
if ( text.empty() )
text = "Dummy";
const wxSize sizeText = GetTextExtent(text);
if ( sizeText.y > size.y )
size.y = sizeText.y;
size.x += sizeText.x;
return size;
}
virtual bool Render(wxRect cell, wxDC* dc, int state) wxOVERRIDE
{
// Draw the checkbox first.
int renderFlags = 0;
switch ( m_value.m_checkedState )
{
case wxCHK_UNCHECKED:
break;
case wxCHK_CHECKED:
renderFlags |= wxCONTROL_CHECKED;
break;
case wxCHK_UNDETERMINED:
renderFlags |= wxCONTROL_UNDETERMINED;
break;
}
if ( state & wxDATAVIEW_CELL_PRELIT )
renderFlags |= wxCONTROL_CURRENT;
const wxSize sizeCheck = GetCheckSize();
wxRect rectCheck(cell.GetPosition(), sizeCheck);
rectCheck = rectCheck.CentreIn(cell, wxVERTICAL);
wxRendererNative::Get().DrawCheckBox
(
GetView(), *dc, rectCheck, renderFlags
);
// Then the icon, if any.
int xoffset = sizeCheck.x + MARGIN_CHECK_ICON;
const wxIcon& icon = m_value.GetIcon();
if ( icon.IsOk() )
{
const wxSize sizeIcon = icon.GetSize();
wxRect rectIcon(cell.GetPosition(), sizeIcon);
rectIcon.x += xoffset;
rectIcon = rectIcon.CentreIn(cell, wxVERTICAL);
dc->DrawIcon(icon, rectIcon.GetPosition());
xoffset += sizeIcon.x + MARGIN_ICON_TEXT;
}
// Finally the text.
RenderText(m_value.GetText(), xoffset, cell, dc, state);
return true;
}
// Event handlers toggling the items checkbox if it was clicked.
virtual bool ActivateCell(const wxRect& WXUNUSED(cell),
wxDataViewModel *model,
const wxDataViewItem & item,
unsigned int WXUNUSED(col),
const wxMouseEvent *mouseEvent) wxOVERRIDE
{
if ( mouseEvent )
{
if ( !wxRect(GetCheckSize()).Contains(mouseEvent->GetPosition()) )
return false;
}
static_cast<wxTreeListModel*>(model)->ToggleItem(item);
return true;
}
protected:
wxSize GetCheckSize() const
{
return wxRendererNative::Get().GetCheckBoxSize(GetView());
}
private:
// Just some arbitrary constants defining margins, in pixels.
enum
{
MARGIN_CHECK_ICON = 3,
MARGIN_ICON_TEXT = 4
};
wxDataViewCheckIconText m_value;
};
} // anonymous namespace
// ============================================================================ // ============================================================================
// wxTreeListModel implementation // wxTreeListModel implementation
// ============================================================================ // ============================================================================
@@ -837,40 +628,6 @@ void wxTreeListModel::CheckItem(Node* item, wxCheckBoxState checkedState)
ItemChanged(ToDVI(item)); ItemChanged(ToDVI(item));
} }
void wxTreeListModel::ToggleItem(wxDataViewItem dvi)
{
Node* const item = FromDVI(dvi);
wxCHECK_RET( item, "Invalid item" );
const wxCheckBoxState stateOld = item->m_checkedState;
// If the 3rd state is user-settable then the cycle is
// unchecked->checked->undetermined.
switch ( stateOld )
{
case wxCHK_CHECKED:
item->m_checkedState = m_treelist->HasFlag(wxTL_USER_3STATE)
? wxCHK_UNDETERMINED
: wxCHK_UNCHECKED;
break;
case wxCHK_UNDETERMINED:
// Whether 3rd state is user-settable or not, the next state is
// unchecked.
item->m_checkedState = wxCHK_UNCHECKED;
break;
case wxCHK_UNCHECKED:
item->m_checkedState = wxCHK_CHECKED;
break;
}
ItemChanged(ToDVI(item));
m_treelist->OnItemToggled(item, stateOld);
}
unsigned wxTreeListModel::GetColumnCount() const unsigned wxTreeListModel::GetColumnCount() const
{ {
return m_numColumns; return m_numColumns;
@@ -881,8 +638,8 @@ wxString wxTreeListModel::GetColumnType(unsigned col) const
if ( col == 0 ) if ( col == 0 )
{ {
return m_treelist->HasFlag(wxTL_CHECKBOX) return m_treelist->HasFlag(wxTL_CHECKBOX)
? wxS("wxDataViewCheckIconText") ? wxDataViewCheckIconTextRenderer::GetDefaultType()
: wxS("wxDataViewIconText"); : wxDataViewIconTextRenderer::GetDefaultType();
} }
else // All the other columns contain just text. else // All the other columns contain just text.
{ {
@@ -928,12 +685,26 @@ wxTreeListModel::GetValue(wxVariant& variant,
} }
bool bool
wxTreeListModel::SetValue(const wxVariant& WXUNUSED(variant), wxTreeListModel::SetValue(const wxVariant& variant,
const wxDataViewItem& WXUNUSED(item), const wxDataViewItem& item,
unsigned WXUNUSED(col)) unsigned WXUNUSED(col))
{ {
// We are not editable currently. Node* const node = FromDVI(item);
return false;
wxCHECK_MSG( item, false, "Invalid item" );
const wxCheckBoxState stateOld = node->m_checkedState;
// We don't allow changing anything but the checked state currently, yet we
// still get the full wxVariant containing the text and the icon as well,
// so we need to extract just the part we're interested in from it first.
wxDataViewCheckIconText value;
value << variant;
node->m_checkedState = value.GetCheckedState();
m_treelist->OnItemToggled(node, stateOld);
return true;
} }
wxDataViewItem wxTreeListModel::GetParent(const wxDataViewItem& item) const wxDataViewItem wxTreeListModel::GetParent(const wxDataViewItem& item) const
@@ -1122,7 +893,12 @@ wxTreeListCtrl::DoInsertColumn(const wxString& title,
if ( HasFlag(wxTL_CHECKBOX) ) if ( HasFlag(wxTL_CHECKBOX) )
{ {
// Use our custom renderer to show the checkbox. // Use our custom renderer to show the checkbox.
renderer = new wxDataViewCheckIconTextRenderer; wxDataViewCheckIconTextRenderer* const
rendererCheckIconText = new wxDataViewCheckIconTextRenderer;
if ( HasFlag(wxTL_USER_3STATE) )
rendererCheckIconText->Allow3rdStateForUser();
renderer = rendererCheckIconText;
} }
else // We still need a special renderer to show the icons. else // We still need a special renderer to show the icons.
{ {