wxwidgets/src/generic/gridctrl.cpp
Frode Roxrud Gill f646e8b11c Allow cloning client data stored in wxGrid attributes etc
Add wxSharedClientDataContainer class storing ref-counted client data
and use it instead of plain wxClientDataContainer in wxGridCellAttr,
wxGridCellEditor and wxGridCellRenderer classes.

This allows to keep the same client data associated with many grid cells
without having to make many copies of it.
2022-04-28 00:28:58 +02:00

1044 lines
33 KiB
C++

///////////////////////////////////////////////////////////////////////////
// Name: src/generic/gridctrl.cpp
// Purpose: wxGrid controls
// Author: Paul Gammans, Roger Gammans
// Modified by:
// Created: 11/04/2001
// Copyright: (c) The Computer Surgery (paul@compsurg.co.uk)
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
#include "wx/wxprec.h"
#if wxUSE_GRID
#include "wx/generic/gridctrl.h"
#include "wx/generic/grideditors.h"
#ifndef WX_PRECOMP
#include "wx/textctrl.h"
#include "wx/dc.h"
#include "wx/combobox.h"
#include "wx/settings.h"
#include "wx/log.h"
#include "wx/checkbox.h"
#endif // WX_PRECOMP
#include "wx/numformatter.h"
#include "wx/tokenzr.h"
#include "wx/renderer.h"
#include "wx/uilocale.h"
#include "wx/generic/private/grid.h"
#include "wx/private/window.h"
// ----------------------------------------------------------------------------
// wxGridCellRenderer
// ----------------------------------------------------------------------------
void wxGridCellRenderer::Draw(wxGrid& grid,
wxGridCellAttr& attr,
wxDC& dc,
const wxRect& rect,
int WXUNUSED(row), int WXUNUSED(col),
bool isSelected)
{
dc.SetBackgroundMode( wxBRUSHSTYLE_SOLID );
wxColour clr;
if ( grid.IsThisEnabled() )
{
if ( isSelected )
{
if ( grid.HasFocus() )
clr = grid.GetSelectionBackground();
else
clr = wxSystemSettings::GetColour(wxSYS_COLOUR_BTNSHADOW);
}
else
{
clr = attr.GetBackgroundColour();
}
}
else // grey out fields if the grid is disabled
{
clr = wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE);
}
dc.SetBrush(clr);
dc.SetPen( *wxTRANSPARENT_PEN );
dc.DrawRectangle(rect);
}
void wxGridCellRenderer::SetTextColoursAndFont(const wxGrid& grid,
const wxGridCellAttr& attr,
wxDC& dc,
bool isSelected)
{
dc.SetBackgroundMode( wxBRUSHSTYLE_TRANSPARENT );
// TODO some special colours for attr.IsReadOnly() case?
// different coloured text when the grid is disabled
if ( grid.IsThisEnabled() )
{
if ( isSelected )
{
wxColour clr;
if ( grid.HasFocus() )
clr = grid.GetSelectionBackground();
else
clr = wxSystemSettings::GetColour(wxSYS_COLOUR_BTNSHADOW);
dc.SetTextBackground( clr );
dc.SetTextForeground( grid.GetSelectionForeground() );
}
else
{
dc.SetTextBackground( attr.GetBackgroundColour() );
dc.SetTextForeground( attr.GetTextColour() );
}
}
else
{
dc.SetTextBackground(wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE));
dc.SetTextForeground(wxSystemSettings::GetColour(wxSYS_COLOUR_GRAYTEXT));
}
dc.SetFont( attr.GetFont() );
}
// ----------------------------------------------------------------------------
// wxGridCellDateTimeRenderer
// ----------------------------------------------------------------------------
#if wxUSE_DATETIME
bool
wxGridPrivate::TryGetValueAsDate(wxDateTime& result,
const DateParseParams& params,
const wxGrid& grid,
int row, int col)
{
wxGridTableBase *table = grid.GetTable();
if ( table->CanGetValueAs(row, col, wxGRID_VALUE_DATETIME) )
{
void * tempval = table->GetValueAsCustom(row, col,wxGRID_VALUE_DATETIME);
if (tempval)
{
result = *((wxDateTime *)tempval);
delete (wxDateTime *)tempval;
return true;
}
}
const wxString text = table->GetValue(row, col);
wxString::const_iterator end;
if ( result.ParseFormat(text, params.format, &end) && end == text.end() )
return true;
// Check if we can fall back to free-form parsing, which notably allows us
// to parse strings such as "today" or "tomorrow" which would be never
// accepted by ParseFormat().
if ( params.fallbackParseDate &&
result.ParseDate(text, &end) && end == text.end() )
return true;
return false;
}
using namespace wxGridPrivate;
// Enables a grid cell to display a formatted date
wxGridCellDateRenderer::wxGridCellDateRenderer(const wxString& outformat)
: wxGridCellStringRenderer()
{
if ( outformat.empty() )
{
m_oformat = wxGetUIDateFormat();
}
else
{
m_oformat = outformat;
}
m_tz = wxDateTime::Local;
}
wxString wxGridCellDateRenderer::GetString(const wxGrid& grid, int row, int col)
{
wxString text;
DateParseParams params;
GetDateParseParams(params);
wxDateTime val;
if ( TryGetValueAsDate(val, params, grid, row, col) )
text = val.Format(m_oformat, m_tz );
// If we failed to parse string just show what we where given?
return text;
}
void
wxGridCellDateRenderer::GetDateParseParams(DateParseParams& params) const
{
params = DateParseParams::WithFallback(m_oformat);
}
void wxGridCellDateRenderer::Draw(wxGrid& grid,
wxGridCellAttr& attr,
wxDC& dc,
const wxRect& rectCell,
int row, int col,
bool isSelected)
{
wxGridCellRenderer::Draw(grid, attr, dc, rectCell, row, col, isSelected);
SetTextColoursAndFont(grid, attr, dc, isSelected);
wxRect rect = rectCell;
rect.Inflate(-1);
// draw the text right aligned by default
grid.DrawTextRectangle(dc, GetString(grid, row, col), rect, attr,
wxALIGN_RIGHT);
}
wxSize wxGridCellDateRenderer::GetBestSize(wxGrid& grid,
wxGridCellAttr& attr,
wxDC& dc,
int row, int 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)
{
if (!params.empty())
m_oformat=params;
}
// Enables a grid cell to display a formatted date and or time
wxGridCellDateTimeRenderer::wxGridCellDateTimeRenderer(const wxString& outformat, const wxString& informat)
: wxGridCellDateRenderer(outformat)
, m_iformat(informat)
{
}
void
wxGridCellDateTimeRenderer::GetDateParseParams(DateParseParams& params) const
{
params = DateParseParams::WithoutFallback(m_iformat);
}
#endif // wxUSE_DATETIME
// ----------------------------------------------------------------------------
// wxGridCellChoiceRenderer
// ----------------------------------------------------------------------------
wxGridCellChoiceRenderer::wxGridCellChoiceRenderer(const wxString& choices)
: wxGridCellStringRenderer()
{
if (!choices.empty())
SetParameters(choices);
}
wxGridCellChoiceRenderer::wxGridCellChoiceRenderer(const wxGridCellChoiceRenderer& other)
: wxGridCellStringRenderer(other),
m_choices(other.m_choices)
{
}
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
// ----------------------------------------------------------------------------
// Renders a number as a textual equivalent.
// eg data in cell is 0,1,2 ... n the cell could be rendered as "John","Fred"..."Bob"
wxString wxGridCellEnumRenderer::GetString(const wxGrid& grid, int row, int col)
{
wxGridTableBase *table = grid.GetTable();
wxString text;
if ( table->CanGetValueAs(row, col, wxGRID_VALUE_NUMBER) )
{
int choiceno = table->GetValueAsLong(row, col);
text.Printf(wxT("%s"), m_choices[ choiceno ] );
}
else
{
text = table->GetValue(row, col);
}
//If we faild to parse string just show what we where given?
return text;
}
void wxGridCellEnumRenderer::Draw(wxGrid& grid,
wxGridCellAttr& attr,
wxDC& dc,
const wxRect& rectCell,
int row, int col,
bool isSelected)
{
wxGridCellRenderer::Draw(grid, attr, dc, rectCell, row, col, isSelected);
SetTextColoursAndFont(grid, attr, dc, isSelected);
wxRect rect = rectCell;
rect.Inflate(-1);
// draw the text right aligned by default
grid.DrawTextRectangle(dc, GetString(grid, row, col), rect, attr,
wxALIGN_RIGHT);
}
wxSize wxGridCellEnumRenderer::GetBestSize(wxGrid& grid,
wxGridCellAttr& attr,
wxDC& dc,
int row, int col)
{
return DoGetBestSize(attr, dc, GetString(grid, row, col));
}
// ----------------------------------------------------------------------------
// wxGridCellAutoWrapStringRenderer
// ----------------------------------------------------------------------------
void
wxGridCellAutoWrapStringRenderer::Draw(wxGrid& grid,
wxGridCellAttr& attr,
wxDC& dc,
const wxRect& rectCell,
int row, int col,
bool isSelected) {
wxGridCellRenderer::Draw(grid, attr, dc, rectCell, row, col, isSelected);
// now we only have to draw the text
SetTextColoursAndFont(grid, attr, dc, isSelected);
int horizAlign, vertAlign;
attr.GetAlignment(&horizAlign, &vertAlign);
wxRect rect = rectCell;
rect.Inflate(-1);
// Do not use here the overload taking the attribute, as this would
// ellipsize the text, which is never necessary with this renderer.
grid.DrawTextRectangle(dc, GetTextLines(grid,dc,attr,rect,row,col),
rect, horizAlign, vertAlign);
}
wxArrayString
wxGridCellAutoWrapStringRenderer::GetTextLines(wxGrid& grid,
wxDC& dc,
const wxGridCellAttr& attr,
const wxRect& rect,
int row, int col)
{
dc.SetFont(attr.GetFont());
const wxCoord maxWidth = rect.GetWidth();
// Transform logical lines into physical ones, wrapping the longer ones.
const wxArrayString
logicalLines = wxSplit(grid.GetCellValue(row, col), '\n', '\0');
// Trying to do anything if the column is hidden anyhow doesn't make sense
// and we run into problems in BreakLine() in this case.
if ( maxWidth <= 0 )
return logicalLines;
wxArrayString physicalLines;
for ( wxArrayString::const_iterator it = logicalLines.begin();
it != logicalLines.end();
++it )
{
const wxString& line = *it;
if ( dc.GetTextExtent(line).x > maxWidth )
{
// Line does not fit, break it up.
BreakLine(dc, line, maxWidth, physicalLines);
}
else // The entire line fits as is
{
physicalLines.push_back(line);
}
}
return physicalLines;
}
void
wxGridCellAutoWrapStringRenderer::BreakLine(wxDC& dc,
const wxString& logicalLine,
wxCoord maxWidth,
wxArrayString& lines)
{
wxCoord lineWidth = 0;
wxString line;
// For each word
wxStringTokenizer wordTokenizer(logicalLine, wxS(" \t"), wxTOKEN_RET_DELIMS);
while ( wordTokenizer.HasMoreTokens() )
{
const wxString word = wordTokenizer.GetNextToken();
const wxCoord wordWidth = dc.GetTextExtent(word).x;
if ( lineWidth + wordWidth < maxWidth )
{
// Word fits, just add it to this line.
line += word;
lineWidth += wordWidth;
}
else
{
// Word does not fit, check whether the word is itself wider that
// available width
if ( wordWidth < maxWidth )
{
// Word can fit in a new line, put it at the beginning
// of the new line.
lines.push_back(line);
line = word;
lineWidth = wordWidth;
}
else // Word cannot fit in available width at all.
{
if ( !line.empty() )
{
lines.push_back(line);
line.clear();
lineWidth = 0;
}
// Break it up in several lines.
lineWidth = BreakWord(dc, word, maxWidth, lines, line);
}
}
}
if ( !line.empty() )
lines.push_back(line);
}
wxCoord
wxGridCellAutoWrapStringRenderer::BreakWord(wxDC& dc,
const wxString& word,
wxCoord maxWidth,
wxArrayString& lines,
wxString& line)
{
wxArrayInt widths;
dc.GetPartialTextExtents(word, widths);
// TODO: Use binary search to find the first element > maxWidth.
const unsigned count = widths.size();
unsigned n;
for ( n = 0; n < count; n++ )
{
if ( widths[n] > maxWidth )
break;
}
if ( n == 0 )
{
// This is a degenerate case: the first character of the word is
// already wider than the available space, so we just can't show it
// completely and have to put the first character in this line.
n = 1;
}
lines.push_back(word.substr(0, n));
// Check if the remainder of the string fits in one line.
//
// Unfortunately we can't use the existing partial text extents as the
// extent of the remainder may be different when it's rendered in a
// separate line instead of as part of the same one, so we have to
// recompute it.
const wxString rest = word.substr(n);
const wxCoord restWidth = dc.GetTextExtent(rest).x;
if ( restWidth <= maxWidth )
{
line = rest;
return restWidth;
}
// Break the rest of the word into lines.
//
// TODO: Perhaps avoid recursion? The code is simpler like this but using a
// loop in this function would probably be more efficient.
return BreakWord(dc, rest, maxWidth, lines, line);
}
wxSize
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();
// 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;
}
int
wxGridCellAutoWrapStringRenderer::GetBestWidth(wxGrid& grid,
wxGridCellAttr& attr,
wxDC& dc,
int row, int col,
int height)
{
const int lineHeight = dc.GetCharHeight();
// Base the maximal number of lines either on how many fit or how many
// (new)lines the cell's text contains, whichever results in the most lines.
//
// It's important to take the newlines into account as GetTextLines() splits
// based on them and the number of lines returned can never drop below that,
// resulting in the while loop below never exiting if there are already more
// lines in the text than can fit in the available height.
const size_t maxLines = wxMax(
(height - AUTOWRAP_Y_MARGIN)/lineHeight,
1 + grid.GetCellValue(row, col).Freq(wxS('\n')));
// 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;
}
// ----------------------------------------------------------------------------
// wxGridCellStringRenderer
// ----------------------------------------------------------------------------
wxSize wxGridCellStringRenderer::DoGetBestSize(const wxGridCellAttr& attr,
wxDC& dc,
const wxString& text)
{
dc.SetFont(attr.GetFont());
return dc.GetMultiLineTextExtent(text);
}
wxSize wxGridCellStringRenderer::GetBestSize(wxGrid& grid,
wxGridCellAttr& attr,
wxDC& dc,
int row, int col)
{
return DoGetBestSize(attr, dc, grid.GetCellValue(row, col));
}
void wxGridCellStringRenderer::Draw(wxGrid& grid,
wxGridCellAttr& attr,
wxDC& dc,
const wxRect& rectCell,
int row, int col,
bool isSelected)
{
wxRect rect = rectCell;
rect.Inflate(-1);
// erase only this cells background, overflow cells should have been erased
wxGridCellRenderer::Draw(grid, attr, dc, rectCell, row, col, isSelected);
if ( attr.CanOverflow() )
{
int hAlign, vAlign;
attr.GetAlignment(&hAlign, &vAlign);
int overflowCols = 0;
int cols = grid.GetNumberCols();
int best_width = GetBestSize(grid,attr,dc,row,col).GetWidth();
int cell_rows, cell_cols;
attr.GetSize( &cell_rows, &cell_cols ); // shouldn't get here if <= 0
if ((best_width > rectCell.width) && (col < cols) && grid.GetTable())
{
int i, c_cols, c_rows;
for (i = col+cell_cols; i < cols; i++)
{
bool is_empty = true;
for (int j=row; j < row + cell_rows; j++)
{
// check w/ anchor cell for multicell block
grid.GetCellSize(j, i, &c_rows, &c_cols);
if (c_rows > 0)
c_rows = 0;
if (!grid.GetTable()->IsEmptyCell(j + c_rows, i))
{
is_empty = false;
break;
}
}
if (is_empty)
{
rect.width += grid.GetColSize(i);
}
else
{
i--;
break;
}
if (rect.width >= best_width)
break;
}
overflowCols = i - col - cell_cols + 1;
if (overflowCols >= cols)
overflowCols = cols - 1;
}
if (overflowCols > 0) // redraw overflow cells w/ proper hilight
{
hAlign = wxALIGN_LEFT; // if oveflowed then it's left aligned
wxRect clip = rect;
clip.x += rectCell.width;
// draw each overflow cell individually
int col_end = col + cell_cols + overflowCols;
if (col_end >= grid.GetNumberCols())
col_end = grid.GetNumberCols() - 1;
for (int i = col + cell_cols; i <= col_end; i++)
{
// redraw the cell to update the background
wxGridCellCoords coords(row, i);
grid.DrawCell(dc, coords);
clip.width = grid.GetColSize(i) - 1;
wxDCClipper clipper(dc, clip);
SetTextColoursAndFont(grid, attr, dc,
grid.IsInSelection(row,i));
grid.DrawTextRectangle(dc, grid.GetCellValue(row, col),
rect, hAlign, vAlign);
clip.x += grid.GetColSize(i) - 1;
}
rect = rectCell;
rect.Inflate(-1);
rect.width++;
}
}
// now we only have to draw the text
SetTextColoursAndFont(grid, attr, dc, isSelected);
grid.DrawTextRectangle(dc, grid.GetCellValue(row, col),
rect, attr);
}
// ----------------------------------------------------------------------------
// wxGridCellNumberRenderer
// ----------------------------------------------------------------------------
wxString wxGridCellNumberRenderer::GetString(const wxGrid& grid, int row, int col)
{
wxGridTableBase *table = grid.GetTable();
wxString text;
if ( table->CanGetValueAs(row, col, wxGRID_VALUE_NUMBER) )
{
text.Printf(wxT("%ld"), table->GetValueAsLong(row, col));
}
else
{
text = table->GetValue(row, col);
}
return text;
}
void wxGridCellNumberRenderer::Draw(wxGrid& grid,
wxGridCellAttr& attr,
wxDC& dc,
const wxRect& rectCell,
int row, int col,
bool isSelected)
{
wxGridCellRenderer::Draw(grid, attr, dc, rectCell, row, col, isSelected);
SetTextColoursAndFont(grid, attr, dc, isSelected);
wxRect rect = rectCell;
rect.Inflate(-1);
// draw the text right aligned by default
grid.DrawTextRectangle(dc, GetString(grid, row, col), rect, attr,
wxALIGN_RIGHT);
}
wxSize wxGridCellNumberRenderer::GetBestSize(wxGrid& grid,
wxGridCellAttr& attr,
wxDC& dc,
int row, int 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::wxGridCellFloatRenderer(int width,
int precision,
int format)
: wxGridCellStringRenderer()
{
SetWidth(width);
SetPrecision(precision);
SetFormat(format);
}
wxString wxGridCellFloatRenderer::GetString(const wxGrid& grid, int row, int col)
{
wxGridTableBase *table = grid.GetTable();
bool hasDouble;
double val;
wxString text;
if ( table->CanGetValueAs(row, col, wxGRID_VALUE_FLOAT) )
{
val = table->GetValueAsDouble(row, col);
hasDouble = true;
}
else
{
text = table->GetValue(row, col);
hasDouble = wxNumberFormatter::FromString(text, &val);
}
if ( hasDouble )
{
if ( !m_format )
{
if ( m_width == -1 )
{
if ( m_precision == -1 )
{
// default width/precision
m_format = wxT("%");
}
else
{
m_format.Printf(wxT("%%.%d"), m_precision);
}
}
else if ( m_precision == -1 )
{
// default precision
m_format.Printf(wxT("%%%d."), m_width);
}
else
{
m_format.Printf(wxT("%%%d.%d"), m_width, m_precision);
}
bool isUpper = ( ( m_style & wxGRID_FLOAT_FORMAT_UPPER ) == wxGRID_FLOAT_FORMAT_UPPER);
if ( ( m_style & wxGRID_FLOAT_FORMAT_SCIENTIFIC ) == wxGRID_FLOAT_FORMAT_SCIENTIFIC)
m_format += isUpper ? wxT('E') : wxT('e');
else if ( ( m_style & wxGRID_FLOAT_FORMAT_COMPACT ) == wxGRID_FLOAT_FORMAT_COMPACT)
m_format += isUpper ? wxT('G') : wxT('g');
else
m_format += wxT('f');
}
text = wxNumberFormatter::Format(m_format, val);
}
//else: text already contains the string
return text;
}
void wxGridCellFloatRenderer::Draw(wxGrid& grid,
wxGridCellAttr& attr,
wxDC& dc,
const wxRect& rectCell,
int row, int col,
bool isSelected)
{
wxGridCellRenderer::Draw(grid, attr, dc, rectCell, row, col, isSelected);
SetTextColoursAndFont(grid, attr, dc, isSelected);
wxRect rect = rectCell;
rect.Inflate(-1);
// draw the text right aligned by default
grid.DrawTextRectangle(dc, GetString(grid, row, col), rect, attr,
wxALIGN_RIGHT);
}
wxSize wxGridCellFloatRenderer::GetBestSize(wxGrid& grid,
wxGridCellAttr& attr,
wxDC& dc,
int row, int col)
{
return DoGetBestSize(attr, dc, GetString(grid, row, col));
}
void wxGridCellFloatRenderer::SetParameters(const wxString& params)
{
if ( !params )
{
// reset to defaults
SetWidth(-1);
SetPrecision(-1);
SetFormat(wxGRID_FLOAT_FORMAT_DEFAULT);
}
else
{
wxString rest;
wxString tmp = params.BeforeFirst(wxT(','), &rest);
if ( !tmp.empty() )
{
long width;
if ( tmp.ToLong(&width) )
{
SetWidth((int)width);
}
else
{
wxLogDebug(wxT("Invalid wxGridCellFloatRenderer width parameter string '%s ignored"), params);
}
}
tmp = rest.BeforeFirst(wxT(','));
if ( !tmp.empty() )
{
long precision;
if ( tmp.ToLong(&precision) )
{
SetPrecision((int)precision);
}
else
{
wxLogDebug(wxT("Invalid wxGridCellFloatRenderer precision parameter string '%s ignored"), params);
}
}
tmp = rest.AfterFirst(wxT(','));
if ( !tmp.empty() )
{
if ( tmp[0] == wxT('f') )
{
SetFormat(wxGRID_FLOAT_FORMAT_FIXED);
}
else if ( tmp[0] == wxT('e') )
{
SetFormat(wxGRID_FLOAT_FORMAT_SCIENTIFIC);
}
else if ( tmp[0] == wxT('g') )
{
SetFormat(wxGRID_FLOAT_FORMAT_COMPACT);
}
else if ( tmp[0] == wxT('E') )
{
SetFormat(wxGRID_FLOAT_FORMAT_SCIENTIFIC |
wxGRID_FLOAT_FORMAT_UPPER);
}
else if ( tmp[0] == wxT('F') )
{
SetFormat(wxGRID_FLOAT_FORMAT_FIXED |
wxGRID_FLOAT_FORMAT_UPPER);
}
else if ( tmp[0] == wxT('G') )
{
SetFormat(wxGRID_FLOAT_FORMAT_COMPACT |
wxGRID_FLOAT_FORMAT_UPPER);
}
else
{
wxLogDebug("Invalid wxGridCellFloatRenderer format "
"parameter string '%s ignored", params);
}
}
}
}
// ----------------------------------------------------------------------------
// wxGridCellBoolRenderer
// ----------------------------------------------------------------------------
wxSize wxGridCellBoolRenderer::GetBestSize(wxGrid& grid,
wxGridCellAttr& attr,
wxDC& dc,
int WXUNUSED(row),
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;
// Get the check mark size in pixels if it hadn't been done yet or if the
// DPI has changed.
if ( s_sizeCheckMark.HasChanged(&grid) )
{
s_sizeCheckMark.SetAtNewDPI
(
wxRendererNative::Get().GetCheckBoxSize(&grid, wxCONTROL_CELL)
);
}
return s_sizeCheckMark.Get();
}
void wxGridCellBoolRenderer::Draw(wxGrid& grid,
wxGridCellAttr& attr,
wxDC& dc,
const wxRect& rect,
int row, int col,
bool isSelected)
{
wxGridCellRenderer::Draw(grid, attr, dc, rect, row, col, isSelected);
int hAlign = wxALIGN_LEFT;
int vAlign = wxALIGN_CENTRE_VERTICAL;
attr.GetNonDefaultAlignment(&hAlign, &vAlign);
const wxRect checkBoxRect =
wxGetContentRect(GetBestSize(grid, attr, dc, row, col),
rect, hAlign, vAlign);
bool value;
if ( grid.GetTable()->CanGetValueAs(row, col, wxGRID_VALUE_BOOL) )
{
value = grid.GetTable()->GetValueAsBool(row, col);
}
else
{
wxString cellval( grid.GetTable()->GetValue(row, col) );
value = wxGridCellBoolEditor::IsTrueValue(cellval);
}
int flags = wxCONTROL_CELL;
if (value)
flags |= wxCONTROL_CHECKED;
wxRendererNative::Get().DrawCheckBox( &grid, dc, checkBoxRect, flags );
}
#endif // wxUSE_GRID