X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/f460c29d593da752aa2bac1c178d2c58ee563ff3..fc2d42090058bb7ebb9545b857a9a435ecbdd876:/src/generic/grid.cpp?ds=sidebyside diff --git a/src/generic/grid.cpp b/src/generic/grid.cpp index 6293c3cd99..bf62e90e3e 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) @@ -197,7 +202,7 @@ public: wxGridRowLabelWindow *rowLblWin, wxGridColLabelWindow *colLblWin, wxWindowID id, const wxPoint &pos, const wxSize &size ); - ~wxGridWindow() {} + virtual ~wxGridWindow() {} void ScrollWindow( int dx, int dy, const wxRect *rect ); @@ -570,6 +575,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 @@ -616,7 +627,7 @@ void wxGridCellTextEditor::Create(wxWindow* parent, m_control = new wxTextCtrl(parent, id, wxEmptyString, wxDefaultPosition, wxDefaultSize #if defined(__WXMSW__) - , wxTE_PROCESS_TAB | wxTE_AUTO_SCROLL + , wxTE_PROCESS_TAB | wxTE_AUTO_SCROLL | wxNO_BORDER #endif ); @@ -652,27 +663,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 +1195,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; + } } } @@ -2272,6 +2292,7 @@ wxGridCellAttr *wxGridCellAttr::Clone() const if ( IsReadOnly() ) attr->SetReadOnly(); + attr->SetOverflow( m_overflow == Overflow ); attr->SetKind( m_attrkind ); return attr; @@ -3500,6 +3521,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 +3604,20 @@ 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 - pos; + numCols = curNumCols - colID; + } + + if ( !m_colLabels.IsEmpty() ) + { + m_colLabels.RemoveAt( colID, numCols ); } for ( row = 0; row < curNumRows; row++ ) @@ -3587,7 +3628,7 @@ bool wxGridStringTable::DeleteCols( size_t pos, size_t numCols ) } else { - m_data[row].RemoveAt( pos, numCols ); + m_data[row].RemoveAt( colID, numCols ); } } @@ -3699,7 +3740,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 ); @@ -3769,7 +3811,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 ); @@ -3845,7 +3891,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, wxSOLID) ); 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 ); @@ -4000,9 +4046,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) @@ -4141,10 +4185,6 @@ 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 @@ -4370,6 +4410,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; @@ -4388,8 +4430,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); @@ -4447,7 +4489,7 @@ void wxGrid::InitColWidths() for ( int i = 0; i < m_numCols; i++ ) { - colRight += m_defaultColWidth; + colRight = ( GetColPos( i ) + 1 ) * m_defaultColWidth; m_colRights.Add( colRight ); } } @@ -4459,13 +4501,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]; } @@ -4497,7 +4539,7 @@ void wxGrid::CalcDimensions() ch -= m_colLabelHeight; // grid total size - int w = m_numCols > 0 ? GetColRight(m_numCols - 1) + m_extraWidth + 1 : 0; + int w = m_numCols > 0 ? GetColRight(GetColAt( m_numCols - 1 )) + m_extraWidth + 1 : 0; int h = m_numRows > 0 ? GetRowBottom(m_numRows - 1) + m_extraHeight + 1 : 0; // take into account editor if shown @@ -4749,6 +4791,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 +4817,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 +4856,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 +4876,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 +4910,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; } @@ -4973,8 +5071,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; @@ -5032,8 +5133,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 +5385,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 +5431,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 +5528,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 +5607,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); @@ -5530,7 +5724,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 +5766,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; @@ -6093,6 +6292,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 +6630,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(), @@ -6504,6 +6835,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() ) { @@ -7088,7 +7427,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 ) @@ -7214,6 +7553,21 @@ void wxGrid::DrawCellHighlight( wxDC& dc, const wxGridCellAttr *attr ) #endif } +wxPen wxGrid::GetDefaultGridLinePen() +{ + return wxPen(GetGridLineColour(), 1, wxSOLID); +} + +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 +7575,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,13 +7664,13 @@ 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__ @@ -7327,8 +7682,11 @@ void wxGrid::DrawAllGridLines( wxDC& dc, const wxRegion & WXUNUSED(reg) ) for (j=topRow; j 1) || (cell_cols > 1)) { @@ -7371,7 +7729,6 @@ void wxGrid::DrawAllGridLines( wxDC& dc, const wxRegion & WXUNUSED(reg) ) dc.SetClippingRegion( clippedcells ); - dc.SetPen( wxPen(GetGridLineColour(), 1, wxSOLID) ); // horizontal grid lines // @@ -7387,15 +7744,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 +7769,7 @@ void wxGrid::DrawAllGridLines( wxDC& dc, const wxRegion & WXUNUSED(reg) ) if ( colRight >= left ) { + dc.SetPen( GetColGridLinePen(i) ); dc.DrawLine( colRight, top, colRight, bottom ); } } @@ -7446,7 +7813,7 @@ void wxGrid::DrawRowLabel( wxDC& dc, int row ) 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, wxSOLID) ); dc.DrawLine( m_rowLabelWidth - 1, rowTop, m_rowLabelWidth - 1, rowBottom ); dc.DrawLine( 0, rowTop, 0, rowBottom ); dc.DrawLine( 0, rowBottom, m_rowLabelWidth, rowBottom ); @@ -7505,7 +7872,7 @@ void wxGrid::DrawColLabel( wxDC& dc, int col ) #else int colRight = GetColRight(col) - 1; - dc.SetPen( wxPen(wxSystemSettings::GetColour(wxSYS_COLOUR_3DDKSHADOW), 1, wxSOLID) ); + dc.SetPen( wxPen(wxSystemSettings::GetColour(wxSYS_COLOUR_3DSHADOW), 1, wxSOLID) ); dc.DrawLine( colRight, 0, colRight, m_colLabelHeight - 1 ); dc.DrawLine( colLeft, 0, colRight, 0 ); dc.DrawLine( colLeft, m_colLabelHeight - 1, @@ -7612,8 +7979,8 @@ void wxGrid::DrawTextRectangle(wxDC& dc, continue; } - long lineWidth, - lineHeight; + long lineWidth = 0, + lineHeight = 0; dc.GetTextExtent(line, &lineWidth, &lineHeight); switch ( horizAlign ) @@ -7874,23 +8241,20 @@ 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)); + dc.SetBrush(wxBrush(GetCellAttr(row, col)->GetBackgroundColour(), wxSOLID)); 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 @@ -7963,19 +8327,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(); @@ -8142,21 +8493,84 @@ int wxGrid::YToRow( int y ) m_minAcceptableRowHeight, m_rowBottoms, m_numRows, false); } -int wxGrid::XToCol( int x ) +int wxGrid::XToCol( int x, bool clipToMinMax ) { - return CoordToRowOrCol(x, m_defaultColWidth, - m_minAcceptableColWidth, m_colRights, m_numCols, false); + if (x < 0) + return clipToMinMax && (m_numCols > 0) ? GetColAt( 0 ) : -1; + + if (!m_defaultColWidth) + m_defaultColWidth = 1; + + 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 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 +8585,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 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. @@ -8425,11 +8840,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 +8875,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 ); } @@ -9819,7 +10236,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 @@ -9850,8 +10267,10 @@ void wxGrid::SetColSize( int col, int width ) m_colWidths[col] = w; int i; - for ( i = col; i < m_numCols; i++ ) + int colPos; + for ( colPos = GetColPos( col ); colPos < m_numCols; colPos++ ) { + i = GetColAt( colPos ); m_colRights[i] += diff; } @@ -9969,12 +10388,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 ) @@ -10451,8 +10870,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(); }