void SetOwner( wxDataViewColumn *owner ) { m_owner = owner; }
wxDataViewColumn* GetOwner() const { return m_owner; }
- // renderer properties:
+ // renderer value and attributes: SetValue() and SetAttr() are called
+ // before a cell is rendered using this renderer
+ virtual bool SetValue(const wxVariant& value) = 0;
+ virtual bool GetValue(wxVariant& value) const = 0;
- virtual bool SetValue( const wxVariant& WXUNUSED(value) ) = 0;
- virtual bool GetValue( wxVariant& WXUNUSED(value) ) const = 0;
+ virtual void SetAttr(const wxDataViewItemAttr& WXUNUSED(attr)) { }
wxString GetVariantType() const { return m_variantType; }
+ // renderer properties:
virtual void SetMode( wxDataViewCellMode mode ) = 0;
virtual wxDataViewCellMode GetMode() const = 0;
}
+ // Render the item using the current value (returned by GetValue()).
+ virtual bool Render(wxRect cell, wxDC *dc, int state) = 0;
+
+ // Return the size of the item appropriate to its current value.
+ virtual wxSize GetSize() const = 0;
+
// Define virtual function which are called when the item is activated
// (double-clicked or Enter is pressed on it), clicked or the user starts
// to drag it: by default they all simply return false indicating that the
{ return false; }
+ // Helper which can be used by Render() implementation in the derived
+ // classes: it will draw the text in the same manner as the standard
+ // renderers do.
+ virtual void RenderText(const wxString& text,
+ int xoffset,
+ wxRect cell,
+ wxDC *dc,
+ int state);
+
+
+ // Override the base class virtual method to simply store the attribute so
+ // that it can be accessed using GetAttr() from Render() if needed.
+ virtual void SetAttr(const wxDataViewItemAttr& attr) { m_attr = attr; }
+ const wxDataViewItemAttr& GetAttr() const { return m_attr; }
+
+
+ // Implementation only from now on
+
+ // Retrieve the DC to use for drawing. This is implemented in derived
+ // platform-specific classes.
+ virtual wxDC *GetDC() = 0;
+
+ // Prepare DC to use attributes and call Render().
+ void WXCallRender(wxRect rect, wxDC *dc, int state);
+
private:
+ wxDataViewItemAttr m_attr;
+
wxDECLARE_NO_COPY_CLASS(wxDataViewCustomRendererBase);
};
int align = wxDVR_DEFAULT_ALIGNMENT );
virtual ~wxDataViewRenderer();
- // these methods are used to draw the cell contents, Render() doesn't care
- // about the attributes while RenderWithAttr() does -- override it if you
- // want to take the attributes defined for this cell into account, otherwise
- // overriding Render() is enough
- virtual bool Render( wxRect cell, wxDC *dc, int state ) = 0;
-
- // NB: RenderWithAttr() also has more standard parameter order and types
- virtual bool
- RenderWithAttr(wxDC& dc,
- const wxRect& rect,
- int align, // combination of horizontal and vertical
- const wxDataViewItemAttr *attr, // may be NULL if none
- int state);
-
- virtual wxSize GetSize() const = 0;
virtual wxDC *GetDC();
- // Draw the text using the provided attributes
- void RenderText(wxDC& dc,
- const wxRect& rect,
- int align,
- const wxString& text,
- const wxDataViewItemAttr *attr, // may be NULL if none
- int state,
- int xoffset = 0);
-
- // Overload using standard attributes
- void RenderText(const wxString& text,
- int xoffset,
- wxRect cell,
- wxDC *dc,
- int state)
- {
- RenderText(*dc, cell, wxALIGN_NOT, text, NULL, state, xoffset);
- }
-
-
virtual void SetAlignment( int align );
virtual int GetAlignment() const;
{ return m_mode; }
// implementation
- int CalculateAlignment() const;
// this is a replacement for dynamic_cast<wxDataViewCustomRenderer> in the
// code checking whether the renderer is interested in mouse events, it's
// never be called
virtual wxDataViewCustomRenderer *WXGetAsCustom() { return NULL; }
-protected:
- // This is just a convenience for the derived classes overriding
- // RenderWithAttr() to avoid repeating the same wxFAIL_MSG() in all of them
- bool DummyRender(wxRect WXUNUSED(cell),
- wxDC * WXUNUSED(dc),
- int WXUNUSED(state))
- {
- wxFAIL_MSG("shouldn't be called at all, use RenderWithAttr() instead");
-
- return false;
- }
-
private:
int m_align;
wxDataViewCellMode m_mode;
bool SetValue( const wxVariant &value );
bool GetValue( wxVariant &value ) const;
- virtual bool RenderWithAttr(wxDC& dc,
- const wxRect& rect,
- int align,
- const wxDataViewItemAttr *attr,
- int state);
- virtual bool Render(wxRect cell, wxDC *dc, int state)
- {
- return DummyRender(cell, dc, state);
- }
-
- wxSize GetSize() const;
+ virtual bool Render(wxRect cell, wxDC *dc, int state);
+ virtual wxSize GetSize() const;
// in-place editing
virtual bool HasEditorCtrl() const;
bool SetValue( const wxVariant &value );
bool GetValue( wxVariant& value ) const;
- virtual bool RenderWithAttr(wxDC& dc,
- const wxRect& rect,
- int align,
- const wxDataViewItemAttr *attr,
- int state);
- virtual bool Render(wxRect cell, wxDC *dc, int state)
- {
- return DummyRender(cell, dc, state);
- }
+ virtual bool Render(wxRect cell, wxDC *dc, int state);
virtual wxSize GetSize() const;
private:
bool SetValue( const wxVariant &value );
bool GetValue( wxVariant &value ) const;
- virtual bool RenderWithAttr(wxDC& dc,
- const wxRect& rect,
- int align,
- const wxDataViewItemAttr *attr,
- int state);
- virtual bool Render(wxRect cell, wxDC *dc, int state)
- {
- return DummyRender(cell, dc, state);
- }
+ virtual bool Render(wxRect cell, wxDC *dc, int state);
virtual wxSize GetSize() const;
virtual bool HasEditorCtrl() const { return true; }
virtual ~wxDataViewCustomRenderer();
- virtual bool Render( wxRect cell, wxDC *dc, int state ) = 0;
-
- void RenderText( const wxString &text, int xoffset, wxRect cell, wxDC *dc, int state );
-
- virtual wxSize GetSize() const = 0;
-
// Create DC on request
virtual wxDC *GetDC();
+ // override the base class function to use GTK text cell renderer
+ virtual void RenderText(const wxString& text,
+ int xoffset,
+ wxRect cell,
+ wxDC *dc,
+ int state);
protected:
virtual ~wxDataViewCustomRenderer();
- void RenderText( const wxString &text, int xoffset, wxRect cell, wxDC *dc, int state );
-
- virtual wxSize GetSize() const = 0;
-
- virtual bool Render(wxRect cell, wxDC* dc, int state) = 0;
-
// implementation only
// -------------------
const wxVariant& value);
/**
- Create DC on request. Internal.
- */
- virtual wxDC* GetDC();
+ Return the attribute to be used for rendering.
+
+ This function may be called from Render() implementation to use the
+ attributes defined for the item if the renderer supports them.
+
+ Notice that when Render() is called, the wxDC object passed to it is
+ already set up to use the correct attributes (e.g. its font is set to
+ bold or italic version if wxDataViewItemAttr::GetBold() or GetItalic()
+ returns true) so it may not be necessary to call it explicitly if you
+ only want to render text using the items attributes.
+
+ @since 2.9.1
+ */
+ const wxDataViewItemAttr& GetAttr() const;
/**
Return size required to show content.
return true;
}
+// ----------------------------------------------------------------------------
+// wxDataViewCustomRendererBase
+// ----------------------------------------------------------------------------
+
+void
+wxDataViewCustomRendererBase::WXCallRender(wxRect rectCell, wxDC *dc, int state)
+{
+ wxCHECK_RET( dc, "no DC to draw on in custom renderer?" );
+
+ // adjust the rectangle ourselves to account for the alignment
+ wxRect rectItem = rectCell;
+ const int align = GetAlignment();
+ if ( align != wxDVR_DEFAULT_ALIGNMENT )
+ {
+ const wxSize size = GetSize();
+
+ // take alignment into account only if there is enough space, otherwise
+ // show as much contents as possible
+ //
+ // notice that many existing renderers (e.g. wxDataViewSpinRenderer)
+ // return hard-coded size which can be more than they need and if we
+ // trusted their GetSize() we'd draw the text out of cell bounds
+ // entirely
+
+ if ( size.x >= 0 && size.x < rectCell.width )
+ {
+ if ( align & wxALIGN_CENTER_HORIZONTAL )
+ rectItem.x += (rectCell.width - size.x)/2;
+ else if ( align & wxALIGN_RIGHT )
+ rectItem.x += rectCell.width - size.x;
+ // else: wxALIGN_LEFT is the default
+
+ rectItem.width = size.x;
+ }
+
+ if ( size.y >= 0 && size.y < rectCell.height )
+ {
+ if ( align & wxALIGN_CENTER_VERTICAL )
+ rectItem.y += (rectCell.height - size.y)/2;
+ else if ( align & wxALIGN_BOTTOM )
+ rectItem.y += rectCell.height - size.y;
+ // else: wxALIGN_TOP is the default
+
+ rectItem.height = size.y;
+ }
+ }
+
+
+ // set up the DC attributes
+
+ // override custom foreground with the standard one for the selected items
+ // because we currently don't allow changing the selection background and
+ // custom colours may be unreadable on it
+ wxColour col;
+ if ( state & wxDATAVIEW_CELL_SELECTED )
+ col = wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT);
+ else if ( m_attr.HasColour() )
+ col = m_attr.GetColour();
+ else // use default foreground
+ col = GetOwner()->GetOwner()->GetForegroundColour();
+
+ wxDCTextColourChanger changeFg(*dc, col);
+
+ wxDCFontChanger changeFont(*dc);
+ if ( m_attr.HasFont() )
+ {
+ wxFont font(dc->GetFont());
+ if ( m_attr.GetBold() )
+ font.MakeBold();
+ if ( m_attr.GetItalic() )
+ font.MakeItalic();
+
+ changeFont.Set(font);
+ }
+
+ Render(rectItem, dc, state);
+}
+
+void
+wxDataViewCustomRendererBase::RenderText(const wxString& text,
+ int xoffset,
+ wxRect rect,
+ wxDC *dc,
+ int WXUNUSED(state))
+{
+ wxRect rectText = rect;
+ rectText.x += xoffset;
+ rectText.width -= xoffset;
+
+ // check if we want to ellipsize the text if it doesn't fit
+ wxString ellipsizedText;
+ if ( GetEllipsizeMode() != wxELLIPSIZE_NONE )
+ {
+ ellipsizedText = wxControl::Ellipsize
+ (
+ text,
+ *dc,
+ GetEllipsizeMode(),
+ rect.width,
+ wxELLIPSIZE_FLAGS_NONE
+ );
+ }
+
+ dc->DrawLabel(ellipsizedText.empty() ? text : ellipsizedText,
+ rectText, GetAlignment());
+}
+
//-----------------------------------------------------------------------------
// wxDataViewEditorCtrlEvtHandler
//-----------------------------------------------------------------------------
return m_align;
}
-int wxDataViewRenderer::CalculateAlignment() const
-{
- if (m_align == wxDVR_DEFAULT_ALIGNMENT)
- {
- if (GetOwner() == NULL)
- return wxALIGN_LEFT | wxALIGN_CENTRE_VERTICAL;
-
- return GetOwner()->GetAlignment() | wxALIGN_CENTRE_VERTICAL;
- }
-
- return m_align;
-}
-
-bool
-wxDataViewRenderer::RenderWithAttr(wxDC& dc,
- const wxRect& cell_rect,
- int align,
- const wxDataViewItemAttr *WXUNUSED(attr),
- int state)
-{
- // adjust the rectangle ourselves to account for the alignment
-
- wxRect item_rect = cell_rect;
- if ( align )
- {
- const wxSize size = GetSize();
-
- // take alignment into account only if there is enough space, otherwise
- // show as much contents as possible
- //
- // notice that many existing renderers (e.g. wxDataViewSpinRenderer)
- // return hard-coded size which can be more than they need and if we
- // trusted their GetSize() we'd draw the text out of cell bounds
- // entirely
-
- if ( size.x < cell_rect.width )
- {
- if (align & wxALIGN_CENTER_HORIZONTAL)
- item_rect.x += (cell_rect.width - size.x)/2;
- else if (align & wxALIGN_RIGHT)
- item_rect.x += cell_rect.width - size.x;
- // else: wxALIGN_LEFT is the default
-
- item_rect.width = size.x;
- }
-
- if ( size.y < cell_rect.height )
- {
- if (align & wxALIGN_CENTER_VERTICAL)
- item_rect.y += (cell_rect.height - size.y)/2;
- else if (align & wxALIGN_BOTTOM)
- item_rect.y += cell_rect.height - size.y;
- // else: wxALIGN_TOP is the default
-
- item_rect.height = size.y;
- }
- }
-
- return Render(item_rect, &dc, state);
-}
-
-void
-wxDataViewRenderer::RenderText(wxDC& dc,
- const wxRect& rect,
- int align,
- const wxString& text,
- const wxDataViewItemAttr *attr,
- int state,
- int xoffset)
-{
- // override custom foreground with the standard one for the selected items
- // because we currently don't allow changing the selection background and
- // custom colours may be unreadable on it
- wxColour col;
- if ( state & wxDATAVIEW_CELL_SELECTED )
- col = wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT);
- else if ( attr && attr->HasColour() )
- col = attr->GetColour();
- else // use default foreground
- col = GetOwner()->GetOwner()->GetForegroundColour();
-
- wxDCTextColourChanger changeFg(dc, col);
-
- wxDCFontChanger changeFont(dc);
- if ( attr && attr->HasFont() )
- {
- wxFont font(dc.GetFont());
- if ( attr->GetBold() )
- font.MakeBold();
- if ( attr->GetItalic() )
- font.MakeItalic();
-
- changeFont.Set(font);
- }
-
- wxRect rectText = rect;
- rectText.x += xoffset;
- rectText.width -= xoffset;
-
- // check if we want to ellipsize the text if it doesn't fit
- wxString ellipsizedText;
- if ( GetEllipsizeMode() != wxELLIPSIZE_NONE )
- {
- ellipsizedText = wxControl::Ellipsize
- (
- text,
- dc,
- GetEllipsizeMode(),
- rect.width,
- wxELLIPSIZE_FLAGS_NONE
- );
- }
-
- dc.DrawLabel(ellipsizedText.empty() ? text : ellipsizedText,
- rectText, align);
-}
-
// ---------------------------------------------------------
// wxDataViewCustomRenderer
// ---------------------------------------------------------
return true;
}
-bool
-wxDataViewTextRenderer::RenderWithAttr(wxDC& dc,
- const wxRect& rect,
- int align,
- const wxDataViewItemAttr *attr,
- int state)
+bool wxDataViewTextRenderer::Render(wxRect rect, wxDC *dc, int state)
{
- RenderText(dc, rect, align, m_text, attr, state);
+ RenderText(m_text, 0, rect, dc, state);
return true;
}
return true;
}
-bool wxDataViewProgressRenderer::RenderWithAttr(wxDC& dc,
- const wxRect& rect,
- int WXUNUSED(align),
- const wxDataViewItemAttr *attr,
- int WXUNUSED(state))
+bool
+wxDataViewProgressRenderer::Render(wxRect rect, wxDC *dc, int WXUNUSED(state))
{
- // deflat the rect to leave a small border between bars in adjacent rows
+ // deflate the rect to leave a small border between bars in adjacent rows
wxRect bar = rect.Deflate(0, 1);
- dc.SetBrush( *wxTRANSPARENT_BRUSH );
- dc.SetPen( *wxBLACK_PEN );
- dc.DrawRectangle( bar );
+ dc->SetBrush( *wxTRANSPARENT_BRUSH );
+ dc->SetPen( *wxBLACK_PEN );
+ dc->DrawRectangle( bar );
bar.width = (int)(bar.width * m_value / 100.);
- dc.SetPen( *wxTRANSPARENT_PEN );
- dc.SetBrush( attr && attr->HasColour() ? wxBrush(attr->GetColour())
- : *wxBLUE_BRUSH );
- dc.DrawRectangle( bar );
+ dc->SetPen( *wxTRANSPARENT_PEN );
+
+ const wxDataViewItemAttr& attr = GetAttr();
+ dc->SetBrush( attr.HasColour() ? wxBrush(attr.GetColour())
+ : *wxBLUE_BRUSH );
+ dc->DrawRectangle( bar );
return true;
}
return false;
}
-bool
-wxDataViewIconTextRenderer::RenderWithAttr(wxDC& dc,
- const wxRect& rect,
- int align,
- const wxDataViewItemAttr *attr,
- int state)
+bool wxDataViewIconTextRenderer::Render(wxRect rect, wxDC *dc, int state)
{
int xoffset = 0;
const wxIcon& icon = m_value.GetIcon();
if ( icon.IsOk() )
{
- dc.DrawIcon(icon, rect.x, rect.y + (rect.height - icon.GetHeight())/2);
+ dc->DrawIcon(icon, rect.x, rect.y + (rect.height - icon.GetHeight())/2);
xoffset = icon.GetWidth()+4;
}
- RenderText(dc, rect, align, m_value.GetText(), attr, state, xoffset);
+ RenderText(m_value.GetText(), xoffset, rect, dc, state);
return true;
}
model->GetValue( value, item, column->GetModelColumn());
cell->SetValue( value );
+ wxDataViewItemAttr attr;
+ model->GetAttr(item, column->GetModelColumn(), attr);
+ cell->SetAttr(attr);
+
wxRect item_rect(x, 0, width, height);
item_rect.Deflate(PADDING_RIGHTLEFT, 0);
// dc.SetClippingRegion( item_rect );
- wxDataViewItemAttr attr;
- const bool
- hasAttr = model->GetAttr(item, column->GetModelColumn(), attr);
- cell->RenderWithAttr(dc, item_rect, cell->CalculateAlignment(),
- hasAttr ? &attr : NULL, 0);
+ cell->WXCallRender(item_rect, &dc, 0);
// dc.DestroyClippingRegion();
x += width;
model->GetValue( value, dataitem, col->GetModelColumn());
cell->SetValue( value );
+ wxDataViewItemAttr attr;
+ model->GetAttr(dataitem, col->GetModelColumn(), attr);
+ cell->SetAttr(attr);
+
// update cell_rect
cell_rect.y = GetLineStart( item );
cell_rect.height = GetLineHeight( item );
// make its own renderer and thus we cannot be sure of that.
wxDCClipper clip(dc, item_rect);
- wxDataViewItemAttr attr;
- const bool
- hasAttr = model->GetAttr(dataitem, col->GetModelColumn(), attr);
- cell->RenderWithAttr(dc, item_rect, cell->CalculateAlignment(),
- hasAttr ? &attr : NULL, state);
+ cell->WXCallRender(item_rect, &dc, state);
}
cell_rect.x += cell_rect.width;
state |= wxDATAVIEW_CELL_INSENSITIVE;
if (flags & GTK_CELL_RENDERER_FOCUSED)
state |= wxDATAVIEW_CELL_FOCUSED;
- cell->Render( renderrect, dc, state );
+ cell->WXCallRender( renderrect, dc, state );
}
}
{
// make sure that 'Render' can draw only in the allowed area:
dc->SetClippingRegion(content.left,content.top,content.right-content.left+1,content.bottom-content.top+1);
- (void) (dataViewCustomRendererPtr->Render( cellrect, dc,
+ (void) (dataViewCustomRendererPtr->WXCallRender( cellrect, dc,
((state == kDataBrowserItemIsSelected) ? wxDATAVIEW_CELL_SELECTED : 0)));
dc->DestroyClippingRegion(); // probably not necessary
}
[[self backgroundColor] set];
NSRectFill(cellFrame);
- // TODO: attributes support
- renderer->Render(wxFromNSRect(controlView, cellFrame), renderer->GetDC(), 0);
+ wxDC * const dc = renderer->GetDC();
+ renderer->WXCallRender(wxFromNSRect(controlView, cellFrame), dc, 0);
renderer->SetDC(NULL);
}
delete m_DCPtr;
}
-void wxDataViewCustomRenderer::RenderText( const wxString &text, int xoffset, wxRect cell, wxDC *dc, int state )
-{
- wxDataViewCtrl *view = GetOwner()->GetOwner();
-
- wxColour col = (state & wxDATAVIEW_CELL_SELECTED) ? *wxWHITE : view->GetForegroundColour();
- dc->SetTextForeground(col);
- dc->DrawText( text, cell.x + xoffset, cell.y + ((cell.height - dc->GetCharHeight()) / 2));
-}
-
wxDC* wxDataViewCustomRenderer::GetDC()
{
if ((m_DCPtr == NULL) && (GetOwner() != NULL) && (GetOwner()->GetOwner() != NULL))