From 2e8988c3d6fdb85c1da626ddaf335ac1ba3217fe Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sun, 4 May 2014 22:12:42 +0000 Subject: [PATCH] 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 --- docs/changes.txt | 1 + include/wx/generic/grid.h | 24 ++++++++++++++ include/wx/generic/gridctrl.h | 12 +++++++ interface/wx/grid.h | 30 ++++++++++++++++++ src/generic/grid.cpp | 7 +++-- src/generic/gridctrl.cpp | 59 ++++++++++++++++++++++++++++------- 6 files changed, 120 insertions(+), 13 deletions(-) diff --git a/docs/changes.txt b/docs/changes.txt index 51a1b11a28..acefdc5a27 100644 --- a/docs/changes.txt +++ b/docs/changes.txt @@ -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: diff --git a/include/wx/generic/grid.h b/include/wx/generic/grid.h index 2fae46edd7..c3d082ac38 100644 --- a/include/wx/generic/grid.h +++ b/include/wx/generic/grid.h @@ -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; }; diff --git a/include/wx/generic/gridctrl.h b/include/wx/generic/gridctrl.h index 63c5a169f5..044f565382 100644 --- a/include/wx/generic/gridctrl.h +++ b/include/wx/generic/gridctrl.h @@ -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; } diff --git a/interface/wx/grid.h b/interface/wx/grid.h index b09fcdea6c..b1123f1b6a 100644 --- a/interface/wx/grid.h +++ b/interface/wx/grid.h @@ -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. diff --git a/src/generic/grid.cpp b/src/generic/grid.cpp index 6030c7fb28..1fed94b434 100644 --- a/src/generic/grid.cpp +++ b/src/generic/grid.cpp @@ -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 ) { diff --git a/src/generic/gridctrl.cpp b/src/generic/gridctrl.cpp index 25c3359d3b..36ff071777 100644 --- a/src/generic/gridctrl.cpp +++ b/src/generic/gridctrl.cpp @@ -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; } // ----------------------------------------------------------------------------