Merge branch 'grid-autosize'
Optimize wxGrid::AutoSizeColumns() for big grids. This includes an optimization of wxDC::GetTextExtent() at the price of slightly reduced precision in wxMSW. See https://github.com/wxWidgets/wxWidgets/pull/1893
This commit is contained in:
@@ -212,6 +212,20 @@ public:
|
|||||||
return GetBestSize(grid, attr, dc, row, col).GetWidth();
|
return GetBestSize(grid, attr, dc, row, col).GetWidth();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Unlike GetBestSize(), this functions is optional: it is used when
|
||||||
|
// auto-sizing columns to determine the best width without iterating over
|
||||||
|
// all cells in this column, if possible.
|
||||||
|
//
|
||||||
|
// If it isn't, return wxDefaultSize as the base class version does by
|
||||||
|
// default.
|
||||||
|
virtual wxSize GetMaxBestSize(wxGrid& WXUNUSED(grid),
|
||||||
|
wxGridCellAttr& WXUNUSED(attr),
|
||||||
|
wxDC& WXUNUSED(dc))
|
||||||
|
{
|
||||||
|
return wxDefaultSize;
|
||||||
|
}
|
||||||
|
|
||||||
// create a new object which is the copy of this one
|
// create a new object which is the copy of this one
|
||||||
virtual wxGridCellRenderer *Clone() const = 0;
|
virtual wxGridCellRenderer *Clone() const = 0;
|
||||||
};
|
};
|
||||||
@@ -1065,6 +1079,16 @@ public:
|
|||||||
return wxGridCellAttrPtr(GetAttr(row, col, kind));
|
return wxGridCellAttrPtr(GetAttr(row, col, kind));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This is an optimization for a common case when the entire column uses
|
||||||
|
// roughly the same attribute, which can thus be reused for measuring all
|
||||||
|
// the cells in this column. Override this to return true (possibly for
|
||||||
|
// some columns only) to speed up AutoSizeColumns() for the grids using
|
||||||
|
// this table.
|
||||||
|
virtual bool CanMeasureColUsingSameAttr(int WXUNUSED(col)) const
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// these functions take ownership of the pointer
|
// these functions take ownership of the pointer
|
||||||
virtual void SetAttr(wxGridCellAttr* attr, int row, int col);
|
virtual void SetAttr(wxGridCellAttr* attr, int row, int col);
|
||||||
virtual void SetRowAttr(wxGridCellAttr *attr, int row);
|
virtual void SetRowAttr(wxGridCellAttr *attr, int row);
|
||||||
@@ -1869,11 +1893,8 @@ public:
|
|||||||
{ AutoSizeColOrRow(row, setAsMin, wxGRID_ROW); }
|
{ AutoSizeColOrRow(row, setAsMin, wxGRID_ROW); }
|
||||||
|
|
||||||
// auto size all columns (very ineffective for big grids!)
|
// auto size all columns (very ineffective for big grids!)
|
||||||
void AutoSizeColumns( bool setAsMin = true )
|
void AutoSizeColumns( bool setAsMin = true );
|
||||||
{ (void)SetOrCalcColumnSizes(false, setAsMin); }
|
void AutoSizeRows( bool setAsMin = true );
|
||||||
|
|
||||||
void AutoSizeRows( bool setAsMin = true )
|
|
||||||
{ (void)SetOrCalcRowSizes(false, setAsMin); }
|
|
||||||
|
|
||||||
// auto size the grid, that is make the columns/rows of the "right" size
|
// auto size the grid, that is make the columns/rows of the "right" size
|
||||||
// and also set the grid size to just fit its contents
|
// and also set the grid size to just fit its contents
|
||||||
@@ -2414,10 +2435,6 @@ protected:
|
|||||||
wxColour m_gridFrozenBorderColour;
|
wxColour m_gridFrozenBorderColour;
|
||||||
int m_gridFrozenBorderPenWidth;
|
int m_gridFrozenBorderPenWidth;
|
||||||
|
|
||||||
// common part of AutoSizeColumn/Row() and GetBestSize()
|
|
||||||
int SetOrCalcColumnSizes(bool calcOnly, bool setAsMin = true);
|
|
||||||
int SetOrCalcRowSizes(bool calcOnly, bool setAsMin = true);
|
|
||||||
|
|
||||||
// common part of AutoSizeColumn/Row()
|
// common part of AutoSizeColumn/Row()
|
||||||
void AutoSizeColOrRow(int n, bool setAsMin, wxGridDirection direction);
|
void AutoSizeColOrRow(int n, bool setAsMin, wxGridDirection direction);
|
||||||
|
|
||||||
|
@@ -57,6 +57,13 @@ protected:
|
|||||||
class WXDLLIMPEXP_ADV wxGridCellNumberRenderer : public wxGridCellStringRenderer
|
class WXDLLIMPEXP_ADV wxGridCellNumberRenderer : public wxGridCellStringRenderer
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
explicit wxGridCellNumberRenderer(long minValue = LONG_MIN,
|
||||||
|
long maxValue = LONG_MAX)
|
||||||
|
: m_minValue(minValue),
|
||||||
|
m_maxValue(maxValue)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
// draw the string right aligned
|
// draw the string right aligned
|
||||||
virtual void Draw(wxGrid& grid,
|
virtual void Draw(wxGrid& grid,
|
||||||
wxGridCellAttr& attr,
|
wxGridCellAttr& attr,
|
||||||
@@ -70,11 +77,21 @@ public:
|
|||||||
wxDC& dc,
|
wxDC& dc,
|
||||||
int row, int col) wxOVERRIDE;
|
int row, int col) wxOVERRIDE;
|
||||||
|
|
||||||
|
virtual wxSize GetMaxBestSize(wxGrid& grid,
|
||||||
|
wxGridCellAttr& attr,
|
||||||
|
wxDC& dc) wxOVERRIDE;
|
||||||
|
|
||||||
|
// Optional parameters for this renderer are "<min>,<max>".
|
||||||
|
virtual void SetParameters(const wxString& params) wxOVERRIDE;
|
||||||
|
|
||||||
virtual wxGridCellRenderer *Clone() const wxOVERRIDE
|
virtual wxGridCellRenderer *Clone() const wxOVERRIDE
|
||||||
{ return new wxGridCellNumberRenderer; }
|
{ return new wxGridCellNumberRenderer(m_minValue, m_maxValue); }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
wxString GetString(const wxGrid& grid, int row, int col);
|
wxString GetString(const wxGrid& grid, int row, int col);
|
||||||
|
|
||||||
|
long m_minValue,
|
||||||
|
m_maxValue;
|
||||||
};
|
};
|
||||||
|
|
||||||
class WXDLLIMPEXP_ADV wxGridCellFloatRenderer : public wxGridCellStringRenderer
|
class WXDLLIMPEXP_ADV wxGridCellFloatRenderer : public wxGridCellStringRenderer
|
||||||
@@ -141,6 +158,10 @@ public:
|
|||||||
wxDC& dc,
|
wxDC& dc,
|
||||||
int row, int col) wxOVERRIDE;
|
int row, int col) wxOVERRIDE;
|
||||||
|
|
||||||
|
virtual wxSize GetMaxBestSize(wxGrid& grid,
|
||||||
|
wxGridCellAttr& attr,
|
||||||
|
wxDC& dc) wxOVERRIDE;
|
||||||
|
|
||||||
virtual wxGridCellRenderer *Clone() const wxOVERRIDE
|
virtual wxGridCellRenderer *Clone() const wxOVERRIDE
|
||||||
{ return new wxGridCellBoolRenderer; }
|
{ return new wxGridCellBoolRenderer; }
|
||||||
};
|
};
|
||||||
@@ -175,6 +196,10 @@ public:
|
|||||||
wxDC& dc,
|
wxDC& dc,
|
||||||
int row, int col) wxOVERRIDE;
|
int row, int col) wxOVERRIDE;
|
||||||
|
|
||||||
|
virtual wxSize GetMaxBestSize(wxGrid& grid,
|
||||||
|
wxGridCellAttr& attr,
|
||||||
|
wxDC& dc) wxOVERRIDE;
|
||||||
|
|
||||||
virtual wxGridCellRenderer *Clone() const wxOVERRIDE;
|
virtual wxGridCellRenderer *Clone() const wxOVERRIDE;
|
||||||
|
|
||||||
// output strptime()-like format string
|
// output strptime()-like format string
|
||||||
@@ -213,8 +238,37 @@ protected:
|
|||||||
|
|
||||||
#endif // wxUSE_DATETIME
|
#endif // wxUSE_DATETIME
|
||||||
|
|
||||||
|
// Renderer for fields taking one of a limited set of values: this is the same
|
||||||
|
// as the renderer for strings, except that it can implement GetMaxBestSize().
|
||||||
|
class WXDLLIMPEXP_ADV wxGridCellChoiceRenderer : public wxGridCellStringRenderer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
wxGridCellChoiceRenderer() { }
|
||||||
|
|
||||||
|
virtual wxSize GetMaxBestSize(wxGrid& grid,
|
||||||
|
wxGridCellAttr& attr,
|
||||||
|
wxDC& dc) wxOVERRIDE;
|
||||||
|
|
||||||
|
// Parameters string is a comma-separated list of values.
|
||||||
|
virtual void SetParameters(const wxString& params) wxOVERRIDE;
|
||||||
|
|
||||||
|
virtual wxGridCellRenderer *Clone() const wxOVERRIDE
|
||||||
|
{
|
||||||
|
return new wxGridCellChoiceRenderer(*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
wxGridCellChoiceRenderer(const wxGridCellChoiceRenderer& other)
|
||||||
|
: m_choices(other.m_choices)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
wxArrayString m_choices;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
// renders a number using the corresponding text string
|
// renders a number using the corresponding text string
|
||||||
class WXDLLIMPEXP_ADV wxGridCellEnumRenderer : public wxGridCellStringRenderer
|
class WXDLLIMPEXP_ADV wxGridCellEnumRenderer : public wxGridCellChoiceRenderer
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
wxGridCellEnumRenderer( const wxString& choices = wxEmptyString );
|
wxGridCellEnumRenderer( const wxString& choices = wxEmptyString );
|
||||||
@@ -234,14 +288,8 @@ public:
|
|||||||
|
|
||||||
virtual wxGridCellRenderer *Clone() const wxOVERRIDE;
|
virtual wxGridCellRenderer *Clone() const wxOVERRIDE;
|
||||||
|
|
||||||
// parameters string format is "item1[,item2[...,itemN]]" where itemN will
|
|
||||||
// be used if the cell value is N-1
|
|
||||||
virtual void SetParameters(const wxString& params) wxOVERRIDE;
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
wxString GetString(const wxGrid& grid, int row, int col);
|
wxString GetString(const wxGrid& grid, int row, int col);
|
||||||
|
|
||||||
wxArrayString m_choices;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@@ -88,6 +88,26 @@ public:
|
|||||||
virtual int GetBestWidth(wxGrid& grid, wxGridCellAttr& attr, wxDC& dc,
|
virtual int GetBestWidth(wxGrid& grid, wxGridCellAttr& attr, wxDC& dc,
|
||||||
int row, int col, int height);
|
int row, int col, int height);
|
||||||
|
|
||||||
|
/**
|
||||||
|
Get the maximum possible size for a cell using this renderer, if
|
||||||
|
possible.
|
||||||
|
|
||||||
|
This function may be overridden in the derived class if it can return
|
||||||
|
the maximum size needed for displaying the cells rendered it without
|
||||||
|
iterating over all cells. The base class version simply returns
|
||||||
|
::wxDefaultSize, indicating that this is infeasible and that
|
||||||
|
GetBestSize() should be called for each cell individually.
|
||||||
|
|
||||||
|
Note that this method will only be used if
|
||||||
|
wxGridTableBase::CanMeasureColUsingSameAttr() is overriden to return
|
||||||
|
@true.
|
||||||
|
|
||||||
|
@since 3.1.4
|
||||||
|
*/
|
||||||
|
virtual wxSize GetMaxBestSize(wxGrid& grid,
|
||||||
|
wxGridCellAttr& attr,
|
||||||
|
wxDC& dc);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/**
|
/**
|
||||||
The destructor is private because only DecRef() can delete us.
|
The destructor is private because only DecRef() can delete us.
|
||||||
@@ -2517,6 +2537,25 @@ public:
|
|||||||
returns @true.
|
returns @true.
|
||||||
*/
|
*/
|
||||||
virtual bool CanHaveAttributes();
|
virtual bool CanHaveAttributes();
|
||||||
|
|
||||||
|
/**
|
||||||
|
Override to return true if the same attribute can be used for measuring
|
||||||
|
all cells in the given column.
|
||||||
|
|
||||||
|
This function is provided for optimization purposes: it returns @false
|
||||||
|
by default, but can be overridden to return @true when all the cells in
|
||||||
|
the same grid column use sensibly the same attribute, i.e. they use the
|
||||||
|
same renderer (either explicitly, or implicitly, due to their type as
|
||||||
|
returned by GetTypeName()) and the font of the same size.
|
||||||
|
|
||||||
|
Returning @true from this function allows AutoSizeColumns() to skip
|
||||||
|
looking up the attribute and the renderer for each individual cell,
|
||||||
|
which results in very noticeable performance improvements for the grids
|
||||||
|
with many rows.
|
||||||
|
|
||||||
|
@since 3.1.4
|
||||||
|
*/
|
||||||
|
virtual bool CanMeasureColUsingSameAttr(int col) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@@ -105,17 +105,27 @@ void wxTextMeasureBase::GetMultiLineTextExtent(const wxString& text,
|
|||||||
wxCoord *height,
|
wxCoord *height,
|
||||||
wxCoord *heightOneLine)
|
wxCoord *heightOneLine)
|
||||||
{
|
{
|
||||||
|
// It's noticeably faster to handle the case of a string which isn't
|
||||||
|
// actually multiline specially here, to skip iteration above in this case.
|
||||||
|
if ( text.find('\n') == wxString::npos )
|
||||||
|
{
|
||||||
|
GetTextExtent(text, width, height);
|
||||||
|
if ( heightOneLine && height )
|
||||||
|
*heightOneLine = *height;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
MeasuringGuard guard(*this);
|
MeasuringGuard guard(*this);
|
||||||
|
|
||||||
wxCoord widthTextMax = 0, widthLine,
|
wxCoord widthTextMax = 0, widthLine,
|
||||||
heightTextTotal = 0, heightLineDefault = 0, heightLine = 0;
|
heightTextTotal = 0, heightLineDefault = 0, heightLine = 0;
|
||||||
|
|
||||||
wxString curLine;
|
wxString::const_iterator lineStart = text.begin();
|
||||||
for ( wxString::const_iterator pc = text.begin(); ; ++pc )
|
for ( wxString::const_iterator pc = text.begin(); ; ++pc )
|
||||||
{
|
{
|
||||||
if ( pc == text.end() || *pc == wxS('\n') )
|
if ( pc == text.end() || *pc == wxS('\n') )
|
||||||
{
|
{
|
||||||
if ( curLine.empty() )
|
if ( pc == lineStart )
|
||||||
{
|
{
|
||||||
// we can't use GetTextExtent - it will return 0 for both width
|
// we can't use GetTextExtent - it will return 0 for both width
|
||||||
// and height and an empty line should count in height
|
// and height and an empty line should count in height
|
||||||
@@ -137,7 +147,7 @@ void wxTextMeasureBase::GetMultiLineTextExtent(const wxString& text,
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
CallGetTextExtent(curLine, &widthLine, &heightLine);
|
CallGetTextExtent(wxString(lineStart, pc), &widthLine, &heightLine);
|
||||||
if ( widthLine > widthTextMax )
|
if ( widthLine > widthTextMax )
|
||||||
widthTextMax = widthLine;
|
widthTextMax = widthLine;
|
||||||
heightTextTotal += heightLine;
|
heightTextTotal += heightLine;
|
||||||
@@ -149,13 +159,10 @@ void wxTextMeasureBase::GetMultiLineTextExtent(const wxString& text,
|
|||||||
}
|
}
|
||||||
else // '\n'
|
else // '\n'
|
||||||
{
|
{
|
||||||
curLine.clear();
|
lineStart = pc;
|
||||||
|
++lineStart;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
curLine += *pc;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( width )
|
if ( width )
|
||||||
|
@@ -9967,6 +9967,14 @@ wxGrid::AutoSizeColOrRow(int colOrRow, bool setAsMin, wxGridDirection direction)
|
|||||||
col = -1;
|
col = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If possible, reuse the same attribute and renderer for all cells: this
|
||||||
|
// is an important optimization (resulting in up to 80% speed up of
|
||||||
|
// AutoSizeColumns()) as finding the attribute and renderer for the cell
|
||||||
|
// are very slow operations, due to the number of steps involved in them.
|
||||||
|
const bool canReuseAttr = column && m_table->CanMeasureColUsingSameAttr(col);
|
||||||
|
wxGridCellAttrPtr attr;
|
||||||
|
wxGridCellRendererPtr renderer;
|
||||||
|
|
||||||
wxCoord extent, extentMax = 0;
|
wxCoord extent, extentMax = 0;
|
||||||
int max = column ? m_numRows : m_numCols;
|
int max = column ? m_numRows : m_numCols;
|
||||||
for ( int rowOrCol = 0; rowOrCol < max; rowOrCol++ )
|
for ( int rowOrCol = 0; rowOrCol < max; rowOrCol++ )
|
||||||
@@ -10005,8 +10013,27 @@ wxGrid::AutoSizeColOrRow(int colOrRow, bool setAsMin, wxGridDirection direction)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// get cell ( main cell if CellSpan_Inside ) renderer best size
|
// get cell ( main cell if CellSpan_Inside ) renderer best size
|
||||||
wxGridCellAttrPtr attr = GetCellAttrPtr(row, col);
|
if ( !canReuseAttr || !attr )
|
||||||
wxGridCellRendererPtr renderer = attr->GetRendererPtr(this, row, col);
|
{
|
||||||
|
attr = GetCellAttrPtr(row, col);
|
||||||
|
renderer = attr->GetRendererPtr(this, row, col);
|
||||||
|
|
||||||
|
if ( canReuseAttr )
|
||||||
|
{
|
||||||
|
// Try to get the best width for the entire column at once, if
|
||||||
|
// it's supported by the renderer.
|
||||||
|
extent = renderer->GetMaxBestSize(*this, *attr, dc).x;
|
||||||
|
|
||||||
|
if ( extent != wxDefaultCoord )
|
||||||
|
{
|
||||||
|
extentMax = extent;
|
||||||
|
|
||||||
|
// No need to check all the values.
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if ( renderer )
|
if ( renderer )
|
||||||
{
|
{
|
||||||
extent = column
|
extent = column
|
||||||
@@ -10206,50 +10233,28 @@ wxCoord wxGrid::CalcColOrRowLabelAreaMinSize(wxGridDirection direction)
|
|||||||
return extentMax;
|
return extentMax;
|
||||||
}
|
}
|
||||||
|
|
||||||
int wxGrid::SetOrCalcColumnSizes(bool calcOnly, bool setAsMin)
|
void wxGrid::AutoSizeColumns(bool setAsMin)
|
||||||
{
|
{
|
||||||
int width = m_rowLabelWidth;
|
wxGridUpdateLocker locker(this);
|
||||||
|
|
||||||
wxGridUpdateLocker locker;
|
|
||||||
if(!calcOnly)
|
|
||||||
locker.Create(this);
|
|
||||||
|
|
||||||
for ( int col = 0; col < m_numCols; col++ )
|
for ( int col = 0; col < m_numCols; col++ )
|
||||||
{
|
AutoSizeColumn(col, setAsMin);
|
||||||
if ( !calcOnly )
|
|
||||||
AutoSizeColumn(col, setAsMin);
|
|
||||||
|
|
||||||
width += GetColWidth(col);
|
|
||||||
}
|
|
||||||
|
|
||||||
return width;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int wxGrid::SetOrCalcRowSizes(bool calcOnly, bool setAsMin)
|
void wxGrid::AutoSizeRows(bool setAsMin)
|
||||||
{
|
{
|
||||||
int height = m_colLabelHeight;
|
wxGridUpdateLocker locker(this);
|
||||||
|
|
||||||
wxGridUpdateLocker locker;
|
|
||||||
if(!calcOnly)
|
|
||||||
locker.Create(this);
|
|
||||||
|
|
||||||
for ( int row = 0; row < m_numRows; row++ )
|
for ( int row = 0; row < m_numRows; row++ )
|
||||||
{
|
AutoSizeRow(row, setAsMin);
|
||||||
if ( !calcOnly )
|
|
||||||
AutoSizeRow(row, setAsMin);
|
|
||||||
|
|
||||||
height += GetRowHeight(row);
|
|
||||||
}
|
|
||||||
|
|
||||||
return height;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void wxGrid::AutoSize()
|
void wxGrid::AutoSize()
|
||||||
{
|
{
|
||||||
wxGridUpdateLocker locker(this);
|
wxGridUpdateLocker locker(this);
|
||||||
|
|
||||||
wxSize size(SetOrCalcColumnSizes(false) - m_rowLabelWidth + m_extraWidth,
|
AutoSizeColumns();
|
||||||
SetOrCalcRowSizes(false) - m_colLabelHeight + m_extraHeight);
|
AutoSizeRows();
|
||||||
|
|
||||||
// we know that we're not going to have scrollbars so disable them now to
|
// we know that we're not going to have scrollbars so disable them now to
|
||||||
// avoid trouble in SetClientSize() which can otherwise set the correct
|
// avoid trouble in SetClientSize() which can otherwise set the correct
|
||||||
@@ -10257,7 +10262,7 @@ void wxGrid::AutoSize()
|
|||||||
SetScrollbars(m_xScrollPixelsPerLine, m_yScrollPixelsPerLine,
|
SetScrollbars(m_xScrollPixelsPerLine, m_yScrollPixelsPerLine,
|
||||||
0, 0, 0, 0, true);
|
0, 0, 0, 0, true);
|
||||||
|
|
||||||
SetClientSize(size.x + m_rowLabelWidth, size.y + m_colLabelHeight);
|
SetSize(DoGetBestSize());
|
||||||
}
|
}
|
||||||
|
|
||||||
void wxGrid::AutoSizeRowLabelSize( int row )
|
void wxGrid::AutoSizeRowLabelSize( int row )
|
||||||
@@ -10294,15 +10299,30 @@ void wxGrid::AutoSizeColLabelSize( int col )
|
|||||||
|
|
||||||
wxSize wxGrid::DoGetBestSize() const
|
wxSize wxGrid::DoGetBestSize() const
|
||||||
{
|
{
|
||||||
wxGrid * const self = const_cast<wxGrid *>(this);
|
wxSize size(m_rowLabelWidth + m_extraWidth,
|
||||||
|
m_colLabelHeight + m_extraHeight);
|
||||||
|
|
||||||
// we do the same as in AutoSize() here with the exception that we don't
|
if ( m_colWidths.empty() )
|
||||||
// change the column/row sizes, only calculate them
|
{
|
||||||
wxSize size(self->SetOrCalcColumnSizes(true) - m_rowLabelWidth + m_extraWidth,
|
size.x += m_defaultColWidth*m_numCols;
|
||||||
self->SetOrCalcRowSizes(true) - m_colLabelHeight + m_extraHeight);
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for ( int col = 0; col < m_numCols; col++ )
|
||||||
|
size.x += GetColWidth(col);
|
||||||
|
}
|
||||||
|
|
||||||
return wxSize(size.x + m_rowLabelWidth, size.y + m_colLabelHeight)
|
if ( m_rowHeights.empty() )
|
||||||
+ GetWindowBorderSize();
|
{
|
||||||
|
size.y += m_defaultRowHeight*m_numRows;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for ( int row = 0; row < m_numRows; row++ )
|
||||||
|
size.y += GetRowHeight(row);
|
||||||
|
}
|
||||||
|
|
||||||
|
return size + GetWindowBorderSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
void wxGrid::Fit()
|
void wxGrid::Fit()
|
||||||
@@ -10997,7 +11017,7 @@ int wxGridTypeRegistry::FindDataType(const wxString& typeName)
|
|||||||
if ( typeName == wxGRID_VALUE_CHOICE )
|
if ( typeName == wxGRID_VALUE_CHOICE )
|
||||||
{
|
{
|
||||||
RegisterDataType(wxGRID_VALUE_CHOICE,
|
RegisterDataType(wxGRID_VALUE_CHOICE,
|
||||||
new wxGridCellStringRenderer,
|
new wxGridCellChoiceRenderer,
|
||||||
new wxGridCellChoiceEditor);
|
new wxGridCellChoiceEditor);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@@ -165,6 +165,24 @@ wxSize wxGridCellDateRenderer::GetBestSize(wxGrid& grid,
|
|||||||
return DoGetBestSize(attr, dc, GetString(grid, row, col));
|
return DoGetBestSize(attr, dc, GetString(grid, row, col));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
wxSize wxGridCellDateRenderer::GetMaxBestSize(wxGrid& WXUNUSED(grid),
|
||||||
|
wxGridCellAttr& attr,
|
||||||
|
wxDC& dc)
|
||||||
|
{
|
||||||
|
wxSize size;
|
||||||
|
|
||||||
|
// Try to produce the longest string in the current format: as we don't
|
||||||
|
// know which month is the longest, we need to try all of them.
|
||||||
|
for ( int m = wxDateTime::Jan; m <= wxDateTime::Dec; ++m )
|
||||||
|
{
|
||||||
|
const wxDateTime d(28, static_cast<wxDateTime::Month>(m), 9999);
|
||||||
|
|
||||||
|
size.IncTo(DoGetBestSize(attr, dc, d.Format(m_oformat, m_tz)));
|
||||||
|
}
|
||||||
|
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
void wxGridCellDateRenderer::SetParameters(const wxString& params)
|
void wxGridCellDateRenderer::SetParameters(const wxString& params)
|
||||||
{
|
{
|
||||||
if (!params.empty())
|
if (!params.empty())
|
||||||
@@ -194,6 +212,38 @@ bool wxGridCellDateTimeRenderer::Parse(const wxString& text, wxDateTime& result)
|
|||||||
|
|
||||||
#endif // wxUSE_DATETIME
|
#endif // wxUSE_DATETIME
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
// wxGridCellChoiceRenderer
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
wxSize wxGridCellChoiceRenderer::GetMaxBestSize(wxGrid& WXUNUSED(grid),
|
||||||
|
wxGridCellAttr& attr,
|
||||||
|
wxDC& dc)
|
||||||
|
{
|
||||||
|
wxSize size;
|
||||||
|
|
||||||
|
for ( size_t n = 0; n < m_choices.size(); ++n )
|
||||||
|
{
|
||||||
|
size.IncTo(DoGetBestSize(attr, dc, m_choices[n]));
|
||||||
|
}
|
||||||
|
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
void wxGridCellChoiceRenderer::SetParameters(const wxString& params)
|
||||||
|
{
|
||||||
|
m_choices.clear();
|
||||||
|
|
||||||
|
if ( params.empty() )
|
||||||
|
return;
|
||||||
|
|
||||||
|
wxStringTokenizer tk(params, wxT(','));
|
||||||
|
while ( tk.HasMoreTokens() )
|
||||||
|
{
|
||||||
|
m_choices.Add(tk.GetNextToken());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
// wxGridCellEnumRenderer
|
// wxGridCellEnumRenderer
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
@@ -260,24 +310,6 @@ wxSize wxGridCellEnumRenderer::GetBestSize(wxGrid& grid,
|
|||||||
return DoGetBestSize(attr, dc, GetString(grid, row, col));
|
return DoGetBestSize(attr, dc, GetString(grid, row, col));
|
||||||
}
|
}
|
||||||
|
|
||||||
void wxGridCellEnumRenderer::SetParameters(const wxString& params)
|
|
||||||
{
|
|
||||||
if ( !params )
|
|
||||||
{
|
|
||||||
// what can we do?
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_choices.Empty();
|
|
||||||
|
|
||||||
wxStringTokenizer tk(params, wxT(','));
|
|
||||||
while ( tk.HasMoreTokens() )
|
|
||||||
{
|
|
||||||
m_choices.Add(tk.GetNextToken());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
// wxGridCellAutoWrapStringRenderer
|
// wxGridCellAutoWrapStringRenderer
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
@@ -557,18 +589,8 @@ wxSize wxGridCellStringRenderer::DoGetBestSize(const wxGridCellAttr& attr,
|
|||||||
wxDC& dc,
|
wxDC& dc,
|
||||||
const wxString& text)
|
const wxString& text)
|
||||||
{
|
{
|
||||||
wxCoord x = 0, y = 0, max_x = 0;
|
|
||||||
dc.SetFont(attr.GetFont());
|
dc.SetFont(attr.GetFont());
|
||||||
wxStringTokenizer tk(text, wxT('\n'));
|
return dc.GetMultiLineTextExtent(text);
|
||||||
while ( tk.HasMoreTokens() )
|
|
||||||
{
|
|
||||||
dc.GetTextExtent(tk.GetNextToken(), &x, &y);
|
|
||||||
max_x = wxMax(max_x, x);
|
|
||||||
}
|
|
||||||
|
|
||||||
y *= 1 + text.Freq(wxT('\n')); // multiply by the number of lines.
|
|
||||||
|
|
||||||
return wxSize(max_x, y);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
wxSize wxGridCellStringRenderer::GetBestSize(wxGrid& grid,
|
wxSize wxGridCellStringRenderer::GetBestSize(wxGrid& grid,
|
||||||
@@ -726,6 +748,34 @@ wxSize wxGridCellNumberRenderer::GetBestSize(wxGrid& grid,
|
|||||||
return DoGetBestSize(attr, dc, GetString(grid, row, col));
|
return DoGetBestSize(attr, dc, GetString(grid, row, col));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
wxSize wxGridCellNumberRenderer::GetMaxBestSize(wxGrid& WXUNUSED(grid),
|
||||||
|
wxGridCellAttr& attr,
|
||||||
|
wxDC& dc)
|
||||||
|
{
|
||||||
|
// In theory, it's possible that there is a value in min..max range which
|
||||||
|
// is longer than both min and max, e.g. we could conceivably have "88" be
|
||||||
|
// wider than both "87" and "91" with some fonts, but it seems something
|
||||||
|
// too exotic to worry about in practice.
|
||||||
|
wxSize size = DoGetBestSize(attr, dc, wxString::Format("%ld", m_minValue));
|
||||||
|
size.IncTo(DoGetBestSize(attr, dc, wxString::Format("%ld", m_maxValue)));
|
||||||
|
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
void wxGridCellNumberRenderer::SetParameters(const wxString& params)
|
||||||
|
{
|
||||||
|
if ( params.empty() )
|
||||||
|
return;
|
||||||
|
|
||||||
|
wxString maxStr;
|
||||||
|
const wxString minStr = params.BeforeFirst(',', &maxStr);
|
||||||
|
|
||||||
|
if ( !minStr.ToLong(&m_minValue) || !maxStr.ToLong(&m_maxValue) )
|
||||||
|
{
|
||||||
|
wxLogDebug("Invalid wxGridCellNumberRenderer parameters \"%s\"", params);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
// wxGridCellFloatRenderer
|
// wxGridCellFloatRenderer
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
@@ -922,10 +972,17 @@ void wxGridCellFloatRenderer::SetParameters(const wxString& params)
|
|||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
wxSize wxGridCellBoolRenderer::GetBestSize(wxGrid& grid,
|
wxSize wxGridCellBoolRenderer::GetBestSize(wxGrid& grid,
|
||||||
wxGridCellAttr& WXUNUSED(attr),
|
wxGridCellAttr& attr,
|
||||||
wxDC& WXUNUSED(dc),
|
wxDC& dc,
|
||||||
int WXUNUSED(row),
|
int WXUNUSED(row),
|
||||||
int WXUNUSED(col))
|
int WXUNUSED(col))
|
||||||
|
{
|
||||||
|
return GetMaxBestSize(grid, attr, dc);
|
||||||
|
}
|
||||||
|
|
||||||
|
wxSize wxGridCellBoolRenderer::GetMaxBestSize(wxGrid& grid,
|
||||||
|
wxGridCellAttr& WXUNUSED(attr),
|
||||||
|
wxDC& WXUNUSED(dc))
|
||||||
{
|
{
|
||||||
static wxPrivate::DpiDependentValue<wxSize> s_sizeCheckMark;
|
static wxPrivate::DpiDependentValue<wxSize> s_sizeCheckMark;
|
||||||
|
|
||||||
|
@@ -1451,22 +1451,12 @@ void wxGridCellChoiceEditor::SetSize(const wxRect& rect)
|
|||||||
wxASSERT_MSG(m_control,
|
wxASSERT_MSG(m_control,
|
||||||
wxT("The wxGridCellChoiceEditor must be created first!"));
|
wxT("The wxGridCellChoiceEditor must be created first!"));
|
||||||
|
|
||||||
// Check that the height is not too small to fit the combobox.
|
// Check that the rectangle is big enough to fit the combobox, we can't
|
||||||
wxRect rectTallEnough = rect;
|
// afford truncating it.
|
||||||
const wxSize bestSize = m_control->GetBestSize();
|
wxSize size = rect.GetSize();
|
||||||
const wxCoord diffY = bestSize.GetHeight() - rectTallEnough.GetHeight();
|
size.IncTo(m_control->GetBestSize());
|
||||||
if ( diffY > 0 )
|
|
||||||
{
|
|
||||||
// Do make it tall enough.
|
|
||||||
rectTallEnough.height += diffY;
|
|
||||||
|
|
||||||
// Also centre the effective rectangle vertically with respect to the
|
wxGridCellEditor::SetSize(wxRect(size).CentreIn(rect));
|
||||||
// original one.
|
|
||||||
rectTallEnough.y -= diffY/2;
|
|
||||||
}
|
|
||||||
//else: The rectangle provided is already tall enough.
|
|
||||||
|
|
||||||
wxGridCellEditor::SetSize(rectTallEnough);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void wxGridCellChoiceEditor::PaintBackground(wxDC& dc,
|
void wxGridCellChoiceEditor::PaintBackground(wxDC& dc,
|
||||||
|
@@ -108,7 +108,13 @@ void wxTextMeasure::DoGetTextExtent(const wxString& string,
|
|||||||
// the result computed by GetTextExtentPoint32() may be too small as it
|
// the result computed by GetTextExtentPoint32() may be too small as it
|
||||||
// accounts for under/overhang of the first/last character while we want
|
// accounts for under/overhang of the first/last character while we want
|
||||||
// just the bounding rect for this string so adjust the width as needed
|
// just the bounding rect for this string so adjust the width as needed
|
||||||
if ( len > 0 )
|
// when using italic fonts as the difference is really noticeable for them
|
||||||
|
// (it may still exist, but seems to be at most 1px for the other fonts,
|
||||||
|
// and calling GetCharABCWidths() is pretty slow and much slower than
|
||||||
|
// calling GetTextExtentPoint32() itself, so avoid its overhead unless it's
|
||||||
|
// really, really necessary).
|
||||||
|
const wxFont font = GetFont();
|
||||||
|
if ( font.IsOk() && font.GetStyle() != wxFONTSTYLE_NORMAL && len > 0 )
|
||||||
{
|
{
|
||||||
ABC widthABC;
|
ABC widthABC;
|
||||||
const wxChar chFirst = *string.begin();
|
const wxChar chFirst = *string.begin();
|
||||||
|
@@ -66,6 +66,7 @@ struct GraphicsBenchmarkOptions
|
|||||||
testCircles =
|
testCircles =
|
||||||
testEllipses =
|
testEllipses =
|
||||||
testTextExtent =
|
testTextExtent =
|
||||||
|
testMultiLineTextExtent =
|
||||||
testPartialTextExtents = false;
|
testPartialTextExtents = false;
|
||||||
|
|
||||||
usePaint =
|
usePaint =
|
||||||
@@ -95,6 +96,7 @@ struct GraphicsBenchmarkOptions
|
|||||||
testCircles,
|
testCircles,
|
||||||
testEllipses,
|
testEllipses,
|
||||||
testTextExtent,
|
testTextExtent,
|
||||||
|
testMultiLineTextExtent,
|
||||||
testPartialTextExtents;
|
testPartialTextExtents;
|
||||||
|
|
||||||
bool usePaint,
|
bool usePaint,
|
||||||
@@ -634,7 +636,10 @@ private:
|
|||||||
wxStopWatch sw;
|
wxStopWatch sw;
|
||||||
for ( long n = 0; n < opts.numIters; n++ )
|
for ( long n = 0; n < opts.numIters; n++ )
|
||||||
{
|
{
|
||||||
size += dc.GetTextExtent(str);
|
if ( opts.testMultiLineTextExtent )
|
||||||
|
size += dc.GetMultiLineTextExtent(str);
|
||||||
|
else
|
||||||
|
size += dc.GetTextExtent(str);
|
||||||
}
|
}
|
||||||
|
|
||||||
const long t = sw.Time();
|
const long t = sw.Time();
|
||||||
@@ -847,6 +852,7 @@ public:
|
|||||||
{ wxCMD_LINE_SWITCH, "", "circles" },
|
{ wxCMD_LINE_SWITCH, "", "circles" },
|
||||||
{ wxCMD_LINE_SWITCH, "", "ellipses" },
|
{ wxCMD_LINE_SWITCH, "", "ellipses" },
|
||||||
{ wxCMD_LINE_SWITCH, "", "textextent" },
|
{ wxCMD_LINE_SWITCH, "", "textextent" },
|
||||||
|
{ wxCMD_LINE_SWITCH, "", "multilinetextextent" },
|
||||||
{ wxCMD_LINE_SWITCH, "", "partialtextextents" },
|
{ wxCMD_LINE_SWITCH, "", "partialtextextents" },
|
||||||
{ wxCMD_LINE_SWITCH, "", "paint" },
|
{ wxCMD_LINE_SWITCH, "", "paint" },
|
||||||
{ wxCMD_LINE_SWITCH, "", "client" },
|
{ wxCMD_LINE_SWITCH, "", "client" },
|
||||||
@@ -922,6 +928,7 @@ public:
|
|||||||
opts.testCircles = parser.Found("circles");
|
opts.testCircles = parser.Found("circles");
|
||||||
opts.testEllipses = parser.Found("ellipses");
|
opts.testEllipses = parser.Found("ellipses");
|
||||||
opts.testTextExtent = parser.Found("textextent");
|
opts.testTextExtent = parser.Found("textextent");
|
||||||
|
opts.testMultiLineTextExtent = parser.Found("multilinetextextent");
|
||||||
opts.testPartialTextExtents = parser.Found("partialtextextents");
|
opts.testPartialTextExtents = parser.Found("partialtextextents");
|
||||||
if ( !(opts.testBitmaps || opts.testImages || opts.testLines
|
if ( !(opts.testBitmaps || opts.testImages || opts.testLines
|
||||||
|| opts.testRawBitmaps || opts.testRectangles
|
|| opts.testRawBitmaps || opts.testRectangles
|
||||||
|
Reference in New Issue
Block a user