X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/8b5f6d9d47549e88538e0e6bf734ce4bc30c9093..4219d8b027a351fb6c2d1580c292e639bd322f77:/src/generic/grid.cpp?ds=sidebyside diff --git a/src/generic/grid.cpp b/src/generic/grid.cpp index e8ca4e0102..1da201ad36 100644 --- a/src/generic/grid.cpp +++ b/src/generic/grid.cpp @@ -47,10 +47,11 @@ #include "wx/spinctrl.h" #include "wx/tokenzr.h" #include "wx/renderer.h" +#include "wx/headerctrl.h" #include "wx/generic/gridsel.h" -const wxChar wxGridNameStr[] = wxT("grid"); +const char wxGridNameStr[] = "grid"; #if defined(__WXMOTIF__) #define WXUNUSED_MOTIF(identifier) WXUNUSED(identifier) @@ -145,8 +146,10 @@ DEFINE_EVENT_TYPE(wxEVT_GRID_LABEL_RIGHT_DCLICK) DEFINE_EVENT_TYPE(wxEVT_GRID_ROW_SIZE) DEFINE_EVENT_TYPE(wxEVT_GRID_COL_SIZE) DEFINE_EVENT_TYPE(wxEVT_GRID_COL_MOVE) +DEFINE_EVENT_TYPE(wxEVT_GRID_COL_SORT) DEFINE_EVENT_TYPE(wxEVT_GRID_RANGE_SELECT) -DEFINE_EVENT_TYPE(wxEVT_GRID_CELL_CHANGE) +DEFINE_EVENT_TYPE(wxEVT_GRID_CELL_CHANGING) +DEFINE_EVENT_TYPE(wxEVT_GRID_CELL_CHANGED) DEFINE_EVENT_TYPE(wxEVT_GRID_SELECT_CELL) DEFINE_EVENT_TYPE(wxEVT_GRID_EDITOR_SHOWN) DEFINE_EVENT_TYPE(wxEVT_GRID_EDITOR_HIDDEN) @@ -156,18 +159,195 @@ DEFINE_EVENT_TYPE(wxEVT_GRID_EDITOR_CREATED) // private classes // ---------------------------------------------------------------------------- +// header column providing access to the column information stored in wxGrid +// via wxHeaderColumn interface +class wxGridHeaderColumn : public wxHeaderColumn +{ +public: + wxGridHeaderColumn(wxGrid *grid, int col) + : m_grid(grid), + m_col(col) + { + } + + virtual wxString GetTitle() const { return m_grid->GetColLabelValue(m_col); } + virtual wxBitmap GetBitmap() const { return wxNullBitmap; } + virtual int GetWidth() const { return m_grid->GetColSize(m_col); } + virtual int GetMinWidth() const { return 0; } + virtual wxAlignment GetAlignment() const + { + int horz, + vert; + m_grid->GetColLabelAlignment(&horz, &vert); + + return static_cast(horz); + } + + virtual int GetFlags() const + { + // we can't know in advance whether we can sort by this column or not + // with wxGrid API so suppose we can by default + int flags = wxCOL_SORTABLE; + if ( m_grid->CanDragColSize() ) + flags |= wxCOL_RESIZABLE; + if ( m_grid->CanDragColMove() ) + flags |= wxCOL_REORDERABLE; + if ( GetWidth() == 0 ) + flags |= wxCOL_HIDDEN; + + return flags; + } + + virtual bool IsSortKey() const + { + return m_grid->IsSortingBy(m_col); + } + + virtual bool IsSortOrderAscending() const + { + return m_grid->IsSortOrderAscending(); + } + +private: + // these really should be const but are not because the column needs to be + // assignable to be used in a wxVector (in STL build, in non-STL build we + // avoid the need for this) + wxGrid *m_grid; + int m_col; +}; + +// header control retreiving column information from the grid +class wxGridHeaderCtrl : public wxHeaderCtrl +{ +public: + wxGridHeaderCtrl(wxGrid *owner) + : wxHeaderCtrl(owner, + wxID_ANY, + wxDefaultPosition, + wxDefaultSize, + wxHD_ALLOW_HIDE | + (owner->CanDragColMove() ? wxHD_ALLOW_REORDER : 0)) + { + } + +protected: + virtual const wxHeaderColumn& GetColumn(unsigned int idx) const + { + return m_columns[idx]; + } + +private: + wxGrid *GetOwner() const { return static_cast(GetParent()); } + + // override the base class method to update our m_columns array + virtual void OnColumnCountChanging(unsigned int count) + { + const unsigned countOld = m_columns.size(); + if ( count < countOld ) + { + // just discard the columns which don't exist any more (notice that + // we can't use resize() here as it would require the vector + // value_type, i.e. wxGridHeaderColumn to be default constructible, + // which it is not) + m_columns.erase(m_columns.begin() + count, m_columns.end()); + } + else // new columns added + { + // add columns for the new elements + for ( unsigned n = countOld; n < count; n++ ) + m_columns.push_back(wxGridHeaderColumn(GetOwner(), n)); + } + } + + // override to implement column auto sizing + virtual bool UpdateColumnWidthToFit(unsigned int idx, int widthTitle) + { + // TODO: currently grid doesn't support computing the column best width + // from its contents so we just use the best label width as is + GetOwner()->SetColSize(idx, widthTitle); + + return true; + } + + // overridden to react to the actions using the columns popup menu + virtual void UpdateColumnVisibility(unsigned int idx, bool show) + { + GetOwner()->SetColSize(idx, show ? wxGRID_AUTOSIZE : 0); + + // as this is done by the user we should notify the main program about + // it + GetOwner()->SendEvent(wxEVT_GRID_COL_SIZE, -1, idx); + } + + // overridden to react to the columns order changes in the customization + // dialog + virtual void UpdateColumnsOrder(const wxArrayInt& order) + { + GetOwner()->SetColumnsOrder(order); + } + + + // event handlers forwarding wxHeaderCtrl events to wxGrid + void OnClick(wxHeaderCtrlEvent& event) + { + GetOwner()->DoColHeaderClick(event.GetColumn()); + } + + void OnBeginResize(wxHeaderCtrlEvent& event) + { + GetOwner()->DoStartResizeCol(event.GetColumn()); + + event.Skip(); + } + + void OnResizing(wxHeaderCtrlEvent& event) + { + GetOwner()->DoUpdateResizeColWidth(event.GetWidth()); + } + + void OnEndResize(wxHeaderCtrlEvent& event) + { + GetOwner()->DoEndDragResizeCol(); + + event.Skip(); + } + + void OnBeginReorder(wxHeaderCtrlEvent& event) + { + GetOwner()->DoStartMoveCol(event.GetColumn()); + } + + void OnEndReorder(wxHeaderCtrlEvent& event) + { + GetOwner()->DoEndMoveCol(event.GetNewOrder()); + } + + wxVector m_columns; + + DECLARE_EVENT_TABLE() + DECLARE_NO_COPY_CLASS(wxGridHeaderCtrl) +}; + +BEGIN_EVENT_TABLE(wxGridHeaderCtrl, wxHeaderCtrl) + EVT_HEADER_CLICK(wxID_ANY, wxGridHeaderCtrl::OnClick) + + EVT_HEADER_BEGIN_RESIZE(wxID_ANY, wxGridHeaderCtrl::OnBeginResize) + EVT_HEADER_RESIZING(wxID_ANY, wxGridHeaderCtrl::OnResizing) + EVT_HEADER_END_RESIZE(wxID_ANY, wxGridHeaderCtrl::OnEndResize) + + EVT_HEADER_BEGIN_REORDER(wxID_ANY, wxGridHeaderCtrl::OnBeginReorder) + EVT_HEADER_END_REORDER(wxID_ANY, wxGridHeaderCtrl::OnEndReorder) +END_EVENT_TABLE() + // common base class for various grid subwindows class WXDLLIMPEXP_ADV wxGridSubwindow : public wxWindow { public: - wxGridSubwindow() { m_owner = NULL; } wxGridSubwindow(wxGrid *owner, - wxWindowID id, - const wxPoint& pos, - const wxSize& size, int additionalStyle = 0, const wxString& name = wxPanelNameStr) - : wxWindow(owner, id, pos, size, + : wxWindow(owner, wxID_ANY, + wxDefaultPosition, wxDefaultSize, wxBORDER_NONE | additionalStyle, name) { @@ -190,16 +370,17 @@ protected: class WXDLLIMPEXP_ADV wxGridRowLabelWindow : public wxGridSubwindow { public: - wxGridRowLabelWindow() { } - wxGridRowLabelWindow( wxGrid *parent, wxWindowID id, - const wxPoint &pos, const wxSize &size ); + wxGridRowLabelWindow(wxGrid *parent) + : wxGridSubwindow(parent) + { + } + private: void OnPaint( wxPaintEvent& event ); void OnMouseEvent( wxMouseEvent& event ); void OnMouseWheel( wxMouseEvent& event ); - DECLARE_DYNAMIC_CLASS(wxGridRowLabelWindow) DECLARE_EVENT_TABLE() DECLARE_NO_COPY_CLASS(wxGridRowLabelWindow) }; @@ -208,16 +389,17 @@ private: class WXDLLIMPEXP_ADV wxGridColLabelWindow : public wxGridSubwindow { public: - wxGridColLabelWindow() { } - wxGridColLabelWindow( wxGrid *parent, wxWindowID id, - const wxPoint &pos, const wxSize &size ); + wxGridColLabelWindow(wxGrid *parent) + : wxGridSubwindow(parent) + { + } + private: void OnPaint( wxPaintEvent& event ); void OnMouseEvent( wxMouseEvent& event ); void OnMouseWheel( wxMouseEvent& event ); - DECLARE_DYNAMIC_CLASS(wxGridColLabelWindow) DECLARE_EVENT_TABLE() DECLARE_NO_COPY_CLASS(wxGridColLabelWindow) }; @@ -226,16 +408,16 @@ private: class WXDLLIMPEXP_ADV wxGridCornerLabelWindow : public wxGridSubwindow { public: - wxGridCornerLabelWindow() { } - wxGridCornerLabelWindow( wxGrid *parent, wxWindowID id, - const wxPoint &pos, const wxSize &size ); + wxGridCornerLabelWindow(wxGrid *parent) + : wxGridSubwindow(parent) + { + } private: void OnMouseEvent( wxMouseEvent& event ); void OnMouseWheel( wxMouseEvent& event ); void OnPaint( wxPaintEvent& event ); - DECLARE_DYNAMIC_CLASS(wxGridCornerLabelWindow) DECLARE_EVENT_TABLE() DECLARE_NO_COPY_CLASS(wxGridCornerLabelWindow) }; @@ -243,25 +425,19 @@ private: class WXDLLIMPEXP_ADV wxGridWindow : public wxGridSubwindow { public: - wxGridWindow() + wxGridWindow(wxGrid *parent) + : wxGridSubwindow(parent, + wxWANTS_CHARS | wxCLIP_CHILDREN, + "GridWindow") { - m_rowLabelWin = NULL; - m_colLabelWin = NULL; } - wxGridWindow( wxGrid *parent, - wxGridRowLabelWindow *rowLblWin, - wxGridColLabelWindow *colLblWin, - wxWindowID id, const wxPoint &pos, const wxSize &size ); - void ScrollWindow( int dx, int dy, const wxRect *rect ); + virtual void ScrollWindow( int dx, int dy, const wxRect *rect ); virtual bool AcceptsFocus() const { return true; } private: - wxGridRowLabelWindow *m_rowLabelWin; - wxGridColLabelWindow *m_colLabelWin; - void OnPaint( wxPaintEvent &event ); void OnMouseWheel( wxMouseEvent& event ); void OnMouseEvent( wxMouseEvent& event ); @@ -271,7 +447,6 @@ private: void OnEraseBackground( wxEraseEvent& ); void OnFocus( wxFocusEvent& ); - DECLARE_DYNAMIC_CLASS(wxGridWindow) DECLARE_EVENT_TABLE() DECLARE_NO_COPY_CLASS(wxGridWindow) }; @@ -486,7 +661,7 @@ public: } - // Return the row or column at the given pixel coordinate. + // Return the index of the row or column at the given pixel coordinate. virtual int PosToLine(const wxGrid *grid, int pos, bool clip = false) const = 0; @@ -965,32 +1140,19 @@ bool wxGridCellEditor::IsAcceptedKey(wxKeyEvent& event) if ((ctrl || alt) && !(ctrl && alt)) return false; - int key = 0; - bool keyOk = true; - -#ifdef __WXGTK20__ - // If it's a F-Key or other special key then it shouldn't start the - // editor. - if (event.GetKeyCode() >= WXK_START) - return false; -#endif #if wxUSE_UNICODE // if the unicode key code is not really a unicode character (it may // be a function key or etc., the platforms appear to always give us a // small value in this case) then fallback to the ASCII key code but // don't do anything for function keys or etc. - key = event.GetUnicodeKey(); - if (key <= 127) - { - key = event.GetKeyCode(); - keyOk = (key <= 127); - } + if ( event.GetUnicodeKey() > 127 && event.GetKeyCode() > 127 ) + return false; #else - key = event.GetKeyCode(); - keyOk = (key <= 255); + if ( event.GetKeyCode() > 255 ) + return false; #endif - return keyOk; + return true; } void wxGridCellEditor::StartingKey(wxKeyEvent& event) @@ -1098,9 +1260,9 @@ 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); + m_value = grid->GetTable()->GetValue(row, col); - DoBeginEdit(m_startValue); + DoBeginEdit(m_value); } void wxGridCellTextEditor::DoBeginEdit(const wxString& startValue) @@ -1111,31 +1273,35 @@ void wxGridCellTextEditor::DoBeginEdit(const wxString& startValue) Text()->SetFocus(); } -bool wxGridCellTextEditor::EndEdit(int row, int col, wxGrid* grid) +bool wxGridCellTextEditor::EndEdit(const wxString& WXUNUSED(oldval), + wxString *newval) { - wxASSERT_MSG(m_control, wxT("The wxGridCellEditor must be created first!")); + wxCHECK_MSG( m_control, false, + "wxGridCellTextEditor must be created first!" ); - bool changed = false; - wxString value = Text()->GetValue(); - if (value != m_startValue) - changed = true; + const wxString value = Text()->GetValue(); + if ( value == m_value ) + return false; - if (changed) - grid->GetTable()->SetValue(row, col, value); + m_value = value; - m_startValue = wxEmptyString; + if ( newval ) + *newval = m_value; - // No point in setting the text of the hidden control - //Text()->SetValue(m_startValue); + return true; +} - return changed; +void wxGridCellTextEditor::ApplyEdit(int row, int col, wxGrid* grid) +{ + grid->GetTable()->SetValue(row, col, m_value); + m_value.clear(); } void wxGridCellTextEditor::Reset() { - wxASSERT_MSG(m_control, wxT("The wxGridCellEditor must be created first!")); + wxASSERT_MSG( m_control, "wxGridCellTextEditor must be created first!" ); - DoReset(m_startValue); + DoReset(m_value); } void wxGridCellTextEditor::DoReset(const wxString& startValue) @@ -1277,13 +1443,13 @@ void wxGridCellNumberEditor::BeginEdit(int row, int col, wxGrid* grid) wxGridTableBase *table = grid->GetTable(); if ( table->CanGetValueAs(row, col, wxGRID_VALUE_NUMBER) ) { - m_valueOld = table->GetValueAsLong(row, col); + m_value = table->GetValueAsLong(row, col); } else { - m_valueOld = 0; + m_value = 0; wxString sValue = table->GetValue(row, col); - if (! sValue.ToLong(&m_valueOld) && ! sValue.empty()) + if (! sValue.ToLong(&m_value) && ! sValue.empty()) { wxFAIL_MSG( _T("this cell doesn't have numeric value") ); return; @@ -1293,7 +1459,7 @@ void wxGridCellNumberEditor::BeginEdit(int row, int col, wxGrid* grid) #if wxUSE_SPINCTRL if ( HasRange() ) { - Spin()->SetValue((int)m_valueOld); + Spin()->SetValue((int)m_value); Spin()->SetFocus(); } else @@ -1303,8 +1469,7 @@ void wxGridCellNumberEditor::BeginEdit(int row, int col, wxGrid* grid) } } -bool wxGridCellNumberEditor::EndEdit(int row, int col, - wxGrid* grid) +bool wxGridCellNumberEditor::EndEdit(const wxString& oldval, wxString *newval) { long value = 0; wxString text; @@ -1313,7 +1478,7 @@ bool wxGridCellNumberEditor::EndEdit(int row, int col, if ( HasRange() ) { value = Spin()->GetValue(); - if ( value == m_valueOld ) + if ( value == m_value ) return false; text.Printf(wxT("%ld"), value); @@ -1321,11 +1486,10 @@ bool wxGridCellNumberEditor::EndEdit(int row, int col, else // using unconstrained input #endif // wxUSE_SPINCTRL { - const wxString textOld(grid->GetCellValue(row, col)); text = Text()->GetValue(); if ( text.empty() ) { - if ( textOld.empty() ) + if ( oldval.empty() ) return false; } else // non-empty text now (maybe 0) @@ -1333,20 +1497,28 @@ bool wxGridCellNumberEditor::EndEdit(int row, int col, if ( !text.ToLong(&value) ) return false; - // if value == m_valueOld == 0 but old text was "" and new one is + // if value == m_value == 0 but old text was "" and new one is // "0" something still did change - if ( value == m_valueOld && (value || !textOld.empty()) ) + if ( value == m_value && (value || !oldval.empty()) ) return false; } } + m_value = value; + + if ( newval ) + *newval = text; + + return true; +} + +void wxGridCellNumberEditor::ApplyEdit(int row, int col, wxGrid* grid) +{ wxGridTableBase * const table = grid->GetTable(); if ( table->CanSetValueAs(row, col, wxGRID_VALUE_NUMBER) ) - table->SetValueAsLong(row, col, value); + table->SetValueAsLong(row, col, m_value); else - table->SetValue(row, col, text); - - return true; + table->SetValue(row, col, wxString::Format("%ld", m_value)); } void wxGridCellNumberEditor::Reset() @@ -1354,7 +1526,7 @@ void wxGridCellNumberEditor::Reset() #if wxUSE_SPINCTRL if ( HasRange() ) { - Spin()->SetValue((int)m_valueOld); + Spin()->SetValue((int)m_value); } else #endif @@ -1482,16 +1654,16 @@ void wxGridCellFloatEditor::BeginEdit(int row, int col, wxGrid* grid) wxGridTableBase * const table = grid->GetTable(); if ( table->CanGetValueAs(row, col, wxGRID_VALUE_FLOAT) ) { - m_valueOld = table->GetValueAsDouble(row, col); + m_value = table->GetValueAsDouble(row, col); } else { - m_valueOld = 0.0; + m_value = 0.0; const wxString value = table->GetValue(row, col); if ( !value.empty() ) { - if ( !value.ToDouble(&m_valueOld) ) + if ( !value.ToDouble(&m_value) ) { wxFAIL_MSG( _T("this cell doesn't have float value") ); return; @@ -1502,10 +1674,9 @@ void wxGridCellFloatEditor::BeginEdit(int row, int col, wxGrid* grid) DoBeginEdit(GetString()); } -bool wxGridCellFloatEditor::EndEdit(int row, int col, wxGrid* grid) +bool wxGridCellFloatEditor::EndEdit(const wxString& oldval, wxString *newval) { - const wxString text(Text()->GetValue()), - textOld(grid->GetCellValue(row, col)); + const wxString text(Text()->GetValue()); double value; if ( !text.empty() ) @@ -1515,7 +1686,7 @@ bool wxGridCellFloatEditor::EndEdit(int row, int col, wxGrid* grid) } else // new value is empty string { - if ( textOld.empty() ) + if ( oldval.empty() ) return false; // nothing changed value = 0.; @@ -1523,17 +1694,25 @@ bool wxGridCellFloatEditor::EndEdit(int row, int col, wxGrid* grid) // the test for empty strings ensures that we don't skip the value setting // when "" is replaced by "0" or vice versa as "" numeric value is also 0. - if ( wxIsSameDouble(value, m_valueOld) && !text.empty() && !textOld.empty() ) + if ( wxIsSameDouble(value, m_value) && !text.empty() && !oldval.empty() ) return false; // nothing changed + m_value = value; + + if ( newval ) + *newval = text; + + return true; +} + +void wxGridCellFloatEditor::ApplyEdit(int row, int col, wxGrid* grid) +{ wxGridTableBase * const table = grid->GetTable(); if ( table->CanSetValueAs(row, col, wxGRID_VALUE_FLOAT) ) - table->SetValueAsDouble(row, col, value); + table->SetValueAsDouble(row, col, m_value); else - table->SetValue(row, col, text); - - return true; + table->SetValue(row, col, Text()->GetValue()); } void wxGridCellFloatEditor::Reset() @@ -1619,7 +1798,7 @@ wxString wxGridCellFloatEditor::GetString() const fmt = _T("%f"); } - return wxString::Format(fmt, m_valueOld); + return wxString::Format(fmt, m_value); } bool wxGridCellFloatEditor::IsAcceptedKey(wxKeyEvent& event) @@ -1767,16 +1946,16 @@ void wxGridCellBoolEditor::BeginEdit(int row, int col, wxGrid* grid) if (grid->GetTable()->CanGetValueAs(row, col, wxGRID_VALUE_BOOL)) { - m_startValue = grid->GetTable()->GetValueAsBool(row, col); + m_value = grid->GetTable()->GetValueAsBool(row, col); } else { wxString cellval( grid->GetTable()->GetValue(row, col) ); if ( cellval == ms_stringValues[false] ) - m_startValue = false; + m_value = false; else if ( cellval == ms_stringValues[true] ) - m_startValue = true; + m_value = true; else { // do not try to be smart here and convert it to true or false @@ -1787,31 +1966,32 @@ void wxGridCellBoolEditor::BeginEdit(int row, int col, wxGrid* grid) } } - CBox()->SetValue(m_startValue); + CBox()->SetValue(m_value); CBox()->SetFocus(); } -bool wxGridCellBoolEditor::EndEdit(int row, int col, - wxGrid* grid) +bool wxGridCellBoolEditor::EndEdit(const wxString& WXUNUSED(oldval), + wxString *newval) { - wxASSERT_MSG(m_control, - wxT("The wxGridCellEditor must be created first!")); - - bool changed = false; bool value = CBox()->GetValue(); - if ( value != m_startValue ) - changed = true; + if ( value == m_value ) + return false; - if ( changed ) - { - wxGridTableBase * const table = grid->GetTable(); - if ( table->CanGetValueAs(row, col, wxGRID_VALUE_BOOL) ) - table->SetValueAsBool(row, col, value); - else - table->SetValue(row, col, GetValue()); - } + m_value = value; + + if ( newval ) + *newval = GetValue(); + + return true; +} - return changed; +void wxGridCellBoolEditor::ApplyEdit(int row, int col, wxGrid* grid) +{ + wxGridTableBase * const table = grid->GetTable(); + if ( table->CanSetValueAs(row, col, wxGRID_VALUE_BOOL) ) + table->SetValueAsBool(row, col, m_value); + else + table->SetValue(row, col, GetValue()); } void wxGridCellBoolEditor::Reset() @@ -1819,7 +1999,7 @@ void wxGridCellBoolEditor::Reset() wxASSERT_MSG(m_control, wxT("The wxGridCellEditor must be created first!")); - CBox()->SetValue(m_startValue); + CBox()->SetValue(m_value); } void wxGridCellBoolEditor::StartingClick() @@ -1962,9 +2142,9 @@ void wxGridCellChoiceEditor::BeginEdit(int row, int col, wxGrid* grid) if (evtHandler) evtHandler->SetInSetFocus(true); - m_startValue = grid->GetTable()->GetValue(row, col); + m_value = grid->GetTable()->GetValue(row, col); - Reset(); // this updates combo box to correspond to m_startValue + Reset(); // this updates combo box to correspond to m_value Combo()->SetFocus(); @@ -1978,29 +2158,37 @@ void wxGridCellChoiceEditor::BeginEdit(int row, int col, wxGrid* grid) } } -bool wxGridCellChoiceEditor::EndEdit(int row, int col, - wxGrid* grid) +bool wxGridCellChoiceEditor::EndEdit(const wxString& WXUNUSED(oldval), + wxString *newval) { - wxString value = Combo()->GetValue(); - if ( value == m_startValue ) + const wxString value = Combo()->GetValue(); + if ( value == m_value ) return false; - grid->GetTable()->SetValue(row, col, value); + m_value = value; + + if ( newval ) + *newval = value; return true; } +void wxGridCellChoiceEditor::ApplyEdit(int row, int col, wxGrid* grid) +{ + grid->GetTable()->SetValue(row, col, m_value); +} + void wxGridCellChoiceEditor::Reset() { if (m_allowOthers) { - Combo()->SetValue(m_startValue); + Combo()->SetValue(m_value); Combo()->SetInsertionPointEnd(); } else // the combobox is read-only { // find the right position, or default to the first if not found - int pos = Combo()->FindString(m_startValue); + int pos = Combo()->FindString(m_value); if (pos == wxNOT_FOUND) pos = 0; Combo()->SetSelection(pos); @@ -3843,15 +4031,6 @@ void wxGridStringTable::SetValue( int row, int col, const wxString& value ) m_data[row][col] = value; } -bool wxGridStringTable::IsEmptyCell( int row, int col ) -{ - wxCHECK_MSG( (row < GetNumberRows()) && (col < GetNumberCols()), - true, - _T("invalid row or column index in wxGridStringTable") ); - - return (m_data[row][col] == wxEmptyString); -} - void wxGridStringTable::Clear() { int row, col; @@ -4179,22 +4358,12 @@ void wxGridSubwindow::OnMouseCaptureLost(wxMouseCaptureLostEvent& WXUNUSED(event m_owner->CancelMouseCapture(); } -IMPLEMENT_DYNAMIC_CLASS( wxGridRowLabelWindow, wxWindow ) - BEGIN_EVENT_TABLE( wxGridRowLabelWindow, wxGridSubwindow ) EVT_PAINT( wxGridRowLabelWindow::OnPaint ) EVT_MOUSEWHEEL( wxGridRowLabelWindow::OnMouseWheel ) EVT_MOUSE_EVENTS( wxGridRowLabelWindow::OnMouseEvent ) END_EVENT_TABLE() -wxGridRowLabelWindow::wxGridRowLabelWindow( wxGrid *parent, - wxWindowID id, - const wxPoint &pos, const wxSize &size ) - : wxGridSubwindow(parent, id, pos, size) -{ - m_owner = parent; -} - void wxGridRowLabelWindow::OnPaint( wxPaintEvent& WXUNUSED(event) ) { wxPaintDC dc(this); @@ -4221,27 +4390,18 @@ void wxGridRowLabelWindow::OnMouseEvent( wxMouseEvent& event ) void wxGridRowLabelWindow::OnMouseWheel( wxMouseEvent& event ) { - m_owner->GetEventHandler()->ProcessEvent( event ); + if (!m_owner->GetEventHandler()->ProcessEvent( event )) + event.Skip(); } ////////////////////////////////////////////////////////////////////// -IMPLEMENT_DYNAMIC_CLASS( wxGridColLabelWindow, wxWindow ) - BEGIN_EVENT_TABLE( wxGridColLabelWindow, wxGridSubwindow ) EVT_PAINT( wxGridColLabelWindow::OnPaint ) EVT_MOUSEWHEEL( wxGridColLabelWindow::OnMouseWheel ) EVT_MOUSE_EVENTS( wxGridColLabelWindow::OnMouseEvent ) END_EVENT_TABLE() -wxGridColLabelWindow::wxGridColLabelWindow( wxGrid *parent, - wxWindowID id, - const wxPoint &pos, const wxSize &size ) - : wxGridSubwindow(parent, id, pos, size) -{ - m_owner = parent; -} - void wxGridColLabelWindow::OnPaint( wxPaintEvent& WXUNUSED(event) ) { wxPaintDC dc(this); @@ -4271,28 +4431,18 @@ void wxGridColLabelWindow::OnMouseEvent( wxMouseEvent& event ) void wxGridColLabelWindow::OnMouseWheel( wxMouseEvent& event ) { - m_owner->GetEventHandler()->ProcessEvent( event ); + if (!m_owner->GetEventHandler()->ProcessEvent( event )) + event.Skip(); } ////////////////////////////////////////////////////////////////////// -IMPLEMENT_DYNAMIC_CLASS( wxGridCornerLabelWindow, wxWindow ) - BEGIN_EVENT_TABLE( wxGridCornerLabelWindow, wxGridSubwindow ) EVT_MOUSEWHEEL( wxGridCornerLabelWindow::OnMouseWheel ) EVT_MOUSE_EVENTS( wxGridCornerLabelWindow::OnMouseEvent ) EVT_PAINT( wxGridCornerLabelWindow::OnPaint ) END_EVENT_TABLE() -wxGridCornerLabelWindow::wxGridCornerLabelWindow( wxGrid *parent, - wxWindowID id, - const wxPoint& pos, - const wxSize& size ) - : wxGridSubwindow(parent, id, pos, size) -{ - m_owner = parent; -} - void wxGridCornerLabelWindow::OnPaint( wxPaintEvent& WXUNUSED(event) ) { wxPaintDC dc(this); @@ -4307,13 +4457,12 @@ void wxGridCornerLabelWindow::OnMouseEvent( wxMouseEvent& event ) void wxGridCornerLabelWindow::OnMouseWheel( wxMouseEvent& event ) { - m_owner->GetEventHandler()->ProcessEvent(event); + if (!m_owner->GetEventHandler()->ProcessEvent(event)) + event.Skip(); } ////////////////////////////////////////////////////////////////////// -IMPLEMENT_DYNAMIC_CLASS( wxGridWindow, wxWindow ) - BEGIN_EVENT_TABLE( wxGridWindow, wxGridSubwindow ) EVT_PAINT( wxGridWindow::OnPaint ) EVT_MOUSEWHEEL( wxGridWindow::OnMouseWheel ) @@ -4326,21 +4475,6 @@ BEGIN_EVENT_TABLE( wxGridWindow, wxGridSubwindow ) EVT_ERASE_BACKGROUND( wxGridWindow::OnEraseBackground ) END_EVENT_TABLE() -wxGridWindow::wxGridWindow( wxGrid *parent, - wxGridRowLabelWindow *rowLblWin, - wxGridColLabelWindow *colLblWin, - wxWindowID id, - const wxPoint &pos, - const wxSize &size ) - : wxGridSubwindow(parent, id, pos, size, - wxWANTS_CHARS | wxCLIP_CHILDREN, - wxT("grid window") ) -{ - m_owner = parent; - m_rowLabelWin = rowLblWin; - m_colLabelWin = colLblWin; -} - void wxGridWindow::OnPaint( wxPaintEvent &WXUNUSED(event) ) { wxPaintDC dc( this ); @@ -4349,17 +4483,18 @@ void wxGridWindow::OnPaint( wxPaintEvent &WXUNUSED(event) ) wxGridCellCoordsArray dirtyCells = m_owner->CalcCellsExposed( reg ); m_owner->DrawGridCellArea( dc, dirtyCells ); + m_owner->DrawGridSpace( dc ); + m_owner->DrawAllGridLines( dc, reg ); - m_owner->DrawGridSpace( dc ); m_owner->DrawHighlight( dc, dirtyCells ); } void wxGridWindow::ScrollWindow( int dx, int dy, const wxRect *rect ) { wxWindow::ScrollWindow( dx, dy, rect ); - m_rowLabelWin->ScrollWindow( 0, dy, rect ); - m_colLabelWin->ScrollWindow( dx, 0, rect ); + m_owner->GetGridRowLabelWindow()->ScrollWindow( 0, dy, rect ); + m_owner->GetGridColLabelWindow()->ScrollWindow( dx, 0, rect ); } void wxGridWindow::OnMouseEvent( wxMouseEvent& event ) @@ -4372,7 +4507,8 @@ void wxGridWindow::OnMouseEvent( wxMouseEvent& event ) void wxGridWindow::OnMouseWheel( wxMouseEvent& event ) { - m_owner->GetEventHandler()->ProcessEvent( event ); + if (!m_owner->GetEventHandler()->ProcessEvent( event )) + event.Skip(); } // This seems to be required for wxMotif/wxGTK otherwise the mouse @@ -4495,22 +4631,6 @@ BEGIN_EVENT_TABLE( wxGrid, wxScrolledWindow ) EVT_ERASE_BACKGROUND( wxGrid::OnEraseBackground ) END_EVENT_TABLE() -wxGrid::wxGrid() -{ - InitVars(); -} - -wxGrid::wxGrid( wxWindow *parent, - wxWindowID id, - const wxPoint& pos, - const wxSize& size, - long style, - const wxString& name ) -{ - InitVars(); - Create(parent, id, pos, size, style, name); -} - bool wxGrid::Create(wxWindow *parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style, const wxString& name) @@ -4532,6 +4652,14 @@ bool wxGrid::Create(wxWindow *parent, wxWindowID id, wxGrid::~wxGrid() { + if ( m_winCapture ) + m_winCapture->ReleaseMouse(); + + // Ensure that the editor control is destroyed before the grid is, + // otherwise we crash later when the editor tries to do something with the + // half destroyed grid + HideCellEditControl(); + // Must do this or ~wxScrollHelper will pop the wrong event handler SetTargetWindow(this); ClearAttrCache(); @@ -4599,31 +4727,11 @@ void wxGrid::Create() m_numCols = 0; m_currentCellCoords = wxGridNoCellCoords; - m_rowLabelWidth = WXGRID_DEFAULT_ROW_LABEL_WIDTH; - m_colLabelHeight = WXGRID_DEFAULT_COL_LABEL_HEIGHT; - // subwindow components that make up the wxGrid - m_rowLabelWin = new wxGridRowLabelWindow( this, - wxID_ANY, - wxDefaultPosition, - wxDefaultSize ); - - m_colLabelWin = new wxGridColLabelWindow( this, - wxID_ANY, - wxDefaultPosition, - wxDefaultSize ); - - m_cornerLabelWin = new wxGridCornerLabelWindow( this, - wxID_ANY, - wxDefaultPosition, - wxDefaultSize ); - - m_gridWin = new wxGridWindow( this, - m_rowLabelWin, - m_colLabelWin, - wxID_ANY, - wxDefaultPosition, - wxDefaultSize ); + m_rowLabelWin = new wxGridRowLabelWindow(this); + CreateColumnWindow(); + m_cornerLabelWin = new wxGridCornerLabelWindow(this); + m_gridWin = new wxGridWindow( this ); SetTargetWindow( m_gridWin ); @@ -4643,13 +4751,38 @@ void wxGrid::Create() m_cornerLabelWin->SetOwnBackgroundColour(lbg); m_rowLabelWin->SetOwnForegroundColour(lfg); m_rowLabelWin->SetOwnBackgroundColour(lbg); - m_colLabelWin->SetOwnForegroundColour(lfg); - m_colLabelWin->SetOwnBackgroundColour(lbg); + m_colWindow->SetOwnForegroundColour(lfg); + m_colWindow->SetOwnBackgroundColour(lbg); m_gridWin->SetOwnForegroundColour(gfg); m_gridWin->SetOwnBackgroundColour(gbg); - Init(); + m_labelBackgroundColour = m_rowLabelWin->GetBackgroundColour(); + m_labelTextColour = m_rowLabelWin->GetForegroundColour(); + + // now that we have the grid window, use its font to compute the default + // row height + m_defaultRowHeight = m_gridWin->GetCharHeight(); +#if defined(__WXMOTIF__) || defined(__WXGTK__) // see also text ctrl sizing in ShowCellEditControl() + m_defaultRowHeight += 8; +#else + m_defaultRowHeight += 4; +#endif + +} + +void wxGrid::CreateColumnWindow() +{ + if ( m_useNativeHeader ) + { + m_colWindow = new wxGridHeaderCtrl(this); + m_colLabelHeight = m_colWindow->GetBestSize().y; + } + else // draw labels ourselves + { + m_colWindow = new wxGridColLabelWindow(this); + m_colLabelHeight = WXGRID_DEFAULT_COL_LABEL_HEIGHT; + } } bool wxGrid::CreateGrid( int numRows, int numCols, @@ -4717,6 +4850,9 @@ wxGrid::SetTable(wxGridTableBase *table, m_numRows = table->GetNumberRows(); m_numCols = table->GetNumberCols(); + if ( m_useNativeHeader ) + GetGridColHeader()->SetColumnCount(m_numCols); + m_table = table; m_table->SetView( this ); m_ownTable = takeOwnership; @@ -4751,13 +4887,13 @@ wxGrid::SetTable(wxGridTableBase *table, return m_created; } -void wxGrid::InitVars() +void wxGrid::Init() { m_created = false; m_cornerLabelWin = NULL; m_rowLabelWin = NULL; - m_colLabelWin = NULL; + m_colWindow = NULL; m_gridWin = NULL; m_table = NULL; @@ -4767,24 +4903,10 @@ void wxGrid::InitVars() m_defaultCellAttr = NULL; m_typeRegistry = NULL; m_winCapture = NULL; -} -void wxGrid::Init() -{ m_rowLabelWidth = WXGRID_DEFAULT_ROW_LABEL_WIDTH; m_colLabelHeight = WXGRID_DEFAULT_COL_LABEL_HEIGHT; - if ( m_rowLabelWin ) - { - m_labelBackgroundColour = m_rowLabelWin->GetBackgroundColour(); - } - else - { - m_labelBackgroundColour = *wxWHITE; - } - - m_labelTextColour = *wxBLACK; - // init attr cache m_attrCache.row = -1; m_attrCache.col = -1; @@ -4801,19 +4923,15 @@ void wxGrid::Init() m_colLabelTextOrientation = wxHORIZONTAL; m_defaultColWidth = WXGRID_DEFAULT_COL_WIDTH; - m_defaultRowHeight = m_gridWin->GetCharHeight(); + m_defaultRowHeight = 0; // this will be initialized after creation m_minAcceptableColWidth = WXGRID_MIN_COL_WIDTH; m_minAcceptableRowHeight = WXGRID_MIN_ROW_HEIGHT; -#if defined(__WXMOTIF__) || defined(__WXGTK__) // see also text ctrl sizing in ShowCellEditControl() - m_defaultRowHeight += 8; -#else - m_defaultRowHeight += 4; -#endif - m_gridLineColour = wxColour( 192,192,192 ); m_gridLinesEnabled = true; + m_gridLinesClipHorz = + m_gridLinesClipVert = true; m_cellHighlightColour = *wxBLACK; m_cellHighlightPenWidth = 2; m_cellHighlightROPenWidth = 1; @@ -4830,6 +4948,11 @@ void wxGrid::Init() m_dragRowOrCol = -1; m_isDragging = false; m_startDragPos = wxDefaultPosition; + + m_sortCol = wxNOT_FOUND; + m_sortIsAscending = true; + + m_useNativeHeader = m_nativeColumnLabels = false; m_waitForSlowClick = false; @@ -4839,7 +4962,9 @@ void wxGrid::Init() m_currentCellCoords = wxGridNoCellCoords; - ClearSelection(); + m_selectedBlockTopLeft = + m_selectedBlockBottomRight = + m_selectedBlockCorner = wxGridNoCellCoords; m_selectionBackground = wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHT); m_selectionForeground = wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT); @@ -4895,10 +5020,9 @@ void wxGrid::InitColWidths() m_colWidths.Add( m_defaultColWidth, m_numCols ); - int colRight = 0; for ( int i = 0; i < m_numCols; i++ ) { - colRight = ( GetColPos( i ) + 1 ) * m_defaultColWidth; + int colRight = ( GetColPos( i ) + 1 ) * m_defaultColWidth; m_colRights.Add( colRight ); } } @@ -5020,8 +5144,8 @@ void wxGrid::CalcWindowSizes() if ( m_cornerLabelWin && m_cornerLabelWin->IsShown() ) m_cornerLabelWin->SetSize( 0, 0, m_rowLabelWidth, m_colLabelHeight ); - if ( m_colLabelWin && m_colLabelWin->IsShown() ) - m_colLabelWin->SetSize( m_rowLabelWidth, 0, gw, m_colLabelHeight ); + if ( m_colWindow && m_colWindow->IsShown() ) + m_colWindow->SetSize( m_rowLabelWidth, 0, gw, m_colLabelHeight ); if ( m_rowLabelWin && m_rowLabelWin->IsShown() ) m_rowLabelWin->SetSize( 0, m_colLabelHeight, m_rowLabelWidth, gh ); @@ -5049,20 +5173,6 @@ bool wxGrid::Redimension( wxGridTableMessage& msg ) // cell it might want to save that stuff to might no longer exist. HideCellEditControl(); -#if 0 - // if we were using the default widths/heights so far, we must change them - // now - if ( m_colWidths.IsEmpty() ) - { - InitColWidths(); - } - - if ( m_rowHeights.IsEmpty() ) - { - InitRowHeights(); - } -#endif - switch ( msg.GetId() ) { case wxGRIDTABLE_NOTIFY_ROWS_INSERTED: @@ -5213,6 +5323,9 @@ bool wxGrid::Redimension( wxGridTableMessage& msg ) int numCols = msg.GetCommandInt2(); m_numCols += numCols; + if ( m_useNativeHeader ) + GetGridColHeader()->SetColumnCount(m_numCols); + if ( !m_colAt.IsEmpty() ) { //Shift the column IDs @@ -5267,7 +5380,7 @@ bool wxGrid::Redimension( wxGridTableMessage& msg ) if ( !GetBatchCount() ) { CalcDimensions(); - m_colLabelWin->Refresh(); + m_colWindow->Refresh(); } } result = true; @@ -5278,6 +5391,8 @@ bool wxGrid::Redimension( wxGridTableMessage& msg ) int numCols = msg.GetCommandInt(); int oldNumCols = m_numCols; m_numCols += numCols; + if ( m_useNativeHeader ) + GetGridColHeader()->SetColumnCount(m_numCols); if ( !m_colAt.IsEmpty() ) { @@ -5320,7 +5435,7 @@ bool wxGrid::Redimension( wxGridTableMessage& msg ) if ( !GetBatchCount() ) { CalcDimensions(); - m_colLabelWin->Refresh(); + m_colWindow->Refresh(); } } result = true; @@ -5331,6 +5446,8 @@ bool wxGrid::Redimension( wxGridTableMessage& msg ) size_t pos = msg.GetCommandInt(); int numCols = msg.GetCommandInt2(); m_numCols -= numCols; + if ( m_useNativeHeader ) + GetGridColHeader()->SetColumnCount(m_numCols); if ( !m_colAt.IsEmpty() ) { @@ -5395,7 +5512,7 @@ bool wxGrid::Redimension( wxGridTableMessage& msg ) if ( !GetBatchCount() ) { CalcDimensions(); - m_colLabelWin->Refresh(); + m_colWindow->Refresh(); } } result = true; @@ -5545,9 +5662,8 @@ wxGridCellCoordsArray wxGrid::CalcCellsExposed( const wxRegion& reg ) const CalcUnscrolledPosition( r.GetRight(), r.GetBottom(), &right, &bottom ); // find the cells within these bounds - // - int row, col; - for ( row = internalYToRow(top); row < m_numRows; row++ ) + wxArrayInt cols; + for ( int row = internalYToRow(top); row < m_numRows; row++ ) { if ( GetRowBottom(row) <= top ) continue; @@ -5555,19 +5671,23 @@ wxGridCellCoordsArray wxGrid::CalcCellsExposed( const wxRegion& reg ) const if ( GetRowTop(row) > bottom ) break; - int colPos; - for ( colPos = GetColPos( internalXToCol(left) ); colPos < m_numCols; colPos++ ) + // add all dirty cells in this row: notice that the columns which + // are dirty don't depend on the row so we compute them only once + // for the first dirty row and then reuse for all the next ones + if ( cols.empty() ) { - col = GetColAt( colPos ); - - if ( GetColRight(col) <= left ) - continue; + // do determine the dirty columns + for ( int pos = XToPos(left); pos <= XToPos(right); pos++ ) + cols.push_back(GetColAt(pos)); - if ( GetColLeft(col) > right ) + // if there are no dirty columns at all, nothing to do + if ( cols.empty() ) break; - - cellsExposed.Add( wxGridCellCoords( row, col ) ); } + + const size_t count = cols.size(); + for ( size_t n = 0; n < count; n++ ) + cellsExposed.Add(wxGridCellCoords(row, cols[n])); } ++iter; @@ -5715,7 +5835,7 @@ void wxGrid::ProcessRowLabelMouseEvent( wxMouseEvent& event ) // adjust row height depending on label text AutoSizeRowLabelSize( row ); - ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL, m_colLabelWin); + ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL, GetColLabelWindow()); m_dragLastPos = -1; } } @@ -5783,21 +5903,107 @@ void wxGrid::ProcessRowLabelMouseEvent( wxMouseEvent& event ) } } +void wxGrid::UpdateColumnSortingIndicator(int col) +{ + wxCHECK_RET( col != wxNOT_FOUND, "invalid column index" ); + + if ( m_useNativeHeader ) + GetGridColHeader()->UpdateColumn(col); + else if ( m_nativeColumnLabels ) + m_colWindow->Refresh(); + //else: sorting indicator display not yet implemented in grid version +} + +void wxGrid::SetSortingColumn(int col, bool ascending) +{ + if ( col == m_sortCol ) + { + // we are already using this column for sorting (or not sorting at all) + // but we might still change the sorting order, check for it + if ( m_sortCol != wxNOT_FOUND && ascending != m_sortIsAscending ) + { + m_sortIsAscending = ascending; + + UpdateColumnSortingIndicator(m_sortCol); + } + } + else // we're changing the column used for sorting + { + const int sortColOld = m_sortCol; + + // change it before updating the column as we want GetSortingColumn() + // to return the correct new value + m_sortCol = col; + + if ( sortColOld != wxNOT_FOUND ) + UpdateColumnSortingIndicator(sortColOld); + + if ( m_sortCol != wxNOT_FOUND ) + { + m_sortIsAscending = ascending; + UpdateColumnSortingIndicator(m_sortCol); + } + } +} + +void wxGrid::DoColHeaderClick(int col) +{ + // we consider that the grid was resorted if this event is processed and + // not vetoed + if ( SendEvent(wxEVT_GRID_COL_SORT, -1, col) == 1 ) + { + SetSortingColumn(col, IsSortingBy(col) ? !m_sortIsAscending : true); + Refresh(); + } +} + +void wxGrid::DoStartResizeCol(int col) +{ + m_dragRowOrCol = col; + m_dragLastPos = -1; + DoUpdateResizeColWidth(GetColWidth(m_dragRowOrCol)); +} + +void wxGrid::DoUpdateResizeCol(int x) +{ + int cw, ch, dummy, top; + m_gridWin->GetClientSize( &cw, &ch ); + CalcUnscrolledPosition( 0, 0, &dummy, &top ); + + wxClientDC dc( m_gridWin ); + PrepareDC( dc ); + + x = wxMax( x, GetColLeft(m_dragRowOrCol) + GetColMinimalWidth(m_dragRowOrCol)); + dc.SetLogicalFunction(wxINVERT); + if ( m_dragLastPos >= 0 ) + { + dc.DrawLine( m_dragLastPos, top, m_dragLastPos, top + ch ); + } + dc.DrawLine( x, top, x, top + ch ); + m_dragLastPos = x; +} + +void wxGrid::DoUpdateResizeColWidth(int w) +{ + DoUpdateResizeCol(GetColLeft(m_dragRowOrCol) + w); +} + void wxGrid::ProcessColLabelMouseEvent( wxMouseEvent& event ) { - int x, y, col; + int x, y; wxPoint pos( event.GetPosition() ); CalcUnscrolledPosition( pos.x, pos.y, &x, &y ); + int col = XToCol(x); if ( event.Dragging() ) { if (!m_isDragging) { m_isDragging = true; - m_colLabelWin->CaptureMouse(); + GetColLabelWindow()->CaptureMouse(); - if ( m_cursorMode == WXGRID_CURSOR_MOVE_COL ) - m_dragRowOrCol = XToCol( x ); + if ( m_cursorMode == WXGRID_CURSOR_MOVE_COL && col != -1 ) + DoStartMoveCol(col); } if ( event.LeftIsDown() ) @@ -5805,29 +6011,12 @@ void wxGrid::ProcessColLabelMouseEvent( wxMouseEvent& event ) switch ( m_cursorMode ) { case WXGRID_CURSOR_RESIZE_COL: - { - int cw, ch, dummy, top; - m_gridWin->GetClientSize( &cw, &ch ); - CalcUnscrolledPosition( 0, 0, &dummy, &top ); - - wxClientDC dc( m_gridWin ); - PrepareDC( dc ); - - x = wxMax( x, GetColLeft(m_dragRowOrCol) + - GetColMinimalWidth(m_dragRowOrCol)); - dc.SetLogicalFunction(wxINVERT); - if ( m_dragLastPos >= 0 ) - { - dc.DrawLine( m_dragLastPos, top, m_dragLastPos, top + ch ); - } - dc.DrawLine( x, top, x, top + ch ); - m_dragLastPos = x; - } + DoUpdateResizeCol(x); break; case WXGRID_CURSOR_SELECT_COL: { - if ( (col = XToCol( x )) >= 0 ) + if ( col != -1 ) { if ( m_selection ) m_selection->SelectCol(col, event); @@ -5837,40 +6026,30 @@ void wxGrid::ProcessColLabelMouseEvent( wxMouseEvent& event ) case WXGRID_CURSOR_MOVE_COL: { - if ( x < 0 ) - m_moveToCol = GetColAt( 0 ); - else - m_moveToCol = XToCol( x ); + int posNew = XToPos(x); + int colNew = GetColAt(posNew); + // determine the position of the drop marker int markerX; - - if ( m_moveToCol < 0 ) - markerX = GetColRight( GetColAt( m_numCols - 1 ) ); - else if ( x >= (GetColLeft( m_moveToCol ) + (GetColWidth(m_moveToCol) / 2)) ) - { - m_moveToCol = GetColAt( GetColPos( m_moveToCol ) + 1 ); - if ( m_moveToCol < 0 ) - markerX = GetColRight( GetColAt( m_numCols - 1 ) ); - else - markerX = GetColLeft( m_moveToCol ); - } + if ( x >= GetColLeft(colNew) + (GetColWidth(colNew) / 2) ) + markerX = GetColRight(colNew); else - markerX = GetColLeft( m_moveToCol ); + markerX = GetColLeft(colNew); if ( markerX != m_dragLastPos ) { - wxClientDC dc( m_colLabelWin ); + wxClientDC dc( GetColLabelWindow() ); DoPrepareDC(dc); int cw, ch; - m_colLabelWin->GetClientSize( &cw, &ch ); + GetColLabelWindow()->GetClientSize( &cw, &ch ); markerX++; //Clean up the last indicator if ( m_dragLastPos >= 0 ) { - wxPen pen( m_colLabelWin->GetBackgroundColour(), 2 ); + wxPen pen( GetColLabelWindow()->GetBackgroundColour(), 2 ); dc.SetPen(pen); dc.DrawLine( m_dragLastPos + 1, 0, m_dragLastPos + 1, ch ); dc.SetPen(wxNullPen); @@ -5881,9 +6060,7 @@ void wxGrid::ProcessColLabelMouseEvent( wxMouseEvent& event ) const wxColour *color; //Moving to the same place? Don't draw a marker - if ( (m_moveToCol == m_dragRowOrCol) - || (GetColPos( m_moveToCol ) == GetColPos( m_dragRowOrCol ) + 1) - || (m_moveToCol < 0 && m_dragRowOrCol == GetColAt( m_numCols - 1 ))) + if ( colNew == m_dragRowOrCol ) color = wxLIGHT_GREY; else color = wxBLUE; @@ -5915,8 +6092,8 @@ void wxGrid::ProcessColLabelMouseEvent( wxMouseEvent& event ) if (m_isDragging) { - if (m_colLabelWin->HasCapture()) - m_colLabelWin->ReleaseMouse(); + if (GetColLabelWindow()->HasCapture()) + GetColLabelWindow()->ReleaseMouse(); m_isDragging = false; } @@ -5924,7 +6101,7 @@ void wxGrid::ProcessColLabelMouseEvent( wxMouseEvent& event ) // if ( event.Entering() || event.Leaving() ) { - ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL, m_colLabelWin); + ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL, GetColLabelWindow()); } // ------------ Left button pressed @@ -5937,21 +6114,20 @@ void wxGrid::ProcessColLabelMouseEvent( wxMouseEvent& event ) // if ( XToEdgeOfCol(x) < 0 ) { - col = XToCol(x); if ( col >= 0 && !SendEvent( wxEVT_GRID_LABEL_LEFT_CLICK, -1, col, event ) ) { if ( m_canDragColMove ) { //Show button as pressed - wxClientDC dc( m_colLabelWin ); + wxClientDC dc( GetColLabelWindow() ); int colLeft = GetColLeft( col ); int colRight = GetColRight( col ) - 1; - dc.SetPen( wxPen( m_colLabelWin->GetBackgroundColour(), 1 ) ); + dc.SetPen( wxPen( GetColLabelWindow()->GetBackgroundColour(), 1 ) ); dc.DrawLine( colLeft, 1, colLeft, m_colLabelHeight-1 ); dc.DrawLine( colLeft, 1, colRight, 1 ); - ChangeCursorMode(WXGRID_CURSOR_MOVE_COL, m_colLabelWin); + ChangeCursorMode(WXGRID_CURSOR_MOVE_COL, GetColLabelWindow()); } else { @@ -5974,7 +6150,7 @@ void wxGrid::ProcessColLabelMouseEvent( wxMouseEvent& event ) } } - ChangeCursorMode(WXGRID_CURSOR_SELECT_COL, m_colLabelWin); + ChangeCursorMode(WXGRID_CURSOR_SELECT_COL, GetColLabelWindow()); } } } @@ -5983,7 +6159,7 @@ void wxGrid::ProcessColLabelMouseEvent( wxMouseEvent& event ) // starting to drag-resize a col // if ( CanDragColSize() ) - ChangeCursorMode(WXGRID_CURSOR_RESIZE_COL, m_colLabelWin); + ChangeCursorMode(WXGRID_CURSOR_RESIZE_COL, GetColLabelWindow()); } } @@ -5991,10 +6167,9 @@ void wxGrid::ProcessColLabelMouseEvent( wxMouseEvent& event ) // if ( event.LeftDClick() ) { - col = XToEdgeOfCol(x); - if ( col < 0 ) + const int colEdge = XToEdgeOfCol(x); + if ( colEdge == -1 ) { - col = XToCol(x); if ( col >= 0 && ! SendEvent( wxEVT_GRID_LABEL_LEFT_DCLICK, -1, col, event ) ) { @@ -6004,9 +6179,9 @@ void wxGrid::ProcessColLabelMouseEvent( wxMouseEvent& event ) else { // adjust column width depending on label text - AutoSizeColLabelSize( col ); + AutoSizeColLabelSize( colEdge ); - ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL, m_colLabelWin); + ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL, GetColLabelWindow()); m_dragLastPos = -1; } } @@ -6019,28 +6194,32 @@ void wxGrid::ProcessColLabelMouseEvent( wxMouseEvent& event ) { case WXGRID_CURSOR_RESIZE_COL: DoEndDragResizeCol(); - - // Note: we are ending the event *after* doing - // default processing in this case - // - SendEvent( wxEVT_GRID_COL_SIZE, -1, m_dragRowOrCol, event ); break; case WXGRID_CURSOR_MOVE_COL: - DoEndDragMoveCol(); - - SendEvent( wxEVT_GRID_COL_MOVE, -1, m_dragRowOrCol, event ); + if ( m_dragLastPos == -1 || col == m_dragRowOrCol ) + { + // the column didn't actually move anywhere + if ( col != -1 ) + DoColHeaderClick(col); + m_colWindow->Refresh(); // "unpress" the column + } + else + { + DoEndMoveCol(XToPos(x)); + } break; case WXGRID_CURSOR_SELECT_COL: case WXGRID_CURSOR_SELECT_CELL: case WXGRID_CURSOR_RESIZE_ROW: case WXGRID_CURSOR_SELECT_ROW: - // nothing to do (?) + if ( col != -1 ) + DoColHeaderClick(col); break; } - ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL, m_colLabelWin); + ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL, GetColLabelWindow()); m_dragLastPos = -1; } @@ -6048,7 +6227,6 @@ void wxGrid::ProcessColLabelMouseEvent( wxMouseEvent& event ) // else if ( event.RightDown() ) { - col = XToCol(x); if ( col >= 0 && !SendEvent( wxEVT_GRID_LABEL_RIGHT_CLICK, -1, col, event ) ) { @@ -6060,7 +6238,6 @@ void wxGrid::ProcessColLabelMouseEvent( wxMouseEvent& event ) // else if ( event.RightDClick() ) { - col = XToCol(x); if ( col >= 0 && !SendEvent( wxEVT_GRID_LABEL_RIGHT_DCLICK, -1, col, event ) ) { @@ -6079,12 +6256,12 @@ void wxGrid::ProcessColLabelMouseEvent( wxMouseEvent& event ) { // don't capture the cursor yet if ( CanDragColSize() ) - ChangeCursorMode(WXGRID_CURSOR_RESIZE_COL, m_colLabelWin, false); + ChangeCursorMode(WXGRID_CURSOR_RESIZE_COL, GetColLabelWindow(), false); } } else if ( m_cursorMode != WXGRID_CURSOR_SELECT_CELL ) { - ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL, m_colLabelWin, false); + ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL, GetColLabelWindow(), false); } } } @@ -6155,9 +6332,9 @@ void wxGrid::ChangeCursorMode(CursorMode mode, wxLogTrace(_T("grid"), _T("wxGrid cursor mode (mouse capture for %s): %s -> %s"), - win == m_colLabelWin ? _T("colLabelWin") - : win ? _T("rowLabelWin") - : _T("gridWin"), + win == m_colWindow ? _T("colLabelWin") + : win ? _T("rowLabelWin") + : _T("gridWin"), cursorModes[m_cursorMode], cursorModes[mode]); #endif @@ -6174,8 +6351,7 @@ void wxGrid::ChangeCursorMode(CursorMode mode, if ( m_winCapture ) { - if (m_winCapture->HasCapture()) - m_winCapture->ReleaseMouse(); + m_winCapture->ReleaseMouse(); m_winCapture = NULL; } @@ -6402,8 +6578,7 @@ wxGrid::DoGridCellLeftUp(wxMouseEvent& event, const wxGridCellCoords& coords) { if (m_winCapture) { - if (m_winCapture->HasCapture()) - m_winCapture->ReleaseMouse(); + m_winCapture->ReleaseMouse(); m_winCapture = NULL; } @@ -6452,11 +6627,6 @@ wxGrid::DoGridCellLeftUp(wxMouseEvent& event, const wxGridCellCoords& coords) { ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL); DoEndDragResizeCol(); - - // Note: we are ending the event *after* doing - // default processing in this case - // - SendEvent( wxEVT_GRID_COL_SIZE, -1, m_dragRowOrCol, event ); } m_dragLastPos = -1; @@ -6496,7 +6666,10 @@ wxGrid::DoGridMouseMoveEvent(wxMouseEvent& WXUNUSED(event), ChangeCursorMode(WXGRID_CURSOR_RESIZE_ROW, NULL, false); } } - else if ( dragCol >= 0 ) + // When using the native header window we can only resize the columns by + // dragging the dividers in it because we can't make it enter into the + // column resizing mode programmatically + else if ( dragCol >= 0 && !m_useNativeHeader ) { m_dragRowOrCol = dragCol; @@ -6617,6 +6790,8 @@ void wxGrid::DoEndDragResizeLine(const wxGridOperations& oper) wxMax(m_dragLastPos - lineStart, oper.GetMinimalLineSize(this, m_dragRowOrCol))); + m_dragLastPos = -1; + // refresh now if we're not frozen if ( !GetBatchCount() ) { @@ -6683,114 +6858,113 @@ void wxGrid::DoEndDragResizeRow() DoEndDragResizeLine(wxGridRowOperations()); } -void wxGrid::DoEndDragResizeCol() +void wxGrid::DoEndDragResizeCol(wxMouseEvent *event) { DoEndDragResizeLine(wxGridColumnOperations()); + + // Note: we are ending the event *after* doing + // default processing in this case + // + if ( event ) + SendEvent( wxEVT_GRID_COL_SIZE, -1, m_dragRowOrCol, *event ); + else + SendEvent( wxEVT_GRID_COL_SIZE, -1, m_dragRowOrCol ); } -void wxGrid::DoEndDragMoveCol() +void wxGrid::DoStartMoveCol(int col) { - //The user clicked on the column but didn't actually drag - if ( m_dragLastPos < 0 ) - { - m_colLabelWin->Refresh(); //Do this to "unpress" the column - return; - } + m_dragRowOrCol = col; +} - int newPos; - if ( m_moveToCol == -1 ) - newPos = m_numCols - 1; - else - { - newPos = GetColPos( m_moveToCol ); - if ( newPos > GetColPos( m_dragRowOrCol ) ) - newPos--; - } +void wxGrid::DoEndMoveCol(int pos) +{ + wxASSERT_MSG( m_dragRowOrCol != -1, "no matching DoStartMoveCol?" ); - SetColPos( m_dragRowOrCol, newPos ); + if ( SendEvent(wxEVT_GRID_COL_MOVE, -1, m_dragRowOrCol) != -1 ) + SetColPos(m_dragRowOrCol, pos); + //else: vetoed by user + + m_dragRowOrCol = -1; } -void wxGrid::SetColPos( int colID, int newPos ) +void wxGrid::RefreshAfterColPosChange() { - if ( m_colAt.IsEmpty() ) + // recalculate the column rights as the column positions have changed, + // unless we calculate them dynamically because all columns widths are the + // same and it's easy to do + if ( !m_colWidths.empty() ) { - m_colAt.Alloc( m_numCols ); - - int i; - for ( i = 0; i < m_numCols; i++ ) + int colRight = 0; + for ( int colPos = 0; colPos < m_numCols; colPos++ ) { - m_colAt.Add( i ); + int colID = GetColAt( colPos ); + + colRight += m_colWidths[colID]; + m_colRights[colID] = colRight; } } - int oldPos = GetColPos( colID ); - - //Reshuffle the m_colAt array - if ( newPos > oldPos ) + // and make the changes visible + if ( m_useNativeHeader ) { - int i; - for ( i = oldPos; i < newPos; i++ ) - { - m_colAt[i] = m_colAt[i+1]; - } + if ( m_colAt.empty() ) + GetGridColHeader()->ResetColumnsOrder(); + else + GetGridColHeader()->SetColumnsOrder(m_colAt); } else { - int i; - for ( i = oldPos; i > newPos; i-- ) - { - m_colAt[i] = m_colAt[i-1]; - } + m_colWindow->Refresh(); } + m_gridWin->Refresh(); +} - m_colAt[newPos] = colID; +void wxGrid::SetColumnsOrder(const wxArrayInt& order) +{ + m_colAt = order; - //Recalculate the column rights - if ( !m_colWidths.IsEmpty() ) - { - int colRight = 0; - int colPos; - for ( colPos = 0; colPos < m_numCols; colPos++ ) - { - int colID = GetColAt( colPos ); + RefreshAfterColPosChange(); +} - colRight += m_colWidths[colID]; - m_colRights[colID] = colRight; - } +void wxGrid::SetColPos(int idx, int pos) +{ + // we're going to need m_colAt now, initialize it if needed + if ( m_colAt.empty() ) + { + m_colAt.reserve(m_numCols); + for ( int i = 0; i < m_numCols; i++ ) + m_colAt.push_back(i); } - m_colLabelWin->Refresh(); - m_gridWin->Refresh(); + wxHeaderCtrl::MoveColumnInOrderArray(m_colAt, idx, pos); + + RefreshAfterColPosChange(); } +void wxGrid::ResetColPos() +{ + m_colAt.clear(); + RefreshAfterColPosChange(); +} void wxGrid::EnableDragColMove( bool enable ) { if ( m_canDragColMove == enable ) return; - m_canDragColMove = enable; - - if ( !m_canDragColMove ) + if ( m_useNativeHeader ) { - m_colAt.Clear(); + // update all columns to make them [not] reorderable + GetGridColHeader()->SetColumnCount(m_numCols); + } - //Recalculate the column rights - if ( !m_colWidths.IsEmpty() ) - { - int colRight = 0; - int colPos; - for ( colPos = 0; colPos < m_numCols; colPos++ ) - { - colRight += m_colWidths[colPos]; - m_colRights[colPos] = colRight; - } - } + m_canDragColMove = enable; - m_colLabelWin->Refresh(); - m_gridWin->Refresh(); - } + // we use to call ResetColPos() from here if !enable but this doesn't seem + // right as it would mean there would be no way to "freeze" the current + // columns order by disabling moving them after putting them in the desired + // order, whereas now you can always call ResetColPos() manually if needed } @@ -6958,7 +7132,8 @@ wxGrid::SendEvent(const wxEventType type, // Generate a grid event of specified type, return value same as above // -int wxGrid::SendEvent(const wxEventType type, int row, int col) +int +wxGrid::SendEvent(const wxEventType type, int row, int col, const wxString& s) { bool claimed, vetoed; @@ -6974,6 +7149,7 @@ int wxGrid::SendEvent(const wxEventType type, int row, int col) else { wxGridEvent gridEvt( GetId(), type, this, row, col ); + gridEvt.SetString(s); claimed = GetEventHandler()->ProcessEvent(gridEvt); vetoed = !gridEvt.IsAllowed(); @@ -7054,7 +7230,7 @@ void wxGrid::Refresh(bool eraseb, const wxRect* rect) if ( width_cell > 0 && height_label > 0 ) { wxRect anotherrect(x, rect_y, width_cell, height_label); - m_colLabelWin->Refresh(eraseb, &anotherrect); + m_colWindow->Refresh(eraseb, &anotherrect); } // Paint row labels part intersecting rect. @@ -7074,7 +7250,7 @@ void wxGrid::Refresh(bool eraseb, const wxRect* rect) else { m_cornerLabelWin->Refresh(eraseb, NULL); - m_colLabelWin->Refresh(eraseb, NULL); + m_colWindow->Refresh(eraseb, NULL); m_rowLabelWin->Refresh(eraseb, NULL); m_gridWin->Refresh(eraseb, NULL); } @@ -7905,7 +8081,7 @@ void wxGrid::DrawHighlight(wxDC& dc, const wxGridCellCoordsArray& cells) // void wxGrid::DrawAllGridLines( wxDC& dc, const wxRegion & WXUNUSED(reg) ) { - if ( !m_gridLinesEnabled || !m_numRows || !m_numCols ) + if ( !m_gridLinesEnabled ) return; int top, bottom, left, right; @@ -7916,9 +8092,25 @@ void wxGrid::DrawAllGridLines( wxDC& dc, const wxRegion & WXUNUSED(reg) ) CalcUnscrolledPosition( cw, ch, &right, &bottom ); // avoid drawing grid lines past the last row and col - // - right = wxMin( right, GetColRight(GetColAt( m_numCols - 1 )) ); - bottom = wxMin( bottom, GetRowBottom(m_numRows - 1) ); + if ( m_gridLinesClipHorz ) + { + if ( !m_numCols ) + return; + + const int lastColRight = GetColRight(GetColAt(m_numCols - 1)); + if ( right > lastColRight ) + right = lastColRight; + } + + if ( m_gridLinesClipVert ) + { + if ( !m_numRows ) + return; + + const int lastRowBottom = GetRowBottom(m_numRows - 1); + if ( bottom > lastRowBottom ) + bottom = lastRowBottom; + } // no gridlines inside multicells, clip them out int leftCol = GetColPos( internalXToCol(left) ); @@ -8040,8 +8232,26 @@ void wxGrid::DrawRowLabel( wxDC& dc, int row ) DrawTextRectangle( dc, GetRowLabelValue( row ), rect, hAlign, vAlign ); } +void wxGrid::UseNativeColHeader(bool native) +{ + if ( native == m_useNativeHeader ) + return; + + delete m_colWindow; + m_useNativeHeader = native; + + CreateColumnWindow(); + + if ( m_useNativeHeader ) + GetGridColHeader()->SetColumnCount(m_numCols); + CalcWindowSizes(); +} + void wxGrid::SetUseNativeColLabels( bool native ) { + wxASSERT_MSG( !m_useNativeHeader, + "doesn't make sense when using native header" ); + m_nativeColumnLabels = native; if (native) { @@ -8049,7 +8259,7 @@ void wxGrid::SetUseNativeColLabels( bool native ) SetColLabelSize( height ); } - m_colLabelWin->Refresh(); + GetColLabelWindow()->Refresh(); m_cornerLabelWin->Refresh(); } @@ -8101,7 +8311,18 @@ void wxGrid::DrawColLabel(wxDC& dc, int col) if ( m_nativeColumnLabels ) { - wxRendererNative::Get().DrawHeaderButton(m_colLabelWin, dc, rect, 0); + wxRendererNative::Get().DrawHeaderButton + ( + GetColLabelWindow(), + dc, + rect, + 0, + IsSortingBy(col) + ? IsSortOrderAscending() + ? wxHDR_SORT_ICON_UP + : wxHDR_SORT_ICON_DOWN + : wxHDR_SORT_ICON_NONE + ); } else { @@ -8317,7 +8538,7 @@ void wxGrid::EndBatch() { CalcDimensions(); m_rowLabelWin->Refresh(); - m_colLabelWin->Refresh(); + m_colWindow->Refresh(); m_cornerLabelWin->Refresh(); m_gridWin->Refresh(); } @@ -8381,7 +8602,6 @@ void wxGrid::EnableCellEditControl( bool enable ) } else { - //FIXME:add veto support SendEvent(wxEVT_GRID_EDITOR_HIDDEN); HideCellEditControl(); @@ -8614,19 +8834,26 @@ void wxGrid::SaveEditControlValue() wxGridCellAttr* attr = GetCellAttr(row, col); wxGridCellEditor* editor = attr->GetEditor(this, row, col); - bool changed = editor->EndEdit(row, col, this); - editor->DecRef(); - attr->DecRef(); + wxString newval; + bool changed = editor->EndEdit(oldval, &newval); - if (changed) + if ( changed && SendEvent(wxEVT_GRID_CELL_CHANGING, newval) != -1 ) { - if ( SendEvent(wxEVT_GRID_CELL_CHANGE) == -1 ) + editor->ApplyEdit(row, col, this); + + // for compatibility reasons dating back to wx 2.8 when this event + // was called wxEVT_GRID_CELL_CHANGE and wxEVT_GRID_CELL_CHANGING + // didn't exist we allow vetoing this one too + if ( SendEvent(wxEVT_GRID_CELL_CHANGED, oldval) == -1 ) { // Event has been vetoed, set the data back. SetCellValue(row, col, oldval); } } + + editor->DecRef(); + attr->DecRef(); } } @@ -8650,15 +8877,14 @@ wxGridCellCoords wxGrid::XYToCell(int x, int y) const // m_defaultRowHeight/m_defaultColWidth or binary search on array of // m_rowBottoms/m_colRights to do it quickly (linear search shouldn't be used // for large grids) -int -wxGrid::PosToLine(int coord, - bool clipToMinMax, - const wxGridOperations& oper) const +int wxGrid::PosToLinePos(int coord, + bool clipToMinMax, + const wxGridOperations& oper) const { const int numLines = oper.GetNumberOfLines(this); if ( coord < 0 ) - return clipToMinMax && numLines > 0 ? oper.GetLineAt(this, 0) : -1; + return clipToMinMax && numLines > 0 ? 0 : wxNOT_FOUND; const int defaultLineSize = oper.GetDefaultLineSize(this); wxCHECK_MSG( defaultLineSize, -1, "can't have 0 default line size" ); @@ -8702,12 +8928,12 @@ wxGrid::PosToLine(int coord, // check if the position is beyond the last column const int lineAtMaxPos = oper.GetLineAt(this, maxPos); if ( coord >= lineEnds[lineAtMaxPos] ) - return clipToMinMax ? lineAtMaxPos : -1; + return clipToMinMax ? maxPos : -1; // or before the first one const int lineAt0 = oper.GetLineAt(this, 0); if ( coord < lineEnds[lineAt0] ) - return lineAt0; + return 0; // finally do perform the binary search @@ -8716,10 +8942,10 @@ wxGrid::PosToLine(int coord, wxCHECK_MSG( lineEnds[oper.GetLineAt(this, minPos)] <= coord && coord < lineEnds[oper.GetLineAt(this, maxPos)], -1, - "wxGrid: internal error in PosToLine()" ); + "wxGrid: internal error in PosToLinePos()" ); if ( coord >= lineEnds[oper.GetLineAt(this, maxPos - 1)] ) - return oper.GetLineAt(this, maxPos); + return maxPos; else maxPos--; @@ -8730,7 +8956,17 @@ wxGrid::PosToLine(int coord, minPos = median; } - return oper.GetLineAt(this, maxPos); + return maxPos; +} + +int +wxGrid::PosToLine(int coord, + bool clipToMinMax, + const wxGridOperations& oper) const +{ + int pos = PosToLinePos(coord, clipToMinMax, oper); + + return pos == wxNOT_FOUND ? wxNOT_FOUND : oper.GetLineAt(this, pos); } int wxGrid::YToRow(int y, bool clipToMinMax) const @@ -8743,6 +8979,11 @@ int wxGrid::XToCol(int x, bool clipToMinMax) const return PosToLine(x, clipToMinMax, wxGridColumnOperations()); } +int wxGrid::XToPos(int x) const +{ + return PosToLinePos(x, true /* clip */, wxGridColumnOperations()); +} + // return the row number that that the y coord is near the edge of, or -1 if // not near an edge. // @@ -9028,7 +9269,7 @@ bool wxGrid::MovePageUp() bool wxGrid::MovePageDown() { return DoMoveCursorByPage( - wxGridForwardOperations(this, wxGridColumnOperations())); + wxGridForwardOperations(this, wxGridRowOperations())); } // helper of DoMoveCursorByBlock(): advance the cell coordinates using diroper @@ -9225,12 +9466,12 @@ void wxGrid::SetColLabelSize( int height ) { if ( height == 0 ) { - m_colLabelWin->Show( false ); + m_colWindow->Show( false ); m_cornerLabelWin->Show( false ); } else if ( m_colLabelHeight == 0 ) { - m_colLabelWin->Show( true ); + m_colWindow->Show( true ); if ( m_rowLabelWidth > 0 ) m_cornerLabelWin->Show( true ); } @@ -9247,13 +9488,13 @@ void wxGrid::SetLabelBackgroundColour( const wxColour& colour ) { m_labelBackgroundColour = colour; m_rowLabelWin->SetBackgroundColour( colour ); - m_colLabelWin->SetBackgroundColour( colour ); + m_colWindow->SetBackgroundColour( colour ); m_cornerLabelWin->SetBackgroundColour( colour ); if ( !GetBatchCount() ) { m_rowLabelWin->Refresh(); - m_colLabelWin->Refresh(); + m_colWindow->Refresh(); m_cornerLabelWin->Refresh(); } } @@ -9267,7 +9508,7 @@ void wxGrid::SetLabelTextColour( const wxColour& colour ) if ( !GetBatchCount() ) { m_rowLabelWin->Refresh(); - m_colLabelWin->Refresh(); + m_colWindow->Refresh(); } } } @@ -9278,7 +9519,7 @@ void wxGrid::SetLabelFont( const wxFont& font ) if ( !GetBatchCount() ) { m_rowLabelWin->Refresh(); - m_colLabelWin->Refresh(); + m_colWindow->Refresh(); } } @@ -9344,7 +9585,7 @@ void wxGrid::SetColLabelAlignment( int horiz, int vert ) if ( !GetBatchCount() ) { - m_colLabelWin->Refresh(); + m_colWindow->Refresh(); } } @@ -9361,7 +9602,7 @@ void wxGrid::SetColLabelTextOrientation( int textOrientation ) m_colLabelTextOrientation = textOrientation; if ( !GetBatchCount() ) - m_colLabelWin->Refresh(); + m_colWindow->Refresh(); } void wxGrid::SetRowLabelValue( int row, const wxString& s ) @@ -9390,13 +9631,20 @@ void wxGrid::SetColLabelValue( int col, const wxString& s ) m_table->SetColLabelValue( col, s ); if ( !GetBatchCount() ) { - wxRect rect = CellToRect( 0, col ); - if ( rect.width > 0 ) + if ( m_useNativeHeader ) { - CalcScrolledPosition(rect.x, 0, &rect.x, &rect.y); - rect.y = 0; - rect.height = m_colLabelHeight; - m_colLabelWin->Refresh( true, &rect ); + GetGridColHeader()->UpdateColumn(col); + } + else + { + wxRect rect = CellToRect( 0, col ); + if ( rect.width > 0 ) + { + CalcScrolledPosition(rect.x, 0, &rect.x, &rect.y); + rect.y = 0; + rect.height = m_colLabelHeight; + GetColLabelWindow()->Refresh( true, &rect ); + } } } } @@ -9408,9 +9656,8 @@ void wxGrid::SetGridLineColour( const wxColour& colour ) { m_gridLineColour = colour; - wxClientDC dc( m_gridWin ); - PrepareDC( dc ); - DrawAllGridLines( dc, wxRegion() ); + if ( GridLinesEnabled() ) + RedrawGridLines(); } } @@ -9465,25 +9712,42 @@ void wxGrid::SetCellHighlightROPenWidth(int width) } } +void wxGrid::RedrawGridLines() +{ + // the lines will be redrawn when the window is thawn + if ( GetBatchCount() ) + return; + + if ( GridLinesEnabled() ) + { + wxClientDC dc( m_gridWin ); + PrepareDC( dc ); + DrawAllGridLines( dc, wxRegion() ); + } + else // remove the grid lines + { + m_gridWin->Refresh(); + } +} + void wxGrid::EnableGridLines( bool enable ) { if ( enable != m_gridLinesEnabled ) { m_gridLinesEnabled = enable; - if ( !GetBatchCount() ) - { - if ( enable ) - { - wxClientDC dc( m_gridWin ); - PrepareDC( dc ); - DrawAllGridLines( dc, wxRegion() ); - } - else - { - m_gridWin->Refresh(); - } - } + RedrawGridLines(); + } +} + +void wxGrid::DoClipGridLines(bool& var, bool clip) +{ + if ( clip != var ) + { + var = clip; + + if ( GridLinesEnabled() ) + RedrawGridLines(); } } @@ -10181,7 +10445,7 @@ void wxGrid::SetColSize( int col, int width ) { long w, h; wxArrayString lines; - wxClientDC dc(m_colLabelWin); + wxClientDC dc(m_colWindow); dc.SetFont(GetLabelFont()); StringToLines(GetColLabelValue(col), lines); if ( GetColLabelTextOrientation() == wxHORIZONTAL ) @@ -10193,15 +10457,12 @@ void wxGrid::SetColSize( int col, int width ) width = wxMax(width, GetColMinimalAcceptableWidth()); } - // should we check that it's bigger than GetColMinimalWidth(col) here? - // (VZ) - // No, because it is reasonable to assume the library user know's - // what he is doing. However we should test against the weaker - // constraint of minimalAcceptableWidth, as this breaks rendering - // - // This test then fixes sf.net bug #645734 - - if ( width < GetColMinimalAcceptableWidth() ) + // we intentionally don't test whether the width is less than + // GetColMinimalWidth() here but we do compare it with + // GetColMinimalAcceptableWidth() as otherwise things currently break (see + // #651) -- and we also always allow the width of 0 as it has the special + // sense of hiding the column + if ( width > 0 && width < GetColMinimalAcceptableWidth() ) return; if ( m_colWidths.IsEmpty() ) @@ -10210,9 +10471,11 @@ void wxGrid::SetColSize( int col, int width ) InitColWidths(); } - int w = wxMax( 0, width ); - int diff = w - m_colWidths[col]; - m_colWidths[col] = w; + const int diff = width - m_colWidths[col]; + m_colWidths[col] = width; + if ( m_useNativeHeader ) + GetGridColHeader()->UpdateColumn(col); + //else: will be refreshed when the header is redrawn for ( int colPos = GetColPos(col); colPos < m_numCols; colPos++ ) { @@ -10220,7 +10483,10 @@ void wxGrid::SetColSize( int col, int width ) } if ( !GetBatchCount() ) + { CalcDimensions(); + Refresh(); + } } void wxGrid::SetColMinimalWidth( int col, int width ) @@ -10373,14 +10639,21 @@ wxGrid::AutoSizeColOrRow(int colOrRow, bool setAsMin, wxGridDirection direction) SetColSize( col, extentMax ); if ( !GetBatchCount() ) { - int cw, ch, dummy; - m_gridWin->GetClientSize( &cw, &ch ); - wxRect rect ( CellToRect( 0, col ) ); - rect.y = 0; - CalcScrolledPosition(rect.x, 0, &rect.x, &dummy); - rect.width = cw - rect.x; - rect.height = m_colLabelHeight; - m_colLabelWin->Refresh( true, &rect ); + if ( m_useNativeHeader ) + { + GetGridColHeader()->UpdateColumn(col); + } + else + { + int cw, ch, dummy; + m_gridWin->GetClientSize( &cw, &ch ); + wxRect rect ( CellToRect( 0, col ) ); + rect.y = 0; + CalcScrolledPosition(rect.x, 0, &rect.x, &dummy); + rect.width = cw - rect.x; + rect.height = m_colLabelHeight; + GetColLabelWindow()->Refresh( true, &rect ); + } } } else