X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/ca65c0440a7163e4e37e48b1c4329709d722db47..bf2c43c76e2819be443ab1d830ab68d9569d66b1:/src/generic/gridctrl.cpp diff --git a/src/generic/gridctrl.cpp b/src/generic/gridctrl.cpp index 6b608141f9..4e9dcd6e48 100644 --- a/src/generic/gridctrl.cpp +++ b/src/generic/gridctrl.cpp @@ -1,18 +1,13 @@ /////////////////////////////////////////////////////////////////////////// -// Name: generic/gridctrl.cpp +// Name: src/generic/gridctrl.cpp // Purpose: wxGrid controls // Author: Paul Gammans, Roger Gammans // Modified by: // Created: 11/04/2001 -// RCS-ID: $Id$ // Copyright: (c) The Computer Surgery (paul@compsurg.co.uk) // Licence: wxWindows licence ///////////////////////////////////////////////////////////////////////////// -#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA) - #pragma implementation "gridctrl.h" -#endif - #include "wx/wxprec.h" #ifdef __BORLANDC__ @@ -21,13 +16,60 @@ #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/generic/gridctrl.h" #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 @@ -35,9 +77,9 @@ #if wxUSE_DATETIME -// Enables a grid cell to display a formated date and or time +// Enables a grid cell to display a formatted date and or time -wxGridCellDateTimeRenderer::wxGridCellDateTimeRenderer(wxString outformat, wxString informat) +wxGridCellDateTimeRenderer::wxGridCellDateTimeRenderer(const wxString& outformat, const wxString& informat) { m_iformat = informat; m_oformat = outformat; @@ -56,7 +98,7 @@ wxGridCellRenderer *wxGridCellDateTimeRenderer::Clone() const return renderer; } -wxString wxGridCellDateTimeRenderer::GetString(wxGrid& grid, int row, int col) +wxString wxGridCellDateTimeRenderer::GetString(const wxGrid& grid, int row, int col) { wxGridTableBase *table = grid.GetTable(); @@ -67,7 +109,8 @@ wxString wxGridCellDateTimeRenderer::GetString(wxGrid& grid, int row, int col) { void * tempval = table->GetValueAsCustom(row, col,wxGRID_VALUE_DATETIME); - if (tempval){ + if (tempval) + { val = *((wxDateTime *)tempval); hasDatetime = true; delete (wxDateTime *)tempval; @@ -78,13 +121,14 @@ wxString wxGridCellDateTimeRenderer::GetString(wxGrid& grid, int row, int col) if (!hasDatetime ) { text = table->GetValue(row, col); - hasDatetime = (val.ParseFormat( text, m_iformat, m_dateDef ) != (wxChar *)NULL) ; + 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 faild to parse string just show what we where given? + // If we failed to parse string just show what we where given? return text; } @@ -100,9 +144,9 @@ void wxGridCellDateTimeRenderer::Draw(wxGrid& grid, SetTextColoursAndFont(grid, attr, dc, isSelected); // draw the text right aligned by default - int hAlign, vAlign; - attr.GetAlignment(&hAlign, &vAlign); - hAlign = wxRIGHT; + int hAlign = wxALIGN_RIGHT, + vAlign = wxALIGN_INVALID; + attr.GetNonDefaultAlignment(&hAlign, &vAlign); wxRect rect = rectCell; rect.Inflate(-1); @@ -118,15 +162,16 @@ wxSize wxGridCellDateTimeRenderer::GetBestSize(wxGrid& grid, return DoGetBestSize(attr, dc, GetString(grid, row, col)); } -void wxGridCellDateTimeRenderer::SetParameters(const wxString& params){ - if (!params.IsEmpty()) +void wxGridCellDateTimeRenderer::SetParameters(const wxString& params) +{ + if (!params.empty()) m_oformat=params; } #endif // wxUSE_DATETIME // ---------------------------------------------------------------------------- -// wxGridCellChoiceNumberRenderer +// 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" @@ -134,7 +179,7 @@ void wxGridCellDateTimeRenderer::SetParameters(const wxString& params){ wxGridCellEnumRenderer::wxGridCellEnumRenderer(const wxString& choices) { - if (!choices.IsEmpty()) + if (!choices.empty()) SetParameters(choices); } @@ -145,14 +190,14 @@ wxGridCellRenderer *wxGridCellEnumRenderer::Clone() const return renderer; } -wxString wxGridCellEnumRenderer::GetString(wxGrid& grid, int row, int col) +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(_T("%s"), m_choices[ choiceno ].c_str() ); + text.Printf(wxT("%s"), m_choices[ choiceno ].c_str() ); } else { @@ -176,9 +221,9 @@ void wxGridCellEnumRenderer::Draw(wxGrid& grid, SetTextColoursAndFont(grid, attr, dc, isSelected); // draw the text right aligned by default - int hAlign, vAlign; - attr.GetAlignment(&hAlign, &vAlign); - hAlign = wxRIGHT; + int hAlign = wxALIGN_RIGHT, + vAlign = wxALIGN_INVALID; + attr.GetNonDefaultAlignment(&hAlign, &vAlign); wxRect rect = rectCell; rect.Inflate(-1); @@ -204,200 +249,707 @@ void wxGridCellEnumRenderer::SetParameters(const wxString& params) m_choices.Empty(); - wxStringTokenizer tk(params, _T(',')); + wxStringTokenizer tk(params, wxT(',')); while ( tk.HasMoreTokens() ) { m_choices.Add(tk.GetNextToken()); } } -#if wxUSE_COMBOBOX // ---------------------------------------------------------------------------- -// wxGridCellEnumEditor +// wxGridCellAutoWrapStringRenderer // ---------------------------------------------------------------------------- -// A cell editor which displays an enum number as a textual equivalent. eg -// data in cell is 0,1,2 ... n the cell could be displayed as -// "John","Fred"..."Bob" in the combo choice box -wxGridCellEnumEditor::wxGridCellEnumEditor(const wxString& choices) - : wxGridCellChoiceEditor() -{ - m_startint = -1; +void +wxGridCellAutoWrapStringRenderer::Draw(wxGrid& grid, + wxGridCellAttr& attr, + wxDC& dc, + const wxRect& rectCell, + int row, int col, + bool isSelected) { - if (!choices.IsEmpty()) - SetParameters(choices); -} -wxGridCellEditor *wxGridCellEnumEditor::Clone() const -{ - wxGridCellEnumEditor *editor = new wxGridCellEnumEditor(); - editor->m_startint = m_startint; - return editor; + 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); } -void wxGridCellEnumEditor::BeginEdit(int row, int col, wxGrid* grid) + +wxArrayString +wxGridCellAutoWrapStringRenderer::GetTextLines(wxGrid& grid, + wxDC& dc, + const wxGridCellAttr& attr, + const wxRect& rect, + int row, int col) { - wxASSERT_MSG(m_control, - wxT("The wxGridCellEnumEditor must be Created first!")); + dc.SetFont(attr.GetFont()); + const wxCoord maxWidth = rect.GetWidth(); - wxGridTableBase *table = grid->GetTable(); + // Transform logical lines into physical ones, wrapping the longer ones. + const wxArrayString + logicalLines = wxSplit(grid.GetCellValue(row, col), '\n', '\0'); - if ( table->CanGetValueAs(row, col, wxGRID_VALUE_NUMBER) ) + wxArrayString physicalLines; + for ( wxArrayString::const_iterator it = logicalLines.begin(); + it != logicalLines.end(); + ++it ) { - m_startint = table->GetValueAsLong(row, col); + 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); + } } - else + + 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() ) { - wxString startValue = table->GetValue(row, col); - if (startValue.IsNumber() && !startValue.IsEmpty()) + const wxString word = wordTokenizer.GetNextToken(); + const wxCoord wordWidth = dc.GetTextExtent(word).x; + if ( lineWidth + wordWidth < maxWidth ) { - startValue.ToLong(&m_startint); + // Word fits, just add it to this line. + line += word; + lineWidth += wordWidth; } else { - m_startint=-1; + // 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); + } } } - Combo()->SetSelection(m_startint); - Combo()->SetInsertionPointEnd(); - Combo()->SetFocus(); - + if ( !line.empty() ) + lines.push_back(line); } -bool wxGridCellEnumEditor::EndEdit(int row, int col, wxGrid* grid) + +wxCoord +wxGridCellAutoWrapStringRenderer::BreakWord(wxDC& dc, + const wxString& word, + wxCoord maxWidth, + wxArrayString& lines, + wxString& line) { - int pos = Combo()->GetSelection(); - bool changed = (pos != m_startint); - if (changed) + 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 (grid->GetTable()->CanSetValueAs(row, col, wxGRID_VALUE_NUMBER)) - grid->GetTable()->SetValueAsLong(row, col, pos); - else - grid->GetTable()->SetValue(row, col,wxString::Format(wxT("%i"),pos)); + 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; } - return changed; + // 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) +{ + wxCoord x,y, height , width = grid.GetColSize(col) -20; + // for width, subtract 20 because ColSize includes a magin of 10 pixels + // that we do not want here and because we always start with an increment + // by 10 in the loop below. + int count = 250; //Limit iterations.. + + wxRect rect(0,0,width,10); + + // M is a nice large character 'y' gives descender!. + dc.GetTextExtent(wxT("My"), &x, &y); + + do + { + width+=10; + rect.SetWidth(width); + height = y * (wx_truncate_cast(wxCoord, GetTextLines(grid,dc,attr,rect,row,col).GetCount())); + count--; + // Search for a shape no taller than the golden ratio. + } while (count && (width < (height*1.68)) ); + + + return wxSize(width,height); } -#endif // wxUSE_COMBOBOX // ---------------------------------------------------------------------------- -// wxGridCellAutoWrapStringEditor +// wxGridCellStringRenderer // ---------------------------------------------------------------------------- -void -wxGridCellAutoWrapStringEditor::Create(wxWindow* parent, - wxWindowID id, - wxEvtHandler* evtHandler) +void wxGridCellStringRenderer::SetTextColoursAndFont(const wxGrid& grid, + const wxGridCellAttr& attr, + wxDC& dc, + bool isSelected) { - m_control = new wxTextCtrl(parent, id, wxEmptyString, - wxDefaultPosition, wxDefaultSize, - wxTE_MULTILINE | wxTE_RICH); + dc.SetBackgroundMode( wxBRUSHSTYLE_TRANSPARENT ); + // TODO some special colours for attr.IsReadOnly() case? - wxGridCellEditor::Create(parent, id, evtHandler); + // 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() ); } -void -wxGridCellAutoWrapStringRenderer::Draw(wxGrid& grid, - wxGridCellAttr& attr, - wxDC& dc, - const wxRect& rectCell, - int row, int col, - bool isSelected) { +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; + dc.DestroyClippingRegion(); + dc.SetClippingRegion(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++; + dc.DestroyClippingRegion(); + } + } + // now we only have to draw the text SetTextColoursAndFont(grid, attr, dc, isSelected); - int horizAlign, vertAlign; - attr.GetAlignment(&horizAlign, &vertAlign); + 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, GetTextLines(grid,dc,attr,rect,row,col), - rect, horizAlign, vertAlign); + 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)); +} -wxArrayString -wxGridCellAutoWrapStringRenderer::GetTextLines(wxGrid& grid, - wxDC& dc, - wxGridCellAttr& attr, - const wxRect& rect, - int row, int col) +// ---------------------------------------------------------------------------- +// wxGridCellFloatRenderer +// ---------------------------------------------------------------------------- + +wxGridCellFloatRenderer::wxGridCellFloatRenderer(int width, + int precision, + int format) { - wxString data = grid.GetCellValue(row, col); + SetWidth(width); + SetPrecision(precision); + SetFormat(format); +} - wxArrayString lines; - dc.SetFont(attr.GetFont()); +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; - //Taken from wxGrid again! - wxCoord x = 0, y = 0, curr_x = 0; - wxCoord max_x = rect.GetWidth(); + return renderer; +} - dc.SetFont(attr.GetFont()); - wxStringTokenizer tk(data , _T(" \n\t\r")); - wxString thisline = wxEmptyString; +wxString wxGridCellFloatRenderer::GetString(const wxGrid& grid, int row, int col) +{ + wxGridTableBase *table = grid.GetTable(); - while ( tk.HasMoreTokens() ) + bool hasDouble; + double val; + wxString text; + if ( table->CanGetValueAs(row, col, wxGRID_VALUE_FLOAT) ) { - wxString tok = tk.GetNextToken(); - //FIXME: this causes us to print an extra unnecesary - // space at the end of the line. But it - // is invisible , simplifies the size calculation - // and ensures tokens are seperated in the display - tok += _T(" "); - - dc.GetTextExtent(tok, &x, &y); - if ( curr_x + x > max_x) { - lines.Add( wxString(thisline) ); - thisline = tok; - curr_x=x; - } else { - thisline+= tok; - curr_x += x; + 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); } - //Add last line - lines.Add( wxString(thisline) ); + //else: text already contains the string - return lines; + 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); -wxSize -wxGridCellAutoWrapStringRenderer::GetBestSize(wxGrid& grid, - wxGridCellAttr& attr, - wxDC& dc, - int row, int col) + 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) { - wxCoord x,y, height , width = grid.GetColSize(col) -10; - int count = 250; //Limit iterations.. + return DoGetBestSize(attr, dc, GetString(grid, row, col)); +} - wxRect rect(0,0,width,10); +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()); + } + } - // M is a nice large character 'y' gives descender!. - dc.GetTextExtent(wxT("My"), &x, &y); + 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()); + } + } - do + 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 ) { - width+=10; - rect.SetWidth(width); - height = y *( GetTextLines(grid,dc,attr,rect,row,col).GetCount()); - count--; - // Search for a shape no taller than the golden ratio. - } while (count && (width < (height*1.68)) ); + ms_sizeCheckMark = wxRendererNative::Get().GetCheckBoxSize(&grid); + } + return ms_sizeCheckMark; +} - return wxSize(width,height); +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