X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/f460c29d593da752aa2bac1c178d2c58ee563ff3..3201a1046ba71ba8e5ef2ed694fde34d12f743f3:/src/generic/grid.cpp diff --git a/src/generic/grid.cpp b/src/generic/grid.cpp index 6293c3cd99..69debf7727 100644 --- a/src/generic/grid.cpp +++ b/src/generic/grid.cpp @@ -2,7 +2,7 @@ // Name: src/generic/grid.cpp // Purpose: wxGrid and related classes // Author: Michael Bedward (based on code by Julian Smart, Robin Dunn) -// Modified by: Robin Dunn, Vadim Zeitlin +// Modified by: Robin Dunn, Vadim Zeitlin, Santiago Palacios // Created: 1/08/1999 // RCS-ID: $Id$ // Copyright: (c) Michael Bedward (mbedward@ozemail.com.au) @@ -18,6 +18,8 @@ #if wxUSE_GRID +#include "wx/grid.h" + #ifndef WX_PRECOMP #include "wx/utils.h" #include "wx/dcclient.h" @@ -29,6 +31,7 @@ #include "wx/valtext.h" #include "wx/intl.h" #include "wx/math.h" + #include "wx/listbox.h" #endif #include "wx/textfile.h" @@ -36,9 +39,10 @@ #include "wx/tokenzr.h" #include "wx/renderer.h" -#include "wx/grid.h" #include "wx/generic/gridsel.h" +const wxChar wxGridNameStr[] = wxT("grid"); + #if defined(__WXMOTIF__) #define WXUNUSED_MOTIF(identifier) WXUNUSED(identifier) #else @@ -104,6 +108,7 @@ DEFINE_EVENT_TYPE(wxEVT_GRID_LABEL_LEFT_DCLICK) 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_RANGE_SELECT) DEFINE_EVENT_TYPE(wxEVT_GRID_CELL_CHANGE) DEFINE_EVENT_TYPE(wxEVT_GRID_SELECT_CELL) @@ -115,22 +120,48 @@ DEFINE_EVENT_TYPE(wxEVT_GRID_EDITOR_CREATED) // private classes // ---------------------------------------------------------------------------- -class WXDLLIMPEXP_ADV wxGridRowLabelWindow : public wxWindow +// 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, + wxBORDER_NONE | additionalStyle, + name) + { + m_owner = owner; + } + + virtual bool AcceptsFocus() const { return false; } + + wxGrid *GetOwner() { return m_owner; } + +protected: + void OnMouseCaptureLost(wxMouseCaptureLostEvent& event); + + wxGrid *m_owner; + + DECLARE_EVENT_TABLE() + DECLARE_NO_COPY_CLASS(wxGridSubwindow) +}; + +class WXDLLIMPEXP_ADV wxGridRowLabelWindow : public wxGridSubwindow { public: - wxGridRowLabelWindow() { m_owner = (wxGrid *)NULL; } + wxGridRowLabelWindow() { } wxGridRowLabelWindow( wxGrid *parent, wxWindowID id, const wxPoint &pos, const wxSize &size ); private: - wxGrid *m_owner; - void OnPaint( wxPaintEvent& event ); void OnMouseEvent( wxMouseEvent& event ); void OnMouseWheel( wxMouseEvent& event ); - void OnKeyDown( wxKeyEvent& event ); - void OnKeyUp( wxKeyEvent& ); - void OnChar( wxKeyEvent& ); DECLARE_DYNAMIC_CLASS(wxGridRowLabelWindow) DECLARE_EVENT_TABLE() @@ -138,22 +169,17 @@ private: }; -class WXDLLIMPEXP_ADV wxGridColLabelWindow : public wxWindow +class WXDLLIMPEXP_ADV wxGridColLabelWindow : public wxGridSubwindow { public: - wxGridColLabelWindow() { m_owner = (wxGrid *)NULL; } + wxGridColLabelWindow() { } wxGridColLabelWindow( wxGrid *parent, wxWindowID id, const wxPoint &pos, const wxSize &size ); private: - wxGrid *m_owner; - void OnPaint( wxPaintEvent& event ); void OnMouseEvent( wxMouseEvent& event ); void OnMouseWheel( wxMouseEvent& event ); - void OnKeyDown( wxKeyEvent& event ); - void OnKeyUp( wxKeyEvent& ); - void OnChar( wxKeyEvent& ); DECLARE_DYNAMIC_CLASS(wxGridColLabelWindow) DECLARE_EVENT_TABLE() @@ -161,21 +187,16 @@ private: }; -class WXDLLIMPEXP_ADV wxGridCornerLabelWindow : public wxWindow +class WXDLLIMPEXP_ADV wxGridCornerLabelWindow : public wxGridSubwindow { public: - wxGridCornerLabelWindow() { m_owner = (wxGrid *)NULL; } + wxGridCornerLabelWindow() { } wxGridCornerLabelWindow( wxGrid *parent, wxWindowID id, const wxPoint &pos, const wxSize &size ); private: - wxGrid *m_owner; - void OnMouseEvent( wxMouseEvent& event ); void OnMouseWheel( wxMouseEvent& event ); - void OnKeyDown( wxKeyEvent& event ); - void OnKeyUp( wxKeyEvent& ); - void OnChar( wxKeyEvent& ); void OnPaint( wxPaintEvent& event ); DECLARE_DYNAMIC_CLASS(wxGridCornerLabelWindow) @@ -183,12 +204,11 @@ private: DECLARE_NO_COPY_CLASS(wxGridCornerLabelWindow) }; -class WXDLLIMPEXP_ADV wxGridWindow : public wxWindow +class WXDLLIMPEXP_ADV wxGridWindow : public wxGridSubwindow { public: wxGridWindow() { - m_owner = NULL; m_rowLabelWin = NULL; m_colLabelWin = NULL; } @@ -197,14 +217,12 @@ public: wxGridRowLabelWindow *rowLblWin, wxGridColLabelWindow *colLblWin, wxWindowID id, const wxPoint &pos, const wxSize &size ); - ~wxGridWindow() {} void ScrollWindow( int dx, int dy, const wxRect *rect ); - wxGrid* GetOwner() { return m_owner; } + virtual bool AcceptsFocus() const { return true; } private: - wxGrid *m_owner; wxGridRowLabelWindow *m_rowLabelWin; wxGridColLabelWindow *m_colLabelWin; @@ -467,7 +485,7 @@ void wxGridCellEditor::PaintBackground(const wxRect& rectCell, gridWindow->GetOwner()->PrepareDC(dc); dc.SetPen(*wxTRANSPARENT_PEN); - dc.SetBrush(wxBrush(attr->GetBackgroundColour(), wxSOLID)); + dc.SetBrush(wxBrush(attr->GetBackgroundColour(), wxBRUSHSTYLE_SOLID)); dc.DrawRectangle(rectCell); // redraw the control we just painted over @@ -570,6 +588,12 @@ bool wxGridCellEditor::IsAcceptedKey(wxKeyEvent& event) 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 @@ -613,17 +637,27 @@ void wxGridCellTextEditor::Create(wxWindow* parent, wxWindowID id, wxEvtHandler* evtHandler) { + DoCreate(parent, id, evtHandler); +} + +void wxGridCellTextEditor::DoCreate(wxWindow* parent, + wxWindowID id, + wxEvtHandler* evtHandler, + long style) +{ + style |= wxTE_PROCESS_ENTER | + wxTE_PROCESS_TAB | + wxTE_AUTO_SCROLL | + wxNO_BORDER; + m_control = new wxTextCtrl(parent, id, wxEmptyString, - wxDefaultPosition, wxDefaultSize -#if defined(__WXMSW__) - , wxTE_PROCESS_TAB | wxTE_AUTO_SCROLL -#endif - ); + wxDefaultPosition, wxDefaultSize, + style); // set max length allowed in the textctrl, if the parameter was set - if (m_maxChars != 0) + if ( m_maxChars != 0 ) { - ((wxTextCtrl*)m_control)->SetMaxLength(m_maxChars); + Text()->SetMaxLength(m_maxChars); } wxGridCellEditor::Create(parent, id, evtHandler); @@ -652,27 +686,33 @@ void wxGridCellTextEditor::SetSize(const wxRect& rectOrig) rect.width -= 1; rect.height -= 1; } -#else // !GTK - int extra_x = ( rect.x > 2 ) ? 2 : 1; +#elif defined(__WXMSW__) + if ( rect.x == 0 ) + rect.x += 2; + else + rect.x += 3; -// MB: treat MSW separately here otherwise the caret doesn't show -// when the editor is in the first row. -#if defined(__WXMSW__) - int extra_y = 2; + if ( rect.y == 0 ) + rect.y += 2; + else + rect.y += 3; + + rect.width -= 2; + rect.height -= 2; #else + int extra_x = ( rect.x > 2 ) ? 2 : 1; int extra_y = ( rect.y > 2 ) ? 2 : 1; -#endif -#if defined(__WXMOTIF__) - extra_x *= 2; - extra_y *= 2; -#endif + #if defined(__WXMOTIF__) + extra_x *= 2; + extra_y *= 2; + #endif rect.SetLeft( wxMax(0, rect.x - extra_x) ); rect.SetTop( wxMax(0, rect.y - extra_y) ); rect.SetRight( rect.GetRight() + 2 * extra_x ); rect.SetBottom( rect.GetBottom() + 2 * extra_y ); -#endif // GTK/!GTK +#endif wxGridCellEditor::SetSize(rect); } @@ -1178,27 +1218,30 @@ bool wxGridCellFloatEditor::IsAcceptedKey(wxKeyEvent& event) { if ( wxGridCellEditor::IsAcceptedKey(event) ) { - int keycode = event.GetKeyCode(); - printf("%d\n", keycode); - // accept digits, 'e' as in '1e+6', also '-', '+', and '.' - char tmpbuf[2]; - tmpbuf[0] = (char) keycode; - tmpbuf[1] = '\0'; - wxString strbuf(tmpbuf, *wxConvCurrent); + const int keycode = event.GetKeyCode(); + if ( isascii(keycode) ) + { + char tmpbuf[2]; + tmpbuf[0] = (char) keycode; + tmpbuf[1] = '\0'; + wxString strbuf(tmpbuf, *wxConvCurrent); #if wxUSE_INTL - bool is_decimal_point = - ( strbuf == wxLocale::GetInfo(wxLOCALE_DECIMAL_POINT, - wxLOCALE_CAT_NUMBER) ); + const wxString decimalPoint = + wxLocale::GetInfo(wxLOCALE_DECIMAL_POINT, wxLOCALE_CAT_NUMBER); #else - bool is_decimal_point = ( strbuf == _T(".") ); + const wxString decimalPoint(_T('.')); #endif - if ( (keycode < 128) && - (wxIsdigit(keycode) || tolower(keycode) == 'e' || - is_decimal_point || keycode == '+' || keycode == '-') ) - { - return true; + // accept digits, 'e' as in '1e+6', also '-', '+', and '.' + if ( wxIsdigit(keycode) || + tolower(keycode) == 'e' || + keycode == decimalPoint || + keycode == '+' || + keycode == '-' ) + { + return true; + } } } @@ -1213,6 +1256,9 @@ bool wxGridCellFloatEditor::IsAcceptedKey(wxKeyEvent& event) // wxGridCellBoolEditor // ---------------------------------------------------------------------------- +// the default values for GetValue() +wxString wxGridCellBoolEditor::ms_stringValues[2] = { _T(""), _T("1") }; + void wxGridCellBoolEditor::Create(wxWindow* parent, wxWindowID id, wxEvtHandler* evtHandler) @@ -1318,7 +1364,19 @@ void wxGridCellBoolEditor::BeginEdit(int row, int col, wxGrid* grid) else { wxString cellval( grid->GetTable()->GetValue(row, col) ); - m_startValue = !( !cellval || (cellval == wxT("0")) ); + + if ( cellval == ms_stringValues[false] ) + m_startValue = false; + else if ( cellval == ms_stringValues[true] ) + m_startValue = true; + else + { + // do not try to be smart here and convert it to true or false + // because we'll still overwrite it with something different and + // this risks to be very surprising for the user code, let them + // know about it + wxFAIL_MSG( _T("invalid value for a cell with bool editor!") ); + } } CBox()->SetValue(m_startValue); @@ -1338,10 +1396,11 @@ bool wxGridCellBoolEditor::EndEdit(int row, int col, if ( changed ) { - if (grid->GetTable()->CanGetValueAs(row, col, wxGRID_VALUE_BOOL)) - grid->GetTable()->SetValueAsBool(row, col, value); + wxGridTableBase * const table = grid->GetTable(); + if ( table->CanGetValueAs(row, col, wxGRID_VALUE_BOOL) ) + table->SetValueAsBool(row, col, value); else - grid->GetTable()->SetValue(row, col, value ? _T("1") : wxEmptyString); + table->SetValue(row, col, GetValue()); } return changed; @@ -1396,12 +1455,23 @@ void wxGridCellBoolEditor::StartingKey(wxKeyEvent& event) } } - -// return the value as "1" for true and the empty string for false wxString wxGridCellBoolEditor::GetValue() const { - bool bSet = CBox()->GetValue(); - return bSet ? _T("1") : wxEmptyString; + return ms_stringValues[CBox()->GetValue()]; +} + +/* static */ void +wxGridCellBoolEditor::UseStringValues(const wxString& valueTrue, + const wxString& valueFalse) +{ + ms_stringValues[false] = valueFalse; + ms_stringValues[true] = valueTrue; +} + +/* static */ bool +wxGridCellBoolEditor::IsTrueValue(const wxString& value) +{ + return value == ms_stringValues[true]; } #endif // wxUSE_CHECKBOX @@ -1445,10 +1515,16 @@ void wxGridCellChoiceEditor::Create(wxWindow* parent, wxWindowID id, wxEvtHandler* evtHandler) { + int style = wxTE_PROCESS_ENTER | + wxTE_PROCESS_TAB | + wxBORDER_NONE; + + if ( !m_allowOthers ) + style |= wxCB_READONLY; m_control = new wxComboBox(parent, id, wxEmptyString, wxDefaultPosition, wxDefaultSize, m_choices, - m_allowOthers ? 0 : wxCB_READONLY); + style); wxGridCellEditor::Create(parent, id, evtHandler); } @@ -1483,8 +1559,9 @@ void wxGridCellChoiceEditor::BeginEdit(int row, int col, wxGrid* grid) if (m_allowOthers) { Combo()->SetValue(m_startValue); + Combo()->SetInsertionPointEnd(); } - else + else // the combobox is read-only { // find the right position, or default to the first if not found int pos = Combo()->FindString(m_startValue); @@ -1493,7 +1570,6 @@ void wxGridCellChoiceEditor::BeginEdit(int row, int col, wxGrid* grid) Combo()->SetSelection(pos); } - Combo()->SetInsertionPointEnd(); Combo()->SetFocus(); if (evtHandler) @@ -1727,23 +1803,28 @@ void wxGridCellRenderer::Draw(wxGrid& grid, int WXUNUSED(row), int WXUNUSED(col), bool isSelected) { - dc.SetBackgroundMode( wxSOLID ); + dc.SetBackgroundMode( wxBRUSHSTYLE_SOLID ); // grey out fields if the grid is disabled if ( grid.IsEnabled() ) { if ( isSelected ) { - dc.SetBrush( wxBrush(grid.GetSelectionBackground(), wxSOLID) ); + wxColour clr; + if ( grid.HasFocus() ) + clr = grid.GetSelectionBackground(); + else + clr = wxSystemSettings::GetColour(wxSYS_COLOUR_BTNSHADOW); + dc.SetBrush( wxBrush(clr, wxBRUSHSTYLE_SOLID) ); } else { - dc.SetBrush( wxBrush(attr.GetBackgroundColour(), wxSOLID) ); + dc.SetBrush( wxBrush(attr.GetBackgroundColour(), wxBRUSHSTYLE_SOLID) ); } } else { - dc.SetBrush(wxBrush(wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE), wxSOLID)); + dc.SetBrush(wxBrush(wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE), wxBRUSHSTYLE_SOLID)); } dc.SetPen( *wxTRANSPARENT_PEN ); @@ -1759,7 +1840,7 @@ void wxGridCellStringRenderer::SetTextColoursAndFont(const wxGrid& grid, wxDC& dc, bool isSelected) { - dc.SetBackgroundMode( wxTRANSPARENT ); + dc.SetBackgroundMode( wxBRUSHSTYLE_TRANSPARENT ); // TODO some special colours for attr.IsReadOnly() case? @@ -1768,7 +1849,12 @@ void wxGridCellStringRenderer::SetTextColoursAndFont(const wxGrid& grid, { if ( isSelected ) { - dc.SetTextBackground( grid.GetSelectionBackground() ); + wxColour clr; + if ( grid.HasFocus() ) + clr = grid.GetSelectionBackground(); + else + clr = wxSystemSettings::GetColour(wxSYS_COLOUR_BTNSHADOW); + dc.SetTextBackground( clr ); dc.SetTextForeground( grid.GetSelectionForeground() ); } else @@ -2129,8 +2215,7 @@ wxSize wxGridCellBoolRenderer::GetBestSize(wxGrid& grid, wxSize size = checkbox->GetBestSize(); wxCoord checkSize = size.y + 2 * wxGRID_CHECKMARK_MARGIN; - // FIXME wxGTK::wxCheckBox::GetBestSize() gives "wrong" result -#if defined(__WXGTK__) || defined(__WXMOTIF__) +#if defined(__WXMOTIF__) checkSize -= size.y / 2; #endif @@ -2159,7 +2244,7 @@ void wxGridCellBoolRenderer::Draw(wxGrid& grid, if ( size.x >= minSize || size.y >= minSize ) { // and even leave (at least) 1 pixel margin - size.x = size.y = minSize - 2; + size.x = size.y = minSize; } // draw a border around checkmark @@ -2197,29 +2282,14 @@ void wxGridCellBoolRenderer::Draw(wxGrid& grid, else { wxString cellval( grid.GetTable()->GetValue(row, col) ); - value = !( !cellval || (cellval == wxT("0")) ); + value = wxGridCellBoolEditor::IsTrueValue(cellval); } - if ( value ) - { - wxRect rectMark = rectBorder; - -#ifdef __WXMSW__ - // MSW DrawCheckMark() is weird (and should probably be changed...) - rectMark.Inflate(-wxGRID_CHECKMARK_MARGIN / 2); - rectMark.x++; - rectMark.y++; -#else - rectMark.Inflate(-wxGRID_CHECKMARK_MARGIN); -#endif - - dc.SetTextForeground(attr.GetTextColour()); - dc.DrawCheckMark(rectMark); - } + int flags = 0; + if (value) + flags |= wxCONTROL_CHECKED; - dc.SetBrush(*wxTRANSPARENT_BRUSH); - dc.SetPen(wxPen(attr.GetTextColour(), 1, wxSOLID)); - dc.DrawRectangle(rectBorder); + wxRendererNative::Get().DrawCheckBox( &grid, dc, rectBorder, flags ); } // ---------------------------------------------------------------------------- @@ -2272,6 +2342,7 @@ wxGridCellAttr *wxGridCellAttr::Clone() const if ( IsReadOnly() ) attr->SetReadOnly(); + attr->SetOverflow( m_overflow == Overflow ); attr->SetKind( m_attrkind ); return attr; @@ -2423,7 +2494,7 @@ void wxGridCellAttr::GetSize( int *num_rows, int *num_cols ) const // 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(wxGrid* grid, int row, int col) const +wxGridCellRenderer* wxGridCellAttr::GetRenderer(const wxGrid* grid, int row, int col) const { wxGridCellRenderer *renderer = NULL; @@ -2467,7 +2538,7 @@ wxGridCellRenderer* wxGridCellAttr::GetRenderer(wxGrid* grid, int row, int col) } // same as above, except for s/renderer/editor/g -wxGridCellEditor* wxGridCellAttr::GetEditor(wxGrid* grid, int row, int col) const +wxGridCellEditor* wxGridCellAttr::GetEditor(const wxGrid* grid, int row, int col) const { wxGridCellEditor *editor = NULL; @@ -2519,8 +2590,12 @@ void wxGridCellAttrData::SetAttr(wxGridCellAttr *attr, int row, int col) int n = FindIndex(row, col); if ( n == wxNOT_FOUND ) { - // add the attribute - m_attrs.Add(new wxGridCellWithAttr(row, col, attr)); + if ( attr ) + { + // add the attribute + m_attrs.Add(new wxGridCellWithAttr(row, col, attr)); + } + //else: nothing to do } else { @@ -2647,7 +2722,7 @@ int wxGridCellAttrData::FindIndex(int row, int col) const wxGridRowOrColAttrData::~wxGridRowOrColAttrData() { - size_t count = m_attrs.Count(); + size_t count = m_attrs.GetCount(); for ( size_t n = 0; n < count; n++ ) { m_attrs[n]->DecRef(); @@ -2673,9 +2748,13 @@ void wxGridRowOrColAttrData::SetAttr(wxGridCellAttr *attr, int rowOrCol) int i = m_rowsOrCols.Index(rowOrCol); if ( i == wxNOT_FOUND ) { - // add the attribute - m_rowsOrCols.Add(rowOrCol); - m_attrs.Add(attr); + if ( attr ) + { + // add the attribute + m_rowsOrCols.Add(rowOrCol); + m_attrs.Add(attr); + } + // nothing to remove } else { @@ -2888,7 +2967,7 @@ void wxGridCellAttrProvider::UpdateAttrCols( size_t pos, int numCols ) wxGridTypeRegistry::~wxGridTypeRegistry() { - size_t count = m_typeinfo.Count(); + size_t count = m_typeinfo.GetCount(); for ( size_t i = 0; i < count; i++ ) delete m_typeinfo[i]; } @@ -3500,6 +3579,15 @@ bool wxGridStringTable::InsertCols( size_t pos, size_t numCols ) return AppendCols( numCols ); } + if ( !m_colLabels.IsEmpty() ) + { + m_colLabels.Insert( wxEmptyString, pos, numCols ); + + size_t i; + for ( i = pos; i < pos + numCols; i++ ) + m_colLabels[i] = wxGridTableBase::GetColLabelValue( i ); + } + for ( row = 0; row < curNumRows; row++ ) { for ( col = pos; col < pos + numCols; col++ ) @@ -3574,9 +3662,25 @@ bool wxGridStringTable::DeleteCols( size_t pos, size_t numCols ) return false; } - if ( numCols > curNumCols - pos ) + int colID; + if ( GetView() ) + colID = GetView()->GetColAt( pos ); + else + colID = pos; + + if ( numCols > curNumCols - colID ) + { + numCols = curNumCols - colID; + } + + if ( !m_colLabels.IsEmpty() ) { - numCols = curNumCols - pos; + // m_colLabels stores just as many elements as it needs, e.g. if only + // the label of the first column had been set it would have only one + // element and not numCols, so account for it + int nToRm = m_colLabels.size() - colID; + if ( nToRm > 0 ) + m_colLabels.RemoveAt( colID, nToRm ); } for ( row = 0; row < curNumRows; row++ ) @@ -3587,7 +3691,7 @@ bool wxGridStringTable::DeleteCols( size_t pos, size_t numCols ) } else { - m_data[row].RemoveAt( pos, numCols ); + m_data[row].RemoveAt( colID, numCols ); } } @@ -3668,21 +3772,27 @@ void wxGridStringTable::SetColLabelValue( int col, const wxString& value ) ////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////// +BEGIN_EVENT_TABLE(wxGridSubwindow, wxWindow) + EVT_MOUSE_CAPTURE_LOST(wxGridSubwindow::OnMouseCaptureLost) +END_EVENT_TABLE() + +void wxGridSubwindow::OnMouseCaptureLost(wxMouseCaptureLostEvent& WXUNUSED(event)) +{ + m_owner->CancelMouseCapture(); +} + IMPLEMENT_DYNAMIC_CLASS( wxGridRowLabelWindow, wxWindow ) -BEGIN_EVENT_TABLE( wxGridRowLabelWindow, wxWindow ) +BEGIN_EVENT_TABLE( wxGridRowLabelWindow, wxGridSubwindow ) EVT_PAINT( wxGridRowLabelWindow::OnPaint ) EVT_MOUSEWHEEL( wxGridRowLabelWindow::OnMouseWheel ) EVT_MOUSE_EVENTS( wxGridRowLabelWindow::OnMouseEvent ) - EVT_KEY_DOWN( wxGridRowLabelWindow::OnKeyDown ) - EVT_KEY_UP( wxGridRowLabelWindow::OnKeyUp ) - EVT_CHAR( wxGridRowLabelWindow::OnChar ) END_EVENT_TABLE() wxGridRowLabelWindow::wxGridRowLabelWindow( wxGrid *parent, wxWindowID id, const wxPoint &pos, const wxSize &size ) - : wxWindow( parent, id, pos, size, wxWANTS_CHARS | wxBORDER_NONE | wxFULL_REPAINT_ON_RESIZE ) + : wxGridSubwindow(parent, id, pos, size) { m_owner = parent; } @@ -3699,7 +3809,8 @@ void wxGridRowLabelWindow::OnPaint( wxPaintEvent& WXUNUSED(event) ) int x, y; m_owner->CalcUnscrolledPosition( 0, 0, &x, &y ); - dc.SetDeviceOrigin( 0, -y ); + wxPoint pt = dc.GetDeviceOrigin(); + dc.SetDeviceOrigin( pt.x, pt.y-y ); wxArrayInt rows = m_owner->CalcRowLabelsExposed( GetUpdateRegion() ); m_owner->DrawRowLabels( dc, rows ); @@ -3715,44 +3826,20 @@ void wxGridRowLabelWindow::OnMouseWheel( wxMouseEvent& event ) m_owner->GetEventHandler()->ProcessEvent( event ); } -// This seems to be required for wxMotif otherwise the mouse -// cursor must be in the cell edit control to get key events -// -void wxGridRowLabelWindow::OnKeyDown( wxKeyEvent& event ) -{ - if ( !m_owner->GetEventHandler()->ProcessEvent( event ) ) - event.Skip(); -} - -void wxGridRowLabelWindow::OnKeyUp( wxKeyEvent& event ) -{ - if ( !m_owner->GetEventHandler()->ProcessEvent( event ) ) - event.Skip(); -} - -void wxGridRowLabelWindow::OnChar( wxKeyEvent& event ) -{ - if ( !m_owner->GetEventHandler()->ProcessEvent( event ) ) - event.Skip(); -} - ////////////////////////////////////////////////////////////////////// IMPLEMENT_DYNAMIC_CLASS( wxGridColLabelWindow, wxWindow ) -BEGIN_EVENT_TABLE( wxGridColLabelWindow, wxWindow ) +BEGIN_EVENT_TABLE( wxGridColLabelWindow, wxGridSubwindow ) EVT_PAINT( wxGridColLabelWindow::OnPaint ) EVT_MOUSEWHEEL( wxGridColLabelWindow::OnMouseWheel ) EVT_MOUSE_EVENTS( wxGridColLabelWindow::OnMouseEvent ) - EVT_KEY_DOWN( wxGridColLabelWindow::OnKeyDown ) - EVT_KEY_UP( wxGridColLabelWindow::OnKeyUp ) - EVT_CHAR( wxGridColLabelWindow::OnChar ) END_EVENT_TABLE() wxGridColLabelWindow::wxGridColLabelWindow( wxGrid *parent, wxWindowID id, const wxPoint &pos, const wxSize &size ) - : wxWindow( parent, id, pos, size, wxWANTS_CHARS | wxBORDER_NONE | wxFULL_REPAINT_ON_RESIZE ) + : wxGridSubwindow(parent, id, pos, size) { m_owner = parent; } @@ -3769,7 +3856,11 @@ void wxGridColLabelWindow::OnPaint( wxPaintEvent& WXUNUSED(event) ) int x, y; m_owner->CalcUnscrolledPosition( 0, 0, &x, &y ); - dc.SetDeviceOrigin( -x, 0 ); + wxPoint pt = dc.GetDeviceOrigin(); + if (GetLayoutDirection() == wxLayout_RightToLeft) + dc.SetDeviceOrigin( pt.x+x, pt.y ); + else + dc.SetDeviceOrigin( pt.x-x, pt.y ); wxArrayInt cols = m_owner->CalcColLabelsExposed( GetUpdateRegion() ); m_owner->DrawColLabels( dc, cols ); @@ -3785,44 +3876,20 @@ void wxGridColLabelWindow::OnMouseWheel( wxMouseEvent& event ) m_owner->GetEventHandler()->ProcessEvent( event ); } -// This seems to be required for wxMotif otherwise the mouse -// cursor must be in the cell edit control to get key events -// -void wxGridColLabelWindow::OnKeyDown( wxKeyEvent& event ) -{ - if ( !m_owner->GetEventHandler()->ProcessEvent( event ) ) - event.Skip(); -} - -void wxGridColLabelWindow::OnKeyUp( wxKeyEvent& event ) -{ - if ( !m_owner->GetEventHandler()->ProcessEvent( event ) ) - event.Skip(); -} - -void wxGridColLabelWindow::OnChar( wxKeyEvent& event ) -{ - if ( !m_owner->GetEventHandler()->ProcessEvent( event ) ) - event.Skip(); -} - ////////////////////////////////////////////////////////////////////// IMPLEMENT_DYNAMIC_CLASS( wxGridCornerLabelWindow, wxWindow ) -BEGIN_EVENT_TABLE( wxGridCornerLabelWindow, wxWindow ) +BEGIN_EVENT_TABLE( wxGridCornerLabelWindow, wxGridSubwindow ) EVT_MOUSEWHEEL( wxGridCornerLabelWindow::OnMouseWheel ) EVT_MOUSE_EVENTS( wxGridCornerLabelWindow::OnMouseEvent ) EVT_PAINT( wxGridCornerLabelWindow::OnPaint ) - EVT_KEY_DOWN( wxGridCornerLabelWindow::OnKeyDown ) - EVT_KEY_UP( wxGridCornerLabelWindow::OnKeyUp ) - EVT_CHAR( wxGridCornerLabelWindow::OnChar ) END_EVENT_TABLE() wxGridCornerLabelWindow::wxGridCornerLabelWindow( wxGrid *parent, wxWindowID id, const wxPoint &pos, const wxSize &size ) - : wxWindow( parent, id, pos, size, wxWANTS_CHARS | wxBORDER_NONE | wxFULL_REPAINT_ON_RESIZE ) + : wxGridSubwindow(parent, id, pos, size) { m_owner = parent; } @@ -3836,7 +3903,8 @@ void wxGridCornerLabelWindow::OnPaint( wxPaintEvent& WXUNUSED(event) ) GetClientSize( &client_width, &client_height ); // VZ: any reason for this ifdef? (FIXME) -#ifdef __WXGTK__ +#if 0 +def __WXGTK__ wxRect rect; rect.SetX( 1 ); rect.SetY( 1 ); @@ -3845,7 +3913,7 @@ void wxGridCornerLabelWindow::OnPaint( wxPaintEvent& WXUNUSED(event) ) wxRendererNative::Get().DrawHeaderButton( this, dc, rect, 0 ); #else // !__WXGTK__ - dc.SetPen( wxPen(wxSystemSettings::GetColour(wxSYS_COLOUR_3DDKSHADOW), 1, wxSOLID) ); + dc.SetPen( wxPen(wxSystemSettings::GetColour(wxSYS_COLOUR_3DSHADOW), 1, wxPENSTYLE_SOLID) ); dc.DrawLine( client_width - 1, client_height - 1, client_width - 1, 0 ); dc.DrawLine( client_width - 1, client_height - 1, 0, client_height - 1 ); dc.DrawLine( 0, 0, client_width, 0 ); @@ -3867,32 +3935,11 @@ void wxGridCornerLabelWindow::OnMouseWheel( wxMouseEvent& event ) m_owner->GetEventHandler()->ProcessEvent(event); } -// This seems to be required for wxMotif otherwise the mouse -// cursor must be in the cell edit control to get key events -// -void wxGridCornerLabelWindow::OnKeyDown( wxKeyEvent& event ) -{ - if ( !m_owner->GetEventHandler()->ProcessEvent( event ) ) - event.Skip(); -} - -void wxGridCornerLabelWindow::OnKeyUp( wxKeyEvent& event ) -{ - if ( !m_owner->GetEventHandler()->ProcessEvent( event ) ) - event.Skip(); -} - -void wxGridCornerLabelWindow::OnChar( wxKeyEvent& event ) -{ - if ( !m_owner->GetEventHandler()->ProcessEvent( event ) ) - event.Skip(); -} - ////////////////////////////////////////////////////////////////////// IMPLEMENT_DYNAMIC_CLASS( wxGridWindow, wxWindow ) -BEGIN_EVENT_TABLE( wxGridWindow, wxWindow ) +BEGIN_EVENT_TABLE( wxGridWindow, wxGridSubwindow ) EVT_PAINT( wxGridWindow::OnPaint ) EVT_MOUSEWHEEL( wxGridWindow::OnMouseWheel ) EVT_MOUSE_EVENTS( wxGridWindow::OnMouseEvent ) @@ -3910,10 +3957,9 @@ wxGridWindow::wxGridWindow( wxGrid *parent, wxWindowID id, const wxPoint &pos, const wxSize &size ) - : wxWindow( - parent, id, pos, size, - wxWANTS_CHARS | wxBORDER_NONE | wxCLIP_CHILDREN | wxFULL_REPAINT_ON_RESIZE, - wxT("grid window") ) + : wxGridSubwindow(parent, id, pos, size, + wxWANTS_CHARS | wxCLIP_CHILDREN, + wxT("grid window") ) { m_owner = parent; m_rowLabelWin = rowLblWin; @@ -3983,6 +4029,29 @@ void wxGridWindow::OnEraseBackground( wxEraseEvent& WXUNUSED(event) ) void wxGridWindow::OnFocus(wxFocusEvent& event) { + // and if we have any selection, it has to be repainted, because it + // uses different colour when the grid is not focused: + if ( m_owner->IsSelection() ) + { + Refresh(); + } + else + { + // NB: Note that this code is in "else" branch only because the other + // branch refreshes everything and so there's no point in calling + // Refresh() again, *not* because it should only be done if + // !IsSelection(). If the above code is ever optimized to refresh + // only selected area, this needs to be moved out of the "else" + // branch so that it's always executed. + + // current cell cursor {dis,re}appears on focus change: + const wxGridCellCoords cursorCoords(m_owner->GetGridCursorRow(), + m_owner->GetGridCursorCol()); + const wxRect cursor = + m_owner->BlockToDeviceRect(cursorCoords, cursorCoords); + Refresh(true, &cursor); + } + if ( !m_owner->GetEventHandler()->ProcessEvent( event ) ) event.Skip(); } @@ -4000,9 +4069,7 @@ static int CoordToRowOrCol(int coord, int defaultDist, int minDist, const wxArrayInt& BorderArray, int nMax, bool clipToMinMax); -#define internalXToCol(x) CoordToRowOrCol(x, m_defaultColWidth, \ - m_minAcceptableColWidth, \ - m_colRights, m_numCols, true) +#define internalXToCol(x) XToCol(x, true) #define internalYToRow(y) CoordToRowOrCol(y, m_defaultRowHeight, \ m_minAcceptableRowHeight, \ m_rowBottoms, m_numRows, true) @@ -4072,12 +4139,7 @@ END_EVENT_TABLE() wxGrid::wxGrid() { - // in order to make sure that a size event is not - // trigerred in a unfinished state - m_cornerLabelWin = NULL; - m_rowLabelWin = NULL; - m_colLabelWin = NULL; - m_gridWin = NULL; + InitVars(); } wxGrid::wxGrid( wxWindow *parent, @@ -4086,12 +4148,9 @@ wxGrid::wxGrid( wxWindow *parent, const wxSize& size, long style, const wxString& name ) - : wxScrolledWindow( parent, id, pos, size, (style | wxWANTS_CHARS), name ), - m_colMinWidths(GRID_HASH_SIZE), - m_rowMinHeights(GRID_HASH_SIZE) { - Create(); - SetBestFittingSize(size); + InitVars(); + Create(parent, id, pos, size, style, name); } bool wxGrid::Create(wxWindow *parent, wxWindowID id, @@ -4106,7 +4165,8 @@ bool wxGrid::Create(wxWindow *parent, wxWindowID id, m_rowMinHeights = wxLongToLongHashMap(GRID_HASH_SIZE); Create(); - SetBestFittingSize(size); + SetInitialSize(size); + CalcDimensions(); return true; } @@ -4126,8 +4186,12 @@ wxGrid::~wxGrid() total ? (gs_nAttrCacheHits*100) / total : 0); #endif - if (m_ownTable) + // if we own the table, just delete it, otherwise at least don't leave it + // with dangling view pointer + if ( m_ownTable ) delete m_table; + else if ( m_table && m_table->GetView() == this ) + m_table->SetView(NULL); delete m_typeRegistry; delete m_selection; @@ -4141,21 +4205,10 @@ wxGrid::~wxGrid() // be removed as well as the #else cases below. #define _USE_VISATTR 0 -#if _USE_VISATTR -#include "wx/listbox.h" -#endif - void wxGrid::Create() { - // set to true by CreateGrid - m_created = false; - // create the type registry m_typeRegistry = new wxGridTypeRegistry; - m_selection = NULL; - - m_table = (wxGridTableBase *) NULL; - m_ownTable = false; m_cellEditCtrlEnabled = false; @@ -4281,24 +4334,33 @@ wxGrid::wxGridSelectionModes wxGrid::GetSelectionMode() const bool wxGrid::SetTable( wxGridTableBase *table, bool takeOwnership, wxGrid::wxGridSelectionModes selmode ) { + bool checkSelection = false; if ( m_created ) { // stop all processing m_created = false; - if (m_ownTable) + if (m_table) { - wxGridTableBase *t = m_table; + m_table->SetView(0); + if( m_ownTable ) + delete m_table; m_table = NULL; - delete t; } delete m_selection; - - m_table = NULL; m_selection = NULL; + + m_ownTable = false; m_numRows = 0; m_numCols = 0; + checkSelection = true; + + // kill row and column size arrays + m_colWidths.Empty(); + m_colRights.Empty(); + m_rowHeights.Empty(); + m_rowBottoms.Empty(); } if (table) @@ -4310,7 +4372,28 @@ bool wxGrid::SetTable( wxGridTableBase *table, bool takeOwnership, m_table->SetView( this ); m_ownTable = takeOwnership; m_selection = new wxGridSelection( this, selmode ); - + if (checkSelection) + { + // If the newly set table is smaller than the + // original one current cell and selection regions + // might be invalid, + m_selectingKeyboard = wxGridNoCellCoords; + m_currentCellCoords = + wxGridCellCoords(wxMin(m_numRows, m_currentCellCoords.GetRow()), + wxMin(m_numCols, m_currentCellCoords.GetCol())); + if (m_selectingTopLeft.GetRow() >= m_numRows || + m_selectingTopLeft.GetCol() >= m_numCols) + { + m_selectingTopLeft = wxGridNoCellCoords; + m_selectingBottomRight = wxGridNoCellCoords; + } + else + m_selectingBottomRight = + wxGridCellCoords(wxMin(m_numRows, + m_selectingBottomRight.GetRow()), + wxMin(m_numCols, + m_selectingBottomRight.GetCol())); + } CalcDimensions(); m_created = true; @@ -4319,6 +4402,24 @@ bool wxGrid::SetTable( wxGridTableBase *table, bool takeOwnership, return m_created; } +void wxGrid::InitVars() +{ + m_created = false; + + m_cornerLabelWin = NULL; + m_rowLabelWin = NULL; + m_colLabelWin = NULL; + m_gridWin = NULL; + + m_table = NULL; + m_ownTable = false; + + m_selection = NULL; + m_defaultCellAttr = NULL; + m_typeRegistry = NULL; + m_winCapture = NULL; +} + void wxGrid::Init() { m_rowLabelWidth = WXGRID_DEFAULT_ROW_LABEL_WIDTH; @@ -4370,6 +4471,8 @@ void wxGrid::Init() m_cellHighlightPenWidth = 2; m_cellHighlightROPenWidth = 1; + m_canDragColMove = false; + m_cursorMode = WXGRID_CURSOR_SELECT_CELL; m_winCapture = (wxWindow *)NULL; m_canDragRowSize = true; @@ -4380,6 +4483,7 @@ void wxGrid::Init() m_dragRowOrCol = -1; m_isDragging = false; m_startDragPos = wxDefaultPosition; + m_nativeColumnLabels = false; m_waitForSlowClick = false; @@ -4388,8 +4492,8 @@ void wxGrid::Init() m_currentCellCoords = wxGridNoCellCoords; - m_selectingTopLeft = wxGridNoCellCoords; - m_selectingBottomRight = wxGridNoCellCoords; + ClearSelection(); + m_selectionBackground = wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHT); m_selectionForeground = wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT); @@ -4411,8 +4515,9 @@ void wxGrid::Init() // default widths/heights are used for all rows/columns, we may not use these // arrays at all // -// with some extra code, it should be possible to only store the -// widths/heights different from default ones but this will be done later... +// with some extra code, it should be possible to only store the widths/heights +// different from default ones (resulting in space savings for huge grids) but +// this is not done currently // ---------------------------------------------------------------------------- void wxGrid::InitRowHeights() @@ -4423,10 +4528,9 @@ void wxGrid::InitRowHeights() m_rowHeights.Alloc( m_numRows ); m_rowBottoms.Alloc( m_numRows ); - int rowBottom = 0; - m_rowHeights.Add( m_defaultRowHeight, m_numRows ); + int rowBottom = 0; for ( int i = 0; i < m_numRows; i++ ) { rowBottom += m_defaultRowHeight; @@ -4441,13 +4545,13 @@ void wxGrid::InitColWidths() m_colWidths.Alloc( m_numCols ); m_colRights.Alloc( m_numCols ); - int colRight = 0; m_colWidths.Add( m_defaultColWidth, m_numCols ); + int colRight = 0; for ( int i = 0; i < m_numCols; i++ ) { - colRight += m_defaultColWidth; + colRight = ( GetColPos( i ) + 1 ) * m_defaultColWidth; m_colRights.Add( colRight ); } } @@ -4459,13 +4563,13 @@ int wxGrid::GetColWidth(int col) const int wxGrid::GetColLeft(int col) const { - return m_colRights.IsEmpty() ? col * m_defaultColWidth + return m_colRights.IsEmpty() ? GetColPos( col ) * m_defaultColWidth : m_colRights[col] - m_colWidths[col]; } int wxGrid::GetColRight(int col) const { - return m_colRights.IsEmpty() ? (col + 1) * m_defaultColWidth + return m_colRights.IsEmpty() ? (GetColPos( col ) + 1) * m_defaultColWidth : m_colRights[col]; } @@ -4488,17 +4592,12 @@ int wxGrid::GetRowBottom(int row) const void wxGrid::CalcDimensions() { - int cw, ch; - GetClientSize( &cw, &ch ); + // compute the size of the scrollable area + int w = m_numCols > 0 ? GetColRight(GetColAt(m_numCols - 1)) : 0; + int h = m_numRows > 0 ? GetRowBottom(m_numRows - 1) : 0; - if ( m_rowLabelWin->IsShown() ) - cw -= m_rowLabelWidth; - if ( m_colLabelWin->IsShown() ) - ch -= m_colLabelHeight; - - // grid total size - int w = m_numCols > 0 ? GetColRight(m_numCols - 1) + m_extraWidth + 1 : 0; - int h = m_numRows > 0 ? GetRowBottom(m_numRows - 1) + m_extraHeight + 1 : 0; + w += m_extraWidth; + h += m_extraHeight; // take into account editor if shown if ( IsCellEditControlShown() ) @@ -4535,7 +4634,8 @@ void wxGrid::CalcDimensions() // do set scrollbar parameters SetScrollbars( m_scrollLineX, m_scrollLineY, - GetScrollX(w), GetScrollY(h), x, y, + GetScrollX(w), GetScrollY(h), + x, y, GetBatchCount() != 0); // if our OnSize() hadn't been called (it would if we have scrollbars), we @@ -4553,17 +4653,53 @@ void wxGrid::CalcWindowSizes() int cw, ch; GetClientSize( &cw, &ch ); + // this block of code tries to work around the following problem: the grid + // could have been just resized to have enough space to show the full grid + // window contents without the scrollbars, but its client size could be + // not big enough because the grid has the scrollbars right now and so the + // scrollbars would remain even though we don't need them any more + // + // to prevent this from happening, check if we have enough space for + // everything without the scrollbars and explicitly disable them then + wxSize size = GetSize() - GetWindowBorderSize(); + if ( size != wxSize(cw, ch) ) + { + // check if we have enough space for grid window after accounting for + // the fixed size elements + size.x -= m_rowLabelWidth; + size.y -= m_colLabelHeight; + + const wxSize vsize = m_gridWin->GetVirtualSize(); + + if ( size.x >= vsize.x && size.y >= vsize.y ) + { + // yes, we do, so remove the scrollbars and use the new client size + // (which should be the same as full window size - borders now) + SetScrollbars(0, 0, 0, 0); + GetClientSize(&cw, &ch); + } + } + + // the grid may be too small to have enough space for the labels yet, don't + // size the windows to negative sizes in this case + int gw = cw - m_rowLabelWidth; + int gh = ch - m_colLabelHeight; + if (gw < 0) + gw = 0; + if (gh < 0) + gh = 0; + 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, cw - m_rowLabelWidth, m_colLabelHeight ); + m_colLabelWin->SetSize( m_rowLabelWidth, 0, gw, m_colLabelHeight ); if ( m_rowLabelWin && m_rowLabelWin->IsShown() ) - m_rowLabelWin->SetSize( 0, m_colLabelHeight, m_rowLabelWidth, ch - m_colLabelHeight ); + m_rowLabelWin->SetSize( 0, m_colLabelHeight, m_rowLabelWidth, gh ); if ( m_gridWin && m_gridWin->IsShown() ) - m_gridWin->SetSize( m_rowLabelWidth, m_colLabelHeight, cw - m_rowLabelWidth, ch - m_colLabelHeight ); + m_gridWin->SetSize( m_rowLabelWidth, m_colLabelHeight, gw, gh ); } // this is called when the grid table sends a message @@ -4749,6 +4885,25 @@ bool wxGrid::Redimension( wxGridTableMessage& msg ) int numCols = msg.GetCommandInt2(); m_numCols += numCols; + if ( !m_colAt.IsEmpty() ) + { + //Shift the column IDs + int i; + for ( i = 0; i < m_numCols - numCols; i++ ) + { + if ( m_colAt[i] >= (int)pos ) + m_colAt[i] += numCols; + } + + m_colAt.Insert( pos, pos, numCols ); + + //Set the new columns' positions + for ( i = pos + 1; i < (int)pos + numCols; i++ ) + { + m_colAt[i] = i; + } + } + if ( !m_colWidths.IsEmpty() ) { m_colWidths.Insert( m_defaultColWidth, pos, numCols ); @@ -4756,10 +4911,13 @@ bool wxGrid::Redimension( wxGridTableMessage& msg ) int right = 0; if ( pos > 0 ) - right = m_colRights[pos - 1]; + right = m_colRights[GetColAt( pos - 1 )]; - for ( i = pos; i < m_numCols; i++ ) + int colPos; + for ( colPos = pos; colPos < m_numCols; colPos++ ) { + i = GetColAt( colPos ); + right += m_colWidths[i]; m_colRights[i] = right; } @@ -4792,6 +4950,19 @@ bool wxGrid::Redimension( wxGridTableMessage& msg ) int numCols = msg.GetCommandInt(); int oldNumCols = m_numCols; m_numCols += numCols; + + if ( !m_colAt.IsEmpty() ) + { + m_colAt.Add( 0, numCols ); + + //Set the new columns' positions + int i; + for ( i = oldNumCols; i < m_numCols; i++ ) + { + m_colAt[i] = i; + } + } + if ( !m_colWidths.IsEmpty() ) { m_colWidths.Add( m_defaultColWidth, numCols ); @@ -4799,10 +4970,13 @@ bool wxGrid::Redimension( wxGridTableMessage& msg ) int right = 0; if ( oldNumCols > 0 ) - right = m_colRights[oldNumCols - 1]; + right = m_colRights[GetColAt( oldNumCols - 1 )]; - for ( i = oldNumCols; i < m_numCols; i++ ) + int colPos; + for ( colPos = oldNumCols; colPos < m_numCols; colPos++ ) { + i = GetColAt( colPos ); + right += m_colWidths[i]; m_colRights[i] = right; } @@ -4830,14 +5004,32 @@ bool wxGrid::Redimension( wxGridTableMessage& msg ) int numCols = msg.GetCommandInt2(); m_numCols -= numCols; + if ( !m_colAt.IsEmpty() ) + { + int colID = GetColAt( pos ); + + m_colAt.RemoveAt( pos, numCols ); + + //Shift the column IDs + int colPos; + for ( colPos = 0; colPos < m_numCols; colPos++ ) + { + if ( m_colAt[colPos] > colID ) + m_colAt[colPos] -= numCols; + } + } + if ( !m_colWidths.IsEmpty() ) { m_colWidths.RemoveAt( pos, numCols ); m_colRights.RemoveAt( pos, numCols ); int w = 0; - for ( i = 0; i < m_numCols; i++ ) + int colPos; + for ( colPos = 0; colPos < m_numCols; colPos++ ) { + i = GetColAt( colPos ); + w += m_colWidths[i]; m_colRights[i] = w; } @@ -4888,7 +5080,7 @@ bool wxGrid::Redimension( wxGridTableMessage& msg ) return result; } -wxArrayInt wxGrid::CalcRowLabelsExposed( const wxRegion& reg ) +wxArrayInt wxGrid::CalcRowLabelsExposed( const wxRegion& reg ) const { wxRegionIterator iter( reg ); wxRect r; @@ -4939,7 +5131,7 @@ wxArrayInt wxGrid::CalcRowLabelsExposed( const wxRegion& reg ) return rowlabels; } -wxArrayInt wxGrid::CalcColLabelsExposed( const wxRegion& reg ) +wxArrayInt wxGrid::CalcColLabelsExposed( const wxRegion& reg ) const { wxRegionIterator iter( reg ); wxRect r; @@ -4973,8 +5165,11 @@ wxArrayInt wxGrid::CalcColLabelsExposed( const wxRegion& reg ) // find the cells within these bounds // int col; - for ( col = internalXToCol(left); col < m_numCols; col++ ) + int colPos; + for ( colPos = GetColPos( internalXToCol(left) ); colPos < m_numCols; colPos++ ) { + col = GetColAt( colPos ); + if ( GetColRight(col) < left ) continue; @@ -4990,7 +5185,7 @@ wxArrayInt wxGrid::CalcColLabelsExposed( const wxRegion& reg ) return colLabels; } -wxGridCellCoordsArray wxGrid::CalcCellsExposed( const wxRegion& reg ) +wxGridCellCoordsArray wxGrid::CalcCellsExposed( const wxRegion& reg ) const { wxRegionIterator iter( reg ); wxRect r; @@ -5032,8 +5227,11 @@ wxGridCellCoordsArray wxGrid::CalcCellsExposed( const wxRegion& reg ) if ( GetRowTop(row) > bottom ) break; - for ( col = internalXToCol(left); col < m_numCols; col++ ) + int colPos; + for ( colPos = GetColPos( internalXToCol(left) ); colPos < m_numCols; colPos++ ) { + col = GetColAt( colPos ); + if ( GetColRight(col) <= left ) continue; @@ -5281,6 +5479,9 @@ void wxGrid::ProcessColLabelMouseEvent( wxMouseEvent& event ) { m_isDragging = true; m_colLabelWin->CaptureMouse(); + + if ( m_cursorMode == WXGRID_CURSOR_MOVE_COL ) + m_dragRowOrCol = XToCol( x ); } if ( event.LeftIsDown() ) @@ -5324,6 +5525,63 @@ void wxGrid::ProcessColLabelMouseEvent( wxMouseEvent& event ) } break; + case WXGRID_CURSOR_MOVE_COL: + { + if ( x < 0 ) + m_moveToCol = GetColAt( 0 ); + else + m_moveToCol = XToCol( x ); + + int markerX; + + if ( m_moveToCol < 0 ) + markerX = GetColRight( GetColAt( m_numCols - 1 ) ); + else + markerX = GetColLeft( m_moveToCol ); + + if ( markerX != m_dragLastPos ) + { + wxClientDC dc( m_colLabelWin ); + + int cw, ch; + m_colLabelWin->GetClientSize( &cw, &ch ); + + markerX++; + + //Clean up the last indicator + if ( m_dragLastPos >= 0 ) + { + wxPen pen( m_colLabelWin->GetBackgroundColour(), 2 ); + dc.SetPen(pen); + dc.DrawLine( m_dragLastPos + 1, 0, m_dragLastPos + 1, ch ); + dc.SetPen(wxNullPen); + + if ( XToCol( m_dragLastPos ) != -1 ) + DrawColLabel( dc, XToCol( m_dragLastPos ) ); + } + + //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 ))) + { + m_dragLastPos = -1; + return; + } + + //Draw the marker + wxPen pen( *wxBLUE, 2 ); + dc.SetPen(pen); + + dc.DrawLine( markerX, 0, markerX, ch ); + + dc.SetPen(wxNullPen); + + m_dragLastPos = markerX - 1; + } + } + break; + // default label to suppress warnings about "enumeration value // 'xxx' not handled in switch default: @@ -5364,31 +5622,46 @@ void wxGrid::ProcessColLabelMouseEvent( wxMouseEvent& event ) if ( col >= 0 && !SendEvent( wxEVT_GRID_LABEL_LEFT_CLICK, -1, col, event ) ) { - if ( !event.ShiftDown() && !event.CmdDown() ) - ClearSelection(); - if ( m_selection ) + if ( m_canDragColMove ) { - if ( event.ShiftDown() ) - { - m_selection->SelectBlock( 0, - m_currentCellCoords.GetCol(), - GetNumberRows() - 1, col, - event.ControlDown(), - event.ShiftDown(), - event.AltDown(), - event.MetaDown() ); - } - else + //Show button as pressed + wxClientDC dc( m_colLabelWin ); + int colLeft = GetColLeft( col ); + int colRight = GetColRight( col ) - 1; + dc.SetPen( wxPen( m_colLabelWin->GetBackgroundColour(), 1 ) ); + dc.DrawLine( colLeft, 1, colLeft, m_colLabelHeight-1 ); + dc.DrawLine( colLeft, 1, colRight, 1 ); + + ChangeCursorMode(WXGRID_CURSOR_MOVE_COL, m_colLabelWin); + } + else + { + if ( !event.ShiftDown() && !event.CmdDown() ) + ClearSelection(); + if ( m_selection ) { - m_selection->SelectCol( col, - event.ControlDown(), - event.ShiftDown(), - event.AltDown(), - event.MetaDown() ); + if ( event.ShiftDown() ) + { + m_selection->SelectBlock( 0, + m_currentCellCoords.GetCol(), + GetNumberRows() - 1, col, + event.ControlDown(), + event.ShiftDown(), + event.AltDown(), + event.MetaDown() ); + } + else + { + m_selection->SelectCol( col, + event.ControlDown(), + event.ShiftDown(), + event.AltDown(), + event.MetaDown() ); + } } - } - ChangeCursorMode(WXGRID_CURSOR_SELECT_COL, m_colLabelWin); + ChangeCursorMode(WXGRID_CURSOR_SELECT_COL, m_colLabelWin); + } } } else @@ -5428,14 +5701,29 @@ void wxGrid::ProcessColLabelMouseEvent( wxMouseEvent& event ) // else if ( event.LeftUp() ) { - if ( m_cursorMode == WXGRID_CURSOR_RESIZE_COL ) + switch ( m_cursorMode ) { - DoEndDragResizeCol(); + 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 ); + // 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 ); + break; + + case WXGRID_CURSOR_SELECT_COL: + case WXGRID_CURSOR_SELECT_CELL: + case WXGRID_CURSOR_RESIZE_ROW: + case WXGRID_CURSOR_SELECT_ROW: + // nothing to do (?) + break; } ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL, m_colLabelWin); @@ -5519,6 +5807,21 @@ void wxGrid::ProcessCornerLabelMouseEvent( wxMouseEvent& event ) } } +void wxGrid::CancelMouseCapture() +{ + // cancel operation currently in progress, whatever it is + if ( m_winCapture ) + { + m_isDragging = false; + m_cursorMode = WXGRID_CURSOR_SELECT_CELL; + m_winCapture->SetCursor( *wxSTANDARD_CURSOR ); + m_winCapture = NULL; + + // remove traces of whatever we drew on screen + Refresh(); + } +} + void wxGrid::ChangeCursorMode(CursorMode mode, wxWindow *win, bool captureMouse) @@ -5530,7 +5833,8 @@ void wxGrid::ChangeCursorMode(CursorMode mode, _T("RESIZE_ROW"), _T("RESIZE_COL"), _T("SELECT_ROW"), - _T("SELECT_COL") + _T("SELECT_COL"), + _T("MOVE_COL"), }; wxLogTrace(_T("grid"), @@ -5571,6 +5875,10 @@ void wxGrid::ChangeCursorMode(CursorMode mode, win->SetCursor( m_colResizeCursor ); break; + case WXGRID_CURSOR_MOVE_COL: + win->SetCursor( wxCursor(wxCURSOR_HAND) ); + break; + default: win->SetCursor( *wxSTANDARD_CURSOR ); break; @@ -5633,13 +5941,6 @@ void wxGrid::ProcessGridCellMouseEvent( wxMouseEvent& event ) SaveEditControlValue(); } - // Have we captured the mouse yet? - if (! m_winCapture) - { - m_winCapture = m_gridWin; - m_winCapture->CaptureMouse(); - } - if ( coords != wxGridNoCellCoords ) { if ( event.CmdDown() ) @@ -5659,6 +5960,7 @@ void wxGrid::ProcessGridCellMouseEvent( wxMouseEvent& event ) coords.GetRow(), coords.GetCol(), event ); + return; } } else @@ -5680,6 +5982,14 @@ void wxGrid::ProcessGridCellMouseEvent( wxMouseEvent& event ) // scrolling is way to fast, at least on MSW - also on GTK. } } + // Have we captured the mouse yet? + if (! m_winCapture) + { + m_winCapture = m_gridWin; + m_winCapture->CaptureMouse(); + } + + } else if ( m_cursorMode == WXGRID_CURSOR_RESIZE_ROW ) { @@ -5950,7 +6260,7 @@ void wxGrid::ProcessGridCellMouseEvent( wxMouseEvent& event ) if ( m_cursorMode == WXGRID_CURSOR_SELECT_CELL ) { if ( CanDragRowSize() && CanDragGridSize() ) - ChangeCursorMode(WXGRID_CURSOR_RESIZE_ROW); + ChangeCursorMode(WXGRID_CURSOR_RESIZE_ROW, NULL, false); } } else if ( dragCol >= 0 ) @@ -5960,7 +6270,7 @@ void wxGrid::ProcessGridCellMouseEvent( wxMouseEvent& event ) if ( m_cursorMode == WXGRID_CURSOR_SELECT_CELL ) { if ( CanDragColSize() && CanDragGridSize() ) - ChangeCursorMode(WXGRID_CURSOR_RESIZE_COL); + ChangeCursorMode(WXGRID_CURSOR_RESIZE_COL, NULL, false); } } else // Neither on a row or col edge @@ -6093,6 +6403,112 @@ void wxGrid::DoEndDragResizeCol() } } +void wxGrid::DoEndDragMoveCol() +{ + //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; + } + + int newPos; + if ( m_moveToCol == -1 ) + newPos = m_numCols - 1; + else + { + newPos = GetColPos( m_moveToCol ); + if ( newPos > GetColPos( m_dragRowOrCol ) ) + newPos--; + } + + SetColPos( m_dragRowOrCol, newPos ); +} + +void wxGrid::SetColPos( int colID, int newPos ) +{ + if ( m_colAt.IsEmpty() ) + { + m_colAt.Alloc( m_numCols ); + + int i; + for ( i = 0; i < m_numCols; i++ ) + { + m_colAt.Add( i ); + } + } + + int oldPos = GetColPos( colID ); + + //Reshuffle the m_colAt array + if ( newPos > oldPos ) + { + int i; + for ( i = oldPos; i < newPos; i++ ) + { + m_colAt[i] = m_colAt[i+1]; + } + } + else + { + int i; + for ( i = oldPos; i > newPos; i-- ) + { + m_colAt[i] = m_colAt[i-1]; + } + } + + m_colAt[newPos] = colID; + + //Recalculate the column rights + if ( !m_colWidths.IsEmpty() ) + { + int colRight = 0; + int colPos; + for ( colPos = 0; colPos < m_numCols; colPos++ ) + { + int colID = GetColAt( colPos ); + + colRight += m_colWidths[colID]; + m_colRights[colID] = colRight; + } + } + + m_colLabelWin->Refresh(); + m_gridWin->Refresh(); +} + + + +void wxGrid::EnableDragColMove( bool enable ) +{ + if ( m_canDragColMove == enable ) + return; + + m_canDragColMove = enable; + + if ( !m_canDragColMove ) + { + m_colAt.Clear(); + + //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_colLabelWin->Refresh(); + m_gridWin->Refresh(); + } +} + + // // ------ interaction with data model // @@ -6325,6 +6741,32 @@ int wxGrid::SendEvent( const wxEventType type, claimed = GetEventHandler()->ProcessEvent(gridEvt); vetoed = !gridEvt.IsAllowed(); } + else if ( type == wxEVT_GRID_LABEL_LEFT_CLICK || + type == wxEVT_GRID_LABEL_LEFT_DCLICK || + type == wxEVT_GRID_LABEL_RIGHT_CLICK || + type == wxEVT_GRID_LABEL_RIGHT_DCLICK ) + { + wxPoint pos = mouseEv.GetPosition(); + + if ( mouseEv.GetEventObject() == GetGridRowLabelWindow() ) + pos.y += GetColLabelSize(); + if ( mouseEv.GetEventObject() == GetGridColLabelWindow() ) + pos.x += GetRowLabelSize(); + + wxGridEvent gridEvt( GetId(), + type, + this, + row, col, + pos.x, + pos.y, + false, + mouseEv.ControlDown(), + mouseEv.ShiftDown(), + mouseEv.AltDown(), + mouseEv.MetaDown() ); + claimed = GetEventHandler()->ProcessEvent(gridEvt); + vetoed = !gridEvt.IsAllowed(); + } else { wxGridEvent gridEvt( GetId(), @@ -6391,7 +6833,7 @@ void wxGrid::Refresh(bool eraseb, const wxRect* rect) { // Don't do anything if between Begin/EndBatch... // EndBatch() will do all this on the last nested one anyway. - if (! GetBatchCount()) + if ( m_created && !GetBatchCount() ) { // Refresh to get correct scrolled position: wxScrolledWindow::Refresh(eraseb, rect); @@ -6476,14 +6918,13 @@ void wxGrid::Refresh(bool eraseb, const wxRect* rect) } } -void wxGrid::OnSize( wxSizeEvent& event ) +void wxGrid::OnSize(wxSizeEvent& WXUNUSED(event)) { - // position the child windows - CalcWindowSizes(); - - // don't call CalcDimensions() from here, the base class handles the size - // changes itself - event.Skip(); + if (m_targetWindow != this) // check whether initialisation has been done + { + // update our children window positions and scrollbars + CalcDimensions(); + } } void wxGrid::OnKeyDown( wxKeyEvent& event ) @@ -6504,6 +6945,14 @@ void wxGrid::OnKeyDown( wxKeyEvent& event ) if ( !parent->GetEventHandler()->ProcessEvent( keyEvt ) ) { + if (GetLayoutDirection() == wxLayout_RightToLeft) + { + if (event.GetKeyCode() == WXK_RIGHT) + event.m_keyCode = WXK_LEFT; + else if (event.GetKeyCode() == WXK_LEFT) + event.m_keyCode = WXK_RIGHT; + } + // try local handlers switch ( event.GetKeyCode() ) { @@ -6731,8 +7180,10 @@ void wxGrid::SetCurrentCell( const wxGridCellCoords& coords ) return; } +#if !defined(__WXMAC__) wxClientDC dc( m_gridWin ); PrepareDC( dc ); +#endif if ( m_currentCellCoords != wxGridNoCellCoords ) { @@ -6755,15 +7206,21 @@ void wxGrid::SetCurrentCell( const wxGridCellCoords& coords ) // Otherwise refresh redraws the highlight! m_currentCellCoords = coords; +#if defined(__WXMAC__) + m_gridWin->Refresh(true /*, & r */); +#else DrawGridCellArea( dc, cells ); DrawAllGridLines( dc, r ); +#endif } } m_currentCellCoords = coords; wxGridCellAttr *attr = GetCellAttr( coords ); +#if !defined(__WXMAC__) DrawCellHighlight( dc, attr ); +#endif attr->DecRef(); } @@ -7088,7 +7545,7 @@ void wxGrid::DrawGridSpace( wxDC& dc ) int right, bottom; CalcUnscrolledPosition( cw, ch, &right, &bottom ); - int rightCol = m_numCols > 0 ? GetColRight(m_numCols - 1) : 0; + int rightCol = m_numCols > 0 ? GetColRight(GetColAt( m_numCols - 1 )) : 0; int bottomRow = m_numRows > 0 ? GetRowBottom(m_numRows - 1) : 0; if ( right > rightCol || bottom > bottomRow ) @@ -7096,7 +7553,7 @@ void wxGrid::DrawGridSpace( wxDC& dc ) int left, top; CalcUnscrolledPosition( 0, 0, &left, &top ); - dc.SetBrush( wxBrush(GetDefaultCellBackgroundColour(), wxSOLID) ); + dc.SetBrush( wxBrush(GetDefaultCellBackgroundColour(), wxBRUSHSTYLE_SOLID) ); dc.SetPen( *wxTRANSPARENT_PEN ); if ( right > rightCol ) @@ -7139,7 +7596,7 @@ void wxGrid::DrawCell( wxDC& dc, const wxGridCellCoords& coords ) // edit control is erased by this code after being rendered. // On wxMac (QD build only), the cell editor is a wxTextCntl and is rendered // implicitly, causing this out-of order render. -#if !defined(__WXMAC__) || wxMAC_USE_CORE_GRAPHICS +#if !defined(__WXMAC__) wxGridCellEditor *editor = attr->GetEditor(this, row, col); editor->PaintBackground(rect, attr); editor->DecRef(); @@ -7158,6 +7615,10 @@ void wxGrid::DrawCell( wxDC& dc, const wxGridCellCoords& coords ) void wxGrid::DrawCellHighlight( wxDC& dc, const wxGridCellAttr *attr ) { + // don't show highlight when the grid doesn't have focus + if ( !HasFocus() ) + return; + int row = m_currentCellCoords.GetRow(); int col = m_currentCellCoords.GetCol(); @@ -7187,7 +7648,7 @@ void wxGrid::DrawCellHighlight( wxDC& dc, const wxGridCellAttr *attr ) // Now draw the rectangle // use the cellHighlightColour if the cell is inside a selection, this // will ensure the cell is always visible. - dc.SetPen(wxPen(IsInSelection(row,col) ? m_selectionForeground : m_cellHighlightColour, penWidth, wxSOLID)); + dc.SetPen(wxPen(IsInSelection(row,col) ? m_selectionForeground : m_cellHighlightColour, penWidth, wxPENSTYLE_SOLID)); dc.SetBrush(*wxTRANSPARENT_BRUSH); dc.DrawRectangle(rect); } @@ -7214,6 +7675,21 @@ void wxGrid::DrawCellHighlight( wxDC& dc, const wxGridCellAttr *attr ) #endif } +wxPen wxGrid::GetDefaultGridLinePen() +{ + return wxPen(GetGridLineColour(), 1, wxPENSTYLE_SOLID); +} + +wxPen wxGrid::GetRowGridLinePen(int WXUNUSED(row)) +{ + return GetDefaultGridLinePen(); +} + +wxPen wxGrid::GetColGridLinePen(int WXUNUSED(col)) +{ + return GetDefaultGridLinePen(); +} + void wxGrid::DrawCellBorder( wxDC& dc, const wxGridCellCoords& coords ) { int row = coords.GetRow(); @@ -7221,15 +7697,16 @@ void wxGrid::DrawCellBorder( wxDC& dc, const wxGridCellCoords& coords ) if ( GetColWidth(col) <= 0 || GetRowHeight(row) <= 0 ) return; - dc.SetPen( wxPen(GetGridLineColour(), 1, wxSOLID) ); wxRect rect = CellToRect( row, col ); // right hand border + dc.SetPen( GetColGridLinePen(col) ); dc.DrawLine( rect.x + rect.width, rect.y, rect.x + rect.width, rect.y + rect.height + 1 ); // bottom border + dc.SetPen( GetRowGridLinePen(row) ); dc.DrawLine( rect.x, rect.y + rect.height, rect.x + rect.width, rect.y + rect.height); } @@ -7309,26 +7786,27 @@ void wxGrid::DrawAllGridLines( wxDC& dc, const wxRegion & WXUNUSED(reg) ) // avoid drawing grid lines past the last row and col // - right = wxMin( right, GetColRight(m_numCols - 1) ); + right = wxMin( right, GetColRight(GetColAt( m_numCols - 1 )) ); bottom = wxMin( bottom, GetRowBottom(m_numRows - 1) ); // no gridlines inside multicells, clip them out - int leftCol = internalXToCol(left); + int leftCol = GetColPos( internalXToCol(left) ); int topRow = internalYToRow(top); - int rightCol = internalXToCol(right); + int rightCol = GetColPos( internalXToCol(right) ); int bottomRow = internalYToRow(bottom); -#ifndef __WXMAC__ - // CS: I don't know why suddenly unscrolled coordinates are used for clipping wxRegion clippedcells(0, 0, cw, ch); int i, j, cell_rows, cell_cols; wxRect rect; - for (j=topRow; j 1) || (cell_cols > 1)) { @@ -7344,34 +7822,9 @@ void wxGrid::DrawAllGridLines( wxDC& dc, const wxRegion & WXUNUSED(reg) ) } } } -#else - wxRegion clippedcells( left, top, right - left, bottom - top ); - int i, j, cell_rows, cell_cols; - wxRect rect; + dc.SetDeviceClippingRegion( clippedcells ); - for (j=topRow; j 1) || (cell_cols > 1)) - { - rect = CellToRect(j, i); - clippedcells.Subtract(rect); - } - else if ((cell_rows < 0) || (cell_cols < 0)) - { - rect = CellToRect(j + cell_rows, i + cell_cols); - clippedcells.Subtract(rect); - } - } - } -#endif - - dc.SetClippingRegion( clippedcells ); - - dc.SetPen( wxPen(GetGridLineColour(), 1, wxSOLID) ); // horizontal grid lines // @@ -7387,15 +7840,24 @@ void wxGrid::DrawAllGridLines( wxDC& dc, const wxRegion & WXUNUSED(reg) ) if ( bot >= top ) { + dc.SetPen( GetRowGridLinePen(i) ); dc.DrawLine( left, bot, right, bot ); } } // vertical grid lines // - for ( i = internalXToCol(left); i < m_numCols; i++ ) + int colPos; + for ( colPos = leftCol; colPos < m_numCols; colPos++ ) { - int colRight = GetColRight(i) - 1; + i = GetColAt( colPos ); + + int colRight = GetColRight(i); +#ifdef __WXGTK__ + if (GetLayoutDirection() != wxLayout_RightToLeft) +#endif + colRight--; + if ( colRight > right ) { break; @@ -7403,6 +7865,7 @@ void wxGrid::DrawAllGridLines( wxDC& dc, const wxRegion & WXUNUSED(reg) ) if ( colRight >= left ) { + dc.SetPen( GetColGridLinePen(i) ); dc.DrawLine( colRight, top, colRight, bottom ); } } @@ -7431,22 +7894,10 @@ void wxGrid::DrawRowLabel( wxDC& dc, int row ) wxRect rect; -#ifdef __WXGTK20__ - rect.SetX( 1 ); - rect.SetY( GetRowTop(row) + 1 ); - rect.SetWidth( m_rowLabelWidth - 2 ); - rect.SetHeight( GetRowHeight(row) - 2 ); - - CalcScrolledPosition( 0, rect.y, NULL, &rect.y ); - - wxWindowDC *win_dc = (wxWindowDC*) &dc; - - wxRendererNative::Get().DrawHeaderButton( win_dc->m_owner, dc, rect, 0 ); -#else int rowTop = GetRowTop(row), rowBottom = GetRowBottom(row) - 1; - dc.SetPen( wxPen(wxSystemSettings::GetColour(wxSYS_COLOUR_3DDKSHADOW), 1, wxSOLID) ); + dc.SetPen( wxPen(wxSystemSettings::GetColour(wxSYS_COLOUR_3DSHADOW), 1, wxPENSTYLE_SOLID) ); dc.DrawLine( m_rowLabelWidth - 1, rowTop, m_rowLabelWidth - 1, rowBottom ); dc.DrawLine( 0, rowTop, 0, rowBottom ); dc.DrawLine( 0, rowBottom, m_rowLabelWidth, rowBottom ); @@ -7454,9 +7905,8 @@ void wxGrid::DrawRowLabel( wxDC& dc, int row ) dc.SetPen( *wxWHITE_PEN ); dc.DrawLine( 1, rowTop, 1, rowBottom ); dc.DrawLine( 1, rowTop, m_rowLabelWidth - 1, rowTop ); -#endif - dc.SetBackgroundMode( wxTRANSPARENT ); + dc.SetBackgroundMode( wxBRUSHSTYLE_TRANSPARENT ); dc.SetTextForeground( GetLabelTextColour() ); dc.SetFont( GetLabelFont() ); @@ -7470,6 +7920,18 @@ void wxGrid::DrawRowLabel( wxDC& dc, int row ) DrawTextRectangle( dc, GetRowLabelValue( row ), rect, hAlign, vAlign ); } +void wxGrid::SetUseNativeColLabels( bool native ) +{ + m_nativeColumnLabels = native; + if (native) + { + int height = wxRendererNative::Get().GetHeaderButtonHeight( this ); + SetColLabelSize( height ); + } + + m_colLabelWin->Refresh(); +} + void wxGrid::DrawColLabels( wxDC& dc,const wxArrayInt& cols ) { if ( !m_numCols ) @@ -7493,30 +7955,32 @@ void wxGrid::DrawColLabel( wxDC& dc, int col ) wxRect rect; -#ifdef __WXGTK20__ - rect.SetX( colLeft + 1 ); - rect.SetY( 1 ); - rect.SetWidth( GetColWidth(col) - 2 ); - rect.SetHeight( m_colLabelHeight - 2 ); - - wxWindowDC *win_dc = (wxWindowDC*) &dc; + if (m_nativeColumnLabels) + { + rect.SetX( colLeft); + rect.SetY( 0 ); + rect.SetWidth( GetColWidth(col)); + rect.SetHeight( m_colLabelHeight ); - wxRendererNative::Get().DrawHeaderButton( win_dc->m_owner, dc, rect, 0 ); -#else - int colRight = GetColRight(col) - 1; + wxWindowDC *win_dc = (wxWindowDC*) &dc; + wxRendererNative::Get().DrawHeaderButton( win_dc->GetWindow(), dc, rect, 0 ); + } + else + { + int colRight = GetColRight(col) - 1; - dc.SetPen( wxPen(wxSystemSettings::GetColour(wxSYS_COLOUR_3DDKSHADOW), 1, wxSOLID) ); - dc.DrawLine( colRight, 0, colRight, m_colLabelHeight - 1 ); - dc.DrawLine( colLeft, 0, colRight, 0 ); - dc.DrawLine( colLeft, m_colLabelHeight - 1, + dc.SetPen( wxPen(wxSystemSettings::GetColour(wxSYS_COLOUR_3DSHADOW), 1, wxPENSTYLE_SOLID) ); + dc.DrawLine( colRight, 0, colRight, m_colLabelHeight - 1 ); + dc.DrawLine( colLeft, 0, colRight, 0 ); + dc.DrawLine( colLeft, m_colLabelHeight - 1, colRight + 1, m_colLabelHeight - 1 ); - dc.SetPen( *wxWHITE_PEN ); - dc.DrawLine( colLeft, 1, colLeft, m_colLabelHeight - 1 ); - dc.DrawLine( colLeft, 1, colRight, 1 ); -#endif + dc.SetPen( *wxWHITE_PEN ); + dc.DrawLine( colLeft, 1, colLeft, m_colLabelHeight - 1 ); + dc.DrawLine( colLeft, 1, colRight, 1 ); + } - dc.SetBackgroundMode( wxTRANSPARENT ); + dc.SetBackgroundMode( wxBRUSHSTYLE_TRANSPARENT ); dc.SetTextForeground( GetLabelTextColour() ); dc.SetFont( GetLabelFont() ); @@ -7612,8 +8076,8 @@ void wxGrid::DrawTextRectangle(wxDC& dc, continue; } - long lineWidth, - lineHeight; + wxCoord lineWidth = 0, + lineHeight = 0; dc.GetTextExtent(line, &lineWidth, &lineHeight); switch ( horizAlign ) @@ -7657,7 +8121,8 @@ void wxGrid::DrawTextRectangle(wxDC& dc, // Split multi-line text up into an array of strings. // Any existing contents of the string array are preserved. // -void wxGrid::StringToLines( const wxString& value, wxArrayString& lines ) +// TODO: refactor wxTextFile::Read() and reuse the same code from here +void wxGrid::StringToLines( const wxString& value, wxArrayString& lines ) const { int startPos = 0; int pos; @@ -7677,25 +8142,25 @@ void wxGrid::StringToLines( const wxString& value, wxArrayString& lines ) } else { - lines.Add( value.Mid(startPos, pos) ); + lines.Add( tVal.Mid(startPos, pos) ); } startPos += pos + 1; } - if ( startPos < (int)value.length() ) + if ( startPos < (int)tVal.length() ) { - lines.Add( value.Mid( startPos ) ); + lines.Add( tVal.Mid( startPos ) ); } } void wxGrid::GetTextBoxSize( const wxDC& dc, const wxArrayString& lines, - long *width, long *height ) + long *width, long *height ) const { - long w = 0; - long h = 0; - long lineW = 0, lineH = 0; + wxCoord w = 0; + wxCoord h = 0; + wxCoord lineW = 0, lineH = 0; size_t i; for ( i = 0; i < lines.GetCount(); i++ ) @@ -7874,23 +8339,21 @@ void wxGrid::ShowCellEditControl() m_currentCellCoords.SetCol( col ); } - // convert to scrolled coords - CalcScrolledPosition( rect.x, rect.y, &rect.x, &rect.y ); - - int nXMove = 0; - if (rect.x < 0) - nXMove = rect.x; - - // performed 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)); + wxGridCellAttr* attr = GetCellAttr(row, col); + dc.SetBrush(wxBrush(attr->GetBackgroundColour(), wxBRUSHSTYLE_SOLID)); dc.SetPen(*wxTRANSPARENT_PEN); dc.DrawRectangle(rect); -#endif + + // convert to scrolled coords + CalcScrolledPosition( rect.x, rect.y, &rect.x, &rect.y ); + + int nXMove = 0; + if (rect.x < 0) + nXMove = rect.x; // cell is shifted by one pixel // However, don't allow x or y to become negative @@ -7901,7 +8364,6 @@ void wxGrid::ShowCellEditControl() if (rect.y > 0) rect.y--; - wxGridCellAttr* attr = GetCellAttr(row, col); wxGridCellEditor* editor = attr->GetEditor(this, row, col); if ( !editor->IsCreated() ) { @@ -7963,19 +8425,6 @@ void wxGrid::ShowCellEditControl() editor->GetControl()->GetPosition().y ); editor->Show( true, attr ); - int colXPos = GetColLeft(col); -// for (int i = 0; i < m_currentCellCoords.GetCol(); i++) -// { -// colXPos += GetColSize( i ); -// } - -// int xUnit = 1, yUnit = 1; -// GetScrollPixelsPerUnit( &xUnit, &yUnit ); -// if (col != 0) -// Scroll( colXPos / xUnit - 1, GetScrollPos( wxVERTICAL ) ); -// else -// Scroll( colXPos / xUnit, GetScrollPos( wxVERTICAL ) ); - // recalc dimensions in case we need to // expand the scrolled window to account for editor CalcDimensions(); @@ -8054,7 +8503,7 @@ void wxGrid::SaveEditControlValue() // coordinates for mouse events etc. // -void wxGrid::XYToCell( int x, int y, wxGridCellCoords& coords ) +void wxGrid::XYToCell( int x, int y, wxGridCellCoords& coords ) const { int row = YToRow(y); int col = XToCol(x); @@ -8136,27 +8585,89 @@ static int CoordToRowOrCol(int coord, int defaultDist, int minDist, return i_max; } -int wxGrid::YToRow( int y ) +int wxGrid::YToRow( int y ) const { return CoordToRowOrCol(y, m_defaultRowHeight, m_minAcceptableRowHeight, m_rowBottoms, m_numRows, false); } -int wxGrid::XToCol( int x ) +int wxGrid::XToCol( int x, bool clipToMinMax ) const { - return CoordToRowOrCol(x, m_defaultColWidth, - m_minAcceptableColWidth, m_colRights, m_numCols, false); + if (x < 0) + return clipToMinMax && (m_numCols > 0) ? GetColAt( 0 ) : -1; + + wxASSERT_MSG(m_defaultColWidth > 0, wxT("Default column width can not be zero")); + + int maxPos = x / m_defaultColWidth; + int minPos = 0; + + if (m_colRights.IsEmpty()) + { + if(maxPos < m_numCols) + return GetColAt( maxPos ); + return clipToMinMax ? GetColAt( m_numCols - 1 ) : -1; + } + + if ( maxPos >= m_numCols) + maxPos = m_numCols - 1; + else + { + if ( x >= m_colRights[GetColAt( maxPos )]) + { + minPos = maxPos; + if (m_minAcceptableColWidth) + maxPos = x / m_minAcceptableColWidth; + else + maxPos = m_numCols - 1; + } + if ( maxPos >= m_numCols) + maxPos = m_numCols - 1; + } + + //X is beyond the last column + if ( x >= m_colRights[GetColAt( maxPos )]) + return clipToMinMax ? GetColAt( maxPos ) : -1; + + //X is before the first column + if ( x < m_colRights[GetColAt( 0 )] ) + return GetColAt( 0 ); + + //Perform a binary search + while ( maxPos - minPos > 0 ) + { + wxCHECK_MSG(m_colRights[GetColAt( minPos )] <= x && x < m_colRights[GetColAt( maxPos )], + 0, _T("wxGrid: internal error in XToCol")); + + if (x >= m_colRights[GetColAt( maxPos - 1 )]) + return GetColAt( maxPos ); + else + maxPos--; + int median = minPos + (maxPos - minPos + 1) / 2; + if (x < m_colRights[GetColAt( median )]) + maxPos = median; + else + minPos = median; + } + return GetColAt( maxPos ); } -// return the row number that that the y coord is near the edge of, or -// -1 if not near an edge +// return the row number that that the y coord is near +// the edge of, or -1 if not near an edge. +// coords can only possibly be near an edge if +// (a) the row/column is large enough to still allow for an "inner" area +// that is _not_ nead the edge (i.e., if the height/width is smaller +// than WXGRID_LABEL_EDGE_ZONE, coords are _never_ considered to be +// near the edge). +// and +// (b) resizing rows/columns (the thing for which edge detection is +// relevant at all) is enabled. // -int wxGrid::YToEdgeOfRow( int y ) +int wxGrid::YToEdgeOfRow( int y ) const { int i; i = internalYToRow(y); - if ( GetRowHeight(i) > WXGRID_LABEL_EDGE_ZONE ) + if ( GetRowHeight(i) > WXGRID_LABEL_EDGE_ZONE && CanDragRowSize() ) { // We know that we are in row i, test whether we are // close enough to lower or upper border, respectively. @@ -8171,13 +8682,14 @@ int wxGrid::YToEdgeOfRow( int y ) // return the col number that that the x coord is near the edge of, or // -1 if not near an edge +// See comment at YToEdgeOfRow for conditions on edge detection. // -int wxGrid::XToEdgeOfCol( int x ) +int wxGrid::XToEdgeOfCol( int x ) const { int i; i = internalXToCol(x); - if ( GetColWidth(i) > WXGRID_LABEL_EDGE_ZONE ) + if ( GetColWidth(i) > WXGRID_LABEL_EDGE_ZONE && CanDragColSize() ) { // We know that we are in column i; test whether we are // close enough to right or left border, respectively. @@ -8190,7 +8702,7 @@ int wxGrid::XToEdgeOfCol( int x ) return -1; } -wxRect wxGrid::CellToRect( int row, int col ) +wxRect wxGrid::CellToRect( int row, int col ) const { wxRect rect( -1, -1, -1, -1 ); @@ -8225,7 +8737,7 @@ wxRect wxGrid::CellToRect( int row, int col ) return rect; } -bool wxGrid::IsVisible( int row, int col, bool wholeCellVisible ) +bool wxGrid::IsVisible( int row, int col, bool wholeCellVisible ) const { // get the cell rectangle in logical coords // @@ -8425,11 +8937,12 @@ bool wxGrid::MoveCursorLeft( bool expandSelection ) HighlightBlock( m_currentCellCoords, m_selectingKeyboard ); } } - else if ( m_currentCellCoords.GetCol() > 0 ) + else if ( GetColPos( m_currentCellCoords.GetCol() ) > 0 ) { int row = m_currentCellCoords.GetRow(); - int col = m_currentCellCoords.GetCol() - 1; + int col = GetColAt( GetColPos( m_currentCellCoords.GetCol() ) - 1 ); ClearSelection(); + MakeCellVisible( row, col ); SetCurrentCell( row, col ); } @@ -8459,11 +8972,12 @@ bool wxGrid::MoveCursorRight( bool expandSelection ) HighlightBlock( m_currentCellCoords, m_selectingKeyboard ); } } - else if ( m_currentCellCoords.GetCol() < m_numCols - 1 ) + else if ( GetColPos( m_currentCellCoords.GetCol() ) < m_numCols - 1 ) { int row = m_currentCellCoords.GetRow(); - int col = m_currentCellCoords.GetCol() + 1; + int col = GetColAt( GetColPos( m_currentCellCoords.GetCol() ) + 1 ); ClearSelection(); + MakeCellVisible( row, col ); SetCurrentCell( row, col ); } @@ -8801,7 +9315,7 @@ bool wxGrid::MoveCursorRightBlock( bool expandSelection ) // ------ Label values and formatting // -void wxGrid::GetRowLabelAlignment( int *horiz, int *vert ) +void wxGrid::GetRowLabelAlignment( int *horiz, int *vert ) const { if ( horiz ) *horiz = m_rowLabelHorizAlign; @@ -8809,7 +9323,7 @@ void wxGrid::GetRowLabelAlignment( int *horiz, int *vert ) *vert = m_rowLabelVertAlign; } -void wxGrid::GetColLabelAlignment( int *horiz, int *vert ) +void wxGrid::GetColLabelAlignment( int *horiz, int *vert ) const { if ( horiz ) *horiz = m_colLabelHorizAlign; @@ -8817,12 +9331,12 @@ void wxGrid::GetColLabelAlignment( int *horiz, int *vert ) *vert = m_colLabelVertAlign; } -int wxGrid::GetColLabelTextOrientation() +int wxGrid::GetColLabelTextOrientation() const { return m_colLabelTextOrientation; } -wxString wxGrid::GetRowLabelValue( int row ) +wxString wxGrid::GetRowLabelValue( int row ) const { if ( m_table ) { @@ -8836,7 +9350,7 @@ wxString wxGrid::GetRowLabelValue( int row ) } } -wxString wxGrid::GetColLabelValue( int col ) +wxString wxGrid::GetColLabelValue( int col ) const { if ( m_table ) { @@ -8852,7 +9366,13 @@ wxString wxGrid::GetColLabelValue( int col ) void wxGrid::SetRowLabelSize( int width ) { - width = wxMax( width, 0 ); + wxASSERT( width >= 0 || width == wxGRID_AUTOSIZE ); + + if ( width == wxGRID_AUTOSIZE ) + { + width = CalcColOrRowLabelAreaMinSize(wxGRID_ROW); + } + if ( width != m_rowLabelWidth ) { if ( width == 0 ) @@ -8875,7 +9395,13 @@ void wxGrid::SetRowLabelSize( int width ) void wxGrid::SetColLabelSize( int height ) { - height = wxMax( height, 0 ); + wxASSERT( height >=0 || height == wxGRID_AUTOSIZE ); + + if ( height == wxGRID_AUTOSIZE ) + { + height = CalcColOrRowLabelAreaMinSize(wxGRID_COLUMN); + } + if ( height != m_colLabelHeight ) { if ( height == 0 ) @@ -9093,7 +9619,7 @@ void wxGrid::SetCellHighlightPenWidth(int width) // make any visible change if the the thickness is getting smaller. int row = m_currentCellCoords.GetRow(); int col = m_currentCellCoords.GetCol(); - if ( GetColWidth(col) <= 0 || GetRowHeight(row) <= 0 ) + if ( row == -1 || col == -1 || GetColWidth(col) <= 0 || GetRowHeight(row) <= 0 ) return; wxRect rect = CellToRect(row, col); @@ -9111,7 +9637,8 @@ void wxGrid::SetCellHighlightROPenWidth(int width) // make any visible change if the the thickness is getting smaller. int row = m_currentCellCoords.GetRow(); int col = m_currentCellCoords.GetCol(); - if ( GetColWidth(col) <= 0 || GetRowHeight(row) <= 0 ) + if ( row == -1 || col == -1 || + GetColWidth(col) <= 0 || GetRowHeight(row) <= 0 ) return; wxRect rect = CellToRect(row, col); @@ -9141,24 +9668,24 @@ void wxGrid::EnableGridLines( bool enable ) } } -int wxGrid::GetDefaultRowSize() +int wxGrid::GetDefaultRowSize() const { return m_defaultRowHeight; } -int wxGrid::GetRowSize( int row ) +int wxGrid::GetRowSize( int row ) const { wxCHECK_MSG( row >= 0 && row < m_numRows, 0, _T("invalid row index") ); return GetRowHeight(row); } -int wxGrid::GetDefaultColSize() +int wxGrid::GetDefaultColSize() const { return m_defaultColWidth; } -int wxGrid::GetColSize( int col ) +int wxGrid::GetColSize( int col ) const { wxCHECK_MSG( col >= 0 && col < m_numCols, 0, _T("invalid column index") ); @@ -9222,30 +9749,30 @@ void wxGrid::SetDefaultEditor(wxGridCellEditor *editor) } // ---------------------------------------------------------------------------- -// access to the default attrbiutes +// access to the default attributes // ---------------------------------------------------------------------------- -wxColour wxGrid::GetDefaultCellBackgroundColour() +wxColour wxGrid::GetDefaultCellBackgroundColour() const { return m_defaultCellAttr->GetBackgroundColour(); } -wxColour wxGrid::GetDefaultCellTextColour() +wxColour wxGrid::GetDefaultCellTextColour() const { return m_defaultCellAttr->GetTextColour(); } -wxFont wxGrid::GetDefaultCellFont() +wxFont wxGrid::GetDefaultCellFont() const { return m_defaultCellAttr->GetFont(); } -void wxGrid::GetDefaultCellAlignment( int *horiz, int *vert ) +void wxGrid::GetDefaultCellAlignment( int *horiz, int *vert ) const { m_defaultCellAttr->GetAlignment(horiz, vert); } -bool wxGrid::GetDefaultCellOverflow() +bool wxGrid::GetDefaultCellOverflow() const { return m_defaultCellAttr->GetOverflow(); } @@ -9264,7 +9791,7 @@ wxGridCellEditor *wxGrid::GetDefaultEditor() const // access to cell attributes // ---------------------------------------------------------------------------- -wxColour wxGrid::GetCellBackgroundColour(int row, int col) +wxColour wxGrid::GetCellBackgroundColour(int row, int col) const { wxGridCellAttr *attr = GetCellAttr(row, col); wxColour colour = attr->GetBackgroundColour(); @@ -9273,7 +9800,7 @@ wxColour wxGrid::GetCellBackgroundColour(int row, int col) return colour; } -wxColour wxGrid::GetCellTextColour( int row, int col ) +wxColour wxGrid::GetCellTextColour( int row, int col ) const { wxGridCellAttr *attr = GetCellAttr(row, col); wxColour colour = attr->GetTextColour(); @@ -9282,7 +9809,7 @@ wxColour wxGrid::GetCellTextColour( int row, int col ) return colour; } -wxFont wxGrid::GetCellFont( int row, int col ) +wxFont wxGrid::GetCellFont( int row, int col ) const { wxGridCellAttr *attr = GetCellAttr(row, col); wxFont font = attr->GetFont(); @@ -9291,14 +9818,14 @@ wxFont wxGrid::GetCellFont( int row, int col ) return font; } -void wxGrid::GetCellAlignment( int row, int col, int *horiz, int *vert ) +void wxGrid::GetCellAlignment( int row, int col, int *horiz, int *vert ) const { wxGridCellAttr *attr = GetCellAttr(row, col); attr->GetAlignment(horiz, vert); attr->DecRef(); } -bool wxGrid::GetCellOverflow( int row, int col ) +bool wxGrid::GetCellOverflow( int row, int col ) const { wxGridCellAttr *attr = GetCellAttr(row, col); bool allow = attr->GetOverflow(); @@ -9307,14 +9834,14 @@ bool wxGrid::GetCellOverflow( int row, int col ) return allow; } -void wxGrid::GetCellSize( int row, int col, int *num_rows, int *num_cols ) +void wxGrid::GetCellSize( int row, int col, int *num_rows, int *num_cols ) const { wxGridCellAttr *attr = GetCellAttr(row, col); attr->GetSize( num_rows, num_cols ); attr->DecRef(); } -wxGridCellRenderer* wxGrid::GetCellRenderer(int row, int col) +wxGridCellRenderer* wxGrid::GetCellRenderer(int row, int col) const { wxGridCellAttr* attr = GetCellAttr(row, col); wxGridCellRenderer* renderer = attr->GetRenderer(this, row, col); @@ -9323,7 +9850,7 @@ wxGridCellRenderer* wxGrid::GetCellRenderer(int row, int col) return renderer; } -wxGridCellEditor* wxGrid::GetCellEditor(int row, int col) +wxGridCellEditor* wxGrid::GetCellEditor(int row, int col) const { wxGridCellAttr* attr = GetCellAttr(row, col); wxGridCellEditor* editor = attr->GetEditor(this, row, col); @@ -9345,7 +9872,7 @@ bool wxGrid::IsReadOnly(int row, int col) const // attribute support: cache, automatic provider creation, ... // ---------------------------------------------------------------------------- -bool wxGrid::CanHaveAttributes() +bool wxGrid::CanHaveAttributes() const { if ( !m_table ) { @@ -9699,10 +10226,7 @@ wxGridCellEditor * wxGrid::GetDefaultEditorForType(const wxString& typeName) con int index = m_typeRegistry->FindOrCloneDataType(typeName); if ( index == wxNOT_FOUND ) { - wxString errStr; - - errStr.Printf(wxT("Unknown data type name [%s]"), typeName.c_str()); - wxFAIL_MSG(errStr.c_str()); + wxFAIL_MSG(wxString::Format(wxT("Unknown data type name [%s]"), typeName.c_str())); return NULL; } @@ -9715,10 +10239,7 @@ wxGridCellRenderer * wxGrid::GetDefaultRendererForType(const wxString& typeName) int index = m_typeRegistry->FindOrCloneDataType(typeName); if ( index == wxNOT_FOUND ) { - wxString errStr; - - errStr.Printf(wxT("Unknown data type name [%s]"), typeName.c_str()); - wxFAIL_MSG(errStr.c_str()); + wxFAIL_MSG(wxString::Format(wxT("Unknown data type name [%s]"), typeName.c_str())); return NULL; } @@ -9785,8 +10306,7 @@ void wxGrid::SetRowSize( int row, int height ) int diff = h - m_rowHeights[row]; m_rowHeights[row] = h; - int i; - for ( i = row; i < m_numRows; i++ ) + for ( int i = row; i < m_numRows; i++ ) { m_rowBottoms[i] += diff; } @@ -9797,7 +10317,8 @@ void wxGrid::SetRowSize( int row, int height ) void wxGrid::SetDefaultColSize( int width, bool resizeExistingCols ) { - m_defaultColWidth = wxMax( width, m_minAcceptableColWidth ); + // we dont allow zero default column width + m_defaultColWidth = wxMax( wxMax( width, m_minAcceptableColWidth ), 1 ); if ( resizeExistingCols ) { @@ -9819,7 +10340,7 @@ void wxGrid::SetColSize( int col, int width ) // 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 whe should test against the weaker + // 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 @@ -9849,10 +10370,9 @@ void wxGrid::SetColSize( int col, int width ) int diff = w - m_colWidths[col]; m_colWidths[col] = w; - int i; - for ( i = col; i < m_numCols; i++ ) + for ( int colPos = GetColPos(col); colPos < m_numCols; colPos++ ) { - m_colRights[i] += diff; + m_colRights[GetColAt(colPos)] += diff; } if ( !GetBatchCount() ) @@ -9923,8 +10443,11 @@ int wxGrid::GetRowMinimalAcceptableHeight() const // auto sizing // ---------------------------------------------------------------------------- -void wxGrid::AutoSizeColOrRow( int colOrRow, bool setAsMin, bool column ) +void +wxGrid::AutoSizeColOrRow(int colOrRow, bool setAsMin, wxGridDirection direction) { + const bool column = direction == wxGRID_COLUMN; + wxClientDC dc(m_gridWin); // cancel editing of cell @@ -9969,12 +10492,12 @@ void wxGrid::AutoSizeColOrRow( int colOrRow, bool setAsMin, bool column ) if ( column ) { - dc.GetTextExtent( GetColLabelValue(col), &w, &h ); + dc.GetMultiLineTextExtent( GetColLabelValue(col), &w, &h ); if ( GetColLabelTextOrientation() == wxVERTICAL ) w = h; } else - dc.GetTextExtent( GetRowLabelValue(row), &w, &h ); + dc.GetMultiLineTextExtent( GetRowLabelValue(row), &w, &h ); extent = column ? w : h; if ( extent > extentMax ) @@ -9997,6 +10520,12 @@ void wxGrid::AutoSizeColOrRow( int colOrRow, bool setAsMin, bool column ) if ( column ) { + // Ensure automatic width is not less than minimal width. See the + // comment in SetColSize() for explanation of why this isn't done + // in SetColSize(). + if ( !setAsMin ) + extentMax = wxMax(extentMax, GetColMinimalWidth(col)); + SetColSize( col, extentMax ); if ( !GetBatchCount() ) { @@ -10012,6 +10541,12 @@ void wxGrid::AutoSizeColOrRow( int colOrRow, bool setAsMin, bool column ) } else { + // Ensure automatic width is not less than minimal height. See the + // comment in SetColSize() for explanation of why this isn't done + // in SetRowSize(). + if ( !setAsMin ) + extentMax = wxMax(extentMax, GetRowMinimalHeight(row)); + SetRowSize(row, extentMax); if ( !GetBatchCount() ) { @@ -10035,12 +10570,66 @@ void wxGrid::AutoSizeColOrRow( int colOrRow, bool setAsMin, bool column ) } } +wxCoord wxGrid::CalcColOrRowLabelAreaMinSize(wxGridDirection direction) +{ + // calculate size for the rows or columns? + const bool calcRows = direction == wxGRID_ROW; + + wxClientDC dc(calcRows ? GetGridRowLabelWindow() + : GetGridColLabelWindow()); + dc.SetFont(GetLabelFont()); + + // which dimension should we take into account for calculations? + // + // for columns, the text can be only horizontal so it's easy but for rows + // we also have to take into account the text orientation + const bool + useWidth = calcRows || (GetColLabelTextOrientation() == wxVERTICAL); + + wxArrayString lines; + wxCoord extentMax = 0; + + const int numRowsOrCols = calcRows ? m_numRows : m_numCols; + for ( int rowOrCol = 0; rowOrCol < numRowsOrCols; rowOrCol++ ) + { + lines.Clear(); + + wxString label = calcRows ? GetRowLabelValue(rowOrCol) + : GetColLabelValue(rowOrCol); + StringToLines(label, lines); + + long w, h; + GetTextBoxSize(dc, lines, &w, &h); + + const wxCoord extent = useWidth ? w : h; + if ( extent > extentMax ) + extentMax = extent; + } + + if ( !extentMax ) + { + // empty column - give default extent (notice that if extentMax is less + // than default extent but != 0, it's OK) + extentMax = calcRows ? GetDefaultRowLabelSize() + : GetDefaultColLabelSize(); + } + + // leave some space around text (taken from AutoSizeColOrRow) + if ( calcRows ) + extentMax += 10; + else + extentMax += 6; + + return extentMax; +} + int wxGrid::SetOrCalcColumnSizes(bool calcOnly, bool setAsMin) { int width = m_rowLabelWidth; - if ( !calcOnly ) - BeginBatch(); + wxGridUpdateLocker locker; + if(!calcOnly) + locker.Create(this); for ( int col = 0; col < m_numCols; col++ ) { @@ -10050,9 +10639,6 @@ int wxGrid::SetOrCalcColumnSizes(bool calcOnly, bool setAsMin) width += GetColWidth(col); } - if ( !calcOnly ) - EndBatch(); - return width; } @@ -10060,8 +10646,9 @@ int wxGrid::SetOrCalcRowSizes(bool calcOnly, bool setAsMin) { int height = m_colLabelHeight; - if ( !calcOnly ) - BeginBatch(); + wxGridUpdateLocker locker; + if(!calcOnly) + locker.Create(this); for ( int row = 0; row < m_numRows; row++ ) { @@ -10071,31 +10658,24 @@ int wxGrid::SetOrCalcRowSizes(bool calcOnly, bool setAsMin) height += GetRowHeight(row); } - if ( !calcOnly ) - EndBatch(); - return height; } void wxGrid::AutoSize() { - BeginBatch(); + wxGridUpdateLocker locker(this); - wxSize size(SetOrCalcColumnSizes(false), SetOrCalcRowSizes(false)); - - // round up the size to a multiple of scroll step - this ensures that we - // won't get the scrollbars if we're sized exactly to this width - // CalcDimension adds m_extraWidth + 1 etc. to calculate the necessary - // scrollbar steps - wxSize sizeFit( - GetScrollX(size.x + m_extraWidth + 1) * m_scrollLineX, - GetScrollY(size.y + m_extraHeight + 1) * m_scrollLineY ); + // we need to round up the size of the scrollable area to a multiple of + // scroll step to ensure that we don't get the scrollbars when we're sized + // exactly to fit our contents + wxSize size(SetOrCalcColumnSizes(false) - m_rowLabelWidth + m_extraWidth, + SetOrCalcRowSizes(false) - m_colLabelHeight + m_extraHeight); + wxSize sizeFit(GetScrollX(size.x) * GetScrollLineX(), + GetScrollY(size.y) * GetScrollLineY()); // distribute the extra space between the columns/rows to avoid having // extra white space - - // Remove the extra m_extraWidth + 1 added above - wxCoord diff = sizeFit.x - size.x + (m_extraWidth + 1); + wxCoord diff = sizeFit.x - size.x; if ( diff && m_numCols ) { // try to resize the columns uniformly @@ -10120,7 +10700,7 @@ void wxGrid::AutoSize() } // same for rows - diff = sizeFit.y - size.y - (m_extraHeight + 1); + diff = sizeFit.y - size.y; if ( diff && m_numRows ) { // try to resize the columns uniformly @@ -10144,9 +10724,11 @@ void wxGrid::AutoSize() } } - EndBatch(); - - SetClientSize(sizeFit); + // we know that we're not going to have scrollbars so disable them now to + // avoid trouble in SetClientSize() which can otherwise set the correct + // client size but also leave space for (not needed any more) scrollbars + SetScrollbars(0, 0, 0, 0, 0, 0, true); + SetClientSize(sizeFit.x + m_rowLabelWidth, sizeFit.y + m_colLabelHeight); } void wxGrid::AutoSizeRowLabelSize( int row ) @@ -10200,46 +10782,22 @@ void wxGrid::AutoSizeColLabelSize( int col ) wxSize wxGrid::DoGetBestSize() const { - // don't set sizes, only calculate them wxGrid *self = (wxGrid *)this; // const_cast - int width, height; - width = self->SetOrCalcColumnSizes(true); - height = self->SetOrCalcRowSizes(true); - - if (!width) - width = 100; - if (!height) - height = 80; - - // Round up to a multiple the scroll rate - // NOTE: this still doesn't get rid of the scrollbars; - // is there any magic incantation for that? - int xpu, ypu; - GetScrollPixelsPerUnit(&xpu, &ypu); - if (xpu) - width += 1 + xpu - (width % xpu); - if (ypu) - height += 1 + ypu - (height % ypu); - - // limit to 1/4 of the screen size - int maxwidth, maxheight; - wxDisplaySize( &maxwidth, &maxheight ); - maxwidth /= 2; - maxheight /= 2; - if ( width > maxwidth ) - width = maxwidth; - if ( height > maxheight ) - height = maxheight; - - wxSize best(width, height); + // we do the same as in AutoSize() here with the exception that we don't + // change the column/row sizes, only calculate them + wxSize size(self->SetOrCalcColumnSizes(true) - m_rowLabelWidth + m_extraWidth, + self->SetOrCalcRowSizes(true) - m_colLabelHeight + m_extraHeight); + wxSize sizeFit(GetScrollX(size.x) * GetScrollLineX(), + GetScrollY(size.y) * GetScrollLineY()); // NOTE: This size should be cached, but first we need to add calls to // InvalidateBestSize everywhere that could change the results of this // calculation. // CacheBestSize(size); - return best; + return wxSize(sizeFit.x + m_rowLabelWidth, sizeFit.y + m_colLabelHeight) + + GetWindowBorderSize(); } void wxGrid::Fit() @@ -10378,7 +10936,7 @@ void wxGrid::DeselectCell( int row, int col ) m_selection->ToggleCellSelection(row, col); } -bool wxGrid::IsSelection() +bool wxGrid::IsSelection() const { return ( m_selection && (m_selection->IsSelection() || ( m_selectingTopLeft != wxGridNoCellCoords && @@ -10451,8 +11009,9 @@ wxArrayInt wxGrid::GetSelectedCols() const void wxGrid::ClearSelection() { - m_selectingTopLeft = wxGridNoCellCoords; - m_selectingBottomRight = wxGridNoCellCoords; + m_selectingTopLeft = + m_selectingBottomRight = + m_selectingKeyboard = wxGridNoCellCoords; if ( m_selection ) m_selection->ClearSelection(); } @@ -10460,37 +11019,36 @@ void wxGrid::ClearSelection() // This function returns the rectangle that encloses the given block // in device coords clipped to the client size of the grid window. // -wxRect wxGrid::BlockToDeviceRect( const wxGridCellCoords &topLeft, - const wxGridCellCoords &bottomRight ) +wxRect wxGrid::BlockToDeviceRect( const wxGridCellCoords& topLeft, + const wxGridCellCoords& bottomRight ) const { - wxRect rect( wxGridNoCellRect ); - wxRect cellRect; - - cellRect = CellToRect( topLeft ); - if ( cellRect != wxGridNoCellRect ) + wxRect resultRect; + wxRect tempCellRect = CellToRect(topLeft); + if ( tempCellRect != wxGridNoCellRect ) { - rect = cellRect; + resultRect = tempCellRect; } else { - rect = wxRect(0, 0, 0, 0); + resultRect = wxRect(0, 0, 0, 0); } - cellRect = CellToRect( bottomRight ); - if ( cellRect != wxGridNoCellRect ) + tempCellRect = CellToRect(bottomRight); + if ( tempCellRect != wxGridNoCellRect ) { - rect += cellRect; + resultRect += tempCellRect; } else { + // If both inputs were "wxGridNoCellRect," then there's nothing to do. return wxGridNoCellRect; } - int i, j; - int left = rect.GetLeft(); - int top = rect.GetTop(); - int right = rect.GetRight(); - int bottom = rect.GetBottom(); + // Ensure that left/right and top/bottom pairs are in order. + int left = resultRect.GetLeft(); + int top = resultRect.GetTop(); + int right = resultRect.GetRight(); + int bottom = resultRect.GetBottom(); int leftCol = topLeft.GetCol(); int topRow = topLeft.GetRow(); @@ -10499,67 +11057,105 @@ wxRect wxGrid::BlockToDeviceRect( const wxGridCellCoords &topLeft, if (left > right) { - i = left; + int tmp = left; left = right; - right = i; - i = leftCol; + right = tmp; + + tmp = leftCol; leftCol = rightCol; - rightCol = i; + rightCol = tmp; } if (top > bottom) { - i = top; + int tmp = top; top = bottom; - bottom = i; - i = topRow; + bottom = tmp; + + tmp = topRow; topRow = bottomRow; - bottomRow = i; + bottomRow = tmp; } - for ( j = topRow; j <= bottomRow; j++ ) + // The following loop is ONLY necessary to detect and handle merged cells. + int cw, ch; + m_gridWin->GetClientSize( &cw, &ch ); + + // Get the origin coordinates: notice that they will be negative if the + // grid is scrolled downwards/to the right. + int gridOriginX = 0; + int gridOriginY = 0; + CalcScrolledPosition(gridOriginX, gridOriginY, &gridOriginX, &gridOriginY); + + int onScreenLeftmostCol = internalXToCol(-gridOriginX); + int onScreenUppermostRow = internalYToRow(-gridOriginY); + + int onScreenRightmostCol = internalXToCol(-gridOriginX + cw); + int onScreenBottommostRow = internalYToRow(-gridOriginY + ch); + + // Bound our loop so that we only examine the portion of the selected block + // that is shown on screen. Therefore, we compare the Top-Left block values + // to the Top-Left screen values, and the Bottom-Right block values to the + // Bottom-Right screen values, choosing appropriately. + const int visibleTopRow = wxMax(topRow, onScreenUppermostRow); + const int visibleBottomRow = wxMin(bottomRow, onScreenBottommostRow); + const int visibleLeftCol = wxMax(leftCol, onScreenLeftmostCol); + const int visibleRightCol = wxMin(rightCol, onScreenRightmostCol); + + for ( int j = visibleTopRow; j <= visibleBottomRow; j++ ) { - for ( i = leftCol; i <= rightCol; i++ ) + for ( int i = visibleLeftCol; i <= visibleRightCol; i++ ) { - if ((j == topRow) || (j == bottomRow) || (i == leftCol) || (i == rightCol)) + if ( (j == visibleTopRow) || (j == visibleBottomRow) || + (i == visibleLeftCol) || (i == visibleRightCol) ) { - cellRect = CellToRect( j, i ); + tempCellRect = CellToRect( j, i ); - if (cellRect.x < left) - left = cellRect.x; - if (cellRect.y < top) - top = cellRect.y; - if (cellRect.x + cellRect.width > right) - right = cellRect.x + cellRect.width; - if (cellRect.y + cellRect.height > bottom) - bottom = cellRect.y + cellRect.height; + if (tempCellRect.x < left) + left = tempCellRect.x; + if (tempCellRect.y < top) + top = tempCellRect.y; + if (tempCellRect.x + tempCellRect.width > right) + right = tempCellRect.x + tempCellRect.width; + if (tempCellRect.y + tempCellRect.height > bottom) + bottom = tempCellRect.y + tempCellRect.height; } else { - i = rightCol; // jump over inner cells. + i = visibleRightCol; // jump over inner cells. } } } - // convert to scrolled coords - // + // Convert to scrolled coords CalcScrolledPosition( left, top, &left, &top ); CalcScrolledPosition( right, bottom, &right, &bottom ); - int cw, ch; - m_gridWin->GetClientSize( &cw, &ch ); - if (right < 0 || bottom < 0 || left > cw || top > ch) return wxRect(0,0,0,0); - rect.SetLeft( wxMax(0, left) ); - rect.SetTop( wxMax(0, top) ); - rect.SetRight( wxMin(cw, right) ); - rect.SetBottom( wxMin(ch, bottom) ); + resultRect.SetLeft( wxMax(0, left) ); + resultRect.SetTop( wxMax(0, top) ); + resultRect.SetRight( wxMin(cw, right) ); + resultRect.SetBottom( wxMin(ch, bottom) ); - return rect; + return resultRect; } +// ---------------------------------------------------------------------------- +// drop target +// ---------------------------------------------------------------------------- + +#if wxUSE_DRAG_AND_DROP + +// this allow setting drop target directly on wxGrid +void wxGrid::SetDropTarget(wxDropTarget *dropTarget) +{ + GetGridWindow()->SetDropTarget(dropTarget); +} + +#endif // wxUSE_DRAG_AND_DROP + // ---------------------------------------------------------------------------- // grid event classes // ----------------------------------------------------------------------------