Add wxGridCellRenderer::GetBest{Height,Width}() and use them in wxGrid.

Allow the renderer to specify the best height at the given width (or vice
versa) instead of the best size in both direction which is not defined for
e.g. wxGridCellAutoWrapStringRenderer.

Closes #15943.

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@76451 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Vadim Zeitlin 2014-05-04 22:12:42 +00:00
parent 02f5b809bd
commit 2e8988c3d6
6 changed files with 120 additions and 13 deletions

View File

@ -46,6 +46,7 @@ All (GUI):
- Add wxFont::GetBaseFont() (Melroy Tellis).
- Update included Scintilla to version 3.3.9 (Christian Walther).
- Add support for loading old V1 BMP files to wxImage (Artur Wieczorek).
- Improve auto sizing of wrapped cells in wxGrid (iwbnwif).
wxGTK:

View File

@ -174,6 +174,30 @@ public:
wxDC& dc,
int row, int col) = 0;
// Get the preferred height for a given width. Override this method if the
// renderer computes height as function of its width, as is the case of the
// standard wxGridCellAutoWrapStringRenderer, for example.
// and vice versa
virtual int GetBestHeight(wxGrid& grid,
wxGridCellAttr& attr,
wxDC& dc,
int row, int col,
int WXUNUSED(width))
{
return GetBestSize(grid, attr, dc, row, col).GetHeight();
}
// Get the preferred width for a given height, this is the symmetric
// version of GetBestHeight().
virtual int GetBestWidth(wxGrid& grid,
wxGridCellAttr& attr,
wxDC& dc,
int row, int col,
int WXUNUSED(height))
{
return GetBestSize(grid, attr, dc, row, col).GetWidth();
}
// create a new object which is the copy of this one
virtual wxGridCellRenderer *Clone() const = 0;
};

View File

@ -238,6 +238,18 @@ public:
wxDC& dc,
int row, int col) wxOVERRIDE;
virtual int GetBestHeight(wxGrid& grid,
wxGridCellAttr& attr,
wxDC& dc,
int row, int col,
int width) wxOVERRIDE;
virtual int GetBestWidth(wxGrid& grid,
wxGridCellAttr& attr,
wxDC& dc,
int row, int col,
int height) wxOVERRIDE;
virtual wxGridCellRenderer *Clone() const wxOVERRIDE
{ return new wxGridCellAutoWrapStringRenderer; }

View File

@ -48,10 +48,40 @@ public:
/**
Get the preferred size of the cell for its contents.
This method must be overridden in the derived classes to return the
minimal fitting size for displaying the content of the given grid cell.
@see GetBestHeight(), GetBestWidth()
*/
virtual wxSize GetBestSize(wxGrid& grid, wxGridCellAttr& attr, wxDC& dc,
int row, int col) = 0;
/**
Get the preferred height of the cell at the given width.
Some renderers may not have a well-defined best size, but only be able
to provide the best height at the given width, e.g. this is the case of
the standard wxGridCellAutoWrapStringRenderer. In this case, they
should override this method, in addition to GetBestSize().
@see GetBestWidth()
@since 3.1.0
*/
virtual wxSize GetBestHeight(wxGrid& grid, wxGridCellAttr& attr, wxDC& dc,
int row, int col, int width);
/**
Get the preferred width of the cell at the given height.
See GetBestHeight(), this method is symmetric to it.
@since 3.1.0
*/
virtual wxSize GetBestWidth(wxGrid& grid, wxGridCellAttr& attr, wxDC& dc,
int row, int col, int height);
protected:
/**
The destructor is private because only DecRef() can delete us.

View File

@ -8407,8 +8407,11 @@ wxGrid::AutoSizeColOrRow(int colOrRow, bool setAsMin, wxGridDirection direction)
wxGridCellRenderer *renderer = attr->GetRenderer(this, row, col);
if ( renderer )
{
wxSize size = renderer->GetBestSize(*this, *attr, dc, row, col);
extent = column ? size.x : size.y;
extent = column
? renderer->GetBestWidth(*this, *attr, dc, row, col,
GetRowHeight(row))
: renderer->GetBestHeight(*this, *attr, dc, row, col,
GetColWidth(col));
if ( span != CellSpan_None )
{

View File

@ -435,21 +435,58 @@ wxGridCellAutoWrapStringRenderer::GetBestSize(wxGrid& grid,
wxGridCellAttr& attr,
wxDC& dc,
int row, int col)
{
// We have to make a choice here and fix either width or height because we
// don't have any naturally best size. This choice is mostly arbitrary, but
// we need to be consistent about it, otherwise wxGrid auto-sizing code
// would get confused. For now we decide to use a single line of text and
// compute the width needed to fully display everything.
const int height = dc.GetCharHeight();
return wxSize(GetBestWidth(grid, attr, dc, row, col, height), height);
}
static const int AUTOWRAP_Y_MARGIN = 4;
int
wxGridCellAutoWrapStringRenderer::GetBestHeight(wxGrid& grid,
wxGridCellAttr& attr,
wxDC& dc,
int row, int col,
int width)
{
const int lineHeight = dc.GetCharHeight();
// Search for a shape no taller than the golden ratio.
wxSize size;
for ( size.x = 10; ; size.x += 10 )
{
const size_t
numLines = GetTextLines(grid, dc, attr, size, row, col).size();
size.y = numLines * lineHeight;
if ( size.x >= size.y*1.68 )
break;
}
// Use as many lines as we need for this width and add a small border to
// improve the appearance.
return GetTextLines(grid, dc, attr, wxSize(width, lineHeight),
row, col).size() * lineHeight + AUTOWRAP_Y_MARGIN;
}
return size;
int
wxGridCellAutoWrapStringRenderer::GetBestWidth(wxGrid& grid,
wxGridCellAttr& attr,
wxDC& dc,
int row, int col,
int height)
{
const int lineHeight = dc.GetCharHeight();
// Maximal number of lines that fully fit but at least 1.
const size_t maxLines = height - AUTOWRAP_Y_MARGIN < lineHeight
? 1
: (height - AUTOWRAP_Y_MARGIN)/lineHeight;
// Increase width until all the text fits.
//
// TODO: this is not the most efficient to do it for the long strings.
const int charWidth = dc.GetCharWidth();
int width = 2*charWidth;
while ( GetTextLines(grid, dc, attr, wxSize(width, height),
row, col).size() > maxLines )
width += charWidth;
return width;
}
// ----------------------------------------------------------------------------