+    virtual void Advance(wxGridCellCoords& coords) const
+    {
+        wxASSERT( !IsAtBoundary(coords) );
+
+        m_oper.Set(coords, m_oper.Select(coords) - 1);
+    }
+
+    virtual int MoveByPixelDistance(int line, int distance) const
+    {
+        int pos = m_oper.GetLineStartPos(m_grid, line);
+        return m_oper.PosToLine(m_grid, pos - distance + 1, true);
+    }
+};
+
+class wxGridForwardOperations : public wxGridDirectionOperations
+{
+public:
+    wxGridForwardOperations(wxGrid *grid, const wxGridOperations& oper)
+        : wxGridDirectionOperations(grid, oper),
+          m_numLines(oper.GetNumberOfLines(grid))
+    {
+    }
+
+    virtual bool IsAtBoundary(const wxGridCellCoords& coords) const
+    {
+        wxASSERT_MSG( m_oper.Select(coords) < m_numLines, "invalid row/column" );
+
+        return m_oper.Select(coords) == m_numLines - 1;
+    }
+
+    virtual void Advance(wxGridCellCoords& coords) const
+    {
+        wxASSERT( !IsAtBoundary(coords) );
+
+        m_oper.Set(coords, m_oper.Select(coords) + 1);
+    }
+
+    virtual int MoveByPixelDistance(int line, int distance) const
+    {
+        int pos = m_oper.GetLineStartPos(m_grid, line);
+        return m_oper.PosToLine(m_grid, pos + distance, true);
+    }
+
+private:
+    const int m_numLines;
+};
+
+// ----------------------------------------------------------------------------
+// globals
+// ----------------------------------------------------------------------------
+
+//#define DEBUG_ATTR_CACHE
+#ifdef DEBUG_ATTR_CACHE
+    static size_t gs_nAttrCacheHits = 0;
+    static size_t gs_nAttrCacheMisses = 0;
+#endif
+
+// ----------------------------------------------------------------------------
+// constants
+// ----------------------------------------------------------------------------
+
+wxGridCellCoords wxGridNoCellCoords( -1, -1 );
+wxRect wxGridNoCellRect( -1, -1, -1, -1 );
+
+namespace
+{
+
+// scroll line size
+const size_t GRID_SCROLL_LINE_X = 15;
+const size_t GRID_SCROLL_LINE_Y = GRID_SCROLL_LINE_X;
+
+// the size of hash tables used a bit everywhere (the max number of elements
+// in these hash tables is the number of rows/columns)
+const int GRID_HASH_SIZE = 100;
+
+// the minimal distance in pixels the mouse needs to move to start a drag
+// operation
+const int DRAG_SENSITIVITY = 3;
+
+} // anonymous namespace
+
+// ----------------------------------------------------------------------------
+// private helpers
+// ----------------------------------------------------------------------------
+
+namespace
+{
+
+// ensure that first is less or equal to second, swapping the values if
+// necessary
+void EnsureFirstLessThanSecond(int& first, int& second)
+{
+    if ( first > second )
+        wxSwap(first, second);
+}
+
+} // anonymous namespace
+
+// ============================================================================
+// implementation
+// ============================================================================
+
+// ----------------------------------------------------------------------------
+// wxGridCellEditor
+// ----------------------------------------------------------------------------
+
+wxGridCellEditor::wxGridCellEditor()
+{
+    m_control = NULL;
+    m_attr = NULL;
+}
+
+wxGridCellEditor::~wxGridCellEditor()
+{
+    Destroy();
+}
+
+void wxGridCellEditor::Create(wxWindow* WXUNUSED(parent),
+                              wxWindowID WXUNUSED(id),
+                              wxEvtHandler* evtHandler)
+{
+    if ( evtHandler )
+        m_control->PushEventHandler(evtHandler);
+}
+
+void wxGridCellEditor::PaintBackground(const wxRect& rectCell,
+                                       wxGridCellAttr *attr)
+{
+    // erase the background because we might not fill the cell
+    wxClientDC dc(m_control->GetParent());
+    wxGridWindow* gridWindow = wxDynamicCast(m_control->GetParent(), wxGridWindow);
+    if (gridWindow)
+        gridWindow->GetOwner()->PrepareDC(dc);
+
+    dc.SetPen(*wxTRANSPARENT_PEN);
+    dc.SetBrush(wxBrush(attr->GetBackgroundColour()));
+    dc.DrawRectangle(rectCell);
+
+    // redraw the control we just painted over
+    m_control->Refresh();
+}
+
+void wxGridCellEditor::Destroy()
+{
+    if (m_control)
+    {
+        m_control->PopEventHandler( true /* delete it*/ );
+
+        m_control->Destroy();
+        m_control = NULL;
+    }
+}
+
+void wxGridCellEditor::Show(bool show, wxGridCellAttr *attr)
+{
+    wxASSERT_MSG(m_control, wxT("The wxGridCellEditor must be created first!"));
+
+    m_control->Show(show);