X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/758cbedf846a9d21a5feb3ac3a89882ccb8a4375..dfde8cd35734463150078a804475402d48e4c241:/src/generic/grid.cpp diff --git a/src/generic/grid.cpp b/src/generic/grid.cpp index 022349a967..1c7a6320f0 100644 --- a/src/generic/grid.cpp +++ b/src/generic/grid.cpp @@ -1,4 +1,4 @@ -///////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////// // Name: grid.cpp // Purpose: wxGrid and related classes // Author: Michael Bedward (based on code by Julian Smart, Robin Dunn) @@ -44,7 +44,8 @@ // this include needs to be outside precomp for BCC #include "wx/textfile.h" -#include "wx/generic/grid.h" +#include "wx/grid.h" + // ---------------------------------------------------------------------------- // array classes @@ -161,11 +162,42 @@ private: void OnPaint( wxPaintEvent &event ); void OnMouseEvent( wxMouseEvent& event ); void OnKeyDown( wxKeyEvent& ); + void OnEraseBackground( wxEraseEvent& ); + DECLARE_DYNAMIC_CLASS(wxGridWindow) DECLARE_EVENT_TABLE() }; + + +class wxGridCellEditorEvtHandler : public wxEvtHandler +{ +public: + wxGridCellEditorEvtHandler() + : m_grid(0), m_editor(0) + { } + wxGridCellEditorEvtHandler(wxGrid* grid, wxGridCellEditor* editor) + : m_grid(grid), m_editor(editor) + { } + + void OnKeyDown(wxKeyEvent& event); + +private: + wxGrid* m_grid; + wxGridCellEditor* m_editor; + DECLARE_DYNAMIC_CLASS(wxGridCellEditorEvtHandler) + DECLARE_EVENT_TABLE() +}; + + +IMPLEMENT_DYNAMIC_CLASS( wxGridCellEditorEvtHandler, wxEvtHandler ) +BEGIN_EVENT_TABLE( wxGridCellEditorEvtHandler, wxEvtHandler ) + EVT_KEY_DOWN( wxGridCellEditorEvtHandler::OnKeyDown ) +END_EVENT_TABLE() + + + // ---------------------------------------------------------------------------- // the internal data representation used by wxGridCellAttrProvider // ---------------------------------------------------------------------------- @@ -237,11 +269,198 @@ static const size_t GRID_SCROLL_LINE = 10; // implementation // ============================================================================ + +// ---------------------------------------------------------------------------- +// wxGridCellEditor +// ---------------------------------------------------------------------------- + +wxGridCellEditor::wxGridCellEditor() +{ + m_control = NULL; +} + + +wxGridCellEditor::~wxGridCellEditor() +{ + Destroy(); +} + + +void wxGridCellEditor::Destroy() +{ + if (m_control) { + m_control->Destroy(); + m_control = NULL; + } +} + +void wxGridCellEditor::Show(bool show) +{ + wxASSERT_MSG(m_control, + wxT("The wxGridCellEditor must be Created first!")); + m_control->Show(show); +} + +void wxGridCellEditor::SetSize(const wxRect& rect) +{ + wxASSERT_MSG(m_control, + wxT("The wxGridCellEditor must be Created first!")); + m_control->SetSize(rect); +} + +void wxGridCellEditor::HandleReturn(wxKeyEvent& event) +{ + event.Skip(); +} + + +void wxGridCellEditor::StartingKey(wxKeyEvent& event) +{ +} + + + +wxGridCellTextEditor::wxGridCellTextEditor() +{ +} + +void wxGridCellTextEditor::Create(wxWindow* parent, + wxWindowID id, + wxEvtHandler* evtHandler) +{ + m_control = new wxTextCtrl(parent, -1, "", + wxDefaultPosition, wxDefaultSize +#if defined(__WXMSW__) + , wxTE_MULTILINE | wxTE_NO_VSCROLL // necessary ??? +#endif + ); + + if (evtHandler) + m_control->PushEventHandler(evtHandler); +} + + +void wxGridCellTextEditor::BeginEdit(int row, int col, wxGrid* grid, + wxGridCellAttr* attr) +{ + wxASSERT_MSG(m_control, + wxT("The wxGridCellEditor must be Created first!")); + + m_startValue = grid->GetTable()->GetValue(row, col); + ((wxTextCtrl*)m_control)->SetValue(m_startValue); + ((wxTextCtrl*)m_control)->SetInsertionPointEnd(); + ((wxTextCtrl*)m_control)->SetFocus(); + + // ??? Should we use attr and try to set colours and font? +} + + + +bool wxGridCellTextEditor::EndEdit(int row, int col, bool saveValue, + wxGrid* grid, wxGridCellAttr* attr) +{ + wxASSERT_MSG(m_control, + wxT("The wxGridCellEditor must be Created first!")); + + bool changed = FALSE; + wxString value = ((wxTextCtrl*)m_control)->GetValue(); + if (value != m_startValue) + changed = TRUE; + + if (changed) + grid->GetTable()->SetValue(row, col, value); + + m_startValue = ""; + ((wxTextCtrl*)m_control)->SetValue(m_startValue); + + return changed; +} + + +void wxGridCellTextEditor::Reset() +{ + wxASSERT_MSG(m_control, + wxT("The wxGridCellEditor must be Created first!")); + + ((wxTextCtrl*)m_control)->SetValue(m_startValue); + ((wxTextCtrl*)m_control)->SetInsertionPointEnd(); +} + + +void wxGridCellTextEditor::StartingKey(wxKeyEvent& event) +{ + wxASSERT_MSG(m_control, + wxT("The wxGridCellEditor must be Created first!")); + + int code = event.KeyCode(); + if (code >= 32 && code < 255) { + wxString st((char)code); + if (! event.ShiftDown()) + st.LowerCase(); + ((wxTextCtrl*)m_control)->AppendText(st); + } +} + + +void wxGridCellTextEditor::HandleReturn(wxKeyEvent& event) +{ +#if defined(__WXMOTIF__) || defined(__WXGTK__) + // wxMotif needs a little extra help... + int pos = ((wxTextCtrl*)m_control)->GetInsertionPoint(); + wxString s( ((wxTextCtrl*)m_control)->GetValue() ); + s = s.Left(pos) + "\n" + s.Mid(pos); + ((wxTextCtrl*)m_control)->SetValue(s); + ((wxTextCtrl*)m_control)->SetInsertionPoint( pos ); +#else + // the other ports can handle a Return key press + // + event.Skip(); +#endif +} + + +void wxGridCellEditorEvtHandler::OnKeyDown(wxKeyEvent& event) +{ + switch ( event.KeyCode() ) + { + case WXK_ESCAPE: + m_editor->Reset(); + m_grid->EnableCellEditControl(FALSE); + break; + +// case WXK_UP: +// case WXK_DOWN: +// case WXK_LEFT: +// case WXK_RIGHT: +// case WXK_PRIOR: +// case WXK_NEXT: +// case WXK_SPACE: +// case WXK_HOME: +// case WXK_END: +// // send the event to the parent grid, skipping the +// // event if nothing happens +// // +// event.Skip( m_grid->ProcessEvent( event ) ); +// break; + + case WXK_TAB: + case WXK_RETURN: + if (!m_grid->ProcessEvent(event)) + m_editor->HandleReturn(event); + break; + + + default: + event.Skip(); + } +} + // ---------------------------------------------------------------------------- // wxGridCellRenderer // ---------------------------------------------------------------------------- void wxGridCellRenderer::Draw(wxGrid& grid, + wxGridCellAttr& attr, wxDC& dc, const wxRect& rect, int row, int col, @@ -251,45 +470,43 @@ void wxGridCellRenderer::Draw(wxGrid& grid, if ( isSelected ) { - // FIXME customize - dc.SetBrush( *wxBLACK_BRUSH ); + dc.SetBrush( wxBrush(grid.GetSelectionBackground(), wxSOLID) ); } else { - dc.SetBrush( wxBrush(grid.GetCellBackgroundColour(row, col), wxSOLID) ); + dc.SetBrush( wxBrush(attr.GetBackgroundColour(), wxSOLID) ); } dc.SetPen( *wxTRANSPARENT_PEN ); - dc.DrawRectangle(rect); } void wxGridCellStringRenderer::Draw(wxGrid& grid, + wxGridCellAttr& attr, wxDC& dc, const wxRect& rectCell, int row, int col, bool isSelected) { - wxGridCellRenderer::Draw(grid, dc, rectCell, row, col, isSelected); + wxGridCellRenderer::Draw(grid, attr, dc, rectCell, row, col, isSelected); // now we only have to draw the text dc.SetBackgroundMode( wxTRANSPARENT ); if ( isSelected ) { - // FIXME customize - dc.SetTextBackground( wxColour(0, 0, 0) ); - dc.SetTextForeground( wxColour(255, 255, 255) ); + dc.SetTextBackground( grid.GetSelectionBackground() ); + dc.SetTextForeground( grid.GetSelectionForeground() ); } else { - dc.SetTextBackground( grid.GetCellBackgroundColour(row, col) ); - dc.SetTextForeground( grid.GetCellTextColour(row, col) ); + dc.SetTextBackground( attr.GetBackgroundColour() ); + dc.SetTextForeground( attr.GetTextColour() ); } - dc.SetFont( grid.GetCellFont(row, col) ); + dc.SetFont( attr.GetFont() ); int hAlign, vAlign; - grid.GetCellAlignment(row, col, &hAlign, &vAlign); + attr.GetAlignment(&hAlign, &vAlign); wxRect rect = rectCell; rect.x++; @@ -301,6 +518,87 @@ void wxGridCellStringRenderer::Draw(wxGrid& grid, rect, hAlign, vAlign); } +// ---------------------------------------------------------------------------- +// wxGridCellAttr +// ---------------------------------------------------------------------------- + +const wxColour& wxGridCellAttr::GetTextColour() const +{ + if (HasTextColour()) + return m_colText; + else if (m_defGridAttr != this) + return m_defGridAttr->GetTextColour(); + else { + wxFAIL_MSG(wxT("Missing default cell attribute")); + return wxNullColour; + } +} + + +const wxColour& wxGridCellAttr::GetBackgroundColour() const +{ + if (HasBackgroundColour()) + return m_colBack; + else if (m_defGridAttr != this) + return m_defGridAttr->GetBackgroundColour(); + else { + wxFAIL_MSG(wxT("Missing default cell attribute")); + return wxNullColour; + } +} + + +const wxFont& wxGridCellAttr::GetFont() const +{ + if (HasFont()) + return m_font; + else if (m_defGridAttr != this) + return m_defGridAttr->GetFont(); + else { + wxFAIL_MSG(wxT("Missing default cell attribute")); + return wxNullFont; + } +} + + +void wxGridCellAttr::GetAlignment(int *hAlign, int *vAlign) const +{ + if (HasAlignment()) { + if ( hAlign ) *hAlign = m_hAlign; + if ( vAlign ) *vAlign = m_vAlign; + } + else if (m_defGridAttr != this) + m_defGridAttr->GetAlignment(hAlign, vAlign); + else { + wxFAIL_MSG(wxT("Missing default cell attribute")); + } +} + + +wxGridCellRenderer* wxGridCellAttr::GetRenderer() const +{ + if (HasRenderer()) + return m_renderer; + else if (m_defGridAttr != this) + return m_defGridAttr->GetRenderer(); + else { + wxFAIL_MSG(wxT("Missing default cell attribute")); + return NULL; + } +} + +wxGridCellEditor* wxGridCellAttr::GetEditor() const +{ + if (HasEditor()) + return m_editor; + else if (m_defGridAttr != this) + return m_defGridAttr->GetEditor(); + else { + wxFAIL_MSG(wxT("Missing default cell attribute")); + return NULL; + } +} + // ---------------------------------------------------------------------------- // wxGridCellAttrData // ---------------------------------------------------------------------------- @@ -1055,116 +1353,7 @@ void wxGridStringTable::SetColLabelValue( int col, const wxString& value ) - ////////////////////////////////////////////////////////////////////// - -IMPLEMENT_DYNAMIC_CLASS( wxGridTextCtrl, wxTextCtrl ) - -BEGIN_EVENT_TABLE( wxGridTextCtrl, wxTextCtrl ) - EVT_KEY_DOWN( wxGridTextCtrl::OnKeyDown ) -END_EVENT_TABLE() - - -wxGridTextCtrl::wxGridTextCtrl( wxWindow *par, - wxGrid *grid, - bool isCellControl, - wxWindowID id, - const wxString& value, - const wxPoint& pos, - const wxSize& size, - long style ) - : wxTextCtrl( par, id, value, pos, size, style ) -{ - m_grid = grid; - m_isCellControl = isCellControl; -} - - -void wxGridTextCtrl::OnKeyDown( wxKeyEvent& event ) -{ - switch ( event.KeyCode() ) - { - case WXK_ESCAPE: - m_grid->SetEditControlValue( startValue ); - SetInsertionPointEnd(); - break; - - case WXK_UP: - case WXK_DOWN: - case WXK_LEFT: - case WXK_RIGHT: - case WXK_PRIOR: - case WXK_NEXT: - case WXK_SPACE: - if ( m_isCellControl ) - { - // send the event to the parent grid, skipping the - // event if nothing happens - // - event.Skip( m_grid->ProcessEvent( event ) ); - } - else - { - // default text control response within the top edit - // control - // - event.Skip(); - } - break; - - case WXK_RETURN: - if ( m_isCellControl ) - { - if ( !m_grid->ProcessEvent( event ) ) - { -#if defined(__WXMOTIF__) || defined(__WXGTK__) - // wxMotif needs a little extra help... - // - int pos = GetInsertionPoint(); - wxString s( GetValue() ); - s = s.Left(pos) + "\n" + s.Mid(pos); - SetValue(s); - SetInsertionPoint( pos ); -#else - // the other ports can handle a Return key press - // - event.Skip(); -#endif - } - } - break; - - case WXK_HOME: - case WXK_END: - if ( m_isCellControl ) - { - // send the event to the parent grid, skipping the - // event if nothing happens - // - event.Skip( m_grid->ProcessEvent( event ) ); - } - else - { - // default text control response within the top edit - // control - // - event.Skip(); - } - break; - - default: - event.Skip(); - } -} - -void wxGridTextCtrl::SetStartValue( const wxString& s ) -{ - startValue = s; - wxTextCtrl::SetValue(s); -} - - - ////////////////////////////////////////////////////////////////////// IMPLEMENT_DYNAMIC_CLASS( wxGridRowLabelWindow, wxWindow ) @@ -1331,6 +1520,7 @@ BEGIN_EVENT_TABLE( wxGridWindow, wxPanel ) EVT_PAINT( wxGridWindow::OnPaint ) EVT_MOUSE_EVENTS( wxGridWindow::OnMouseEvent ) EVT_KEY_DOWN( wxGridWindow::OnKeyDown ) + EVT_ERASE_BACKGROUND( wxGridWindow::OnEraseBackground ) END_EVENT_TABLE() wxGridWindow::wxGridWindow( wxGrid *parent, @@ -1342,7 +1532,6 @@ wxGridWindow::wxGridWindow( wxGrid *parent, m_owner = parent; m_rowLabelWin = rowLblWin; m_colLabelWin = colLblWin; - SetBackgroundColour( "WHITE" ); } @@ -1387,16 +1576,22 @@ void wxGridWindow::OnKeyDown( wxKeyEvent& event ) if ( !m_owner->ProcessEvent( event ) ) event.Skip(); } +void wxGridWindow::OnEraseBackground(wxEraseEvent&) +{ } + + ////////////////////////////////////////////////////////////////////// + IMPLEMENT_DYNAMIC_CLASS( wxGrid, wxScrolledWindow ) BEGIN_EVENT_TABLE( wxGrid, wxScrolledWindow ) EVT_PAINT( wxGrid::OnPaint ) EVT_SIZE( wxGrid::OnSize ) EVT_KEY_DOWN( wxGrid::OnKeyDown ) + EVT_ERASE_BACKGROUND( wxGrid::OnEraseBackground ) END_EVENT_TABLE() wxGrid::wxGrid( wxWindow *parent, @@ -1414,6 +1609,7 @@ wxGrid::wxGrid( wxWindow *parent, wxGrid::~wxGrid() { ClearAttrCache(); + m_defaultCellAttr->SafeDecRef(); #ifdef DEBUG_ATTR_CACHE size_t total = gs_nAttrCacheHits + gs_nAttrCacheMisses; @@ -1423,8 +1619,8 @@ wxGrid::~wxGrid() total ? (gs_nAttrCacheHits*100) / total : 0); #endif - delete m_defaultRenderer; - delete m_table; + if (m_ownTable) + delete m_table; } @@ -1435,10 +1631,17 @@ wxGrid::~wxGrid() void wxGrid::Create() { m_created = FALSE; // set to TRUE by CreateGrid - m_displayed = FALSE; // set to TRUE by OnPaint + m_displayed = TRUE; // FALSE; // set to TRUE by OnPaint m_table = (wxGridTableBase *) NULL; - m_cellEditCtrl = (wxWindow *) NULL; + m_ownTable = FALSE; + + m_cellEditCtrlEnabled = FALSE; + + m_defaultCellAttr = new wxGridCellAttr; + m_defaultCellAttr->SetDefAttr(m_defaultCellAttr); + // RD: Should we fill the default attrs now or is waiting until Init() okay? + m_numRows = 0; m_numCols = 0; @@ -1477,7 +1680,7 @@ bool wxGrid::CreateGrid( int numRows, int numCols ) { if ( m_created ) { - wxFAIL_MSG( wxT("wxGrid::CreateGrid called more than once") ); + wxFAIL_MSG( wxT("wxGrid::CreateGrid or wxGrid::SetTable called more than once") ); return FALSE; } else @@ -1487,6 +1690,35 @@ bool wxGrid::CreateGrid( int numRows, int numCols ) m_table = new wxGridStringTable( m_numRows, m_numCols ); m_table->SetView( this ); + m_ownTable = TRUE; + Init(); + m_created = TRUE; + } + + return m_created; +} + +bool wxGrid::SetTable( wxGridTableBase *table, bool takeOwnership ) +{ + if ( m_created ) + { + // RD: Actually, this should probably be allowed. I think it would be + // nice to be able to switch multiple Tables in and out of a single + // View at runtime. Is there anything in the implmentation that would + // prevent this? + + wxFAIL_MSG( wxT("wxGrid::CreateGrid or wxGrid::SetTable called more than once") ); + return FALSE; + } + else + { + m_numRows = table->GetNumberRows(); + m_numCols = table->GetNumberCols(); + + m_table = table; + m_table->SetView( this ); + if (takeOwnership) + m_ownTable = TRUE; Init(); m_created = TRUE; } @@ -1562,14 +1794,16 @@ void wxGrid::Init() m_colRights.Add( colRight ); } - // TODO: improve this by using wxSystemSettings? - // - m_defaultCellFont = GetFont(); - - m_defaultCellHAlign = wxLEFT; - m_defaultCellVAlign = wxTOP; + // Set default cell attributes + m_defaultCellAttr->SetFont(GetFont()); + m_defaultCellAttr->SetAlignment(wxLEFT, wxTOP); + m_defaultCellAttr->SetRenderer(new wxGridCellStringRenderer); + m_defaultCellAttr->SetEditor(new wxGridCellTextEditor); + m_defaultCellAttr->SetTextColour( + wxSystemSettings::GetSystemColour(wxSYS_COLOUR_WINDOWTEXT)); + m_defaultCellAttr->SetBackgroundColour( + wxSystemSettings::GetSystemColour(wxSYS_COLOUR_WINDOW)); - m_defaultRenderer = (wxGridCellRenderer *)NULL; m_gridLineColour = wxColour( 128, 128, 255 ); m_gridLinesEnabled = TRUE; @@ -1579,6 +1813,9 @@ void wxGrid::Init() m_dragLastPos = -1; m_dragRowOrCol = -1; m_isDragging = FALSE; + m_startDragPos = wxDefaultPosition; + + m_waitForSlowClick = FALSE; m_rowResizeCursor = wxCursor( wxCURSOR_SIZENS ); m_colResizeCursor = wxCursor( wxCURSOR_SIZEWE ); @@ -1587,29 +1824,14 @@ void wxGrid::Init() m_selectedTopLeft = wxGridNoCellCoords; m_selectedBottomRight = wxGridNoCellCoords; + m_selectionBackground = wxSystemSettings::GetSystemColour(wxSYS_COLOUR_HIGHLIGHT); + m_selectionForeground = wxSystemSettings::GetSystemColour(wxSYS_COLOUR_HIGHLIGHTTEXT); m_editable = TRUE; // default for whole grid m_inOnKeyDown = FALSE; m_batchCount = 0; - // TODO: extend this to other types of controls - // - m_cellEditCtrl = new wxGridTextCtrl( m_gridWin, - this, - TRUE, - wxGRID_CELLCTRL, - "", - wxPoint(1,1), - wxSize(1,1) -#if defined(__WXMSW__) - , wxTE_MULTILINE | wxTE_NO_VSCROLL -#endif - ); - - m_cellEditCtrl->Show( FALSE ); - m_cellEditCtrlEnabled = TRUE; - m_editCtrlType = wxGRID_TEXTCTRL; } @@ -1969,7 +2191,7 @@ void wxGrid::CalcCellsExposed( wxRegion& reg ) int colLeft, rowTop; for ( row = 0; row < m_numRows; row++ ) { - if ( m_rowBottoms[row] < top ) continue; + if ( m_rowBottoms[row] <= top ) continue; rowTop = m_rowBottoms[row] - m_rowHeights[row]; if ( rowTop > bottom ) break; @@ -1978,7 +2200,7 @@ void wxGrid::CalcCellsExposed( wxRegion& reg ) for ( col = 0; col < m_numCols; col++ ) { - if ( m_colRights[col] < left ) continue; + if ( m_colRights[col] <= left ) continue; colLeft = m_colRights[col] - m_colWidths[col]; if ( colLeft > right ) break; @@ -2015,6 +2237,10 @@ void wxGrid::ProcessRowLabelMouseEvent( wxMouseEvent& event ) wxClientDC dc( m_gridWin ); PrepareDC( dc ); + y = wxMax( y, + m_rowBottoms[m_dragRowOrCol] - + m_rowHeights[m_dragRowOrCol] + + WXGRID_MIN_ROW_HEIGHT ); dc.SetLogicalFunction(wxINVERT); if ( m_dragLastPos >= 0 ) { @@ -2177,6 +2403,10 @@ void wxGrid::ProcessColLabelMouseEvent( wxMouseEvent& event ) wxClientDC dc( m_gridWin ); PrepareDC( dc ); + x = wxMax( x, + m_colRights[m_dragRowOrCol] - + m_colWidths[m_dragRowOrCol] + + WXGRID_MIN_COL_WIDTH ); dc.SetLogicalFunction(wxINVERT); if ( m_dragLastPos >= 0 ) { @@ -2427,6 +2657,19 @@ void wxGrid::ProcessGridCellMouseEvent( wxMouseEvent& event ) if ( event.Dragging() ) { + //wxLogDebug("pos(%d, %d) coords(%d, %d)", pos.x, pos.y, coords.GetRow(), coords.GetCol()); + + // Don't start doing anything until the mouse has been drug at + // least 3 pixels in any direction... + if (! m_isDragging) { + if (m_startDragPos == wxDefaultPosition) { + m_startDragPos = pos; + return; + } + if (abs(m_startDragPos.x - pos.x) < 4 && abs(m_startDragPos.y - pos.y) < 4) + return; + } + m_isDragging = TRUE; if ( m_cursorMode == WXGRID_CURSOR_SELECT_CELL ) { @@ -2434,6 +2677,13 @@ void wxGrid::ProcessGridCellMouseEvent( wxMouseEvent& event ) // won't interfer with drag-shrinking. if ( IsCellEditControlEnabled() ) HideCellEditControl(); + + // Have we captured the mouse yet? + if (! m_winCapture) { + m_winCapture = m_gridWin; + m_winCapture->CaptureMouse(); + } + if ( coords != wxGridNoCellCoords ) { if ( !IsSelection() ) @@ -2444,6 +2694,12 @@ void wxGrid::ProcessGridCellMouseEvent( wxMouseEvent& event ) { SelectBlock( m_currentCellCoords, coords ); } + + if (! IsVisible(coords)) { + MakeCellVisible(coords); + // TODO: need to introduce a delay or something here. The + // scrolling is way to fast, at least on MSW. + } } } else if ( m_cursorMode == WXGRID_CURSOR_RESIZE_ROW ) @@ -2454,6 +2710,10 @@ void wxGrid::ProcessGridCellMouseEvent( wxMouseEvent& event ) wxClientDC dc( m_gridWin ); PrepareDC( dc ); + y = wxMax( y, + m_rowBottoms[m_dragRowOrCol] - + m_rowHeights[m_dragRowOrCol] + + WXGRID_MIN_ROW_HEIGHT ); dc.SetLogicalFunction(wxINVERT); if ( m_dragLastPos >= 0 ) { @@ -2470,6 +2730,9 @@ void wxGrid::ProcessGridCellMouseEvent( wxMouseEvent& event ) wxClientDC dc( m_gridWin ); PrepareDC( dc ); + x = wxMax( x, + m_colRights[m_dragRowOrCol] - + m_colWidths[m_dragRowOrCol] + WXGRID_MIN_COL_WIDTH ); dc.SetLogicalFunction(wxINVERT); if ( m_dragLastPos >= 0 ) { @@ -2483,6 +2746,8 @@ void wxGrid::ProcessGridCellMouseEvent( wxMouseEvent& event ) } m_isDragging = FALSE; + m_startDragPos = wxDefaultPosition; + if ( coords != wxGridNoCellCoords ) { @@ -2502,6 +2767,7 @@ void wxGrid::ProcessGridCellMouseEvent( wxMouseEvent& event ) // if ( event.LeftDown() ) { + EnableCellEditControl( FALSE ); if ( event.ShiftDown() ) { SelectBlock( m_currentCellCoords, coords ); @@ -2515,7 +2781,18 @@ void wxGrid::ProcessGridCellMouseEvent( wxMouseEvent& event ) event ) ) { MakeCellVisible( coords ); - SetCurrentCell( coords ); + + // if this is the second click on this cell then start + // the edit control + if (m_waitForSlowClick && coords == m_currentCellCoords) { + EnableCellEditControl(TRUE); + ShowCellEditControl(); + m_waitForSlowClick = FALSE; + } + else { + SetCurrentCell( coords ); + m_waitForSlowClick = TRUE; + } } } } @@ -2525,6 +2802,7 @@ void wxGrid::ProcessGridCellMouseEvent( wxMouseEvent& event ) // else if ( event.LeftDClick() ) { + EnableCellEditControl( FALSE ); if ( XToEdgeOfCol(x) < 0 && YToEdgeOfRow(y) < 0 ) { SendEvent( EVT_GRID_CELL_LEFT_DCLICK, @@ -2543,6 +2821,10 @@ void wxGrid::ProcessGridCellMouseEvent( wxMouseEvent& event ) { if ( IsSelection() ) { + if (m_winCapture) { + m_winCapture->ReleaseMouse(); + m_winCapture = NULL; + } SendEvent( EVT_GRID_RANGE_SELECT, -1, -1, event ); } @@ -2580,6 +2862,7 @@ void wxGrid::ProcessGridCellMouseEvent( wxMouseEvent& event ) // else if ( event.RightDown() ) { + EnableCellEditControl( FALSE ); if ( !SendEvent( EVT_GRID_CELL_RIGHT_CLICK, coords.GetRow(), coords.GetCol(), @@ -2594,6 +2877,7 @@ void wxGrid::ProcessGridCellMouseEvent( wxMouseEvent& event ) // else if ( event.RightDClick() ) { + EnableCellEditControl( FALSE ); if ( !SendEvent( EVT_GRID_CELL_RIGHT_DCLICK, coords.GetRow(), coords.GetCol(), @@ -3120,7 +3404,7 @@ void wxGrid::OnKeyDown( wxKeyEvent& event ) { // shouldn't be here - we are going round in circles... // - wxFAIL_MSG( wxT("wxGrid::OnKeyDown called while alread active") ); + wxFAIL_MSG( wxT("wxGrid::OnKeyDown called while already active") ); } m_inOnKeyDown = TRUE; @@ -3181,17 +3465,6 @@ void wxGrid::OnKeyDown( wxKeyEvent& event ) } break; - case WXK_SPACE: - if ( !IsEditable() ) - { - MoveCursorRight(); - } - else - { - event.Skip(); - } - break; - case WXK_RETURN: if ( event.ControlDown() ) { @@ -3203,6 +3476,13 @@ void wxGrid::OnKeyDown( wxKeyEvent& event ) } break; + case WXK_TAB: + if (event.ShiftDown()) + MoveCursorLeft(); + else + MoveCursorRight(); + break; + case WXK_HOME: if ( event.ControlDown() ) { @@ -3235,13 +3515,31 @@ void wxGrid::OnKeyDown( wxKeyEvent& event ) MovePageDown(); break; + // We don't want these keys to trigger the edit control, any others? + case WXK_SHIFT: + case WXK_ALT: + case WXK_CONTROL: + case WXK_CAPITAL: + event.Skip(); + break; + + case WXK_SPACE: + if ( !IsEditable() ) + { + MoveCursorRight(); + break; + } + // Otherwise fall through to default + default: // now try the cell edit control // - if ( IsCellEditControlEnabled() ) - { - event.SetEventObject( m_cellEditCtrl ); - m_cellEditCtrl->GetEventHandler()->ProcessEvent( event ); + if ( !IsCellEditControlEnabled() ) + EnableCellEditControl( TRUE ); + if (IsCellEditControlEnabled()) { + wxGridCellAttr* attr = GetCellAttr(m_currentCellCoords); + attr->GetEditor()->StartingKey(event); + attr->DecRef(); } break; } @@ -3251,6 +3549,12 @@ void wxGrid::OnKeyDown( wxKeyEvent& event ) } +void wxGrid::OnEraseBackground(wxEraseEvent&) +{ } + + + + void wxGrid::SetCurrentCell( const wxGridCellCoords& coords ) { if ( SendEvent( EVT_GRID_SELECT_CELL, coords.GetRow(), coords.GetCol() ) ) @@ -3264,6 +3568,12 @@ void wxGrid::SetCurrentCell( const wxGridCellCoords& coords ) { HideCellEditControl(); SaveEditControlValue(); + EnableCellEditControl(FALSE); + + // Clear the old current cell highlight + wxRect r = BlockToDeviceRect(m_currentCellCoords, m_currentCellCoords); + m_currentCellCoords = coords; // Otherwise refresh redraws the highlight! + m_gridWin->Refresh( FALSE, &r ); } m_currentCellCoords = coords; @@ -3272,7 +3582,9 @@ void wxGrid::SetCurrentCell( const wxGridCellCoords& coords ) if ( m_displayed ) { - ShowCellEditControl(); + wxClientDC dc(m_gridWin); + PrepareDC(dc); + DrawCellHighlight(dc); if ( IsSelection() ) { @@ -3358,14 +3670,39 @@ void wxGrid::DrawCell( wxDC& dc, const wxGridCellCoords& coords ) // but all the rest is drawn by the cell renderer and hence may be // customized - wxGridCellRenderer *renderer = GetCellRenderer(row, col); wxRect rect; - rect.x = m_colRights[col] - m_colWidths[col] + 1; - rect.y = m_rowBottoms[row] - m_rowHeights[row] + 1; + rect.x = m_colRights[col] - m_colWidths[col]; + rect.y = m_rowBottoms[row] - m_rowHeights[row]; + rect.width = m_colWidths[col]; + rect.height = m_rowHeights[row]; + + wxGridCellAttr* attr = GetCellAttr(row, col); + attr->GetRenderer()->Draw(*this, *attr, dc, rect, row, col, IsInSelection(coords)); + attr->DecRef(); + + if (m_currentCellCoords == coords) + DrawCellHighlight(dc); +} + + +void wxGrid::DrawCellHighlight( wxDC& dc ) +{ + int row = m_currentCellCoords.GetRow(); + int col = m_currentCellCoords.GetCol(); + + if ( m_colWidths[col] <= 0 || m_rowHeights[row] <= 0 ) + return; + + wxRect rect; + rect.x = m_colRights[col] - m_colWidths[col]; + rect.y = m_rowBottoms[row] - m_rowHeights[row]; rect.width = m_colWidths[col] - 1; rect.height = m_rowHeights[row] - 1; - renderer->Draw(*this, dc, rect, row, col, IsInSelection(coords)); + dc.SetPen(wxPen(m_gridLineColour, 3, wxSOLID)); + dc.SetBrush(*wxTRANSPARENT_BRUSH); + + dc.DrawRectangle(rect); } void wxGrid::DrawCellBorder( wxDC& dc, const wxGridCellCoords& coords ) @@ -3429,13 +3766,13 @@ void wxGrid::DrawAllGridLines( wxDC& dc, const wxRegion & reg ) int i; for ( i = 0; i < m_numRows; i++ ) { - if ( m_rowBottoms[i] > bottom ) + if ( m_rowBottoms[i]-1 > bottom ) { break; } - else if ( m_rowBottoms[i] >= top ) + else if ( m_rowBottoms[i]-1 >= top ) { - dc.DrawLine( left, m_rowBottoms[i], right, m_rowBottoms[i] ); + dc.DrawLine( left, m_rowBottoms[i]-1, right, m_rowBottoms[i]-1 ); } } @@ -3444,13 +3781,13 @@ void wxGrid::DrawAllGridLines( wxDC& dc, const wxRegion & reg ) // for ( i = 0; i < m_numCols; i++ ) { - if ( m_colRights[i] > right ) + if ( m_colRights[i]-1 > right ) { break; } - else if ( m_colRights[i] >= left ) + else if ( m_colRights[i]-1 >= left ) { - dc.DrawLine( m_colRights[i], top, m_colRights[i], bottom ); + dc.DrawLine( m_colRights[i]-1, top, m_colRights[i]-1, bottom ); } } } @@ -3683,26 +4020,24 @@ void wxGrid::EnableEditing( bool edit ) { m_editable = edit; - // TODO: extend this for other edit control types - // - if ( m_editCtrlType == wxGRID_TEXTCTRL ) - { - ((wxTextCtrl *)m_cellEditCtrl)->SetEditable( m_editable ); - } + EnableCellEditControl(m_editable); } } -#if 0 // disabled for the moment - the cell control is always active void wxGrid::EnableCellEditControl( bool enable ) { - if ( m_cellEditCtrl && - enable != m_cellEditCtrlEnabled ) - { - m_cellEditCtrlEnabled = enable; + if (! m_editable) + return; + + if ( m_currentCellCoords == wxGridNoCellCoords ) + SetCurrentCell( 0, 0 ); - if ( m_cellEditCtrlEnabled ) + if ( enable != m_cellEditCtrlEnabled ) + { + if ( enable ) { + m_cellEditCtrlEnabled = enable; SetEditControlValue(); ShowCellEditControl(); } @@ -3710,16 +4045,14 @@ void wxGrid::EnableCellEditControl( bool enable ) { HideCellEditControl(); SaveEditControlValue(); + m_cellEditCtrlEnabled = enable; } } } -#endif void wxGrid::ShowCellEditControl() { - wxRect rect; - if ( IsCellEditControlEnabled() ) { if ( !IsVisible( m_currentCellCoords ) ) @@ -3728,14 +4061,16 @@ void wxGrid::ShowCellEditControl() } else { - rect = CellToRect( m_currentCellCoords ); + wxRect rect = CellToRect( m_currentCellCoords ); + int row = m_currentCellCoords.GetRow(); + int col = m_currentCellCoords.GetCol(); // convert to scrolled coords // int left, top, right, bottom; CalcScrolledPosition( rect.GetLeft(), rect.GetTop(), &left, &top ); CalcScrolledPosition( rect.GetRight(), rect.GetBottom(), &right, &bottom ); - + left--; top--; right--; bottom--; // cell is shifted by one pixel int cw, ch; m_gridWin->GetClientSize( &cw, &ch ); @@ -3744,8 +4079,7 @@ void wxGrid::ShowCellEditControl() // int extra; #if defined(__WXMOTIF__) - if ( m_currentCellCoords.GetRow() == 0 || - m_currentCellCoords.GetCol() == 0 ) + if ( row == 0 || col == 0 ) { extra = 2; } @@ -3754,8 +4088,7 @@ void wxGrid::ShowCellEditControl() extra = 4; } #else - if ( m_currentCellCoords.GetRow() == 0 || - m_currentCellCoords.GetCol() == 0 ) + if ( row == 0 || col == 0 ) { extra = 1; } @@ -3781,33 +4114,18 @@ void wxGrid::ShowCellEditControl() rect.SetBottom( rect.GetBottom() + 2*extra ); #endif - m_cellEditCtrl->SetSize( rect ); - m_cellEditCtrl->Show( TRUE ); - - switch ( m_editCtrlType ) - { - case wxGRID_TEXTCTRL: - ((wxTextCtrl *) m_cellEditCtrl)->SetInsertionPointEnd(); - break; - - case wxGRID_CHECKBOX: - // TODO: anything ??? - // - break; - - case wxGRID_CHOICE: - // TODO: anything ??? - // - break; - - case wxGRID_COMBOBOX: - // TODO: anything ??? - // - break; + wxGridCellAttr* attr = GetCellAttr(row, col); + wxGridCellEditor* editor = attr->GetEditor(); + if (! editor->IsCreated()) { + editor->Create(m_gridWin, -1, + new wxGridCellEditorEvtHandler(this, editor)); } - m_cellEditCtrl->SetFocus(); - } + editor->SetSize( rect ); + editor->Show( TRUE ); + editor->BeginEdit(row, col, this, attr); + attr->DecRef(); + } } } @@ -3816,93 +4134,36 @@ void wxGrid::HideCellEditControl() { if ( IsCellEditControlEnabled() ) { - m_cellEditCtrl->Show( FALSE ); + int row = m_currentCellCoords.GetRow(); + int col = m_currentCellCoords.GetCol(); + + wxGridCellAttr* attr = GetCellAttr(row, col); + attr->GetEditor()->Show( FALSE ); + attr->DecRef(); + m_gridWin->SetFocus(); } } void wxGrid::SetEditControlValue( const wxString& value ) { - if ( m_table ) - { - wxString s; - if ( !value ) - s = GetCellValue(m_currentCellCoords); - else - s = value; - - if ( IsCellEditControlEnabled() ) - { - switch ( m_editCtrlType ) - { - case wxGRID_TEXTCTRL: - ((wxGridTextCtrl *)m_cellEditCtrl)->SetStartValue(s); - break; - - case wxGRID_CHECKBOX: - // TODO: implement this - // - break; - - case wxGRID_CHOICE: - // TODO: implement this - // - break; - - case wxGRID_COMBOBOX: - // TODO: implement this - // - break; - } - } - } + // RD: The new Editors get the value from the table themselves now. This + // method can probably be removed... } void wxGrid::SaveEditControlValue() { - if ( m_table ) - { - wxWindow *ctrl = (wxWindow *)NULL; - - if ( IsCellEditControlEnabled() ) - { - ctrl = m_cellEditCtrl; - } - else - { - return; - } - - bool valueChanged = FALSE; - - switch ( m_editCtrlType ) - { - case wxGRID_TEXTCTRL: - valueChanged = (((wxGridTextCtrl *)ctrl)->GetValue() != - ((wxGridTextCtrl *)ctrl)->GetStartValue()); - SetCellValue( m_currentCellCoords, - ((wxTextCtrl *) ctrl)->GetValue() ); - break; - - case wxGRID_CHECKBOX: - // TODO: implement this - // - break; + if (IsCellEditControlEnabled()) { + int row = m_currentCellCoords.GetRow(); + int col = m_currentCellCoords.GetCol(); - case wxGRID_CHOICE: - // TODO: implement this - // - break; + wxGridCellAttr* attr = GetCellAttr(row, col); + bool changed = attr->GetEditor()->EndEdit(row, col, TRUE, this, attr); - case wxGRID_COMBOBOX: - // TODO: implement this - // - break; - } + attr->DecRef(); - if ( valueChanged ) - { + if (changed) { SendEvent( EVT_GRID_CELL_CHANGE, m_currentCellCoords.GetRow(), m_currentCellCoords.GetCol() ); @@ -3943,7 +4204,7 @@ int wxGrid::YToRow( int y ) if ( y < m_rowBottoms[i] ) return i; } - return -1; + return m_numRows; //-1; } @@ -3956,7 +4217,7 @@ int wxGrid::XToCol( int x ) if ( x < m_colRights[i] ) return i; } - return -1; + return m_numCols; //-1; } @@ -4768,23 +5029,27 @@ int wxGrid::GetColSize( int col ) void wxGrid::SetDefaultCellBackgroundColour( const wxColour& col ) { - m_gridWin->SetBackgroundColour(col); + m_defaultCellAttr->SetBackgroundColour(col); } void wxGrid::SetDefaultCellTextColour( const wxColour& col ) { - m_gridWin->SetForegroundColour(col); + m_defaultCellAttr->SetTextColour(col); } void wxGrid::SetDefaultCellAlignment( int horiz, int vert ) { - m_defaultCellHAlign = horiz; - m_defaultCellVAlign = vert; + m_defaultCellAttr->SetAlignment(horiz, vert); } void wxGrid::SetDefaultCellFont( const wxFont& font ) { - m_defaultCellFont = font; + m_defaultCellAttr->SetFont(font); +} + +void wxGrid::SetDefaultRenderer(wxGridCellRenderer *renderer) +{ + m_defaultCellAttr->SetRenderer(renderer); } // ---------------------------------------------------------------------------- @@ -4793,49 +5058,27 @@ void wxGrid::SetDefaultCellFont( const wxFont& font ) wxColour wxGrid::GetDefaultCellBackgroundColour() { - return m_gridWin->GetBackgroundColour(); + return m_defaultCellAttr->GetBackgroundColour(); } wxColour wxGrid::GetDefaultCellTextColour() { - return m_gridWin->GetForegroundColour(); + return m_defaultCellAttr->GetTextColour(); } wxFont wxGrid::GetDefaultCellFont() { - return m_defaultCellFont; + return m_defaultCellAttr->GetFont(); } void wxGrid::GetDefaultCellAlignment( int *horiz, int *vert ) { - if ( horiz ) - *horiz = m_defaultCellHAlign; - if ( vert ) - *vert = m_defaultCellVAlign; + m_defaultCellAttr->GetAlignment(horiz, vert); } -wxGridCellRenderer *wxGrid::GetCellRenderer(int row, int col) +wxGridCellRenderer *wxGrid::GetDefaultRenderer() const { - wxGridCellRenderer *renderer = (wxGridCellRenderer *)NULL; - wxGridCellAttr *attr = m_table ? m_table->GetAttr(row, col) : NULL; - if ( attr ) - { - renderer = attr->GetRenderer(); - - attr->DecRef(); - } - - if ( !renderer ) - { - if ( !m_defaultRenderer ) - { - m_defaultRenderer = new wxGridCellStringRenderer; - } - - renderer = m_defaultRenderer; - } - - return renderer; + return m_defaultCellAttr->GetRenderer(); } // ---------------------------------------------------------------------------- @@ -4845,60 +5088,42 @@ wxGridCellRenderer *wxGrid::GetCellRenderer(int row, int col) wxColour wxGrid::GetCellBackgroundColour(int row, int col) { wxGridCellAttr *attr = GetCellAttr(row, col); - - wxColour colour; - if ( attr && attr->HasBackgroundColour() ) - colour = attr->GetBackgroundColour(); - else - colour = GetDefaultCellBackgroundColour(); - + wxColour colour = attr->GetBackgroundColour(); attr->SafeDecRef(); - return colour; } wxColour wxGrid::GetCellTextColour( int row, int col ) { wxGridCellAttr *attr = GetCellAttr(row, col); - - wxColour colour; - if ( attr && attr->HasTextColour() ) - colour = attr->GetTextColour(); - else - colour = GetDefaultCellTextColour(); - + wxColour colour = attr->GetTextColour(); attr->SafeDecRef(); - return colour; } wxFont wxGrid::GetCellFont( int row, int col ) { wxGridCellAttr *attr = GetCellAttr(row, col); - - wxFont font; - if ( attr && attr->HasFont() ) - font = attr->GetFont(); - else - font = GetDefaultCellFont(); - + wxFont font = attr->GetFont(); attr->SafeDecRef(); - return font; } void wxGrid::GetCellAlignment( int row, int col, int *horiz, int *vert ) { wxGridCellAttr *attr = GetCellAttr(row, col); - - if ( attr && attr->HasAlignment() ) - attr->GetAlignment(horiz, vert); - else - GetDefaultCellAlignment(horiz, vert); - + attr->GetAlignment(horiz, vert); attr->SafeDecRef(); } +wxGridCellRenderer* wxGrid::GetCellRenderer(int row, int col) +{ + wxGridCellAttr* attr = GetCellAttr(row, col); + wxGridCellRenderer* renderer = attr->GetRenderer(); + attr->DecRef(); + return renderer; +} + // ---------------------------------------------------------------------------- // attribute support: cache, automatic provider creation, ... // ---------------------------------------------------------------------------- @@ -4910,6 +5135,10 @@ bool wxGrid::CanHaveAttributes() return FALSE; } + // RD: Maybe m_table->CanHaveAttributes() would be better in case the + // table is providing the attributes itself??? In which case + // I don't think the grid should create a Provider object for the + // table but the table should be smart enough to do that on its own. if ( !m_table->GetAttrProvider() ) { // use the default attr provider by default @@ -4971,6 +5200,12 @@ wxGridCellAttr *wxGrid::GetCellAttr(int row, int col) const attr = m_table ? m_table->GetAttr(row, col) : (wxGridCellAttr *)NULL; CacheAttr(row, col, attr); } + if (attr) { + attr->SetDefAttr(m_defaultCellAttr); + } else { + attr = m_defaultCellAttr; + attr->IncRef(); + } return attr; } @@ -4997,7 +5232,7 @@ wxGridCellAttr *wxGrid::GetOrCreateCellAttr(int row, int col) const CacheAttr(row, col, attr); } - + attr->SetDefAttr(m_defaultCellAttr); return attr; }