Files
wxWidgets/src/generic/gridctrl.cpp
jonkraber 7f52ff751f Fix clipping of cell contents in wxGrid
Use wxDCClipper, now that it doesn't lose the previously set clipping
region any more, in wxGridCellStringRenderer::Draw() to ensure that we
don't overflow the area allocated for the cell.

Closes #17872.
2017-12-24 15:46:57 +01:00

988 lines
30 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"
#ifdef __BORLANDC__
#pragma hdrstop
#endif
#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/tokenzr.h"
#include "wx/renderer.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);
}
// ----------------------------------------------------------------------------
// wxGridCellDateTimeRenderer
// ----------------------------------------------------------------------------
#if wxUSE_DATETIME
// Enables a grid cell to display a formatted date and or time
wxGridCellDateTimeRenderer::wxGridCellDateTimeRenderer(const wxString& outformat, const wxString& informat)
{
m_iformat = informat;
m_oformat = outformat;
m_tz = wxDateTime::Local;
m_dateDef = wxDefaultDateTime;
}
wxGridCellRenderer *wxGridCellDateTimeRenderer::Clone() const
{
wxGridCellDateTimeRenderer *renderer = new wxGridCellDateTimeRenderer;
renderer->m_iformat = m_iformat;
renderer->m_oformat = m_oformat;
renderer->m_dateDef = m_dateDef;
renderer->m_tz = m_tz;
return renderer;
}
wxString wxGridCellDateTimeRenderer::GetString(const wxGrid& grid, int row, int col)
{
wxGridTableBase *table = grid.GetTable();
bool hasDatetime = false;
wxDateTime val;
wxString text;
if ( table->CanGetValueAs(row, col, wxGRID_VALUE_DATETIME) )
{
void * tempval = table->GetValueAsCustom(row, col,wxGRID_VALUE_DATETIME);
if (tempval)
{
val = *((wxDateTime *)tempval);
hasDatetime = true;
delete (wxDateTime *)tempval;
}
}
if (!hasDatetime )
{
text = table->GetValue(row, col);
const char * const end = val.ParseFormat(text, m_iformat, m_dateDef);
hasDatetime = end && !*end;
}
if ( hasDatetime )
text = val.Format(m_oformat, m_tz );
// If we failed to parse string just show what we where given?
return text;
}
void wxGridCellDateTimeRenderer::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);
// draw the text right aligned by default
int hAlign = wxALIGN_RIGHT,
vAlign = wxALIGN_INVALID;
attr.GetNonDefaultAlignment(&hAlign, &vAlign);
wxRect rect = rectCell;
rect.Inflate(-1);
grid.DrawTextRectangle(dc, GetString(grid, row, col), rect, hAlign, vAlign);
}
wxSize wxGridCellDateTimeRenderer::GetBestSize(wxGrid& grid,
wxGridCellAttr& attr,
wxDC& dc,
int row, int col)
{
return DoGetBestSize(attr, dc, GetString(grid, row, col));
}
void wxGridCellDateTimeRenderer::SetParameters(const wxString& params)
{
if (!params.empty())
m_oformat=params;
}
#endif // wxUSE_DATETIME
// ----------------------------------------------------------------------------
// 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"
wxGridCellEnumRenderer::wxGridCellEnumRenderer(const wxString& choices)
{
if (!choices.empty())
SetParameters(choices);
}
wxGridCellRenderer *wxGridCellEnumRenderer::Clone() const
{
wxGridCellEnumRenderer *renderer = new wxGridCellEnumRenderer;
renderer->m_choices = m_choices;
return renderer;
}
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 ].c_str() );
}
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);
// draw the text right aligned by default
int hAlign = wxALIGN_RIGHT,
vAlign = wxALIGN_INVALID;
attr.GetNonDefaultAlignment(&hAlign, &vAlign);
wxRect rect = rectCell;
rect.Inflate(-1);
grid.DrawTextRectangle(dc, GetString(grid, row, col), rect, hAlign, vAlign);
}
wxSize wxGridCellEnumRenderer::GetBestSize(wxGrid& grid,
wxGridCellAttr& attr,
wxDC& dc,
int row, int 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
// ----------------------------------------------------------------------------
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);
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();
// 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;
}
// ----------------------------------------------------------------------------
// wxGridCellStringRenderer
// ----------------------------------------------------------------------------
void wxGridCellStringRenderer::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() );
}
wxSize wxGridCellStringRenderer::DoGetBestSize(const wxGridCellAttr& attr,
wxDC& dc,
const wxString& text)
{
wxCoord x = 0, y = 0, max_x = 0;
dc.SetFont(attr.GetFont());
wxStringTokenizer tk(text, wxT('\n'));
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,
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);
int hAlign, vAlign;
attr.GetAlignment(&hAlign, &vAlign);
int overflowCols = 0;
if (attr.GetOverflow())
{
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++)
{
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, hAlign, vAlign);
}
// ----------------------------------------------------------------------------
// 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);
// draw the text right aligned by default
int hAlign = wxALIGN_RIGHT,
vAlign = wxALIGN_INVALID;
attr.GetNonDefaultAlignment(&hAlign, &vAlign);
wxRect rect = rectCell;
rect.Inflate(-1);
grid.DrawTextRectangle(dc, GetString(grid, row, col), rect, hAlign, vAlign);
}
wxSize wxGridCellNumberRenderer::GetBestSize(wxGrid& grid,
wxGridCellAttr& attr,
wxDC& dc,
int row, int col)
{
return DoGetBestSize(attr, dc, GetString(grid, row, col));
}
// ----------------------------------------------------------------------------
// wxGridCellFloatRenderer
// ----------------------------------------------------------------------------
wxGridCellFloatRenderer::wxGridCellFloatRenderer(int width,
int precision,
int format)
{
SetWidth(width);
SetPrecision(precision);
SetFormat(format);
}
wxGridCellRenderer *wxGridCellFloatRenderer::Clone() const
{
wxGridCellFloatRenderer *renderer = new wxGridCellFloatRenderer;
renderer->m_width = m_width;
renderer->m_precision = m_precision;
renderer->m_style = m_style;
renderer->m_format = m_format;
return renderer;
}
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 = text.ToDouble(&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.Printf(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);
// draw the text right aligned by default
int hAlign = wxALIGN_RIGHT,
vAlign = wxALIGN_INVALID;
attr.GetNonDefaultAlignment(&hAlign, &vAlign);
wxRect rect = rectCell;
rect.Inflate(-1);
grid.DrawTextRectangle(dc, GetString(grid, row, col), rect, hAlign, vAlign);
}
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.c_str());
}
}
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.c_str());
}
}
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::ms_sizeCheckMark;
wxSize wxGridCellBoolRenderer::GetBestSize(wxGrid& grid,
wxGridCellAttr& WXUNUSED(attr),
wxDC& WXUNUSED(dc),
int WXUNUSED(row),
int WXUNUSED(col))
{
// compute it only once (no locks for MT safeness in GUI thread...)
if ( !ms_sizeCheckMark.x )
{
ms_sizeCheckMark = wxRendererNative::Get().GetCheckBoxSize(&grid);
}
return ms_sizeCheckMark;
}
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);
// draw a check mark in the centre (ignoring alignment - TODO)
wxSize size = GetBestSize(grid, attr, dc, row, col);
// don't draw outside the cell
wxCoord minSize = wxMin(rect.width, rect.height);
if ( size.x >= minSize || size.y >= minSize )
{
// and even leave (at least) 1 pixel margin
size.x = size.y = minSize;
}
// draw a border around checkmark
int vAlign, hAlign;
attr.GetAlignment(&hAlign, &vAlign);
wxRect rectBorder;
if (hAlign == wxALIGN_CENTRE)
{
rectBorder.x = rect.x + rect.width / 2 - size.x / 2;
rectBorder.y = rect.y + rect.height / 2 - size.y / 2;
rectBorder.width = size.x;
rectBorder.height = size.y;
}
else if (hAlign == wxALIGN_LEFT)
{
rectBorder.x = rect.x + 2;
rectBorder.y = rect.y + rect.height / 2 - size.y / 2;
rectBorder.width = size.x;
rectBorder.height = size.y;
}
else if (hAlign == wxALIGN_RIGHT)
{
rectBorder.x = rect.x + rect.width - size.x - 2;
rectBorder.y = rect.y + rect.height / 2 - size.y / 2;
rectBorder.width = size.x;
rectBorder.height = size.y;
}
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 = 0;
if (value)
flags |= wxCONTROL_CHECKED;
wxRendererNative::Get().DrawCheckBox( &grid, dc, rectBorder, flags );
}
#endif // wxUSE_GRID