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; } // ----------------------------------------------------------------------------