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