X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/7c1cb261228c78cac34ee9f0b08e2674b07c37ee..2912e35f1774b140b44cb9f9568aa5ab8122cd02:/src/generic/grid.cpp?ds=inline diff --git a/src/generic/grid.cpp b/src/generic/grid.cpp index 55107437f3..dd06aeda0b 100644 --- a/src/generic/grid.cpp +++ b/src/generic/grid.cpp @@ -41,14 +41,15 @@ #include "wx/log.h" #include "wx/textctrl.h" #include "wx/checkbox.h" + #include "wx/combobox.h" + #include "wx/valtext.h" #endif -// this include needs to be outside precomp for BCC #include "wx/textfile.h" +#include "wx/spinctrl.h" #include "wx/grid.h" - // ---------------------------------------------------------------------------- // array classes // ---------------------------------------------------------------------------- @@ -249,6 +250,46 @@ public: m_colAttrs; }; + +// ---------------------------------------------------------------------------- +// data structures used for the data type registry +// ---------------------------------------------------------------------------- + +struct wxGridDataTypeInfo { + wxGridDataTypeInfo(const wxString& typeName, + wxGridCellRenderer* renderer, + wxGridCellEditor* editor) + : m_typeName(typeName), m_renderer(renderer), m_editor(editor) + { } + + ~wxGridDataTypeInfo() { delete m_renderer; delete m_editor; } + + wxString m_typeName; + wxGridCellRenderer* m_renderer; + wxGridCellEditor* m_editor; +}; + + +WX_DEFINE_ARRAY(wxGridDataTypeInfo*, wxGridDataTypeInfoArray); + + +class WXDLLEXPORT wxGridTypeRegistry { +public: + ~wxGridTypeRegistry(); + void RegisterDataType(const wxString& typeName, + wxGridCellRenderer* renderer, + wxGridCellEditor* editor); + int FindDataType(const wxString& typeName); + wxGridCellRenderer* GetRenderer(int index); + wxGridCellEditor* GetEditor(int index); + +private: + wxGridDataTypeInfoArray m_typeinfo; +}; + + + + // ---------------------------------------------------------------------------- // conditional compilation // ---------------------------------------------------------------------------- @@ -267,6 +308,10 @@ public: static size_t gs_nAttrCacheMisses = 0; #endif // DEBUG_ATTR_CACHE +// ---------------------------------------------------------------------------- +// constants +// ---------------------------------------------------------------------------- + wxGridCellCoords wxGridNoCellCoords( -1, -1 ); wxRect wxGridNoCellRect( -1, -1, -1, -1 ); @@ -274,6 +319,10 @@ wxRect wxGridNoCellRect( -1, -1, -1, -1 ); // TODO: fixed so far - make configurable later (and also different for x/y) static const size_t GRID_SCROLL_LINE = 10; +// the size of hash tables used a bit everywhere (the max number of elements +// in these hash tables is the number of rows/columns) +static const int GRID_HASH_SIZE = 100; + // ============================================================================ // implementation // ============================================================================ @@ -334,23 +383,14 @@ void wxGridCellEditor::Show(bool show, wxGridCellAttr *attr) // set the colours/fonts if we have any if ( attr ) { - if ( attr->HasTextColour() ) - { - m_colFgOld = m_control->GetForegroundColour(); - m_control->SetForegroundColour(attr->GetTextColour()); - } + m_colFgOld = m_control->GetForegroundColour(); + m_control->SetForegroundColour(attr->GetTextColour()); - if ( attr->HasBackgroundColour() ) - { - m_colBgOld = m_control->GetBackgroundColour(); - m_control->SetBackgroundColour(attr->GetBackgroundColour()); - } + m_colBgOld = m_control->GetBackgroundColour(); + m_control->SetBackgroundColour(attr->GetBackgroundColour()); - if ( attr->HasFont() ) - { - m_fontOld = m_control->GetFont(); - m_control->SetFont(attr->GetFont()); - } + m_fontOld = m_control->GetFont(); + m_control->SetFont(attr->GetFont()); // can't do anything more in the base class version, the other // attributes may only be used by the derived classes @@ -430,18 +470,49 @@ void wxGridCellTextEditor::PaintBackground(const wxRect& WXUNUSED(rectCell), // flicker } +void wxGridCellTextEditor::SetSize(const wxRect& rectOrig) +{ + wxRect rect(rectOrig); + + // Make the edit control large enough to allow for internal + // margins + // + // TODO: remove this if the text ctrl sizing is improved esp. for + // unix + // +#if defined(__WXGTK__) + rect.Inflate(rect.x ? 1 : 0, rect.y ? 1 : 0); +#else // !GTK + int extra = row && col ? 2 : 1; +#if defined(__WXMOTIF__) + extra *= 2; +#endif + rect.SetLeft( wxMax(0, rect.x - extra) ); + rect.SetTop( wxMax(0, rect.y - extra) ); + rect.SetRight( rect.GetRight() + 2*extra ); + rect.SetBottom( rect.GetBottom() + 2*extra ); +#endif // GTK/!GTK + + wxGridCellEditor::SetSize(rect); +} + void wxGridCellTextEditor::BeginEdit(int row, int col, wxGrid* grid) { wxASSERT_MSG(m_control, wxT("The wxGridCellEditor must be Created first!")); m_startValue = grid->GetTable()->GetValue(row, col); - Text()->SetValue(m_startValue); + + DoBeginEdit(m_startValue); +} + +void wxGridCellTextEditor::DoBeginEdit(const wxString& startValue) +{ + Text()->SetValue(startValue); Text()->SetInsertionPointEnd(); Text()->SetFocus(); } - bool wxGridCellTextEditor::EndEdit(int row, int col, bool saveValue, wxGrid* grid) { @@ -468,7 +539,12 @@ void wxGridCellTextEditor::Reset() wxASSERT_MSG(m_control, wxT("The wxGridCellEditor must be Created first!")); - Text()->SetValue(m_startValue); + DoReset(m_startValue); +} + +void wxGridCellTextEditor::DoReset(const wxString& startValue) +{ + Text()->SetValue(startValue); Text()->SetInsertionPointEnd(); } @@ -512,6 +588,187 @@ void wxGridCellTextEditor::HandleReturn(wxKeyEvent& event) #endif } +// ---------------------------------------------------------------------------- +// wxGridCellNumberEditor +// ---------------------------------------------------------------------------- + +wxGridCellNumberEditor::wxGridCellNumberEditor(int min, int max) +{ + m_min = min; + m_max = max; +} + +void wxGridCellNumberEditor::Create(wxWindow* parent, + wxWindowID id, + wxEvtHandler* evtHandler) +{ + if ( HasRange() ) + { + // create a spin ctrl + m_control = new wxSpinCtrl(parent, -1, wxEmptyString, + wxDefaultPosition, wxDefaultSize, + wxSP_ARROW_KEYS, + m_min, m_max); + + wxGridCellEditor::Create(parent, id, evtHandler); + } + else + { + // just a text control + wxGridCellTextEditor::Create(parent, id, evtHandler); + +#if wxUSE_VALIDATORS + Text()->SetValidator(new wxTextValidator(wxFILTER_NUMERIC)); +#endif // wxUSE_VALIDATORS + } +} + +void wxGridCellNumberEditor::BeginEdit(int row, int col, wxGrid* grid) +{ + // first get the value + wxGridTableBase *table = grid->GetTable(); + if ( table->CanGetValueAs(row, col, wxGRID_VALUE_NUMBER) ) + { + m_valueOld = table->GetValueAsLong(row, col); + } + else + { + wxFAIL_MSG( _T("this cell doesn't have numeric value") ); + + return; + } + + if ( HasRange() ) + { + Spin()->SetValue(m_valueOld); + } + else + { + DoBeginEdit(GetString()); + } +} + +bool wxGridCellNumberEditor::EndEdit(int row, int col, bool saveValue, + wxGrid* grid) +{ + bool changed; + long value; + + if ( HasRange() ) + { + value = Spin()->GetValue(); + changed = value != m_valueOld; + } + else + { + changed = Text()->GetValue().ToLong(&value) && (value != m_valueOld); + } + + if ( changed ) + { + grid->GetTable()->SetValueAsLong(row, col, value); + } + + return changed; +} + +void wxGridCellNumberEditor::Reset() +{ + if ( HasRange() ) + { + Spin()->SetValue(m_valueOld); + } + else + { + DoReset(GetString()); + } +} + +void wxGridCellNumberEditor::StartingKey(wxKeyEvent& event) +{ + if ( !HasRange() ) + { + long keycode = event.KeyCode(); + if ( isdigit(keycode) || keycode == '+' || keycode == '-' ) + { + wxGridCellTextEditor::StartingKey(event); + + // skip Skip() below + return; + } + } + + event.Skip(); +} +// ---------------------------------------------------------------------------- +// wxGridCellFloatEditor +// ---------------------------------------------------------------------------- + +void wxGridCellFloatEditor::Create(wxWindow* parent, + wxWindowID id, + wxEvtHandler* evtHandler) +{ + wxGridCellTextEditor::Create(parent, id, evtHandler); + +#if wxUSE_VALIDATORS + Text()->SetValidator(new wxTextValidator(wxFILTER_NUMERIC)); +#endif // wxUSE_VALIDATORS +} + +void wxGridCellFloatEditor::BeginEdit(int row, int col, wxGrid* grid) +{ + // first get the value + wxGridTableBase *table = grid->GetTable(); + if ( table->CanGetValueAs(row, col, wxGRID_VALUE_FLOAT) ) + { + m_valueOld = table->GetValueAsDouble(row, col); + } + else + { + wxFAIL_MSG( _T("this cell doesn't have float value") ); + + return; + } + + DoBeginEdit(GetString()); +} + +bool wxGridCellFloatEditor::EndEdit(int row, int col, bool saveValue, + wxGrid* grid) +{ + double value; + if ( Text()->GetValue().ToDouble(&value) && (value != m_valueOld) ) + { + grid->GetTable()->SetValueAsDouble(row, col, value); + + return TRUE; + } + else + { + return FALSE; + } +} + +void wxGridCellFloatEditor::Reset() +{ + DoReset(GetString()); +} + +void wxGridCellFloatEditor::StartingKey(wxKeyEvent& event) +{ + long keycode = event.KeyCode(); + if ( isdigit(keycode) || + keycode == '+' || keycode == '-' || keycode == '.' ) + { + wxGridCellTextEditor::StartingKey(event); + + // skip Skip() below + return; + } + + event.Skip(); +} + // ---------------------------------------------------------------------------- // wxGridCellBoolEditor // ---------------------------------------------------------------------------- @@ -544,10 +801,10 @@ void wxGridCellBoolEditor::SetSize(const wxRect& r) void wxGridCellBoolEditor::Show(bool show, wxGridCellAttr *attr) { - wxGridCellEditor::Show(show, attr); + m_control->Show(show); + if ( show ) { - // VZ: normally base class already does it, but it doesn't work (FIXME) wxColour colBg = attr ? attr->GetBackgroundColour() : *wxLIGHT_GREY; CBox()->SetBackgroundColour(colBg); } @@ -558,7 +815,10 @@ void wxGridCellBoolEditor::BeginEdit(int row, int col, wxGrid* grid) wxASSERT_MSG(m_control, wxT("The wxGridCellEditor must be Created first!")); - m_startValue = !!grid->GetTable()->GetValue(row, col); // FIXME-DATA + if (grid->GetTable()->CanGetValueAs(row, col, wxT("bool"))) + m_startValue = grid->GetTable()->GetValueAsBool(row, col); + else + m_startValue = !!grid->GetTable()->GetValue(row, col); CBox()->SetValue(m_startValue); CBox()->SetFocus(); } @@ -577,8 +837,10 @@ bool wxGridCellBoolEditor::EndEdit(int row, int col, if ( changed ) { - // FIXME-DATA - grid->GetTable()->SetValue(row, col, value ? _T("1") : wxEmptyString); + if (grid->GetTable()->CanGetValueAs(row, col, wxT("bool"))) + grid->GetTable()->SetValueAsBool(row, col, value); + else + grid->GetTable()->SetValue(row, col, value ? _T("1") : wxEmptyString); } return changed; @@ -597,6 +859,84 @@ void wxGridCellBoolEditor::StartingClick() CBox()->SetValue(!CBox()->GetValue()); } +// ---------------------------------------------------------------------------- +// wxGridCellChoiceEditor +// ---------------------------------------------------------------------------- + +wxGridCellChoiceEditor::wxGridCellChoiceEditor(size_t count, + const wxChar* choices[], + bool allowOthers) + : m_allowOthers(allowOthers) +{ + m_choices.Alloc(count); + for ( size_t n = 0; n < count; n++ ) + { + m_choices.Add(choices[n]); + } +} + +void wxGridCellChoiceEditor::Create(wxWindow* parent, + wxWindowID id, + wxEvtHandler* evtHandler) +{ + size_t count = m_choices.GetCount(); + wxString *choices = new wxString[count]; + for ( size_t n = 0; n < count; n++ ) + { + choices[n] = m_choices[n]; + } + + m_control = new wxComboBox(parent, id, wxEmptyString, + wxDefaultPosition, wxDefaultSize, + count, choices, + m_allowOthers ? 0 : wxCB_READONLY); + + delete [] choices; + + wxGridCellEditor::Create(parent, id, evtHandler); +} + +void wxGridCellChoiceEditor::PaintBackground(const wxRect& WXUNUSED(rectCell), + wxGridCellAttr * WXUNUSED(attr)) +{ + // as we fill the entire client area, don't do anything here to minimize + // flicker +} + +void wxGridCellChoiceEditor::BeginEdit(int row, int col, wxGrid* grid) +{ + wxASSERT_MSG(m_control, + wxT("The wxGridCellEditor must be Created first!")); + + m_startValue = grid->GetTable()->GetValue(row, col); + + Combo()->SetValue(m_startValue); + Combo()->SetInsertionPointEnd(); + Combo()->SetFocus(); +} + +bool wxGridCellChoiceEditor::EndEdit(int row, int col, + bool saveValue, + wxGrid* grid) +{ + wxString value = Combo()->GetValue(); + bool changed = value != m_startValue; + + if ( changed ) + grid->GetTable()->SetValue(row, col, value); + + m_startValue = wxEmptyString; + Combo()->SetValue(m_startValue); + + return changed; +} + +void wxGridCellChoiceEditor::Reset() +{ + Combo()->SetValue(m_startValue); + Combo()->SetInsertionPointEnd(); +} + // ---------------------------------------------------------------------------- // wxGridCellEditorEvtHandler // ---------------------------------------------------------------------------- @@ -669,10 +1009,56 @@ void wxGridCellRenderer::Draw(wxGrid& grid, dc.DrawRectangle(rect); } +wxGridCellRenderer::~wxGridCellRenderer() +{ +} + // ---------------------------------------------------------------------------- // wxGridCellStringRenderer // ---------------------------------------------------------------------------- +void wxGridCellStringRenderer::SetTextColoursAndFont(wxGrid& grid, + wxGridCellAttr& attr, + wxDC& dc, + bool isSelected) +{ + dc.SetBackgroundMode( wxTRANSPARENT ); + + // TODO some special colours for attr.IsReadOnly() case? + + if ( isSelected ) + { + dc.SetTextBackground( grid.GetSelectionBackground() ); + dc.SetTextForeground( grid.GetSelectionForeground() ); + } + else + { + dc.SetTextBackground( attr.GetBackgroundColour() ); + dc.SetTextForeground( attr.GetTextColour() ); + } + + dc.SetFont( attr.GetFont() ); +} + +wxSize wxGridCellStringRenderer::DoGetBestSize(wxGridCellAttr& attr, + wxDC& dc, + const wxString& text) +{ + wxCoord x, y; + dc.SetFont(attr.GetFont()); + dc.GetTextExtent(text, &x, &y); + + return wxSize(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, @@ -683,81 +1069,190 @@ void wxGridCellStringRenderer::Draw(wxGrid& grid, wxGridCellRenderer::Draw(grid, attr, dc, rectCell, row, col, isSelected); // now we only have to draw the text - dc.SetBackgroundMode( wxTRANSPARENT ); + SetTextColoursAndFont(grid, attr, dc, isSelected); - // TODO some special colours for attr.IsReadOnly() case? + int hAlign, vAlign; + attr.GetAlignment(&hAlign, &vAlign); - if ( isSelected ) + wxRect rect = rectCell; + rect.Inflate(-1); + + grid.DrawTextRectangle(dc, grid.GetCellValue(row, col), + rect, hAlign, vAlign); +} + +// ---------------------------------------------------------------------------- +// wxGridCellNumberRenderer +// ---------------------------------------------------------------------------- + +wxString wxGridCellNumberRenderer::GetString(wxGrid& grid, int row, int col) +{ + wxGridTableBase *table = grid.GetTable(); + wxString text; + if ( table->CanGetValueAs(row, col, wxGRID_VALUE_NUMBER) ) { - dc.SetTextBackground( grid.GetSelectionBackground() ); - dc.SetTextForeground( grid.GetSelectionForeground() ); + text.Printf(_T("%ld"), table->GetValueAsLong(row, col)); } - else + //else: leave the string empty or put 0 into it? + + 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 = wxRIGHT; + + 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); +} + +wxString wxGridCellFloatRenderer::GetString(wxGrid& grid, int row, int col) +{ + wxGridTableBase *table = grid.GetTable(); + wxString text; + if ( table->CanGetValueAs(row, col, wxGRID_VALUE_FLOAT) ) { - dc.SetTextBackground( attr.GetBackgroundColour() ); - dc.SetTextForeground( attr.GetTextColour() ); + if ( !m_format ) + { + m_format.Printf(_T("%%%d.%d%%f"), m_width, m_precision); + } + + text.Printf(m_format, table->GetValueAsDouble(row, col)); } - dc.SetFont( attr.GetFont() ); + //else: leave the string empty or put 0 into it? + + 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 = wxRIGHT; wxRect rect = rectCell; - rect.x++; - rect.y++; - rect.width -= 2; - rect.height -= 2; + rect.Inflate(-1); - grid.DrawTextRectangle(dc, grid.GetCellValue(row, col), - rect, hAlign, vAlign); + 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)); } // ---------------------------------------------------------------------------- // wxGridCellBoolRenderer // ---------------------------------------------------------------------------- -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); +wxSize wxGridCellBoolRenderer::ms_sizeCheckMark; - // between checkmark and box - static const wxCoord margin = 4; +// between checkmark and box +static const wxCoord wxGRID_CHECKMARK_MARGIN = 4; - // get checkbox size - static wxCoord s_checkSize = 0; - if ( s_checkSize == 0 ) +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 ) { - // compute it only once (no locks for MT safeness in GUI thread...) + // get checkbox size + wxCoord checkSize = 0; wxCheckBox *checkbox = new wxCheckBox(&grid, -1, wxEmptyString); wxSize size = checkbox->GetBestSize(); - s_checkSize = size.y + margin; + checkSize = size.y + wxGRID_CHECKMARK_MARGIN; - // FIXME wxGTK::wxCheckBox::GetBestSize() is really weird... + // FIXME wxGTK::wxCheckBox::GetBestSize() gives "wrong" result #ifdef __WXGTK__ - s_checkSize -= size.y / 2; + 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); wxRect rectMark; - rectMark.x = rect.x + rect.width/2 - s_checkSize/2; - rectMark.y = rect.y + rect.height/2 - s_checkSize/2; - rectMark.width = rectMark.height = s_checkSize; + rectMark.x = rect.x + rect.width/2 - size.x/2; + rectMark.y = rect.y + rect.height/2 - size.y/2; + rectMark.width = size.x; + rectMark.height = size.y; dc.SetBrush(*wxTRANSPARENT_BRUSH); dc.SetPen(wxPen(attr.GetTextColour(), 1, wxSOLID)); dc.DrawRectangle(rectMark); - rectMark.Inflate(-margin); + rectMark.Inflate(-wxGRID_CHECKMARK_MARGIN); - if ( !!grid.GetTable()->GetValue(row, col) ) // FIXME-DATA + bool value; + if (grid.GetTable()->CanGetValueAs(row, col, wxT("bool"))) + value = grid.GetTable()->GetValueAsBool(row, col); + else + value = !!grid.GetTable()->GetValue(row, col); + + if ( value ) { dc.SetTextForeground(attr.GetTextColour()); dc.DrawCheckMark(rectMark); @@ -830,12 +1325,21 @@ void wxGridCellAttr::GetAlignment(int *hAlign, int *vAlign) const } -wxGridCellRenderer* wxGridCellAttr::GetRenderer() const +// GetRenderer and GetEditor use a slightly different decision path about +// which to use. If a non-default attr object has one then it is used, +// otherwise the default editor or renderer passed in is used. It should be +// the default for the data type of the cell. If it is NULL (because the +// table has a type that the grid does not have in its registry,) then the +// grid's default editor or renderer is used. + +wxGridCellRenderer* wxGridCellAttr::GetRenderer(wxGridCellRenderer* def) const { - if (HasRenderer()) + if ((m_defGridAttr != this || def == NULL) && HasRenderer()) return m_renderer; + else if (def) + return def; else if (m_defGridAttr != this) - return m_defGridAttr->GetRenderer(); + return m_defGridAttr->GetRenderer(NULL); else { wxFAIL_MSG(wxT("Missing default cell attribute")); @@ -843,12 +1347,14 @@ wxGridCellRenderer* wxGridCellAttr::GetRenderer() const } } -wxGridCellEditor* wxGridCellAttr::GetEditor() const +wxGridCellEditor* wxGridCellAttr::GetEditor(wxGridCellEditor* def) const { - if (HasEditor()) + if ((m_defGridAttr != this || def == NULL) && HasEditor()) return m_editor; + else if (def) + return def; else if (m_defGridAttr != this) - return m_defGridAttr->GetEditor(); + return m_defGridAttr->GetEditor(NULL); else { wxFAIL_MSG(wxT("Missing default cell attribute")); @@ -1149,14 +1655,64 @@ void wxGridCellAttrProvider::UpdateAttrCols( size_t pos, int numCols ) } } +// ---------------------------------------------------------------------------- +// wxGridTypeRegistry +// ---------------------------------------------------------------------------- + +wxGridTypeRegistry::~wxGridTypeRegistry() +{ + for (size_t i=0; im_typeName) { + found = i; + break; + } + } + + return found; +} + +wxGridCellRenderer* wxGridTypeRegistry::GetRenderer(int index) +{ + wxGridCellRenderer* renderer = m_typeinfo[index]->m_renderer; + return renderer; +} + +wxGridCellEditor* wxGridTypeRegistry::GetEditor(int index) +{ + wxGridCellEditor* editor = m_typeinfo[index]->m_editor; + return editor; +} + // ---------------------------------------------------------------------------- // wxGridTableBase // ---------------------------------------------------------------------------- -////////////////////////////////////////////////////////////////////// -// -// Abstract base class for grid data (the model) -// IMPLEMENT_ABSTRACT_CLASS( wxGridTableBase, wxObject ) @@ -1177,6 +1733,16 @@ void wxGridTableBase::SetAttrProvider(wxGridCellAttrProvider *attrProvider) m_attrProvider = attrProvider; } +bool wxGridTableBase::CanHaveAttributes() +{ + if ( ! GetAttrProvider() ) + { + // use the default attr provider by default + SetAttrProvider(new wxGridCellAttrProvider); + } + return TRUE; +} + wxGridCellAttr *wxGridTableBase::GetAttr(int row, int col) { if ( m_attrProvider ) @@ -1295,7 +1861,8 @@ bool wxGridTableBase::DeleteCols( size_t pos, size_t numCols ) wxString wxGridTableBase::GetRowLabelValue( int row ) { wxString s; - s << row; + s << row + 1; // RD: Starting the rows at zero confuses users, no matter + // how much it makes sense to us geeks. return s; } @@ -1326,6 +1893,65 @@ wxString wxGridTableBase::GetColLabelValue( int col ) } +wxString wxGridTableBase::GetTypeName( int WXUNUSED(row), int WXUNUSED(col) ) +{ + return wxGRID_VALUE_STRING; +} + +bool wxGridTableBase::CanGetValueAs( int WXUNUSED(row), int WXUNUSED(col), + const wxString& typeName ) +{ + return typeName == wxGRID_VALUE_STRING; +} + +bool wxGridTableBase::CanSetValueAs( int row, int col, const wxString& typeName ) +{ + return CanGetValueAs(row, col, typeName); +} + +long wxGridTableBase::GetValueAsLong( int WXUNUSED(row), int WXUNUSED(col) ) +{ + return 0; +} + +double wxGridTableBase::GetValueAsDouble( int WXUNUSED(row), int WXUNUSED(col) ) +{ + return 0.0; +} + +bool wxGridTableBase::GetValueAsBool( int WXUNUSED(row), int WXUNUSED(col) ) +{ + return FALSE; +} + +void wxGridTableBase::SetValueAsLong( int WXUNUSED(row), int WXUNUSED(col), + long WXUNUSED(value) ) +{ +} + +void wxGridTableBase::SetValueAsDouble( int WXUNUSED(row), int WXUNUSED(col), + double WXUNUSED(value) ) +{ +} + +void wxGridTableBase::SetValueAsBool( int WXUNUSED(row), int WXUNUSED(col), + bool WXUNUSED(value) ) +{ +} + + +void* wxGridTableBase::GetValueAsCustom( int WXUNUSED(row), int WXUNUSED(col), + const wxString& WXUNUSED(typeName) ) +{ + return NULL; +} + +void wxGridTableBase::SetValueAsCustom( int WXUNUSED(row), int WXUNUSED(col), + const wxString& WXUNUSED(typeName), + void* WXUNUSED(value) ) +{ +} + ////////////////////////////////////////////////////////////////////// // @@ -1411,11 +2037,11 @@ wxString wxGridStringTable::GetValue( int row, int col ) return m_data[row][col]; } -void wxGridStringTable::SetValue( int row, int col, const wxString& s ) +void wxGridStringTable::SetValue( int row, int col, const wxString& value ) { // TODO: bounds checking // - m_data[row][col] = s; + m_data[row][col] = value; } bool wxGridStringTable::IsEmptyCell( int row, int col ) @@ -1973,29 +2599,29 @@ void wxGridWindow::OnEraseBackground(wxEraseEvent& event) { int cw, ch; GetClientSize( &cw, &ch ); - + int right, bottom; m_owner->CalcUnscrolledPosition( cw, ch, &right, &bottom ); - + wxRect rightRect; rightRect = m_owner->CellToRect( 0, m_owner->GetNumberCols()-1 ); wxRect bottomRect; bottomRect = m_owner->CellToRect( m_owner->GetNumberRows()-1, 0 ); - + if ( right > rightRect.GetRight() || bottom > bottomRect.GetBottom() ) { int left, top; m_owner->CalcUnscrolledPosition( 0, 0, &left, &top ); - + wxClientDC dc( this ); m_owner->PrepareDC( dc ); dc.SetBrush( wxBrush(m_owner->GetDefaultCellBackgroundColour(), wxSOLID) ); dc.SetPen( *wxTRANSPARENT_PEN ); - + if ( right > rightRect.GetRight() ) dc.DrawRectangle( rightRect.GetRight()+1, top, right - rightRect.GetRight(), ch ); - + if ( bottom > bottomRect.GetBottom() ) dc.DrawRectangle( left, bottomRect.GetBottom()+1, cw, bottom - bottomRect.GetBottom() ); } @@ -2020,7 +2646,8 @@ wxGrid::wxGrid( wxWindow *parent, const wxSize& size, long style, const wxString& name ) - : wxScrolledWindow( parent, id, pos, size, style, name ) + : wxScrolledWindow( parent, id, pos, size, style, name ), + m_colMinWidths(wxKEY_INTEGER, GRID_HASH_SIZE) { Create(); } @@ -2041,6 +2668,8 @@ wxGrid::~wxGrid() if (m_ownTable) delete m_table; + + delete m_typeRegistry; } @@ -2060,7 +2689,16 @@ void wxGrid::Create() m_defaultCellAttr = new wxGridCellAttr; m_defaultCellAttr->SetDefAttr(m_defaultCellAttr); - // RD: Should we fill the default attrs now or is waiting until Init() okay? + + // Set default cell attributes + m_defaultCellAttr->SetFont(GetFont()); + m_defaultCellAttr->SetAlignment(wxLEFT, wxTOP); + m_defaultCellAttr->SetTextColour( + wxSystemSettings::GetSystemColour(wxSYS_COLOUR_WINDOWTEXT)); + m_defaultCellAttr->SetBackgroundColour( + wxSystemSettings::GetSystemColour(wxSYS_COLOUR_WINDOW)); + m_defaultCellAttr->SetRenderer(new wxGridCellStringRenderer); + m_defaultCellAttr->SetEditor(new wxGridCellTextEditor); m_numRows = 0; @@ -2070,6 +2708,20 @@ void wxGrid::Create() m_rowLabelWidth = WXGRID_DEFAULT_ROW_LABEL_WIDTH; m_colLabelHeight = WXGRID_DEFAULT_COL_LABEL_HEIGHT; + // data type registration: register all standard data types + // TODO: may be allow the app to selectively disable some of them? + m_typeRegistry = new wxGridTypeRegistry; + RegisterDataType(wxGRID_VALUE_STRING, + new wxGridCellStringRenderer, + new wxGridCellTextEditor); + RegisterDataType(wxGRID_VALUE_BOOL, + new wxGridCellBoolRenderer, + new wxGridCellBoolEditor); + RegisterDataType(wxGRID_VALUE_NUMBER, + new wxGridCellNumberRenderer, + new wxGridCellNumberEditor); + + // subwindow components that make up the wxGrid m_cornerLabelWin = new wxGridCornerLabelWindow( this, -1, wxDefaultPosition, @@ -2192,22 +2844,13 @@ void wxGrid::Init() m_defaultRowHeight += 4; #endif - // Set default cell attributes - m_defaultCellAttr->SetFont(GetFont()); - m_defaultCellAttr->SetAlignment(wxLEFT, wxTOP); - m_defaultCellAttr->SetRenderer(new wxGridCellStringRenderer); - m_defaultCellAttr->SetEditor(new wxGridCellTextEditor); - m_defaultCellAttr->SetTextColour( - wxSystemSettings::GetSystemColour(wxSYS_COLOUR_WINDOWTEXT)); - m_defaultCellAttr->SetBackgroundColour( - wxSystemSettings::GetSystemColour(wxSYS_COLOUR_WINDOW)); - - m_gridLineColour = wxColour( 128, 128, 255 ); m_gridLinesEnabled = TRUE; m_cursorMode = WXGRID_CURSOR_SELECT_CELL; m_winCapture = (wxWindow *)NULL; + m_canDragRowSize = TRUE; + m_canDragColSize = TRUE; m_dragLastPos = -1; m_dragRowOrCol = -1; m_isDragging = FALSE; @@ -2577,7 +3220,7 @@ void wxGrid::CalcRowLabelsExposed( wxRegion& reg ) if ( GetRowBottom(row) < top ) continue; - if ( GetRowTop(top) > bottom ) + if ( GetRowTop(row) > bottom ) break; m_rowLabelsExposed.Add( row ); @@ -2784,7 +3427,8 @@ void wxGrid::ProcessRowLabelMouseEvent( wxMouseEvent& event ) { // starting to drag-resize a row // - ChangeCursorMode(WXGRID_CURSOR_RESIZE_ROW, m_rowLabelWin); + if ( CanDragRowSize() ) + ChangeCursorMode(WXGRID_CURSOR_RESIZE_ROW, m_rowLabelWin); } } @@ -2854,7 +3498,8 @@ void wxGrid::ProcessRowLabelMouseEvent( wxMouseEvent& event ) if ( m_cursorMode == WXGRID_CURSOR_SELECT_CELL ) { // don't capture the mouse yet - ChangeCursorMode(WXGRID_CURSOR_RESIZE_ROW, m_rowLabelWin, FALSE); + if ( CanDragRowSize() ) + ChangeCursorMode(WXGRID_CURSOR_RESIZE_ROW, m_rowLabelWin, FALSE); } } else if ( m_cursorMode != WXGRID_CURSOR_SELECT_CELL ) @@ -2887,7 +3532,9 @@ void wxGrid::ProcessColLabelMouseEvent( wxMouseEvent& event ) wxClientDC dc( m_gridWin ); PrepareDC( dc ); - x = wxMax( x, GetColLeft(m_dragRowOrCol) + WXGRID_MIN_COL_WIDTH ); + + x = wxMax( x, GetColLeft(m_dragRowOrCol) + + GetColMinimalWidth(m_dragRowOrCol)); dc.SetLogicalFunction(wxINVERT); if ( m_dragLastPos >= 0 ) { @@ -2947,7 +3594,8 @@ void wxGrid::ProcessColLabelMouseEvent( wxMouseEvent& event ) { // starting to drag-resize a col // - ChangeCursorMode(WXGRID_CURSOR_RESIZE_COL, m_colLabelWin); + if ( CanDragColSize() ) + ChangeCursorMode(WXGRID_CURSOR_RESIZE_COL, m_colLabelWin); } } @@ -3017,7 +3665,8 @@ void wxGrid::ProcessColLabelMouseEvent( wxMouseEvent& event ) if ( m_cursorMode == WXGRID_CURSOR_SELECT_CELL ) { // don't capture the cursor yet - ChangeCursorMode(WXGRID_CURSOR_RESIZE_COL, m_colLabelWin, FALSE); + if ( CanDragColSize() ) + ChangeCursorMode(WXGRID_CURSOR_RESIZE_COL, m_colLabelWin, FALSE); } } else if ( m_cursorMode != WXGRID_CURSOR_SELECT_CELL ) @@ -3212,7 +3861,8 @@ void wxGrid::ProcessGridCellMouseEvent( wxMouseEvent& event ) wxClientDC dc( m_gridWin ); PrepareDC( dc ); - x = wxMax( x, GetColLeft(m_dragRowOrCol) + WXGRID_MIN_COL_WIDTH ); + x = wxMax( x, GetColLeft(m_dragRowOrCol) + + GetColMinimalWidth(m_dragRowOrCol) ); dc.SetLogicalFunction(wxINVERT); if ( m_dragLastPos >= 0 ) { @@ -3271,7 +3921,7 @@ void wxGrid::ProcessGridCellMouseEvent( wxMouseEvent& event ) EnableCellEditControl(); wxGridCellAttr* attr = GetCellAttr(m_currentCellCoords); - attr->GetEditor()->StartingClick(); + attr->GetEditor(GetDefaultEditorForCell(coords.GetRow(), coords.GetCol()))->StartingClick(); attr->DecRef(); m_waitForSlowClick = FALSE; @@ -3397,7 +4047,8 @@ void wxGrid::ProcessGridCellMouseEvent( wxMouseEvent& event ) if ( m_cursorMode == WXGRID_CURSOR_SELECT_CELL ) { - ChangeCursorMode(WXGRID_CURSOR_RESIZE_ROW); + if ( CanDragRowSize() ) + ChangeCursorMode(WXGRID_CURSOR_RESIZE_ROW); } return; @@ -3409,7 +4060,8 @@ void wxGrid::ProcessGridCellMouseEvent( wxMouseEvent& event ) if ( m_cursorMode == WXGRID_CURSOR_SELECT_CELL ) { - ChangeCursorMode(WXGRID_CURSOR_RESIZE_COL); + if ( CanDragColSize() ) + ChangeCursorMode(WXGRID_CURSOR_RESIZE_COL); } return; @@ -3482,7 +4134,8 @@ void wxGrid::DoEndDragResizeCol() int colLeft = GetColLeft(m_dragRowOrCol); SetColSize( m_dragRowOrCol, - wxMax( m_dragLastPos - colLeft, WXGRID_MIN_COL_WIDTH ) ); + wxMax( m_dragLastPos - colLeft, + GetColMinimalWidth(m_dragRowOrCol) ) ); if ( !GetBatchCount() ) { @@ -4031,8 +4684,10 @@ void wxGrid::OnKeyDown( wxKeyEvent& event ) if ( !IsCellEditControlEnabled() && CanEnableCellControl() ) { EnableCellEditControl(); - wxGridCellAttr* attr = GetCellAttr(m_currentCellCoords); - attr->GetEditor()->StartingKey(event); + int row = m_currentCellCoords.GetRow(); + int col = m_currentCellCoords.GetCol(); + wxGridCellAttr* attr = GetCellAttr(row, col); + attr->GetEditor(GetDefaultEditorForCell(row, col))->StartingKey(event); attr->DecRef(); } else @@ -4184,13 +4839,16 @@ void wxGrid::DrawCell( wxDC& dc, const wxGridCellCoords& coords ) // if the editor is shown, we should use it and not the renderer if ( isCurrent && IsCellEditControlEnabled() ) { - attr->GetEditor()->PaintBackground(rect, attr); + attr->GetEditor(GetDefaultEditorForCell(row, col))-> + PaintBackground(rect, attr); } else { // but all the rest is drawn by the cell renderer and hence may be // customized - attr->GetRenderer()->Draw(*this, *attr, dc, rect, row, col, IsInSelection(coords)); + attr->GetRenderer(GetDefaultRendererForCell(row,col))-> + Draw(*this, *attr, dc, rect, row, col, IsInSelection(coords)); + } attr->DecRef(); @@ -4240,6 +4898,7 @@ void wxGrid::DrawCellHighlight( wxDC& dc, const wxGridCellAttr *attr ) #endif // 0 } + void wxGrid::DrawCellBorder( wxDC& dc, const wxGridCellCoords& coords ) { int row = coords.GetRow(); @@ -4262,6 +4921,12 @@ void wxGrid::DrawCellBorder( wxDC& dc, const wxGridCellCoords& coords ) void wxGrid::DrawHighlight(wxDC& dc) { + if ( IsCellEditControlEnabled() ) + { + // don't show highlight when the edit control is shown + return; + } + // if the active cell was repainted, repaint its highlight too because it // might have been damaged by the grid lines size_t count = m_cellsExposed.GetCount(); @@ -4320,16 +4985,16 @@ void wxGrid::DrawAllGridLines( wxDC& dc, const wxRegion & reg ) int i; for ( i = 0; i < m_numRows; i++ ) { - int bottom = GetRowBottom(i) - 1; + int bot = GetRowBottom(i) - 1; - if ( bottom > bottom ) + if ( bot > bottom ) { break; } - if ( bottom >= top ) + if ( bot >= top ) { - dc.DrawLine( left, bottom, right, bottom ); + dc.DrawLine( left, bot, right, bot ); } } @@ -4648,11 +5313,6 @@ bool wxGrid::IsCellEditControlEnabled() const return m_cellEditCtrlEnabled ? !IsCurrentCellReadOnly() : FALSE; } -wxWindow *wxGrid::GetGridWindow() const -{ - return m_gridWin; -} - void wxGrid::ShowCellEditControl() { if ( IsCellEditControlEnabled() ) @@ -4669,61 +5329,25 @@ void wxGrid::ShowCellEditControl() // convert to scrolled coords // - int left, top, right, bottom; - CalcScrolledPosition( rect.GetLeft(), rect.GetTop(), &left, &top ); - CalcScrolledPosition( rect.GetRight(), rect.GetBottom(), &right, &bottom ); - - // cell is shifted by one pixel - left--; - top--; - right--; - bottom--; + CalcScrolledPosition( rect.x, rect.y, &rect.x, &rect.y ); - // Make the edit control large enough to allow for internal - // margins - // - // TODO: remove this if the text ctrl sizing is improved esp. for - // unix - // - int extra; -#if defined(__WXMOTIF__) - if ( row == 0 || col == 0 ) - { - extra = 2; - } - else - { - extra = 4; - } -#else - if ( row == 0 || col == 0 ) - { - extra = 1; - } - else - { - extra = 2; - } -#endif + // done in PaintBackground() +#if 0 + // erase the highlight and the cell contents because the editor + // might not cover the entire cell + wxClientDC dc( m_gridWin ); + PrepareDC( dc ); + dc.SetBrush(*wxLIGHT_GREY_BRUSH); //wxBrush(attr->GetBackgroundColour(), wxSOLID)); + dc.SetPen(*wxTRANSPARENT_PEN); + dc.DrawRectangle(rect); +#endif // 0 -#if defined(__WXGTK__) - int top_diff = 0; - int left_diff = 0; - if (left != 0) left_diff++; - if (top != 0) top_diff++; - rect.SetLeft( left + left_diff ); - rect.SetTop( top + top_diff ); - rect.SetRight( rect.GetRight() - left_diff ); - rect.SetBottom( rect.GetBottom() - top_diff ); -#else - rect.SetLeft( wxMax(0, left - extra) ); - rect.SetTop( wxMax(0, top - extra) ); - rect.SetRight( rect.GetRight() + 2*extra ); - rect.SetBottom( rect.GetBottom() + 2*extra ); -#endif + // cell is shifted by one pixel + rect.x--; + rect.y--; wxGridCellAttr* attr = GetCellAttr(row, col); - wxGridCellEditor* editor = attr->GetEditor(); + wxGridCellEditor* editor = attr->GetEditor(GetDefaultEditorForCell(row, col)); if ( !editor->IsCreated() ) { editor->Create(m_gridWin, -1, @@ -4731,6 +5355,7 @@ void wxGrid::ShowCellEditControl() } editor->SetSize( rect ); + editor->Show( TRUE, attr ); editor->BeginEdit(row, col, this); attr->DecRef(); @@ -4747,7 +5372,7 @@ void wxGrid::HideCellEditControl() int col = m_currentCellCoords.GetCol(); wxGridCellAttr* attr = GetCellAttr(row, col); - attr->GetEditor()->Show( FALSE ); + attr->GetEditor(GetDefaultEditorForCell(row, col))->Show( FALSE ); attr->DecRef(); m_gridWin->SetFocus(); } @@ -4769,7 +5394,8 @@ void wxGrid::SaveEditControlValue() int col = m_currentCellCoords.GetCol(); wxGridCellAttr* attr = GetCellAttr(row, col); - bool changed = attr->GetEditor()->EndEdit(row, col, TRUE, this); + wxGridCellEditor* editor = attr->GetEditor(GetDefaultEditorForCell(row, col)); + bool changed = editor->EndEdit(row, col, TRUE, this); attr->DecRef(); @@ -4816,7 +5442,7 @@ int wxGrid::YToRow( int y ) return i; } - return m_numRows; //-1; + return -1; } @@ -4830,7 +5456,7 @@ int wxGrid::XToCol( int x ) return i; } - return m_numCols; //-1; + return -1; } @@ -5701,12 +6327,12 @@ void wxGrid::GetDefaultCellAlignment( int *horiz, int *vert ) wxGridCellRenderer *wxGrid::GetDefaultRenderer() const { - return m_defaultCellAttr->GetRenderer(); + return m_defaultCellAttr->GetRenderer(NULL); } wxGridCellEditor *wxGrid::GetDefaultEditor() const { - return m_defaultCellAttr->GetEditor(); + return m_defaultCellAttr->GetEditor(NULL); } // ---------------------------------------------------------------------------- @@ -5747,7 +6373,7 @@ void wxGrid::GetCellAlignment( int row, int col, int *horiz, int *vert ) wxGridCellRenderer* wxGrid::GetCellRenderer(int row, int col) { wxGridCellAttr* attr = GetCellAttr(row, col); - wxGridCellRenderer* renderer = attr->GetRenderer(); + wxGridCellRenderer* renderer = attr->GetRenderer(GetDefaultRendererForCell(row,col)); attr->DecRef(); return renderer; } @@ -5755,7 +6381,7 @@ wxGridCellRenderer* wxGrid::GetCellRenderer(int row, int col) wxGridCellEditor* wxGrid::GetCellEditor(int row, int col) { wxGridCellAttr* attr = GetCellAttr(row, col); - wxGridCellEditor* editor = attr->GetEditor(); + wxGridCellEditor* editor = attr->GetEditor(GetDefaultEditorForCell(row, col)); attr->DecRef(); return editor; } @@ -5779,19 +6405,7 @@ bool wxGrid::CanHaveAttributes() return FALSE; } - // RD: Maybe m_table->CanHaveAttributes() would be better in case the - // table is providing the attributes itself??? In which case - // I don't think the grid should create a Provider object for the - // table but the table should be smart enough to do that on its own. - if ( !m_table->GetAttrProvider() ) - { - // use the default attr provider by default - // (another choice would be to just return FALSE thus forcing the user - // to it himself) - m_table->SetAttrProvider(new wxGridCellAttrProvider); - } - - return TRUE; + return m_table->CanHaveAttributes(); } void wxGrid::ClearAttrCache() @@ -5981,10 +6595,71 @@ void wxGrid::SetReadOnly(int row, int col, bool isReadOnly) } } +// ---------------------------------------------------------------------------- +// Data type registration +// ---------------------------------------------------------------------------- + +void wxGrid::RegisterDataType(const wxString& typeName, + wxGridCellRenderer* renderer, + wxGridCellEditor* editor) +{ + m_typeRegistry->RegisterDataType(typeName, renderer, editor); +} + + +wxGridCellEditor* wxGrid::GetDefaultEditorForCell(int row, int col) const +{ + wxString typeName = m_table->GetTypeName(row, col); + return GetDefaultEditorForType(typeName); +} + +wxGridCellRenderer* wxGrid::GetDefaultRendererForCell(int row, int col) const +{ + wxString typeName = m_table->GetTypeName(row, col); + return GetDefaultRendererForType(typeName); +} + +wxGridCellEditor* +wxGrid::GetDefaultEditorForType(const wxString& typeName) const +{ + int index = m_typeRegistry->FindDataType(typeName); + if (index == -1) { + // Should we force the failure here or let it fallback to string handling??? + // wxFAIL_MSG(wxT("Unknown data type name")); + return NULL; + } + return m_typeRegistry->GetEditor(index); +} + +wxGridCellRenderer* +wxGrid::GetDefaultRendererForType(const wxString& typeName) const +{ + int index = m_typeRegistry->FindDataType(typeName); + if (index == -1) { + // Should we force the failure here or let it fallback to string handling??? + // wxFAIL_MSG(wxT("Unknown data type name")); + return NULL; + } + return m_typeRegistry->GetRenderer(index); +} + + // ---------------------------------------------------------------------------- // row/col size // ---------------------------------------------------------------------------- +void wxGrid::EnableDragRowSize( bool enable ) +{ + m_canDragRowSize = enable; +} + + +void wxGrid::EnableDragColSize( bool enable ) +{ + m_canDragColSize = enable; +} + + void wxGrid::SetDefaultRowSize( int height, bool resizeExistingRows ) { m_defaultRowHeight = wxMax( height, WXGRID_MIN_ROW_HEIGHT ); @@ -6035,6 +6710,8 @@ void wxGrid::SetColSize( int col, int width ) { wxCHECK_RET( col >= 0 && col < m_numCols, _T("invalid column index") ); + // should we check that it's bigger than GetColMinimalWidth(col) here? + if ( m_colWidths.IsEmpty() ) { // need to really create the array @@ -6054,6 +6731,73 @@ void wxGrid::SetColSize( int col, int width ) } +void wxGrid::SetColMinimalWidth( int col, int width ) +{ + m_colMinWidths.Put(col, (wxObject *)width); +} + +int wxGrid::GetColMinimalWidth(int col) const +{ + wxObject *obj = m_colMinWidths.Get(m_dragRowOrCol); + return obj ? (int)obj : WXGRID_MIN_COL_WIDTH; +} + +void wxGrid::AutoSizeColumn( int col, bool setAsMin ) +{ + wxClientDC dc(m_gridWin); + + wxCoord width, widthMax = 0; + for ( int row = 0; row < m_numRows; row++ ) + { + wxGridCellAttr* attr = GetCellAttr(row, col); + wxGridCellRenderer* renderer = attr->GetRenderer(GetDefaultRendererForCell(row,col)); + if ( renderer ) + { + width = renderer->GetBestSize(*this, *attr, dc, row, col).x; + if ( width > widthMax ) + { + widthMax = width; + } + } + + attr->DecRef(); + } + + // now also compare with the column label width + dc.SetFont( GetLabelFont() ); + dc.GetTextExtent( GetColLabelValue(col), &width, NULL ); + if ( width > widthMax ) + { + widthMax = width; + } + + if ( !widthMax ) + { + // empty column - give default width (notice that if widthMax is less + // than default width but != 0, it's ok) + widthMax = m_defaultColWidth; + } + else + { + // leave some space around text + widthMax += 10; + } + + SetColSize(col, widthMax); + if ( setAsMin ) + { + SetColMinimalWidth(col, widthMax); + } +} + +void wxGrid::AutoSizeColumns( bool setAsMin ) +{ + for ( int col = 0; col < m_numCols; col++ ) + { + AutoSizeColumn(col, setAsMin); + } +} + // // ------ cell value accessor functions //