split wxGrid implementation in grideditors.cpp (for wxGridCellEditor-derived classes), gridctrl.cpp (for wxGridCellRenderer-derived classes)

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@58024 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Francesco Montorsi
2009-01-11 15:49:37 +00:00
parent d0bbcd06d2
commit 29efc6e4a4
21 changed files with 3718 additions and 3429 deletions

View File

@@ -18,6 +18,7 @@
#if wxUSE_GRID
#include "wx/generic/gridctrl.h"
#include "wx/generic/grideditors.h"
#ifndef WX_PRECOMP
#include "wx/textctrl.h"
@@ -26,6 +27,7 @@
#endif // WX_PRECOMP
#include "wx/tokenzr.h"
#include "wx/renderer.h"
// ----------------------------------------------------------------------------
// wxGridCellDateTimeRenderer
@@ -212,100 +214,11 @@ void wxGridCellEnumRenderer::SetParameters(const wxString& params)
}
}
#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_index = -1;
if (!choices.empty())
SetParameters(choices);
}
wxGridCellEditor *wxGridCellEnumEditor::Clone() const
{
wxGridCellEnumEditor *editor = new wxGridCellEnumEditor();
editor->m_index = m_index;
return editor;
}
void wxGridCellEnumEditor::BeginEdit(int row, int col, wxGrid* grid)
{
wxASSERT_MSG(m_control,
wxT("The wxGridCellEnumEditor must be Created first!"));
wxGridTableBase *table = grid->GetTable();
if ( table->CanGetValueAs(row, col, wxGRID_VALUE_NUMBER) )
{
m_index = table->GetValueAsLong(row, col);
}
else
{
wxString startValue = table->GetValue(row, col);
if (startValue.IsNumber() && !startValue.empty())
{
startValue.ToLong(&m_index);
}
else
{
m_index = -1;
}
}
Combo()->SetSelection(m_index);
Combo()->SetInsertionPointEnd();
Combo()->SetFocus();
}
bool wxGridCellEnumEditor::EndEdit(const wxString& WXUNUSED(oldval),
wxString *newval)
{
long idx = Combo()->GetSelection();
if ( idx == m_index )
return false;
m_index = idx;
if ( newval )
newval->Printf("%ld", m_index);
return true;
}
void wxGridCellEnumEditor::ApplyEdit(int row, int col, wxGrid* grid)
{
wxGridTableBase * const table = grid->GetTable();
if ( table->CanSetValueAs(row, col, wxGRID_VALUE_NUMBER) )
table->SetValueAsLong(row, col, m_index);
else
table->SetValue(row, col, wxString::Format("%ld", m_index));
}
#endif // wxUSE_COMBOBOX
// ----------------------------------------------------------------------------
// wxGridCellAutoWrapStringEditor
// ----------------------------------------------------------------------------
void
wxGridCellAutoWrapStringEditor::Create(wxWindow* parent,
wxWindowID id,
wxEvtHandler* evtHandler)
{
wxGridCellTextEditor::DoCreate(parent, id, evtHandler,
wxTE_MULTILINE | wxTE_RICH);
}
void
wxGridCellAutoWrapStringRenderer::Draw(wxGrid& grid,
@@ -411,5 +324,505 @@ wxGridCellAutoWrapStringRenderer::GetBestSize(wxGrid& grid,
return wxSize(width,height);
}
// ----------------------------------------------------------------------------
// 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.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
{
clr = wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE);
}
dc.SetBrush(clr);
dc.SetPen( *wxTRANSPARENT_PEN );
dc.DrawRectangle(rect);
}
// ----------------------------------------------------------------------------
// 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.IsEnabled() )
{
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, _T('\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);
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(_T("%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, vAlign;
attr.GetAlignment(&hAlign, &vAlign);
hAlign = wxALIGN_RIGHT;
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)
{
SetWidth(width);
SetPrecision(precision);
}
wxGridCellRenderer *wxGridCellFloatRenderer::Clone() const
{
wxGridCellFloatRenderer *renderer = new wxGridCellFloatRenderer;
renderer->m_width = m_width;
renderer->m_precision = m_precision;
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 = _T("%f");
}
else
{
m_format.Printf(_T("%%.%df"), m_precision);
}
}
else if ( m_precision == -1 )
{
// default precision
m_format.Printf(_T("%%%d.f"), m_width);
}
else
{
m_format.Printf(_T("%%%d.%df"), m_width, m_precision);
}
}
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, vAlign;
attr.GetAlignment(&hAlign, &vAlign);
hAlign = wxALIGN_RIGHT;
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);
}
else
{
wxString tmp = params.BeforeFirst(_T(','));
if ( !tmp.empty() )
{
long width;
if ( tmp.ToLong(&width) )
{
SetWidth((int)width);
}
else
{
wxLogDebug(_T("Invalid wxGridCellFloatRenderer width parameter string '%s ignored"), params.c_str());
}
}
tmp = params.AfterFirst(_T(','));
if ( !tmp.empty() )
{
long precision;
if ( tmp.ToLong(&precision) )
{
SetPrecision((int)precision);
}
else
{
wxLogDebug(_T("Invalid wxGridCellFloatRenderer precision parameter string '%s ignored"), params.c_str());
}
}
}
}
// ----------------------------------------------------------------------------
// wxGridCellBoolRenderer
// ----------------------------------------------------------------------------
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),
int WXUNUSED(row),
int WXUNUSED(col))
{
// 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;
}
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