X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/5c3a7f71a6a9d40a64af96b587161adfb54f90af..bddab017c6c78f1dab68745a532996bab37f3ee8:/src/generic/gridctrl.cpp diff --git a/src/generic/gridctrl.cpp b/src/generic/gridctrl.cpp index 3098fd5ad5..25c3359d3b 100644 --- a/src/generic/gridctrl.cpp +++ b/src/generic/gridctrl.cpp @@ -1,10 +1,9 @@ /////////////////////////////////////////////////////////////////////////// -// 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 ///////////////////////////////////////////////////////////////////////////// @@ -24,7 +23,7 @@ #include "wx/textctrl.h" #include "wx/dc.h" #include "wx/combobox.h" - #include "wx/settings.h" + #include "wx/settings.h" #include "wx/log.h" #include "wx/checkbox.h" #endif // WX_PRECOMP @@ -32,6 +31,46 @@ #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 // ---------------------------------------------------------------------------- @@ -105,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); @@ -132,7 +171,7 @@ void wxGridCellDateTimeRenderer::SetParameters(const wxString& 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" @@ -158,7 +197,7 @@ wxString wxGridCellEnumRenderer::GetString(const wxGrid& grid, int row, int col) 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 { @@ -182,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); @@ -210,7 +249,7 @@ 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()); @@ -255,125 +294,162 @@ wxGridCellAutoWrapStringRenderer::GetTextLines(wxGrid& grid, const wxRect& rect, int row, int col) { - wxString data = grid.GetCellValue(row, col); - - wxArrayString lines; dc.SetFont(attr.GetFont()); + const wxCoord maxWidth = rect.GetWidth(); - //Taken from wxGrid again! - wxCoord x = 0, y = 0, curr_x = 0; - wxCoord max_x = rect.GetWidth(); + // Transform logical lines into physical ones, wrapping the longer ones. + const wxArrayString + logicalLines = wxSplit(grid.GetCellValue(row, col), '\n', '\0'); - dc.SetFont(attr.GetFont()); - wxStringTokenizer tk(data , _T(" \n\t\r")); - wxString thisline = wxEmptyString; + // 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; - while ( tk.HasMoreTokens() ) + wxArrayString physicalLines; + for ( wxArrayString::const_iterator it = logicalLines.begin(); + it != logicalLines.end(); + ++it ) { - 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 separated in the display - tok += _T(" "); + const wxString& line = *it; - dc.GetTextExtent(tok, &x, &y); - if ( curr_x + x > max_x) + if ( dc.GetTextExtent(line).x > maxWidth ) { - if ( curr_x == 0 ) + // 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 ) { - // this means that a single token is wider than the maximal - // width -- still use it as is as we need to show at least the - // part of it which fits - lines.Add(tok); + // 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 + else // Word cannot fit in available width at all. { - lines.Add(thisline); - thisline = tok; - curr_x = x; + if ( !line.empty() ) + { + lines.push_back(line); + line.clear(); + lineWidth = 0; + } + + // Break it up in several lines. + lineWidth = BreakWord(dc, word, maxWidth, lines, line); } } - else - { - thisline+= tok; - curr_x += x; - } } - //Add last line - lines.Add( wxString(thisline) ); - return lines; + if ( !line.empty() ) + lines.push_back(line); } -wxSize -wxGridCellAutoWrapStringRenderer::GetBestSize(wxGrid& grid, - wxGridCellAttr& attr, - wxDC& dc, - int row, int col) +wxCoord +wxGridCellAutoWrapStringRenderer::BreakWord(wxDC& dc, + const wxString& word, + wxCoord maxWidth, + wxArrayString& lines, + wxString& line) { - 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); + wxArrayInt widths; + dc.GetPartialTextExtents(word, widths); - // M is a nice large character 'y' gives descender!. - dc.GetTextExtent(wxT("My"), &x, &y); + // 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; + } - do + if ( n == 0 ) { - 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)) ); + // 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 wxSize(width,height); + // 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); } - -// ---------------------------------------------------------------------------- -// wxGridCellRenderer -// ---------------------------------------------------------------------------- - -void wxGridCellRenderer::Draw(wxGrid& grid, - wxGridCellAttr& attr, - wxDC& dc, - const wxRect& rect, - int WXUNUSED(row), int WXUNUSED(col), - bool isSelected) +wxSize +wxGridCellAutoWrapStringRenderer::GetBestSize(wxGrid& grid, + wxGridCellAttr& attr, + wxDC& dc, + int row, int col) { - dc.SetBackgroundMode( wxBRUSHSTYLE_SOLID ); + const int lineHeight = dc.GetCharHeight(); - wxColour clr; - if ( grid.IsEnabled() ) - { - 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 + // Search for a shape no taller than the golden ratio. + wxSize size; + for ( size.x = 10; ; size.x += 10 ) { - clr = wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE); + const size_t + numLines = GetTextLines(grid, dc, attr, size, row, col).size(); + size.y = numLines * lineHeight; + if ( size.x >= size.y*1.68 ) + break; } - dc.SetBrush(clr); - dc.SetPen( *wxTRANSPARENT_PEN ); - dc.DrawRectangle(rect); + return size; } // ---------------------------------------------------------------------------- @@ -390,7 +466,7 @@ void wxGridCellStringRenderer::SetTextColoursAndFont(const wxGrid& grid, // TODO some special colours for attr.IsReadOnly() case? // different coloured text when the grid is disabled - if ( grid.IsEnabled() ) + if ( grid.IsThisEnabled() ) { if ( isSelected ) { @@ -423,7 +499,7 @@ wxSize wxGridCellStringRenderer::DoGetBestSize(const wxGridCellAttr& attr, { wxCoord x = 0, y = 0, max_x = 0; dc.SetFont(attr.GetFont()); - wxStringTokenizer tk(text, _T('\n')); + wxStringTokenizer tk(text, wxT('\n')); while ( tk.HasMoreTokens() ) { dc.GetTextExtent(tk.GetNextToken(), &x, &y); @@ -552,7 +628,7 @@ wxString wxGridCellNumberRenderer::GetString(const wxGrid& grid, int row, int co wxString text; if ( table->CanGetValueAs(row, col, wxGRID_VALUE_NUMBER) ) { - text.Printf(_T("%ld"), table->GetValueAsLong(row, col)); + text.Printf(wxT("%ld"), table->GetValueAsLong(row, col)); } else { @@ -574,9 +650,9 @@ void wxGridCellNumberRenderer::Draw(wxGrid& grid, SetTextColoursAndFont(grid, attr, dc, isSelected); // draw the text right aligned by default - int hAlign, vAlign; - attr.GetAlignment(&hAlign, &vAlign); - hAlign = wxALIGN_RIGHT; + int hAlign = wxALIGN_RIGHT, + vAlign = wxALIGN_INVALID; + attr.GetNonDefaultAlignment(&hAlign, &vAlign); wxRect rect = rectCell; rect.Inflate(-1); @@ -596,10 +672,13 @@ wxSize wxGridCellNumberRenderer::GetBestSize(wxGrid& grid, // wxGridCellFloatRenderer // ---------------------------------------------------------------------------- -wxGridCellFloatRenderer::wxGridCellFloatRenderer(int width, int precision) +wxGridCellFloatRenderer::wxGridCellFloatRenderer(int width, + int precision, + int format) { SetWidth(width); SetPrecision(precision); + SetFormat(format); } wxGridCellRenderer *wxGridCellFloatRenderer::Clone() const @@ -607,6 +686,7 @@ 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; @@ -639,22 +719,30 @@ wxString wxGridCellFloatRenderer::GetString(const wxGrid& grid, int row, int col if ( m_precision == -1 ) { // default width/precision - m_format = _T("%f"); + m_format = wxT("%"); } else { - m_format.Printf(_T("%%.%df"), m_precision); + m_format.Printf(wxT("%%.%d"), m_precision); } } else if ( m_precision == -1 ) { // default precision - m_format.Printf(_T("%%%d.f"), m_width); + m_format.Printf(wxT("%%%d."), m_width); } else { - m_format.Printf(_T("%%%d.%df"), m_width, m_precision); + 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); @@ -677,9 +765,9 @@ void wxGridCellFloatRenderer::Draw(wxGrid& grid, SetTextColoursAndFont(grid, attr, dc, isSelected); // draw the text right aligned by default - int hAlign, vAlign; - attr.GetAlignment(&hAlign, &vAlign); - hAlign = wxALIGN_RIGHT; + int hAlign = wxALIGN_RIGHT, + vAlign = wxALIGN_INVALID; + attr.GetNonDefaultAlignment(&hAlign, &vAlign); wxRect rect = rectCell; rect.Inflate(-1); @@ -702,10 +790,12 @@ void wxGridCellFloatRenderer::SetParameters(const wxString& params) // reset to defaults SetWidth(-1); SetPrecision(-1); + SetFormat(wxGRID_FLOAT_FORMAT_DEFAULT); } else { - wxString tmp = params.BeforeFirst(_T(',')); + wxString rest; + wxString tmp = params.BeforeFirst(wxT(','), &rest); if ( !tmp.empty() ) { long width; @@ -715,11 +805,11 @@ void wxGridCellFloatRenderer::SetParameters(const wxString& params) } else { - wxLogDebug(_T("Invalid wxGridCellFloatRenderer width parameter string '%s ignored"), params.c_str()); + wxLogDebug(wxT("Invalid wxGridCellFloatRenderer width parameter string '%s ignored"), params.c_str()); } } - tmp = params.AfterFirst(_T(',')); + tmp = rest.BeforeFirst(wxT(',')); if ( !tmp.empty() ) { long precision; @@ -729,7 +819,44 @@ void wxGridCellFloatRenderer::SetParameters(const wxString& params) } else { - wxLogDebug(_T("Invalid wxGridCellFloatRenderer precision parameter string '%s ignored"), params.c_str()); + 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); } } } @@ -741,11 +868,6 @@ void wxGridCellFloatRenderer::SetParameters(const wxString& params) wxSize wxGridCellBoolRenderer::ms_sizeCheckMark; -// FIXME these checkbox size calculations are really ugly... - -// between checkmark and box -static const wxCoord wxGRID_CHECKMARK_MARGIN = 2; - wxSize wxGridCellBoolRenderer::GetBestSize(wxGrid& grid, wxGridCellAttr& WXUNUSED(attr), wxDC& WXUNUSED(dc), @@ -755,18 +877,7 @@ wxSize wxGridCellBoolRenderer::GetBestSize(wxGrid& grid, // compute it only once (no locks for MT safeness in GUI thread...) if ( !ms_sizeCheckMark.x ) { - // get checkbox size - wxCheckBox *checkbox = new wxCheckBox(&grid, wxID_ANY, wxEmptyString); - wxSize size = checkbox->GetBestSize(); - wxCoord checkSize = size.y + 2 * wxGRID_CHECKMARK_MARGIN; - -#if defined(__WXMOTIF__) - checkSize -= size.y / 2; -#endif - - delete checkbox; - - ms_sizeCheckMark.x = ms_sizeCheckMark.y = checkSize; + ms_sizeCheckMark = wxRendererNative::Get().GetCheckBoxSize(&grid); } return ms_sizeCheckMark;