///////////////////////////////////////////////////////////////////////////
-// Name: generic/gridctrl.cpp
+// Name: src/generic/gridctrl.cpp
// Purpose: wxGrid controls
// Author: Paul Gammans, Roger Gammans
// Modified by:
#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
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);
#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"
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);
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 , wxT(" \n\t\r"));
- wxString thisline = wxEmptyString;
-
- 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 += wxT(" ");
+ 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;
- dc.GetTextExtent(tok, &x, &y);
- if ( curr_x + x > max_x)
+ // 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 )
{
- if ( curr_x == 0 )
+ // 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);
}
+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,
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);
// 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
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;
if ( m_precision == -1 )
{
// default width/precision
- m_format = wxT("%f");
+ m_format = wxT("%");
}
else
{
- m_format.Printf(wxT("%%.%df"), m_precision);
+ m_format.Printf(wxT("%%.%d"), m_precision);
}
}
else if ( m_precision == -1 )
{
// default precision
- m_format.Printf(wxT("%%%d.f"), m_width);
+ m_format.Printf(wxT("%%%d."), m_width);
}
else
{
- m_format.Printf(wxT("%%%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);
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);
// reset to defaults
SetWidth(-1);
SetPrecision(-1);
+ SetFormat(wxGRID_FLOAT_FORMAT_DEFAULT);
}
else
{
- wxString tmp = params.BeforeFirst(wxT(','));
+ wxString rest;
+ wxString tmp = params.BeforeFirst(wxT(','), &rest);
if ( !tmp.empty() )
{
long width;
}
}
- tmp = params.AfterFirst(wxT(','));
+ tmp = rest.BeforeFirst(wxT(','));
if ( !tmp.empty() )
{
long precision;
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);
+ }
+ }
}
}