]> git.saurik.com Git - wxWidgets.git/commitdiff
Major redesign of grid classes:
authorMichael Bedward <mbedward@ozemail.com.au>
Thu, 3 Feb 2000 04:43:45 +0000 (04:43 +0000)
committerMichael Bedward <mbedward@ozemail.com.au>
Thu, 3 Feb 2000 04:43:45 +0000 (04:43 +0000)
- wxGrid now derives from wxScrolledWindow
- Row labels, col labels, corner labels and grid cell area
  implemented as separate classes

The new design fixes the display problems (bad flicker when
scrolling) and simplifies the internal handling of grid cell
coordinates, the edit control etc.

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@5818 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775

include/wx/generic/grid.h
src/generic/grid.cpp

index 23bef5c25a003bae6974b591ee9d959737505cdc..84536996ab316d7978573c0d113f8544943fb70d 100644 (file)
@@ -24,6 +24,7 @@
 #endif
 
 #include "wx/panel.h"
+#include "wx/scrolwin.h"
 #include "wx/string.h"
 #include "wx/scrolbar.h"
 #include "wx/event.h"
@@ -62,7 +63,7 @@ class WXDLLEXPORT wxGrid;
 //////////////////////////////////////////////////////////////////////
 
 
-class wxGridTableBase : public wxObject
+class WXDLLEXPORT wxGridTableBase : public wxObject
 {
     wxGrid * m_view;
     
@@ -114,7 +115,7 @@ enum wxGridTableRequest {
     wxGRIDTABLE_NOTIFY_COLS_DELETED
 };
 
-class wxGridTableMessage
+class WXDLLEXPORT wxGridTableMessage
 {
     wxGridTableBase *m_table;
     int m_id;
@@ -143,7 +144,8 @@ class wxGridTableMessage
 // A 2-dimensional array of strings for data values
 //
 
-WX_DECLARE_OBJARRAY(wxArrayString, wxGridStringArray);
+WX_DECLARE_EXPORTED_OBJARRAY(wxArrayString, wxGridStringArray);
+
 
 
 // ------ wxGridStringTable
@@ -152,7 +154,7 @@ WX_DECLARE_OBJARRAY(wxArrayString, wxGridStringArray);
 // that are stored in memory
 //
 
-class wxGridStringTable : public wxGridTableBase
+class WXDLLEXPORT wxGridStringTable : public wxGridTableBase
 {
     wxGridStringArray m_data;
 
@@ -201,7 +203,7 @@ class wxGridStringTable : public wxGridTableBase
 //
 //////////////////////////////////////////////////////////////////////
 
-class wxGridCellCoords
+class WXDLLEXPORT wxGridCellCoords
 {
     long m_row;
     long m_col;
@@ -250,13 +252,20 @@ class wxGridCellCoords
 extern wxGridCellCoords wxGridNoCellCoords;
 extern wxRect           wxGridNoCellRect;
 
+// An array of cell coords...
+//
+WX_DECLARE_EXPORTED_OBJARRAY(wxGridCellCoords, wxGridCellCoordsArray);
+
+
 
 // This set of classes is to provide for the use of different types of
 // cell edit controls in the grid while avoiding the wx class info 
 // system in deference to wxPython
 
-class wxGridTextCtrl : public wxTextCtrl
+class WXDLLEXPORT wxGridTextCtrl : public wxTextCtrl
 {
+    wxGrid *m_grid;
+    
     // TRUE for controls placed over cells,
     // FALSE for a control on a grid control panel
     bool m_isCellControl;  
@@ -268,6 +277,7 @@ class wxGridTextCtrl : public wxTextCtrl
   public:
     wxGridTextCtrl() {}
     wxGridTextCtrl( wxWindow *,
+                    wxGrid *,
                     bool isCellControl,
                     wxWindowID id,
                     const wxString& value = wxEmptyString,
@@ -283,14 +293,101 @@ class wxGridTextCtrl : public wxTextCtrl
 };
 
 
-class WXDLLEXPORT wxGrid : public wxPanel
+class WXDLLEXPORT wxGridRowLabelWindow : public wxWindow
 {
-    DECLARE_DYNAMIC_CLASS( wxGrid )
+    wxGrid   *m_owner;
+    
+    void OnPaint( wxPaintEvent& event );
+    void OnMouseEvent( wxMouseEvent& event );
+    void OnKeyDown( wxKeyEvent& event );
+
+public:
+    wxGridRowLabelWindow() {}
+    wxGridRowLabelWindow( wxGrid *parent, wxWindowID id, 
+                          const wxPoint &pos, const wxSize &size );
+   
+    DECLARE_DYNAMIC_CLASS(wxGridRowLabelWindow)
+    DECLARE_EVENT_TABLE()
+};
+
+
+class WXDLLEXPORT wxGridColLabelWindow : public wxWindow
+{
+    wxGrid   *m_owner;
+    
+    void OnPaint( wxPaintEvent &event );
+    void OnMouseEvent( wxMouseEvent& event );
+    void OnKeyDown( wxKeyEvent& event );
+
+public:
+    wxGridColLabelWindow() {}
+    wxGridColLabelWindow( wxGrid *parent, wxWindowID id, 
+                          const wxPoint &pos, const wxSize &size );
+   
+    DECLARE_DYNAMIC_CLASS(wxGridColLabelWindow)
+    DECLARE_EVENT_TABLE()
+};
+
+
+class WXDLLEXPORT wxGridCornerLabelWindow : public wxWindow
+{
+    wxGrid *m_owner;
+    
+    void OnMouseEvent( wxMouseEvent& event );
+    void OnKeyDown( wxKeyEvent& event );
+    
+  public:
+    wxGridCornerLabelWindow() {}
+    wxGridCornerLabelWindow( wxGrid *parent, wxWindowID id,
+                             const wxPoint &pos, const wxSize &size );
+
+    DECLARE_DYNAMIC_CLASS(wxGridCornerLabelWindow)
+    DECLARE_EVENT_TABLE()
+};
+
+
+
+class WXDLLEXPORT wxGridWindow : public wxPanel
+{
+    wxGrid                   *m_owner;
+    wxGridRowLabelWindow     *m_rowLabelWin;
+    wxGridColLabelWindow     *m_colLabelWin;
+
+    void OnPaint( wxPaintEvent &event );
+    void OnMouseEvent( wxMouseEvent& event );
+    void OnKeyDown( wxKeyEvent& );
+
+public:
+    wxGridWindow() {}
+    wxGridWindow( wxGrid *parent, 
+                  wxGridRowLabelWindow *rowLblWin,
+                  wxGridColLabelWindow *colLblWin,
+                  wxWindowID id, const wxPoint &pos, const wxSize &size );
+    ~wxGridWindow();
 
+    void ScrollWindow( int dx, int dy, const wxRect *rect );
+
+    DECLARE_DYNAMIC_CLASS(wxGridWindow)
+    DECLARE_EVENT_TABLE()
+};
+
+
+
+class WXDLLEXPORT wxGrid : public wxScrolledWindow
+{
   protected:
     bool m_created;
 
-    wxGridTableBase *m_table;
+    wxGridWindow             *m_gridWin;
+    wxGridRowLabelWindow     *m_rowLabelWin;
+    wxGridColLabelWindow     *m_colLabelWin;
+    wxGridCornerLabelWindow  *m_cornerLabelWin;
+
+    wxBoxSizer               *m_mainSizer;
+    wxBoxSizer               *m_topSizer;
+    wxBoxSizer               *m_middleSizer;
+    
+    wxGridTableBase          *m_table;
 
     int m_left;
     int m_top;
@@ -309,12 +406,10 @@ class WXDLLEXPORT wxGrid : public wxPanel
     int        m_defaultRowHeight;
     wxArrayInt m_rowHeights;
     wxArrayInt m_rowBottoms;
-    int        m_sumRowHeights;
 
     int        m_defaultColWidth;
     wxArrayInt m_colWidths;
     wxArrayInt m_colRights;
-    int        m_sumColWidths;
 
     int m_rowLabelWidth;
     int m_colLabelHeight;
@@ -336,17 +431,13 @@ class WXDLLEXPORT wxGrid : public wxPanel
 
     wxFont     m_defaultCellFont;
     
-    wxScrollBar * m_horizScrollBar;
-    wxScrollBar * m_vertScrollBar;
-    int m_scrollBarWidth;
-    int m_scrollPosX;
-    int m_scrollPosY;
-    int m_wholeColsVisible;
-    int m_wholeRowsVisible;
+    wxGridCellCoordsArray  m_cellsExposed;    
+    wxArrayInt             m_rowsExposed;
+    wxArrayInt             m_colsExposed;
+    wxArrayInt             m_rowLabelsExposed;
+    wxArrayInt             m_colLabelsExposed;
 
     bool m_inOnKeyDown;
-    bool m_inOnText;
-    bool m_firstPaint;
     int  m_batchCount;
 
     int  m_cursorMode;
@@ -366,7 +457,7 @@ class WXDLLEXPORT wxGrid : public wxPanel
     
     wxCursor m_rowResizeCursor;
     wxCursor m_colResizeCursor;
-
+   
     bool       m_editable;  // applies to whole grid
     int        m_editCtrlType;  // for current cell
     wxWindow*  m_cellEditCtrl;
@@ -374,16 +465,13 @@ class WXDLLEXPORT wxGrid : public wxPanel
     wxWindow*  m_topEditCtrl;
     bool       m_topEditCtrlEnabled;
     
-    // ------ internal init and update functions
-    //
-    void Create();                 
+
+    void Create();
     void Init();
     void CalcDimensions();
-    bool IsOnScreen();    
     bool Redimension( wxGridTableMessage& );
+
     
-    // ------ event processing
-    //
     bool SendEvent( const wxEventType,
                     int row, int col,
                     wxMouseEvent& );
@@ -391,114 +479,17 @@ class WXDLLEXPORT wxGrid : public wxPanel
     bool SendEvent( const wxEventType,
                     int row, int col );
     
+
     void OnPaint( wxPaintEvent& );
     void OnSize( wxSizeEvent& );
-    void OnMouse( wxMouseEvent& );
     void OnKeyDown( wxKeyEvent& );
-    void OnText( wxCommandEvent& );
-    void OnGridScroll( wxScrollEvent& );
-
-    void SelectCell( const wxGridCellCoords& coords );
-    void SelectCell( int row, int col )
-        { SelectCell( wxGridCellCoords(row, col) ); }
-
-
-    // ------ edit controls
-    //
-    void ShowCellEditControl();
-    void HideCellEditControl();
-    void SaveEditControlValue();
-
-    
-    // ------ grid location functions
-    //
-    int  XYToArea( int x, int y );  // returns one of the following...
-    enum { WXGRID_NOAREA,
-           WXGRID_ROWLABEL,
-           WXGRID_ROWLABEL_EDGE,
-           WXGRID_COLLABEL,
-           WXGRID_COLLABEL_EDGE,
-           WXGRID_CORNERLABEL,
-           WXGRID_CELL };
-    
-    void XYToCell( int x, int y, wxGridCellCoords& );
-    int  YToRow( int y );
-    int  XToCol( int x );
 
-    int  YToEdgeOfRow( int y );
-    int  XToEdgeOfCol( int x );
-
-    wxRect CellToRect( int row, int col );
-    wxRect CellToRect( const wxGridCellCoords& coords )
-        { return CellToRect( coords.GetRow(), coords.GetCol() ); }
-
-    bool MoveCursorUp();
-    bool MoveCursorDown();
-    bool MoveCursorLeft();
-    bool MoveCursorRight();
-    bool MovePageDown();
-    bool MovePageUp();
-    bool MoveCursorUpBlock();
-    bool MoveCursorDownBlock();
-    bool MoveCursorLeftBlock();
-    bool MoveCursorRightBlock();
-    
-    
-    // ------ label drawing functions
-    //
-    void DrawLabelAreas( wxDC& dc );
-    void DrawColLabelBorders( wxDC& dc );
-    void DrawColLabels( wxDC& dc );
-    void DrawColLabel( wxDC& dc, const wxRect&, int col );
-    void DrawRowLabelBorders( wxDC& dc );
-    void DrawRowLabels( wxDC& dc );
-    void DrawRowLabel( wxDC& dc, const wxRect&, int col );
-
-
-    // ------ cell drawing functions
-    //
-    void DrawCellArea( wxDC& dc );
-    void DrawGridLines( wxDC& dc );
-    void DrawCells( wxDC& dc );
-    void DrawCellBackground( wxDC& dc, const wxRect&, int row, int col );
-    void DrawCellValue( wxDC& dc, const wxRect&, int row, int col,
-                        const wxString& value = wxEmptyString, bool useValueArg = FALSE );
-    
-    // this updates the displayed cell text value but not the underlying 
-    // table cell value (it is used to echo text being entered into
-    // the top edit control when in-place editing is turned off)
-    //
-    void DrawCellValue( const wxGridCellCoords& coords, const wxString& value );
-    
-    // these are useful when you just need to draw one or a few
-    // cells
-    void DrawCell( int row, int col );
-    void DrawCell( const wxGridCellCoords& coords )
-        { DrawCell( coords.GetRow(), coords.GetCol() ); }
-        
-    void DrawCellHighlight( wxDC& dc, int row, int col );
-    void DrawCellHighlight( wxDC& dc, wxGridCellCoords& coords )
-        { DrawCellHighlight( dc, coords.GetRow(), coords.GetCol() ); }
-    void ShowCurrentCellHighlight( wxDC& dc );
-    void HideCurrentCellHighlight( wxDC& dc );
-            
-
-    // ------ generic drawing functions
-    //
-    void DrawTextRectangle( wxDC& dc, const wxString&, const wxRect&,
-                            int horizontalAlignment = wxLEFT,
-                            int verticalAlignment = wxTOP );
 
-    // Split a string containing newline chararcters into an array of
-    // strings and return the number of lines
-    //
-    void StringToLines( const wxString& value, wxArrayString& lines );
+    void SetCurrentCell( const wxGridCellCoords& coords );
+    void SetCurrentCell( int row, int col )
+        { SetCurrentCell( wxGridCellCoords(row, col) ); }
     
-    void GetTextBoxSize( wxDC& dc,
-                         wxArrayString& lines,
-                         long *width, long *height );
 
-    
     // ------ functions to get/send data (see also public functions)
     //
     bool GetModelValues();
@@ -516,17 +507,35 @@ class WXDLLEXPORT wxGrid : public wxPanel
             const wxPoint& pos = wxDefaultPosition,
             const wxSize& size = wxDefaultSize,
             long style = 0,
-            const wxString& name = wxPanelNameStr )
-        : wxPanel( parent, id, pos, size, style, name )
-        {
-            Create();
-        }
-        
+            const wxString& name = wxPanelNameStr );
+
     ~wxGrid();    
 
-    bool CreateGrid( int numRows = WXGRID_DEFAULT_NUMBER_ROWS,
-                     int numCols = WXGRID_DEFAULT_NUMBER_COLS );
+    bool CreateGrid( int numRows, int numCols );
+
+    
+    // ------ grid dimensions
+    //
+    int      GetNumberRows() { return  m_numRows; }
+    int      GetNumberCols() { return  m_numCols; }
+
+    
+    // ------ display update functions
+    //
+    void CalcRowLabelsExposed( wxRegion& reg );    
+    void CalcColLabelsExposed( wxRegion& reg );    
+    void CalcCellsExposed( wxRegion& reg );    
+
+    
+    // ------ event handlers
+    //
+    void ProcessRowLabelMouseEvent( wxMouseEvent& event );
+    void ProcessColLabelMouseEvent( wxMouseEvent& event );
+    void ProcessCornerLabelMouseEvent( wxMouseEvent& event );
+    void ProcessGridCellMouseEvent( wxMouseEvent& event );  
+    bool ProcessTableMessage( wxGridTableMessage& );
 
+    
     wxGridTableBase * GetTable() const { return m_table; }
     void SetTable( wxGridTableBase *table ) { m_table = table; }
 
@@ -538,28 +547,35 @@ class WXDLLEXPORT wxGrid : public wxPanel
     bool AppendCols( int numCols = 1, bool updateLabels=TRUE );
     bool DeleteCols( int pos = 0, int numCols = 1, bool updateLabels=TRUE );    
 
-    // ------ editing and edit controls
-    //
-    bool IsEditable() { return m_editable; }
-    void EnableEditing( bool edit );
-
-    void     EnableTopEditControl( bool enable );
-    bool     IsTopEditControlEnabled()
-             { return (m_topEditCtrl && m_topEditCtrlEnabled); }
-    void     EnableCellEditControl( bool enable );
-    bool     IsCellEditControlEnabled()
-             { return (m_cellEditCtrl && m_cellEditCtrlEnabled); }
-    void     SetEditControlValue( const wxString& s = wxEmptyString );
+    void DrawGridCellArea( wxDC& dc );
+    void DrawCellBorder( wxDC& dc, const wxGridCellCoords& );
+    void DrawAllGridLines( wxDC& dc );  // TODO - delete this ?
+    void DrawCell( wxDC& dc, const wxGridCellCoords& );
+    void DrawCellBackground( wxDC& dc, const wxGridCellCoords& );
+    void DrawCellValue( wxDC& dc, const wxGridCellCoords& );
+    
+    void DrawRowLabels( wxDC& dc );
+    void DrawRowLabel( wxDC& dc, int row );
+    void DrawColLabels( wxDC& dc );
+    void DrawColLabel( wxDC& dc, int col );
     
 
-    // ------ grid dimensions
+    // ------ Cell text drawing functions
     //
-    int      GetNumberRows() { return  m_numRows; }
-    int      GetNumberCols() { return  m_numCols; }
-    int      GetNumberVisibleRows() { return m_wholeRowsVisible; }
-    int      GetNumberVisibleCols() { return m_wholeColsVisible; }
+    void DrawTextRectangle( wxDC& dc, const wxString&, const wxRect&,
+                            int horizontalAlignment = wxLEFT,
+                            int verticalAlignment = wxTOP );
 
+    // Split a string containing newline chararcters into an array of
+    // strings and return the number of lines
+    //
+    void StringToLines( const wxString& value, wxArrayString& lines );
     
+    void GetTextBoxSize( wxDC& dc,
+                         wxArrayString& lines,
+                         long *width, long *height );
+    
+
     // ------
     // Code that does a lot of grid modification can be enclosed
     // between BeginBatch() and EndBatch() calls to avoid screen
@@ -569,6 +585,71 @@ class WXDLLEXPORT wxGrid : public wxPanel
     void     EndBatch() { if ( m_batchCount > 0 ) m_batchCount--; }
     int      GetBatchCount() { return m_batchCount; }
 
+
+    // ------ edit control functions
+    //
+    bool IsEditable() { return m_editable; }
+    void EnableEditing( bool edit );
+
+    void     EnableCellEditControl( bool enable );
+
+    bool     IsCellEditControlEnabled()
+             { return (m_cellEditCtrl && m_cellEditCtrlEnabled); }
+
+    void     EnableTopEditControl( bool enable );
+
+    bool     IsTopEditControlEnabled()
+             { return (m_topEditCtrl && m_topEditCtrlEnabled); }
+    
+    void ShowCellEditControl();
+    void HideCellEditControl();
+    void SetEditControlValue( const wxString& s = wxEmptyString );
+    void SaveEditControlValue();
+
+    
+    // ------ grid location functions
+    //  Note that all of these functions work with the logical coordinates of 
+    //  grid cells and labels so you will need to convert from device
+    //  coordinates for mouse events etc.
+    //
+    void XYToCell( int x, int y, wxGridCellCoords& );
+    int  YToRow( int y );
+    int  XToCol( int x );
+
+    int  YToEdgeOfRow( int y );
+    int  XToEdgeOfCol( int x );
+
+    wxRect CellToRect( int row, int col );
+    wxRect CellToRect( const wxGridCellCoords& coords )
+        { return CellToRect( coords.GetRow(), coords.GetCol() ); }
+
+    int  GetGridCursorRow() { return m_currentCellCoords.GetRow(); }
+    int  GetGridCursorCol() { return m_currentCellCoords.GetCol(); }
+    
+    // check to see if a cell is either wholly visible (the default arg) or
+    // at least partially visible in the grid window
+    //
+    bool IsVisible( int row, int col, bool wholeCellVisible = TRUE );
+    bool IsVisible( const wxGridCellCoords& coords, bool wholeCellVisible = TRUE )
+        { return IsVisible( coords.GetRow(), coords.GetCol(), wholeCellVisible ); }
+    void MakeCellVisible( int row, int col );
+    void MakeCellVisible( const wxGridCellCoords& coords )
+        { MakeCellVisible( coords.GetRow(), coords.GetCol() ); }
+
+    
+    // ------ grid cursor movement functions
+    //
+    bool MoveCursorUp();
+    bool MoveCursorDown();
+    bool MoveCursorLeft();
+    bool MoveCursorRight();
+    bool MovePageDown();
+    bool MovePageUp();
+    bool MoveCursorUpBlock();
+    bool MoveCursorDownBlock();
+    bool MoveCursorLeftBlock();
+    bool MoveCursorRightBlock();
+
     
     // ------ label and gridline formatting
     //
@@ -585,7 +666,7 @@ class WXDLLEXPORT wxGrid : public wxPanel
     wxString GetColLabelValue( int col );
     wxColour GetGridLineColour() { return m_gridLineColour; }
 
-    void     SetRowLabelSize( int width );
+        void     SetRowLabelSize( int width );
     void     SetColLabelSize( int height );
     void     SetLabelBackgroundColour( const wxColour& );
     void     SetLabelTextColour( const wxColour& );
@@ -599,7 +680,7 @@ class WXDLLEXPORT wxGrid : public wxPanel
     void     EnableGridLines( bool enable = TRUE );
     bool     GridLinesEnabled() { return m_gridLinesEnabled; }
 
-    
+
     // ------ row and col formatting
     //
     int      GetDefaultRowSize();
@@ -651,33 +732,8 @@ class WXDLLEXPORT wxGrid : public wxPanel
     void SetCellValue( int row, int col, const wxString& s );
     void SetCellValue( const wxGridCellCoords& coords, const wxString& s )
         { SetCellValue( coords.GetRow(), coords.GetCol(), s ); }
-            
-
-    // ------ interaction with data model
-    //
-    bool ProcessTableMessage( wxGridTableMessage& );
-    
-
-
-    // ------ grid location functions
-    //
-    
-    int  GetGridCursorRow() { return m_currentCellCoords.GetRow(); }
-    int  GetGridCursorCol() { return m_currentCellCoords.GetCol(); }
-    int  GetHorizontalScrollPos() { return m_scrollPosX; }
-    int  GetVerticalScrollPos() { return m_scrollPosY; }
-    
-    bool IsVisible( const wxGridCellCoords& );
-    void MakeCellVisible( int row, int col );
-    void MakeCellVisible( const wxGridCellCoords& coords )
-        { MakeCellVisible( coords.GetRow(), coords.GetCol() ); }
-                          
-    void SetGridCursor( int row, int col )
-        { SelectCell( wxGridCellCoords(row, col) ); }
-
-    void SetHorizontalScrollPos( int leftMostCol );
-    void SetVerticalScrollPos( int topMostRow );
 
+            
 
     // ------ selections of blocks of cells
     //
@@ -721,9 +777,11 @@ class WXDLLEXPORT wxGrid : public wxPanel
             *rightCol  = m_selectedBottomRight.GetCol();
         }
 
-    // get coordinates of selected block edges for repainting etc.
+    // This function returns the rectangle that encloses the selected cells
+    // in device coords and clipped to the client size of the grid window.
     //
-    wxRect SelectionToRect();
+    wxRect SelectionToDeviceRect();
+    
     
 
     // ------ For compatibility with previous wxGrid only...
@@ -739,7 +797,7 @@ class WXDLLEXPORT wxGrid : public wxPanel
             int x = -1, int y = -1, int w = -1, int h = -1,
             long style = 0,
             const wxString& name = wxPanelNameStr )
-        : wxPanel( parent, -1, wxPoint(x,y), wxSize(w,h), style, name )
+        : wxScrolledWindow( parent, -1, wxPoint(x,y), wxSize(w,h), style, name )
         { 
             Create();
         }    
@@ -747,9 +805,6 @@ class WXDLLEXPORT wxGrid : public wxPanel
     void SetCellValue( const wxString& val, int row, int col )
         { SetCellValue( row, col, val ); }
     
-    void AdjustScrollbars()
-        { CalcDimensions(); }
-
     void UpdateDimensions()
         { CalcDimensions(); }
 
@@ -757,11 +812,12 @@ class WXDLLEXPORT wxGrid : public wxPanel
     int GetCols() { return GetNumberCols(); }
     int GetCursorRow() { return GetGridCursorRow(); }
     int GetCursorColumn() { return GetGridCursorCol(); }
-    int GetScrollPosX() { return GetHorizontalScrollPos(); }
-    int GetScrollPosY() { return GetVerticalScrollPos(); }
     
-    void SetScrollX( int x ) { SetHorizontalScrollPos( x ); }
-    void SetScrollY( int y ) { SetVerticalScrollPos( y ); }
+    int GetScrollPosX() { return 0; }
+    int GetScrollPosY() { return 0; }
+    
+    void SetScrollX( int x ) { }
+    void SetScrollY( int y ) { }
 
     void SetColumnWidth( int col, int width )
         { SetColSize( col, width ); }
@@ -775,11 +831,11 @@ class WXDLLEXPORT wxGrid : public wxPanel
     int GetRowHeight( int row )
         { return GetRowSize( row ); }
         
-    int GetViewHeight()
-        { return m_wholeRowsVisible; }
+    int GetViewHeight() // returned num whole rows visible
+        { return 0; }
     
-    int GetViewWidth()
-        { return m_wholeColsVisible; }
+    int GetViewWidth() // returned num whole cols visible
+        { return 0; }
 
     void SetLabelSize( int orientation, int sz )
         {
@@ -876,20 +932,20 @@ class WXDLLEXPORT wxGrid : public wxPanel
             
     // ******** End of compatibility functions **********
 
-        
+
+
     // ------ control IDs
-    enum { wxGRID_HORIZSCROLL = 2000,
-           wxGRID_VERTSCROLL,
-           wxGRID_CELLCTRL,
+    enum { wxGRID_CELLCTRL = 2000,
            wxGRID_TOPCTRL };
 
     // ------ control types
-    enum { wxGRID_TEXTCTRL = 100,
+    enum { wxGRID_TEXTCTRL = 2100,
            wxGRID_CHECKBOX,
            wxGRID_CHOICE,
            wxGRID_COMBOBOX };
 
     
+    DECLARE_DYNAMIC_CLASS( wxGrid )
     DECLARE_EVENT_TABLE()
 };
 
@@ -903,8 +959,6 @@ class WXDLLEXPORT wxGrid : public wxPanel
 
 class WXDLLEXPORT wxGridEvent : public wxNotifyEvent
 {
-    DECLARE_DYNAMIC_CLASS(wxGridEvent)
-
   protected:
     int         m_row;
     int         m_col;
@@ -933,13 +987,13 @@ class WXDLLEXPORT wxGridEvent : public wxNotifyEvent
     bool        MetaDown() { return m_meta; }
     bool        ShiftDown() { return m_shift; }
     bool        AltDown() { return m_alt; }
+
+    DECLARE_DYNAMIC_CLASS(wxGridEvent)
 };
 
 
 class WXDLLEXPORT wxGridSizeEvent : public wxNotifyEvent
 {
-    DECLARE_DYNAMIC_CLASS(wxGridSizeEvent)
-
   protected:
     int         m_rowOrCol;
     int         m_x;
@@ -966,13 +1020,13 @@ class WXDLLEXPORT wxGridSizeEvent : public wxNotifyEvent
     bool        MetaDown() { return m_meta; }
     bool        ShiftDown() { return m_shift; }
     bool        AltDown() { return m_alt; }
+
+    DECLARE_DYNAMIC_CLASS(wxGridSizeEvent)
 };
 
 
 class WXDLLEXPORT wxGridRangeSelectEvent : public wxNotifyEvent
 {
-    DECLARE_DYNAMIC_CLASS(wxGridRangeSelectEvent)
-
   protected:
     wxGridCellCoords  m_topLeft;
     wxGridCellCoords  m_bottomRight;
@@ -1009,6 +1063,8 @@ class WXDLLEXPORT wxGridRangeSelectEvent : public wxNotifyEvent
     bool        MetaDown()     { return m_meta; }
     bool        ShiftDown()    { return m_shift; }
     bool        AltDown()      { return m_alt; }
+
+    DECLARE_DYNAMIC_CLASS(wxGridRangeSelectEvent)
 };
 
 
index f4738531348510f1d8210336743169a06c0f5c98..fd543009782ba2987b4aa210d6b842e9ff6bbf2b 100644 (file)
@@ -31,6 +31,7 @@
     #include "wx/dcclient.h"
     #include "wx/settings.h"
     #include "wx/log.h"
+    #include "wx/sizer.h"
 #endif
 
 #include "wx/generic/grid.h"
 wxGridCellCoords wxGridNoCellCoords( -1, -1 );
 wxRect           wxGridNoCellRect( -1, -1, -1, -1 );
 
+// this is a magic incantation which must be done!
+#include "wx/arrimpl.cpp"
+
+WX_DEFINE_OBJARRAY(wxGridCellCoordsArray)
 
 
 //////////////////////////////////////////////////////////////////////
@@ -182,10 +187,6 @@ wxGridTableMessage::wxGridTableMessage( wxGridTableBase *table, int id,
 // created by wxGrid if you don't specify an alternative table class.
 //
 
-
-// this is a magic incantation which must be done!
-#include "wx/arrimpl.cpp"
-
 WX_DEFINE_OBJARRAY(wxGridStringArray)
 
 IMPLEMENT_DYNAMIC_CLASS( wxGridStringTable, wxGridTableBase )
@@ -576,6 +577,7 @@ END_EVENT_TABLE()
 
 
 wxGridTextCtrl::wxGridTextCtrl( wxWindow *par,
+                                wxGrid *grid,
                                 bool isCellControl,
                                 wxWindowID id,
                                 const wxString& value,
@@ -584,16 +586,17 @@ wxGridTextCtrl::wxGridTextCtrl( wxWindow *par,
                                 long style )
         : wxTextCtrl( par, id, value, pos, size, style )
 {
+    m_grid = grid;
     m_isCellControl = isCellControl;
 }
 
 
-void wxGridTextCtrl::OnKeyDown( wxKeyEvent& ev )
+void wxGridTextCtrl::OnKeyDown( wxKeyEvent& event )
 {
-    switch ( ev.KeyCode() )
+    switch ( event.KeyCode() )
     {
         case WXK_ESCAPE:
-            ((wxGrid *)GetParent())->SetEditControlValue( startValue );
+            m_grid->SetEditControlValue( startValue );
             SetInsertionPointEnd();
             break;
 
@@ -609,14 +612,14 @@ void wxGridTextCtrl::OnKeyDown( wxKeyEvent& ev )
                 // send the event to the parent grid, skipping the
                 // event if nothing happens
                 //
-                ev.Skip( !GetParent()->ProcessEvent( ev ) );
+                event.Skip( m_grid->ProcessEvent( event ) );
             }
             else
             {
                 // default text control response within the top edit
                 // control
                 //
-                ev.Skip();
+                event.Skip();
             }
             break;
 
@@ -627,19 +630,19 @@ void wxGridTextCtrl::OnKeyDown( wxKeyEvent& ev )
                 // send the event to the parent grid, skipping the
                 // event if nothing happens
                 //
-                ev.Skip( !GetParent()->ProcessEvent( ev ) );
+                event.Skip( m_grid->ProcessEvent( event ) );
             }
             else
             {
                 // default text control response within the top edit
                 // control
                 //
-                ev.Skip();
+                event.Skip();
             }
             break;
 
         default:
-            ev.Skip();
+            event.Skip();
     }
 }
 
@@ -650,22 +653,275 @@ void wxGridTextCtrl::SetStartValue( const wxString& s )
 }
 
 
+
+//////////////////////////////////////////////////////////////////////
+
+IMPLEMENT_DYNAMIC_CLASS( wxGridRowLabelWindow, wxWindow )
+
+BEGIN_EVENT_TABLE( wxGridRowLabelWindow, wxWindow )
+    EVT_PAINT( wxGridRowLabelWindow::OnPaint )
+    EVT_MOUSE_EVENTS( wxGridRowLabelWindow::OnMouseEvent )
+    EVT_KEY_DOWN( wxGridRowLabelWindow::OnKeyDown )
+END_EVENT_TABLE()
+
+wxGridRowLabelWindow::wxGridRowLabelWindow( wxGrid *parent, 
+                                            wxWindowID id, 
+                                            const wxPoint &pos, const wxSize &size )
+  : wxWindow( parent, id, pos, size )
+{
+    m_owner = parent;
+}
+
+void wxGridRowLabelWindow::OnPaint( wxPaintEvent &event )
+{
+    wxPaintDC dc(this);
+
+    // NO - don't do this because it will set both the x and y origin
+    // coords to match the parent scrolled window and we just want to
+    // set the y coord  - MB
+    //
+    // m_owner->PrepareDC( dc );
+    
+    wxCoord x, y;
+    m_owner->CalcUnscrolledPosition( 0, 0, &x, &y );
+    dc.SetDeviceOrigin( 0, -y );
+    
+    m_owner->CalcRowLabelsExposed( GetUpdateRegion() );
+    m_owner->DrawRowLabels( dc );
+}
+
+
+void wxGridRowLabelWindow::OnMouseEvent( wxMouseEvent& event )
+{
+    m_owner->ProcessRowLabelMouseEvent( 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->ProcessEvent( event ) ) event.Skip();
+}
+
+
+
+//////////////////////////////////////////////////////////////////////
+
+IMPLEMENT_DYNAMIC_CLASS( wxGridColLabelWindow, wxWindow )
+
+BEGIN_EVENT_TABLE( wxGridColLabelWindow, wxWindow )
+    EVT_PAINT( wxGridColLabelWindow::OnPaint )
+    EVT_MOUSE_EVENTS( wxGridColLabelWindow::OnMouseEvent )
+    EVT_KEY_DOWN( wxGridColLabelWindow::OnKeyDown )
+END_EVENT_TABLE()
+
+wxGridColLabelWindow::wxGridColLabelWindow( wxGrid *parent, 
+                                            wxWindowID id, 
+                                            const wxPoint &pos, const wxSize &size )
+  : wxWindow( parent, id, pos, size )
+{
+    m_owner = parent;
+}
+
+void wxGridColLabelWindow::OnPaint( wxPaintEvent &event )
+{
+    wxPaintDC dc(this);
+
+    // NO - don't do this because it will set both the x and y origin
+    // coords to match the parent scrolled window and we just want to
+    // set the x coord  - MB
+    //
+    // m_owner->PrepareDC( dc );
+    
+    wxCoord x, y;
+    m_owner->CalcUnscrolledPosition( 0, 0, &x, &y );
+    dc.SetDeviceOrigin( -x, 0 );
+
+    m_owner->CalcColLabelsExposed( GetUpdateRegion() );    
+    m_owner->DrawColLabels( dc );    
+}
+
+
+void wxGridColLabelWindow::OnMouseEvent( wxMouseEvent& event )
+{
+    m_owner->ProcessColLabelMouseEvent( 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->ProcessEvent( event ) ) event.Skip();
+}
+
+
+
+//////////////////////////////////////////////////////////////////////
+
+IMPLEMENT_DYNAMIC_CLASS( wxGridCornerLabelWindow, wxWindow )
+
+BEGIN_EVENT_TABLE( wxGridCornerLabelWindow, wxWindow )
+    EVT_MOUSE_EVENTS( wxGridCornerLabelWindow::OnMouseEvent )
+    EVT_KEY_DOWN( wxGridCornerLabelWindow::OnKeyDown )
+END_EVENT_TABLE()
+
+wxGridCornerLabelWindow::wxGridCornerLabelWindow( wxGrid *parent, 
+                                                  wxWindowID id, 
+                                                  const wxPoint &pos, const wxSize &size )
+  : wxWindow( parent, id, pos, size, wxRAISED_BORDER )
+{
+    m_owner = parent;
+}
+
+
+void wxGridCornerLabelWindow::OnMouseEvent( wxMouseEvent& event )
+{
+    m_owner->ProcessCornerLabelMouseEvent( 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->ProcessEvent( event ) ) event.Skip();
+}
+
+
+
 //////////////////////////////////////////////////////////////////////
 
-IMPLEMENT_DYNAMIC_CLASS( wxGrid, wxPanel )
+IMPLEMENT_DYNAMIC_CLASS( wxGridWindow, wxPanel )
+
+BEGIN_EVENT_TABLE( wxGridWindow, wxPanel )
+    EVT_PAINT( wxGridWindow::OnPaint )
+    EVT_SCROLLWIN( wxGridWindow::ScrollWindow )
+    EVT_MOUSE_EVENTS( wxGridWindow::OnMouseEvent )
+    EVT_KEY_DOWN( wxGridWindow::OnKeyDown )
+END_EVENT_TABLE()
+
+wxGridWindow::wxGridWindow( wxGrid *parent, 
+                            wxGridRowLabelWindow *rowLblWin, 
+                            wxGridColLabelWindow *colLblWin,
+                            wxWindowID id, const wxPoint &pos, const wxSize &size )
+        : wxPanel( parent, id, pos, size, wxSUNKEN_BORDER, "grid window" )
+{
+    m_owner = parent;
+    m_rowLabelWin = rowLblWin;
+    m_colLabelWin = colLblWin;
+    
+    SetBackgroundColour( "WHITE" );
+}
+
+
+wxGridWindow::~wxGridWindow()
+{
+}
+
+
+void wxGridWindow::OnPaint( wxPaintEvent &WXUNUSED(event) )
+{
+    wxPaintDC dc( this );
+    m_owner->PrepareDC( dc );
+
+    m_owner->CalcCellsExposed( GetUpdateRegion() );
+    m_owner->DrawGridCellArea( dc );
+}
+
+
+void wxGridWindow::ScrollWindow( int dx, int dy, const wxRect *rect )
+{
+    wxPanel::ScrollWindow( dx, dy, rect );
+    m_rowLabelWin->ScrollWindow( 0, dy, rect );
+    m_colLabelWin->ScrollWindow( dx, 0, rect );
+}
+
+
+void wxGridWindow::OnMouseEvent( wxMouseEvent& event )
+{
+    m_owner->ProcessGridCellMouseEvent( event );
+}
+
+
+// This seems to be required for wxMotif otherwise the mouse
+// cursor must be in the cell edit control to get key events
+//
+void wxGridWindow::OnKeyDown( wxKeyEvent& event )
+{
+    if ( !m_owner->ProcessEvent( event ) ) event.Skip();
+}
 
 
-BEGIN_EVENT_TABLE( wxGrid, wxPanel )
+
+//////////////////////////////////////////////////////////////////////
+
+IMPLEMENT_DYNAMIC_CLASS( wxGrid, wxScrolledWindow )
+
+BEGIN_EVENT_TABLE( wxGrid, wxScrolledWindow )
     EVT_PAINT( wxGrid::OnPaint )
     EVT_SIZE( wxGrid::OnSize )
-    EVT_MOUSE_EVENTS( wxGrid::OnMouse )
     EVT_KEY_DOWN( wxGrid::OnKeyDown )
-    EVT_TEXT( wxGRID_CELLCTRL, wxGrid::OnText )
-    EVT_TEXT( wxGRID_TOPCTRL, wxGrid::OnText )
-    EVT_COMMAND_SCROLL( wxGRID_HORIZSCROLL, wxGrid::OnGridScroll)
-    EVT_COMMAND_SCROLL( wxGRID_VERTSCROLL, wxGrid::OnGridScroll)
 END_EVENT_TABLE()
 
+wxGrid::wxGrid( wxWindow *parent,
+                 wxWindowID id,
+                 const wxPoint& pos,
+                 const wxSize& size,
+                 long style,
+                 const wxString& name )
+  : wxScrolledWindow( parent, id, pos, size, style, name )
+{
+    Create();
+
+    int colLblH = WXGRID_DEFAULT_COL_LABEL_HEIGHT;
+    int rowLblW = WXGRID_DEFAULT_ROW_LABEL_WIDTH;
+
+    m_rowLabelWin = new wxGridRowLabelWindow( this, 
+                                              -1, 
+                                              wxDefaultPosition, 
+                                              wxSize(rowLblW,-1) );
+
+    m_colLabelWin = new wxGridColLabelWindow( this,
+                                              -1,
+                                              wxDefaultPosition,
+                                              wxSize(-1, colLblH ) );
+                                              
+    m_cornerLabelWin = new wxGridCornerLabelWindow( this,
+                                                    -1,
+                                                    wxDefaultPosition,
+                                                    wxSize(rowLblW, colLblH ) );
+                                              
+    m_gridWin = new wxGridWindow( this, 
+                                  m_rowLabelWin, 
+                                  m_colLabelWin, 
+                                  -1, 
+                                  wxDefaultPosition, 
+                                  wxDefaultSize );
+
+    SetTargetWindow( m_gridWin );
+    
+    m_mainSizer = new wxBoxSizer( wxVERTICAL );
+    
+    m_topSizer = new wxBoxSizer( wxHORIZONTAL );
+    m_topSizer->Add( m_cornerLabelWin, 0 );
+    m_topSizer->Add( m_colLabelWin, 1 );
+    
+    m_mainSizer->Add( m_topSizer, 0, wxEXPAND );
+    
+    m_middleSizer = new wxBoxSizer( wxHORIZONTAL );
+    m_middleSizer->Add( m_rowLabelWin, 0, wxEXPAND );
+    m_middleSizer->Add( m_gridWin, 1, wxEXPAND );
+    
+    m_mainSizer->Add( m_middleSizer, 1, wxEXPAND );
+
+    SetAutoLayout( TRUE );
+    SetSizer( m_mainSizer );
+}
 
 wxGrid::~wxGrid()
 {
@@ -680,36 +936,44 @@ wxGrid::~wxGrid()
 void wxGrid::Create()
 {
     m_table          = (wxGridTableBase *) NULL;
+    m_gridWin        = (wxGridWindow *) NULL;
+    m_rowLabelWin    = (wxGridRowLabelWindow *) NULL;
+    m_colLabelWin    = (wxGridColLabelWindow *) NULL;
+    m_cornerLabelWin = (wxGridCornerLabelWindow *) NULL;
+    m_cellEditCtrl   = (wxWindow *) NULL;    
+
+    // TODO: do we need this or should the top edit control be an add-on ?
+    //
     m_topEditCtrl    = (wxWindow *) NULL;
-    m_cellEditCtrl   = (wxWindow *) NULL;
-    m_horizScrollBar = (wxScrollBar *) NULL;
-    m_vertScrollBar  = (wxScrollBar *) NULL;
+}
+
+
+bool wxGrid::CreateGrid( int numRows, int numCols )
+{
+    if ( m_created )
+    {
+        wxLogError( wxT("wxGrid::CreateGrid(numRows, numCols) called more than once") );
+        return FALSE;
+    }
+    else
+    {
+        m_numRows = numRows;
+        m_numCols = numCols;
+
+        m_table = new wxGridStringTable( m_numRows, m_numCols );
+        m_table->SetView( this );
+        Init();
+        m_created = TRUE;
+    }
 
-    m_numRows = 0;
-    m_numCols = 0;
-    m_created = FALSE;
+    return m_created;
 }
 
+
 void wxGrid::Init()
 {
     int i;
 
-    m_left = 0;
-    m_top  = 0;
-
-    // TODO: perhaps have a style flag for control panel
-    //
-    m_topEditCtrlEnabled = FALSE;
-    m_topEditCtrl = new wxGridTextCtrl( this,
-                                        FALSE,
-                                        wxGRID_TOPCTRL,
-                                        "",
-                                        wxPoint(10, 10),
-                                        wxSize(WXGRID_DEFAULT_TOPEDIT_WIDTH,
-                                               WXGRID_DEFAULT_TOPEDIT_HEIGHT),
-                                        wxTE_MULTILINE );
-    m_topEditCtrl->Show( FALSE );
-
     if ( m_numRows <= 0 )
         m_numRows = WXGRID_DEFAULT_NUMBER_ROWS;
 
@@ -719,10 +983,8 @@ void wxGrid::Init()
     m_rowLabelWidth  = WXGRID_DEFAULT_ROW_LABEL_WIDTH;
     m_colLabelHeight = WXGRID_DEFAULT_COL_LABEL_HEIGHT;
 
-    // default labels are pale grey with black text
-    //
-    m_labelBackgroundColour = wxColour( 192, 192, 192 );
-    m_labelTextColour       = wxColour(   0,   0,   0 );
+    m_labelBackgroundColour = m_rowLabelWin->GetBackgroundColour();
+    m_labelTextColour       = wxColour( "BLACK" );
 
     // TODO: something better than this ?
     //
@@ -735,58 +997,36 @@ void wxGrid::Init()
     m_colLabelHorizAlign = wxCENTRE;
     m_colLabelVertAlign  = wxTOP;
 
-    m_defaultRowHeight = WXGRID_DEFAULT_ROW_HEIGHT;
     m_defaultColWidth  = WXGRID_DEFAULT_COL_WIDTH;
-
+    m_defaultRowHeight = m_gridWin->GetCharHeight() + 8;
+    
     m_rowHeights.Alloc( m_numRows );
     m_rowBottoms.Alloc( m_numRows );
-    m_sumRowHeights = 0;
+    int rowBottom = 0;
     for ( i = 0;  i < m_numRows;  i++ )
     {
         m_rowHeights.Add( m_defaultRowHeight );
-        m_rowBottoms.Add( 0 );  // set by CalcDimensions()
+        rowBottom += m_defaultRowHeight;
+        m_rowBottoms.Add( rowBottom );
     }
-    m_sumRowHeights = m_defaultRowHeight * m_numRows;
 
     m_colWidths.Alloc( m_numCols );
-    m_colRights.Alloc( m_numRows );
-    m_sumColWidths = 0;
+    m_colRights.Alloc( m_numCols );
+    int colRight = 0;
     for ( i = 0;  i < m_numCols;  i++ )
     {
         m_colWidths.Add( m_defaultColWidth );
-        m_colRights.Add( 0 );  // set by CalcDimensions()
+        colRight += m_defaultColWidth;
+        m_colRights.Add( colRight );
     }
-    m_sumColWidths = m_defaultColWidth * m_numCols;
 
     // TODO: improve this ?
     //
     m_defaultCellFont = this->GetFont();
 
-    m_gridLineColour = wxColour(   0,   0, 255 );
+    m_gridLineColour = wxColour( 128, 128, 255 );
     m_gridLinesEnabled = TRUE;
 
-    m_scrollBarWidth = WXGRID_DEFAULT_SCROLLBAR_WIDTH;
-
-    m_horizScrollBar = new wxScrollBar( this,
-                                        wxGRID_HORIZSCROLL,
-                                        wxPoint(0, 0),
-                                        wxSize(10, 10),
-                                        wxHORIZONTAL);
-
-    m_vertScrollBar = new wxScrollBar( this,
-                                       wxGRID_VERTSCROLL,
-                                       wxPoint(0, 0),
-                                       wxSize(10, 10),
-                                       wxVERTICAL);
-    m_scrollPosX = 0;
-    m_scrollPosY = 0;
-    m_wholeColsVisible = 0;
-    m_wholeRowsVisible = 0;
-
-    m_firstPaint = TRUE;
-    m_inOnKeyDown = FALSE;
-    m_batchCount = 0;
-
     m_cursorMode  = WXGRID_CURSOR_DEFAULT;
     m_dragLastPos  = -1;
     m_dragRowOrCol = -1;
@@ -803,9 +1043,13 @@ void wxGrid::Init()
 
     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( this,
+    m_cellEditCtrl = new wxGridTextCtrl( m_gridWin,
+                                         this,
                                          TRUE,
                                          wxGRID_CELLCTRL,
                                          "",
@@ -819,196 +1063,31 @@ void wxGrid::Init()
     m_cellEditCtrl->Show( FALSE );
     m_cellEditCtrlEnabled = TRUE;
     m_editCtrlType = wxGRID_TEXTCTRL;
-
-    // This is here in case OnSize does not get called when the grid is
-    // displayed
-    //
-    CalcDimensions();
+    
+    // TODO: do we need this or should the top edit control be an add-on ?
+    //    
+    m_topEditCtrlEnabled = FALSE;    
 }
 
 
 void wxGrid::CalcDimensions()
 {
-    int i;
-
-    if ( IsTopEditControlEnabled() )
-    {
-        int ctrlW, ctrlH;
-        m_topEditCtrl->GetSize( &ctrlW, &ctrlH );
-
-        m_top = ctrlH + 20;
-    }
-    else
-    {
-        m_top = 0;
-    }
-
-    // check to see if either of the scroll bars are required
-    //
     int cw, ch;
-    GetClientSize(&cw, &ch);
-
-    // begin by assuming that we don't need either scroll bar
-    //
-    int vertScrollBarWidth = 0;
-    int horizScrollBarHeight = 0;
-
-    // Each scroll bar needs to eventually know if the other one is
-    // required in deciding whether or not it is also required - hence
-    // this loop. A bit inelegant but simple and it works.
-    //
-    int check;
-    for ( check = 0;  check < 2;  check++ )
-    {
-        if ( m_top + m_colLabelHeight + m_sumRowHeights + horizScrollBarHeight > ch )
-        {
-            vertScrollBarWidth = m_scrollBarWidth;
-        }
-
-        if ( m_left + m_rowLabelWidth + m_sumColWidths + vertScrollBarWidth > cw)
-        {
-            horizScrollBarHeight = m_scrollBarWidth;
-        }
-    }
-
-
-    // if the window has been resized while scrolled then the scroll
-    // position might need to be adjusted...
-    //
-    bool adjustScrollPos = FALSE;
-    if ( !vertScrollBarWidth )
-    {
-        if ( m_scrollPosY )
-        {
-            adjustScrollPos = TRUE;
-            m_scrollPosY = 0;
-        }
-    }
-    if ( !horizScrollBarHeight )
-    {
-        if ( m_scrollPosX )
-        {
-            adjustScrollPos = TRUE;
-            m_scrollPosX = 0;
-        }
-    }
-
-
-    // calculate the coords of row bottom edges and col right edges
-    //
-    int bottom =  m_top + m_colLabelHeight;
-    for ( i = m_scrollPosY;  i < m_numRows;  i++ )
-    {
-        bottom += m_rowHeights[i];
-        m_rowBottoms[i] = bottom;
-    }
-
-    int right = m_left + m_rowLabelWidth;
-    for ( i = m_scrollPosX;  i < m_numCols;  i++ )
-    {
-        right += m_colWidths[i];
-        m_colRights[i] = right;
-    }
-
-
-    // check how many rows and cols are visible
-    //
-    m_wholeRowsVisible = 0;
-    if ( m_numRows > 0 )
-    {
-        for ( i = m_scrollPosY; i < m_numRows; i++ )
-        {
-            // A partial row doesn't count, we still have to scroll to
-            // see the rest of it
-            if ( m_rowBottoms[i] + horizScrollBarHeight > ch ) break;
-
-            m_wholeRowsVisible++ ;
-        }
-    }
-
-    m_wholeColsVisible = 0;
-    if ( m_numCols )
-    {
-        for ( i = m_scrollPosX; i < m_numCols; i++ )
-        {
-            // A partial col doesn't count, we still have to scroll to
-            // see the rest of it
-            if ( m_colRights[i] + vertScrollBarWidth > cw ) break;
-
-            m_wholeColsVisible++ ;
-        }
-    }
-
-    if ( m_vertScrollBar )
-    {
-        if ( !vertScrollBarWidth )
-        {
-            m_vertScrollBar->Show(FALSE);
-        }
-        else
-        {
-            m_vertScrollBar->Show(TRUE);
-            m_vertScrollBar->SetScrollbar(
-                m_scrollPosY,
-                wxMax(m_wholeRowsVisible, 1),
-                (m_wholeRowsVisible == 0 ? 1 : m_numRows),
-                wxMax(m_wholeRowsVisible, 1) );
-
-            m_vertScrollBar->SetSize( cw - m_scrollBarWidth,
-                                      m_top,
-                                      m_scrollBarWidth,
-                                      ch - m_top - horizScrollBarHeight);
-        }
-    }
-
-    if ( m_horizScrollBar )
-    {
-        if ( !horizScrollBarHeight )
-        {
-            m_horizScrollBar->Show(FALSE);
-        }
-        else
-        {
-            m_horizScrollBar->Show(TRUE);
-
-            m_horizScrollBar->SetScrollbar(
-                m_scrollPosX,
-                wxMax(m_wholeColsVisible, 1),
-                (m_wholeColsVisible == 0) ? 1 : m_numCols,
-                wxMax(m_wholeColsVisible, 1) );
-
-            m_horizScrollBar->SetSize( m_left,
-                                       ch - m_scrollBarWidth,
-                                       cw - m_left - vertScrollBarWidth,
-                                       m_scrollBarWidth );
-        }
-    }
+    GetClientSize( &cw, &ch );
 
-    m_bottom = m_right = 0;
-    if ( m_numRows > 0 )
-    {
-        m_bottom = wxMin( m_rowBottoms[m_numRows-1],
-                          ch - horizScrollBarHeight );
-    }
-    if ( m_numCols > 0 )
+    if ( m_numRows > 0  &&  m_numCols > 0 )
     {
-        m_right = wxMin( m_colRights[m_numCols-1],
-                         cw - vertScrollBarWidth );
+        int right = m_colRights[ m_numCols-1 ] + 20;
+        int bottom = m_rowBottoms[ m_numRows-1 ] + 20;
+    
+        // TODO: restore the scroll position that we had before sizing
+        //
+        int x, y;
+        GetViewStart( &x, &y );
+        SetScrollbars( 10, 10, 
+                       right/10, bottom/10,
+                       x, y );
     }
-
-    // if the scroll position was adjusted (due to a window resize)
-    // ensure that the cell highlight and edit control are displayed
-    // correctly
-    //
-    if ( adjustScrollPos ) SelectCell( m_currentCellCoords );
-}
-
-
-bool wxGrid::IsOnScreen()
-{
-    int cw, ch;
-    GetClientSize( &cw, &ch );
-    return ( cw > 10 );
 }
 
 
@@ -1029,9 +1108,17 @@ bool wxGrid::Redimension( wxGridTableMessage& msg )
             {
                 m_rowHeights.Insert( m_defaultRowHeight, pos );
                 m_rowBottoms.Insert( 0, pos );
-                m_sumRowHeights += m_defaultRowHeight;
             }
             m_numRows += numRows;
+
+            int bottom = 0;
+            if ( pos > 0 ) bottom = m_rowBottoms[pos-1];
+                
+            for ( i = pos;  i < m_numRows;  i++ )
+            {
+                bottom += m_rowHeights[i];
+                m_rowBottoms[i] = bottom;
+            }
             CalcDimensions();
         }
         return TRUE;
@@ -1043,9 +1130,19 @@ bool wxGrid::Redimension( wxGridTableMessage& msg )
             {
                 m_rowHeights.Add( m_defaultRowHeight );
                 m_rowBottoms.Add( 0 );
-                m_sumRowHeights += m_defaultRowHeight;
             }
+
+            int oldNumRows = m_numRows;
             m_numRows += numRows;
+
+            int bottom = 0;
+            if ( oldNumRows > 0 ) bottom = m_rowBottoms[oldNumRows-1];
+                
+            for ( i = oldNumRows;  i < m_numRows;  i++ )
+            {
+                bottom += m_rowHeights[i];
+                m_rowBottoms[i] = bottom;
+            }
             CalcDimensions();
         }
         return TRUE;
@@ -1056,17 +1153,11 @@ bool wxGrid::Redimension( wxGridTableMessage& msg )
             int numRows = msg.GetCommandInt2();
             for ( i = 0;  i < numRows;  i++ )
             {
-                m_sumRowHeights -= m_rowHeights[ pos ];
                 m_rowHeights.Remove( pos );
                 m_rowBottoms.Remove( pos );
             }
             m_numRows -= numRows;
 
-            // TODO: improve these adjustments...
-            //
-            if ( m_scrollPosY >= m_numRows )
-                m_scrollPosY = 0;
-
             if ( !m_numRows )
             {
                 m_numCols = 0;
@@ -1074,10 +1165,19 @@ bool wxGrid::Redimension( wxGridTableMessage& msg )
                 m_colRights.Clear();
                 m_currentCellCoords = wxGridNoCellCoords;
             }
-            else if ( m_currentCellCoords.GetRow() >= m_numRows )
+            else
             {
-                m_currentCellCoords.Set( 0, 0 );
+                if ( m_currentCellCoords.GetRow() >= m_numRows )
+                    m_currentCellCoords.Set( 0, 0 );
+
+                int h = 0;
+                for ( i = 0;  i < m_numRows;  i++ )
+                {
+                    h += m_rowHeights[i];
+                    m_rowBottoms[i] = h;
+                }
             }
+                
             CalcDimensions();
         }
         return TRUE;
@@ -1090,9 +1190,17 @@ bool wxGrid::Redimension( wxGridTableMessage& msg )
             {
                 m_colWidths.Insert( m_defaultColWidth, pos );
                 m_colRights.Insert( 0, pos );
-                m_sumColWidths += m_defaultColWidth;
             }
             m_numCols += numCols;
+
+            int right = 0;
+            if ( pos > 0 ) right = m_colRights[pos-1];
+            
+            for ( i = pos;  i < m_numCols;  i++ )
+            {
+                right += m_colWidths[i];
+                m_colRights[i] = right;
+            }
             CalcDimensions();
         }
         return TRUE;
@@ -1104,9 +1212,19 @@ bool wxGrid::Redimension( wxGridTableMessage& msg )
             {
                 m_colWidths.Add( m_defaultColWidth );
                 m_colRights.Add( 0 );
-                m_sumColWidths += m_defaultColWidth;
             }
+
+            int oldNumCols = m_numCols;
             m_numCols += numCols;
+
+            int right = 0;
+            if ( oldNumCols > 0 ) right = m_colRights[oldNumCols-1];
+            
+            for ( i = oldNumCols;  i < m_numCols;  i++ )
+            {
+                right += m_colWidths[i];
+                m_colRights[i] = right;
+            }
             CalcDimensions();
         }
         return TRUE;
@@ -1117,16 +1235,10 @@ bool wxGrid::Redimension( wxGridTableMessage& msg )
             int numCols = msg.GetCommandInt2();
             for ( i = 0;  i < numCols;  i++ )
             {
-                m_sumColWidths -= m_colWidths[ pos ];
                 m_colWidths.Remove( pos );
                 m_colRights.Remove( pos );
             }
             m_numCols -= numCols;
-            //
-            // TODO: improve these adjustments...
-            //
-            if ( m_scrollPosX >= m_numCols )
-                m_scrollPosX = 0;
 
             if ( !m_numCols )
             {
@@ -1137,9 +1249,17 @@ bool wxGrid::Redimension( wxGridTableMessage& msg )
 #endif
                 m_currentCellCoords = wxGridNoCellCoords;
             }
-            else if ( m_currentCellCoords.GetCol() >= m_numCols )
+            else 
             {
-                m_currentCellCoords.Set( 0, 0 );
+                if ( m_currentCellCoords.GetCol() >= m_numCols )
+                    m_currentCellCoords.Set( 0, 0 );
+
+                int w = 0;
+                for ( i = 0;  i < m_numCols;  i++ )
+                {
+                    w += m_colWidths[i];
+                    m_colRights[i] = w;
+                }
             }
             CalcDimensions();
         }
@@ -1150,234 +1270,196 @@ bool wxGrid::Redimension( wxGridTableMessage& msg )
 }
 
 
-//
-// ----- event handlers
-//
-
-// Generate a grid event based on a mouse event and
-// return the result of ProcessEvent()
-//
-bool wxGrid::SendEvent( const wxEventType type,
-                        int row, int col,
-                        wxMouseEvent& mouseEv )
+void wxGrid::CalcRowLabelsExposed( wxRegion& reg )
 {
-    if ( type == EVT_GRID_ROW_SIZE ||
-         type == EVT_GRID_COL_SIZE )
-    {
-        int rowOrCol = (row == -1 ? col : row);
+    wxRegionIterator iter( reg );
+    wxRect r;
 
-        wxGridSizeEvent gridEvt( GetId(),
-                                 type,
-                                 this,
-                                 rowOrCol,
-                                 mouseEv.GetX(), mouseEv.GetY(),
-                                 mouseEv.ControlDown(),
-                                 mouseEv.ShiftDown(),
-                                 mouseEv.AltDown(),
-                                 mouseEv.MetaDown() );
+    m_rowLabelsExposed.Empty();
 
-        return GetEventHandler()->ProcessEvent(gridEvt);
-    }
-    else if ( type == EVT_GRID_RANGE_SELECT )
+    int top, bottom;
+    while ( iter )
     {
-        wxGridRangeSelectEvent gridEvt( GetId(),
-                                        type,
-                                        this,
-                                        m_selectedTopLeft,
-                                        m_selectedBottomRight,
-                                        mouseEv.ControlDown(),
-                                        mouseEv.ShiftDown(),
-                                        mouseEv.AltDown(),
-                                        mouseEv.MetaDown() );
+        r = iter.GetRect();
 
-        return GetEventHandler()->ProcessEvent(gridEvt);
-    }
-    else
-    {
-        wxGridEvent gridEvt( GetId(),
-                             type,
-                             this,
-                             row, col,
-                             mouseEv.GetX(), mouseEv.GetY(),
-                             mouseEv.ControlDown(),
-                             mouseEv.ShiftDown(),
-                             mouseEv.AltDown(),
-                             mouseEv.MetaDown() );
+        // TODO: remove this when we can...
+        // There is a bug in wxMotif that gives garbage update
+        // rectangles if you jump-scroll a long way by clicking the
+        // scrollbar with middle button.  This is a work-around
+        //
+#if defined(__WXMOTIF__)
+        int cw, ch;
+        m_gridWin->GetClientSize( &cw, &ch );
+        if ( r.GetTop() > ch ) r.SetTop( 0 );
+        r.SetBottom( wxMin( r.GetBottom(), ch ) );
+#endif
 
-        return GetEventHandler()->ProcessEvent(gridEvt);
+        // logical bounds of update region
+        //
+        int dummy;
+        CalcUnscrolledPosition( 0, r.GetTop(), &dummy, &top );
+        CalcUnscrolledPosition( 0, r.GetBottom(), &dummy, &bottom );
+
+        // find the row labels within these bounds
+        //
+        int row;
+        int rowTop;
+        for ( row = 0;  row < m_numRows;  row++ )
+        {
+            if ( m_rowBottoms[row] < top ) continue;
+
+            rowTop = m_rowBottoms[row] - m_rowHeights[row];
+            if ( rowTop > bottom ) break;
+            
+            m_rowLabelsExposed.Add( row );
+        }
+        
+        iter++ ;
     }
 }
 
 
-// Generate a grid event of specified type and return the result
-// of ProcessEvent().
-//
-bool wxGrid::SendEvent( const wxEventType type,
-                        int row, int col )
+void wxGrid::CalcColLabelsExposed( wxRegion& reg )
 {
-    if ( type == EVT_GRID_ROW_SIZE ||
-         type == EVT_GRID_COL_SIZE )
-    {
-        int rowOrCol = (row == -1 ? col : row);
+    wxRegionIterator iter( reg );
+    wxRect r;
 
-        wxGridSizeEvent gridEvt( GetId(),
-                                 type,
-                                 this,
-                                 rowOrCol );
+    m_colLabelsExposed.Empty();
 
-        return GetEventHandler()->ProcessEvent(gridEvt);
-    }
-    else
+    int left, right;
+    while ( iter )
     {
-        wxGridEvent gridEvt( GetId(),
-                             type,
-                             this,
-                             row, col );
+        r = iter.GetRect();
 
-        return GetEventHandler()->ProcessEvent(gridEvt);
+        // TODO: remove this when we can...
+        // There is a bug in wxMotif that gives garbage update
+        // rectangles if you jump-scroll a long way by clicking the
+        // scrollbar with middle button.  This is a work-around
+        //
+#if defined(__WXMOTIF__)
+        int cw, ch;
+        m_gridWin->GetClientSize( &cw, &ch );
+        if ( r.GetLeft() > cw ) r.SetLeft( 0 );
+        r.SetRight( wxMin( r.GetRight(), cw ) );
+#endif
+
+        // logical bounds of update region
+        //
+        int dummy;
+        CalcUnscrolledPosition( r.GetLeft(), 0, &left, &dummy );
+        CalcUnscrolledPosition( r.GetRight(), 0, &right, &dummy );
+
+        // find the cells within these bounds
+        //
+        int col;
+        int colLeft;
+        for ( col = 0;  col < m_numCols;  col++ )
+        {
+            if ( m_colRights[col] < left ) continue;
+                
+            colLeft = m_colRights[col] - m_colWidths[col];
+            if ( colLeft > right ) break;
+
+            m_colLabelsExposed.Add( col );
+        }
+        
+        iter++ ;
     }
 }
 
 
-void wxGrid::OnPaint( wxPaintEvent& WXUNUSED(ev) )
+void wxGrid::CalcCellsExposed( wxRegion& reg )
 {
-    wxPaintDC dc( this );
+    wxRegionIterator iter( reg );
+    wxRect r;
 
-    if ( !m_batchCount )
-    {
-        // define a clipping region to avoid painting over the scroll bars
-        //
-        int vs = 0;
-        if ( m_vertScrollBar && m_vertScrollBar->IsShown() )
-            vs = m_scrollBarWidth;
+    m_cellsExposed.Empty();
+    m_rowsExposed.Empty();
+    m_colsExposed.Empty();
 
-        int hs = 0;
-        if ( m_horizScrollBar && m_horizScrollBar->IsShown() )
-            hs = m_scrollBarWidth;
+    int left, top, right, bottom;
+    while ( iter )
+    {
+        r = iter.GetRect();
 
+        // TODO: remove this when we can...
+        // There is a bug in wxMotif that gives garbage update
+        // rectangles if you jump-scroll a long way by clicking the
+        // scrollbar with middle button.  This is a work-around
+        //
+#if defined(__WXMOTIF__)
         int cw, ch;
-        GetClientSize( &cw, &ch );
-        dc.SetClippingRegion( 0, 0, cw - vs, ch - hs );
-
-        HideCurrentCellHighlight( dc );
+        m_gridWin->GetClientSize( &cw, &ch );
+        if ( r.GetTop() > ch ) r.SetTop( 0 );
+        if ( r.GetLeft() > cw ) r.SetLeft( 0 );
+        r.SetRight( wxMin( r.GetRight(), cw ) );
+        r.SetBottom( wxMin( r.GetBottom(), ch ) );
+#endif
 
-        DrawLabelAreas( dc );
-        DrawColLabels( dc );
-        DrawRowLabels( dc );
-        DrawCellArea( dc );
-        DrawGridLines( dc );
-        DrawCells( dc );
+        // logical bounds of update region
+        //
+        CalcUnscrolledPosition( r.GetLeft(), r.GetTop(), &left, &top );
+        CalcUnscrolledPosition( r.GetRight(), r.GetBottom(), &right, &bottom );
 
-        // TODO: something more elegant than this...
+        // find the cells within these bounds
         //
-        if ( m_firstPaint )
+        int row, col;
+        int colLeft, rowTop;
+        for ( row = 0;  row < m_numRows;  row++ )
         {
-            if ( m_currentCellCoords == wxGridNoCellCoords )
-                m_currentCellCoords.Set(0, 0);
-
-            SetEditControlValue();
-            ShowCellEditControl();
-            m_firstPaint = FALSE;
-        }
+            if ( m_rowBottoms[row] < top ) continue;
 
-        ShowCurrentCellHighlight( dc );
+            rowTop = m_rowBottoms[row] - m_rowHeights[row];
+            if ( rowTop > bottom ) break;
+            
+            m_rowsExposed.Add( row );
 
-        dc.DestroyClippingRegion();
+            for ( col = 0;  col < m_numCols;  col++ )
+            {
+                if ( m_colRights[col] < left ) continue;
+                
+                colLeft = m_colRights[col] - m_colWidths[col];
+                if ( colLeft > right ) break;
+                
+                if ( m_colsExposed.Index( col ) == wxNOT_FOUND ) m_colsExposed.Add( col );
+                m_cellsExposed.Add( wxGridCellCoords( row, col ) );
+            }
+        }
+        
+        iter++ ;
     }
 }
 
 
-void wxGrid::OnSize( wxSizeEvent& WXUNUSED(ev) )
-{
-    if ( m_created ) CalcDimensions();
-}
-
-
-void wxGrid::OnMouse( wxMouseEvent& ev )
+void wxGrid::ProcessRowLabelMouseEvent( wxMouseEvent& event )
 {
-    int x = ev.GetX();
-    int y = ev.GetY();
-    int row, col;
-
-    // ------------------------------------------------------------
-    //
-    // Mouse dragging
-    //
-    if ( ev.Dragging() )
+    int x, y, row;
+    wxPoint pos( event.GetPosition() );
+    CalcUnscrolledPosition( pos.x, pos.y, &x, &y );
+    
+    if ( event.Dragging() )
     {
         m_isDragging = TRUE;
 
-        if ( ev.LeftIsDown() )
+        if ( event.LeftIsDown() )
         {
             switch( m_cursorMode )
             {
-                case WXGRID_CURSOR_SELECT_CELL:
-                {
-                    wxGridCellCoords cellCoords;
-                    XYToCell( x, y, cellCoords );
-                    if ( cellCoords != wxGridNoCellCoords )
-                    {
-                        if ( !IsSelection() )
-                        {
-                            SelectBlock( cellCoords, cellCoords );
-                        }
-                        else
-                        {
-                            // check for the mouse being outside the cell area
-                            // (we still want to let the user grow the selected block)
-                            //
-                            if ( cellCoords.GetCol() == -1 )
-                            {
-                                if ( x >= m_right )
-                                    cellCoords.SetCol( m_numCols-1 );
-                                else
-                                    cellCoords.SetCol( m_scrollPosX );
-                            }
-
-                            if ( cellCoords.GetRow() == -1 )
-                            {
-                                if ( y >= m_bottom )
-                                    cellCoords.SetRow( m_numRows-1 );
-                                else
-                                    cellCoords.SetRow( m_scrollPosY );
-                            }
-
-                            if ( !IsInSelection( cellCoords ) )
-                                SelectBlock( m_currentCellCoords, cellCoords );
-                        }
-                    }
-                }
-                break;
-
                 case WXGRID_CURSOR_RESIZE_ROW:
                 {
-                    wxClientDC dc(this);
+                    int cw, ch, left, dummy;
+                    m_gridWin->GetClientSize( &cw, &ch );
+                    CalcUnscrolledPosition( 0, 0, &left, &dummy );
+                    
+                    wxClientDC dc( m_gridWin );
+                    PrepareDC( dc );
                     dc.SetLogicalFunction(wxXOR);
                     if ( m_dragLastPos >= 0 )
                     {
-                        dc.DrawLine( m_left, m_dragLastPos,
-                                     m_right, m_dragLastPos );
-                    }
-                    dc.DrawLine( m_left, ev.GetY(),
-                                 m_right, ev.GetY());
-
-                    m_dragLastPos = ev.GetY();
-                }
-                break;
-
-                case WXGRID_CURSOR_RESIZE_COL:
-                {
-                    wxClientDC dc(this);
-                    dc.SetLogicalFunction(wxINVERT);
-                    if ( m_dragLastPos >= 0 )
-                    {
-                        dc.DrawLine( m_dragLastPos, m_top,
-                                     m_dragLastPos, m_bottom );
+                        dc.DrawLine( left, m_dragLastPos, left+cw, m_dragLastPos );
                     }
-                    dc.DrawLine( ev.GetX(), m_top,
-                                 ev.GetX(), m_bottom );
-
-                    m_dragLastPos = ev.GetX();
+                    dc.DrawLine( left, y, left+cw, y );
+                    m_dragLastPos = y;
                 }
                 break;
 
@@ -1390,16 +1472,6 @@ void wxGrid::OnMouse( wxMouseEvent& ev )
                     }
                 }
                 break;
-
-                case WXGRID_CURSOR_SELECT_COL:
-                {
-                    if ( (col = XToCol( x )) >= 0  &&
-                         !IsInSelection( 0, col ) )
-                    {
-                        SelectCol( col, TRUE );
-                    }
-                }
-                break;
             }
         }
         return;
@@ -1407,1882 +1479,1341 @@ void wxGrid::OnMouse( wxMouseEvent& ev )
 
     m_isDragging = FALSE;
 
-    // ------------------------------------------------------------
+    
+    // ------------ Left button pressed
     //
-    // Left mouse button down
-    //
-    if ( ev.LeftDown() )
+    if ( event.LeftDown() )
     {
-        row = -1;
-        col = -1;
-        wxGridCellCoords cellCoords;
-
-        switch( XYToArea( x, y ) )
+        // don't send a label click event for a hit on the
+        // edge of the row label - this is probably the user
+        // wanting to resize the row
+        //
+        if ( YToEdgeOfRow(y) < 0 )
         {
-            case WXGRID_ROWLABEL:
-            {
-                // don't send a label click event for a hit on the
-                // edge of the row label - this is probably the user
-                // wanting to resize the row
-                //
-                if ( YToEdgeOfRow(y) < 0 )
-                {
-                    row = YToRow(y);
-                    if ( !SendEvent( EVT_GRID_LABEL_LEFT_CLICK, row, col, ev ) )
-                    {
-                        SelectRow( row, ev.ShiftDown() );
-                        m_cursorMode = WXGRID_CURSOR_SELECT_ROW;
-                    }
-                }
-            }
-            break;
-
-            case WXGRID_COLLABEL:
-            {
-                // don't send a label click event for a hit on the
-                // edge of the col label - this is probably the user
-                // wanting to resize the col
-                //
-                if ( XToEdgeOfCol(x) < 0 )
-                {
-                    col = XToCol(x);
-                    if ( !SendEvent( EVT_GRID_LABEL_LEFT_CLICK, row, col, ev ) )
-                    {
-                        SelectCol( col, ev.ShiftDown() );
-                        m_cursorMode = WXGRID_CURSOR_SELECT_COL;
-                    }
-                }
-            }
-            break;
-
-            case WXGRID_CORNERLABEL:
+            row = YToRow(y);
+            if ( !SendEvent( EVT_GRID_LABEL_LEFT_CLICK, row, -1, event ) )
             {
-                // leave both row and col as -1
-                //
-                if ( !SendEvent( EVT_GRID_LABEL_LEFT_CLICK, row, col, ev ) )
-                {
-                    SelectAll();
-                }
+                SelectRow( row, event.ShiftDown() );
+                m_cursorMode = WXGRID_CURSOR_SELECT_ROW;
             }
-            break;
+        }
+        else
+        {
+            // starting to drag-resize a row
+            //
+            m_rowLabelWin->CaptureMouse();
+        }
+    }
 
-            case WXGRID_CELL:
-            {
-                XYToCell( x, y, cellCoords );
-                if ( !SendEvent( EVT_GRID_CELL_LEFT_CLICK,
-                                 cellCoords.GetRow(),
-                                 cellCoords.GetCol(),
-                                 ev ) )
-                {
-                    MakeCellVisible( cellCoords );
-                    SelectCell( cellCoords );
-                }
-            }
-            break;
 
-            default:
-#if 0
-                wxLogMessage( "outside grid area" );
-#endif
-                break;
+    // ------------ Left double click
+    //
+    else if (event.LeftDClick() )
+    {
+        if ( YToEdgeOfRow(y) < 0 )
+        {
+            row = YToRow(y);
+            SendEvent(  EVT_GRID_LABEL_LEFT_DCLICK, row, -1, event );
         }
     }
-    // ------------------------------------------------------------
+    
+    // ------------ Left button released
     //
-    // Left mouse button double click
-    //
-    else if ( ev.LeftDClick() )
+    else if ( event.LeftUp() )
     {
-        row = -1;
-        col = -1;
-        wxGridCellCoords cellCoords;
-
-        switch( XYToArea( x, y ) )
+        if ( m_cursorMode == WXGRID_CURSOR_RESIZE_ROW )
         {
-            case WXGRID_ROWLABEL:
+            m_rowLabelWin->ReleaseMouse();
+            
+            if ( m_dragLastPos >= 0 )
             {
-                // don't send a label click event for a hit on the
-                // edge of the row label - this is probably the user
-                // wanting to resize the row
+                // erase the last line and resize the row
                 //
-                if ( YToEdgeOfRow(y) < 0 )
+                int cw, ch, left, dummy;
+                m_gridWin->GetClientSize( &cw, &ch );
+                CalcUnscrolledPosition( 0, 0, &left, &dummy );
+                
+                wxClientDC dc( m_gridWin );
+                PrepareDC( dc );
+                dc.SetLogicalFunction( wxINVERT );
+                dc.DrawLine( left, m_dragLastPos, left+cw, m_dragLastPos );
+                HideCellEditControl();
+
+                int rowTop = m_rowBottoms[m_dragRowOrCol] - m_rowHeights[m_dragRowOrCol];
+                SetRowSize( m_dragRowOrCol, wxMax( y - rowTop, WXGRID_MIN_ROW_HEIGHT ) ); 
+                if ( !GetBatchCount() )
                 {
-                    row = YToRow(y);
-                    SendEvent(  EVT_GRID_LABEL_LEFT_DCLICK, row, col, ev );
+                  // TODO: optimize this
+                  m_rowLabelWin->Refresh();
+                  m_gridWin->Refresh();
                 }
-            }
-            break;
+                
+                ShowCellEditControl();
 
-            case WXGRID_COLLABEL:
-            {
-                // don't send a label click event for a hit on the
-                // edge of the col label - this is probably the user
-                // wanting to resize the col
+                // Note: we are ending the event *after* doing
+                // default processing in this case
                 //
-                if ( XToEdgeOfCol(x) < 0 )
-                {
-                    col = XToCol(x);
-                    SendEvent(  EVT_GRID_LABEL_LEFT_DCLICK, row, col, ev );
-                }
+                SendEvent( EVT_GRID_ROW_SIZE, m_dragRowOrCol, -1, event );
             }
-            break;
+        }
 
-            case WXGRID_CORNERLABEL:
-            {
-                // leave both row and col as -1
-                //
-                SendEvent(  EVT_GRID_LABEL_LEFT_DCLICK, row, col, ev );
-            }
-            break;
+        m_dragLastPos  = -1;
+    }
 
-            case WXGRID_CELL:
-            {
-                XYToCell( x, y, cellCoords );
-                SendEvent( EVT_GRID_CELL_LEFT_DCLICK,
-                                 cellCoords.GetRow(),
-                                 cellCoords.GetCol(),
-                                 ev );
-            }
-            break;
 
-            default:
-#if 0
-                wxLogMessage( "outside grid area" );
-#endif
-                break;
+    // ------------ Right button down
+    //
+    else if ( event.RightDown() )
+    {
+        row = YToRow(y);
+        if ( !SendEvent( EVT_GRID_LABEL_RIGHT_CLICK, row, -1, event ) )
+        {
+            // no default action at the moment
         }
     }
-    // ------------------------------------------------------------
+    
+    
+    // ------------ Right double click
     //
-    // Left mouse button released
+    else if ( event.RightDClick() )
+    {
+        row = YToRow(y);
+        if ( !SendEvent( EVT_GRID_LABEL_RIGHT_DCLICK, row, -1, event ) )
+        {
+            // no default action at the moment
+        }
+    }
+    
+    
+    // ------------ No buttons down and mouse moving
     //
-    else if ( ev.LeftUp() )
+    else if ( event.Moving() )
     {
-        switch ( m_cursorMode )
+        m_dragRowOrCol = YToEdgeOfRow( y );
+        if ( m_dragRowOrCol >= 0 )
         {
-            case WXGRID_CURSOR_RESIZE_ROW:
-            {
-                if ( m_dragLastPos >= 0 )
-                {
-                    // erase the last line and resize the row
-                    //
-                    wxClientDC dc( this );
-                    dc.SetLogicalFunction( wxINVERT );
-                    dc.DrawLine( m_left, m_dragLastPos,
-                                 m_right, m_dragLastPos );
-                    HideCellEditControl();
-                    int top = m_top + m_colLabelHeight;
-                    if ( m_dragRowOrCol > 0 )
-                        top = m_rowBottoms[m_dragRowOrCol-1];
-
-                    m_sumRowHeights -= m_rowHeights[ m_dragRowOrCol ];
-                    m_rowHeights[m_dragRowOrCol] = wxMax( ev.GetY() - top,
-                                                          WXGRID_MIN_ROW_HEIGHT );
-                    m_sumRowHeights += m_rowHeights[ m_dragRowOrCol ];
-                    CalcDimensions();
-                    ShowCellEditControl();
-                    Refresh();
-
-                    // Note: we are ending the event *after* doing
-                    // default processing in this case
-                    //
-                    SendEvent( EVT_GRID_ROW_SIZE, m_dragRowOrCol, -1, ev );
-                }
-            }
-            break;
-
-            case WXGRID_CURSOR_RESIZE_COL:
+            if ( m_cursorMode == WXGRID_CURSOR_SELECT_CELL )
             {
-                if ( m_dragLastPos >= 0 )
-                {
-                    // erase the last line and resize the col
-                    //
-                    wxClientDC dc( this );
-                    dc.SetLogicalFunction( wxINVERT );
-                    dc.DrawLine( m_left, m_dragLastPos,
-                                 m_right, m_dragLastPos );
-                    HideCellEditControl();
-                    int left = m_left + m_rowLabelWidth;
-                    if ( m_dragRowOrCol > 0 )
-                        left = m_colRights[m_dragRowOrCol-1];
-
-                    m_sumColWidths -= m_colWidths[m_dragRowOrCol];
-                    m_colWidths[m_dragRowOrCol] = wxMax( ev.GetX() - left,
-                                                         WXGRID_MIN_COL_WIDTH );
-                    m_sumColWidths += m_colWidths[m_dragRowOrCol];
-
-                    CalcDimensions();
-                    ShowCellEditControl();
-                    Refresh();
-
-                    // Note: we are ending the event *after* doing
-                    // default processing in this case
-                    //
-                    SendEvent( EVT_GRID_COL_SIZE, -1, m_dragRowOrCol, ev );
-                }
+                m_cursorMode = WXGRID_CURSOR_RESIZE_ROW;
+                m_rowLabelWin->SetCursor( m_rowResizeCursor );
             }
-            break;
-
-            case WXGRID_CURSOR_SELECT_CELL:
+        }
+        else
+        {
+            if ( m_cursorMode != WXGRID_CURSOR_SELECT_CELL )
             {
-                if ( IsSelection() )
-                {
-                    // Note: we are ending the event *after* doing
-                    // default processing in this case
-                    //
-                    SendEvent( EVT_GRID_RANGE_SELECT, -1, -1, ev );
-                }
+                m_cursorMode = WXGRID_CURSOR_SELECT_CELL;
+                m_rowLabelWin->SetCursor( *wxSTANDARD_CURSOR );
             }
-            break;
         }
-
-        m_dragLastPos  = -1;
     }
-    // ------------------------------------------------------------
-    //
-    // Right mouse button down
-    //
-    else if ( ev.RightDown() )
+}
+
+
+void wxGrid::ProcessColLabelMouseEvent( wxMouseEvent& event )
+{
+    int x, y, col;
+    wxPoint pos( event.GetPosition() );
+    CalcUnscrolledPosition( pos.x, pos.y, &x, &y );
+    
+    if ( event.Dragging() )
     {
-        row = -1;
-        col = -1;
-        wxGridCellCoords cellCoords;
+        m_isDragging = TRUE;
 
-        switch( XYToArea( x, y ) )
+        if ( event.LeftIsDown() )
         {
-
-            case WXGRID_ROWLABEL:
+            switch( m_cursorMode )
             {
-                row = YToRow(y);
-                if ( !SendEvent( EVT_GRID_LABEL_RIGHT_CLICK, row, col, ev ) )
+                case WXGRID_CURSOR_RESIZE_COL:
                 {
-                    // TODO: default processing ?
+                    int cw, ch, dummy, top;
+                    m_gridWin->GetClientSize( &cw, &ch );
+                    CalcUnscrolledPosition( 0, 0, &dummy, &top );
+                    
+                    wxClientDC dc( m_gridWin );
+                    PrepareDC( dc );
+                    dc.SetLogicalFunction(wxXOR);
+                    if ( m_dragLastPos >= 0 )
+                    {
+                        dc.DrawLine( m_dragLastPos, top, m_dragLastPos, top+ch );
+                    }
+                    dc.DrawLine( x, top, x, top+ch );
+                    m_dragLastPos = x;
                 }
-            }
-            break;
+                break;
 
-            case WXGRID_COLLABEL:
-            {
-                col = XToCol(x);
-                if ( !SendEvent( EVT_GRID_LABEL_RIGHT_CLICK, row, col, ev ) )
+                case WXGRID_CURSOR_SELECT_COL:
                 {
-                    // TODO: default processing ?
-                }
-            }
-            break;
-
-            case WXGRID_CORNERLABEL:
-            {
-                // leave both row and col as -1
-                //
-                if ( !SendEvent( EVT_GRID_LABEL_RIGHT_CLICK, row, col, ev ) )
-                {
-                    // TODO: default processing ?
-                }
-            }
-            break;
-
-            case WXGRID_CELL:
-            {
-                XYToCell( x, y, cellCoords );
-                if ( !SendEvent( EVT_GRID_CELL_RIGHT_CLICK,
-                                cellCoords.GetRow(),
-                                cellCoords.GetCol(),
-                                ev ) )
-                {
-                    // TODO: default processing ?
+                    if ( (col = XToCol( x )) >= 0  &&
+                         !IsInSelection( 0, col ) )
+                    {
+                        SelectCol( col, TRUE );
+                    }
                 }
-            }
-            break;
-
-            default:
-#if 0
-                wxLogMessage( "outside grid area" );
-#endif
                 break;
+            }
         }
+        return;
     }
-    // ------------------------------------------------------------
-    //
-    // Right mouse button double click
+
+    m_isDragging = FALSE;
+
+    
+    // ------------ Left button pressed
     //
-    else if ( ev.RightDClick() )
+    if ( event.LeftDown() )
     {
-        row = -1;
-        col = -1;
-        wxGridCellCoords cellCoords;
-
-        switch( XYToArea( x, y ) )
+        // don't send a label click event for a hit on the
+        // edge of the col label - this is probably the user
+        // wanting to resize the col
+        //
+        if ( XToEdgeOfCol(x) < 0 )
         {
-
-            case WXGRID_ROWLABEL:
+            col = XToCol(x);
+            if ( !SendEvent( EVT_GRID_LABEL_LEFT_CLICK, -1, col, event ) )
             {
-                row = YToRow(y);
-                SendEvent( EVT_GRID_LABEL_RIGHT_DCLICK, row, col, ev );
+                SelectCol( col, event.ShiftDown() );
+                m_cursorMode = WXGRID_CURSOR_SELECT_COL;
             }
-            break;
+        }
+        else
+        {
+            // starting to drag-resize a col
+            //
+            m_colLabelWin->CaptureMouse();
+        }
+    }
 
-            case WXGRID_COLLABEL:
-            {
-                col = XToCol(x);
-                SendEvent( EVT_GRID_LABEL_RIGHT_DCLICK, row, col, ev );
-            }
-            break;
 
-            case WXGRID_CORNERLABEL:
+    // ------------ Left double click
+    //
+    if ( event.LeftDClick() )
+    {
+        if ( XToEdgeOfCol(x) < 0 )
+        {
+            col = XToCol(x);
+            SendEvent(  EVT_GRID_LABEL_LEFT_DCLICK, -1, col, event );
+        }
+    }
+    
+    
+    // ------------ Left button released
+    //
+    else if ( event.LeftUp() )
+    {
+        if ( m_cursorMode == WXGRID_CURSOR_RESIZE_COL )
+        {
+            m_colLabelWin->ReleaseMouse();
+            
+            if ( m_dragLastPos >= 0 )
             {
-                // leave both row and col as -1
+                // erase the last line and resize the col
                 //
-                SendEvent( EVT_GRID_LABEL_RIGHT_DCLICK, row, col, ev );
-            }
-            break;
+                int cw, ch, dummy, top;
+                m_gridWin->GetClientSize( &cw, &ch );
+                CalcUnscrolledPosition( 0, 0, &dummy, &top );
+                
+                wxClientDC dc( m_gridWin );
+                PrepareDC( dc );
+                dc.SetLogicalFunction( wxINVERT );
+                dc.DrawLine( m_dragLastPos, top, m_dragLastPos, top+ch );
+                HideCellEditControl();
+
+                int colLeft = m_colRights[m_dragRowOrCol] - m_colWidths[m_dragRowOrCol];
+                SetColSize( m_dragRowOrCol, wxMax( x - colLeft, WXGRID_MIN_COL_WIDTH ) ); 
+                              
+                if ( !GetBatchCount() )
+                {
+                  // TODO: optimize this
+                  m_colLabelWin->Refresh();
+                  m_gridWin->Refresh();
+                }
+                
+                ShowCellEditControl();
 
-            case WXGRID_CELL:
-            {
-                XYToCell( x, y, cellCoords );
-                SendEvent( EVT_GRID_CELL_RIGHT_DCLICK,
-                           cellCoords.GetRow(),
-                           cellCoords.GetCol(),
-                           ev );
+                // Note: we are ending the event *after* doing
+                // default processing in this case
+                //
+                SendEvent( EVT_GRID_COL_SIZE, -1, m_dragRowOrCol, event );
             }
-            break;
+        }
 
-            default:
-#if 0
-                wxLogMessage( "outside grid area" );
-#endif
-                break;
+        m_dragLastPos  = -1;
+    }    
+    
+    
+    // ------------ Right button down
+    //
+    else if ( event.RightDown() )
+    {
+        col = XToCol(x);
+        if ( !SendEvent( EVT_GRID_LABEL_RIGHT_CLICK, -1, col, event ) )
+        {
+            // no default action at the moment
         }
     }
-    // ------------------------------------------------------------
+    
+    
+    // ------------ Right double click
     //
-    // No buttons down and mouse moving
+    else if ( event.RightDClick() )
+    {
+        col = XToCol(x);
+        if ( !SendEvent( EVT_GRID_LABEL_RIGHT_DCLICK, -1, col, event ) )
+        {
+            // no default action at the moment
+        }
+    }
+    
+    
+    // ------------ No buttons down and mouse moving
     //
-    else if ( ev.Moving() )
+    else if ( event.Moving() )
     {
-        switch( XYToArea( x, y ) )
+        m_dragRowOrCol = XToEdgeOfCol( x );
+        if ( m_dragRowOrCol >= 0 )
         {
-            case WXGRID_ROWLABEL:
-            {
-                m_dragRowOrCol = YToEdgeOfRow( y );
-                if ( m_dragRowOrCol >= 0 )
-                {
-                    if ( m_cursorMode == WXGRID_CURSOR_SELECT_CELL )
-                    {
-                        m_cursorMode = WXGRID_CURSOR_RESIZE_ROW;
-                        SetCursor( m_rowResizeCursor );
-                    }
-                }
-                else
-                {
-                    if ( m_cursorMode != WXGRID_CURSOR_SELECT_CELL )
-                    {
-                        m_cursorMode = WXGRID_CURSOR_SELECT_CELL;
-                        SetCursor( *wxSTANDARD_CURSOR );
-                    }
-                }
-            }
-            break;
-
-            case WXGRID_COLLABEL:
+            if ( m_cursorMode == WXGRID_CURSOR_SELECT_CELL )
             {
-                m_dragRowOrCol = XToEdgeOfCol( x );
-                if ( m_dragRowOrCol >= 0 )
-                {
-                    if ( m_cursorMode == WXGRID_CURSOR_SELECT_CELL )
-                    {
-                        m_cursorMode = WXGRID_CURSOR_RESIZE_COL;
-                        SetCursor( m_colResizeCursor );
-                    }
-                }
-                else
-                {
-                    if ( m_cursorMode != WXGRID_CURSOR_SELECT_CELL )
-                    {
-                        m_cursorMode = WXGRID_CURSOR_SELECT_CELL;
-                        SetCursor( *wxSTANDARD_CURSOR );
-                    }
-                }
+                m_cursorMode = WXGRID_CURSOR_RESIZE_COL;
+                m_colLabelWin->SetCursor( m_colResizeCursor );
             }
-            break;
-
-            default:
+        }
+        else
+        {
+            if ( m_cursorMode != WXGRID_CURSOR_SELECT_CELL )
             {
-                if ( m_cursorMode != WXGRID_CURSOR_SELECT_CELL )
-                {
-                    m_cursorMode = WXGRID_CURSOR_SELECT_CELL;
-                    SetCursor( *wxSTANDARD_CURSOR );
-                }
+                m_cursorMode = WXGRID_CURSOR_SELECT_CELL;
+                m_colLabelWin->SetCursor( *wxSTANDARD_CURSOR );
             }
-            break;
         }
     }
 }
 
 
-void wxGrid::OnKeyDown( wxKeyEvent& ev )
+void wxGrid::ProcessCornerLabelMouseEvent( wxMouseEvent& event )
 {
-    if ( m_inOnKeyDown )
+    if ( event.LeftDown() )
     {
-        // shouldn't be here - we are going round in circles...
+        // indicate corner label by having both row and
+        // col args == -1
         //
-        wxLogFatalError( wxT("wxGrid::OnKeyDown called while alread active") );
+        if ( !SendEvent( EVT_GRID_LABEL_LEFT_CLICK, -1, -1, event ) )
+        {
+            SelectAll();
+        }
     }
 
-    m_inOnKeyDown = TRUE;
-
-    // propagate the event up and see if it gets processed
-    //
-    wxWindow *parent = GetParent();
-    wxKeyEvent keyEvt( ev );
-    keyEvt.SetEventObject( parent );
+    else if ( event.LeftDClick() )
+    {
+        SendEvent( EVT_GRID_LABEL_LEFT_DCLICK, -1, -1, event );
+    }
 
-    if ( !parent->GetEventHandler()->ProcessEvent( keyEvt ) )
+    else if ( event.RightDown() )
     {
-        // try local handlers
-        //
-        switch ( ev.KeyCode() )
+        if ( !SendEvent( EVT_GRID_LABEL_RIGHT_CLICK, -1, -1, event ) )
         {
-            case WXK_UP:
-                if ( ev.ControlDown() )
-                {
-                    MoveCursorUpBlock();
-                }
-                else
-                {
-                    MoveCursorUp();
-                }
-                break;
-
-            case WXK_DOWN:
-                if ( ev.ControlDown() )
-                {
-                    MoveCursorDownBlock();
-                }
-                else
-                {
-                    MoveCursorDown();
-                }
-                break;
-
-            case WXK_LEFT:
-                if ( ev.ControlDown() )
-                {
-                    MoveCursorLeftBlock();
-                }
-                else
-                {
-                    MoveCursorLeft();
-                }
-                break;
-
-            case WXK_RIGHT:
-                if ( ev.ControlDown() )
-                {
-                    MoveCursorRightBlock();
-                }
-                else
-                {
-                    MoveCursorRight();
-                }
-                break;
+            // no default action at the moment
+        }
+    }
 
-            case WXK_RETURN:
-                MoveCursorDown();
-                break;
+    else if ( event.RightDClick() )
+    {
+        if ( !SendEvent( EVT_GRID_LABEL_RIGHT_DCLICK, -1, -1, event ) )
+        {
+            // no default action at the moment
+        }
+    }
+}
 
-            case WXK_HOME:
-                if ( ev.ControlDown() )
-                {
-                    MakeCellVisible( 0, 0 );
-                    SelectCell( 0, 0 );
-                }
-                else
-                {
-                    ev.Skip();
-                }
-                break;
 
-            case WXK_END:
-                if ( ev.ControlDown() )
+void wxGrid::ProcessGridCellMouseEvent( wxMouseEvent& event )
+{
+    int x, y;
+    wxPoint pos( event.GetPosition() );
+    CalcUnscrolledPosition( pos.x, pos.y, &x, &y );
+    
+    wxGridCellCoords coords;
+    XYToCell( x, y, coords );
+    
+    if ( event.Dragging() )
+    {
+        m_isDragging = TRUE;
+        
+        if ( m_cursorMode == WXGRID_CURSOR_SELECT_CELL )
+        {
+            if ( coords != wxGridNoCellCoords )
+            {
+                if ( !IsSelection() )
                 {
-                    MakeCellVisible( m_numRows-1, m_numCols-1 );
-                    SelectCell( m_numRows-1, m_numCols-1 );
+                    SelectBlock( coords, coords );
                 }
                 else
                 {
-                    ev.Skip();
+                    if ( !IsInSelection( coords ) )
+                        SelectBlock( m_currentCellCoords, coords );
                 }
-                break;
+            }
+        }
 
-            case WXK_PRIOR:
-                MovePageUp();
-                break;
+        return;
+    }
 
-            case WXK_NEXT:
-                MovePageDown();
-                break;
+    m_isDragging = FALSE;
 
-            default:
-                // now try the cell edit control
-                //
-                if ( IsCellEditControlEnabled() )
-                {
-                    ev.SetEventObject( m_cellEditCtrl );
-                    m_cellEditCtrl->GetEventHandler()->ProcessEvent( ev );
-                }
-                break;
+    if ( event.LeftDown() )
+    {
+        if ( !SendEvent( EVT_GRID_CELL_LEFT_CLICK,
+                         coords.GetRow(),
+                         coords.GetCol(),
+                         event ) )
+        {
+            MakeCellVisible( coords );
+            SetCurrentCell( coords );
         }
     }
 
-    m_inOnKeyDown = FALSE;
-}
-
 
-// Text updated in an edit control - either a text control or a
-// combo box
-//
-void wxGrid::OnText( wxCommandEvent& ev )
-{
-    if ( !m_inOnText )
+    // ------------ Left double click
+    //
+    else if ( event.LeftDClick() )
     {
-        m_inOnText = TRUE;
-        wxWindow *ctrl = (wxWindow *)ev.GetEventObject();
+        SendEvent( EVT_GRID_CELL_LEFT_DCLICK,
+                   coords.GetRow(),
+                   coords.GetCol(),
+                   event );
+    }
 
-        if ( ctrl == m_cellEditCtrl &&
-             IsTopEditControlEnabled() )
-        {
-            // set the value of the top edit control
-            //
-            switch ( m_editCtrlType )
-            {
-                case wxGRID_TEXTCTRL:
-                    ((wxTextCtrl *)m_topEditCtrl)->
-                        SetValue(((wxTextCtrl *)ctrl)->GetValue());
-                    break;
 
-                case wxGRID_COMBOBOX:
-                    ((wxComboBox *)m_topEditCtrl)->
-                        SetValue(((wxComboBox *)ctrl)->GetValue());
-                    break;
-            }
-        }
-        else if ( ctrl == m_topEditCtrl )
+    // ------------ Left button released
+    //
+    else if ( event.LeftUp() )
+    {
+        if ( m_cursorMode == WXGRID_CURSOR_SELECT_CELL )
         {
-            if ( IsCellEditControlEnabled() )
-            {
-                switch ( m_editCtrlType )
-                {
-                    case wxGRID_TEXTCTRL:
-                        ((wxTextCtrl *)m_cellEditCtrl)->
-                            SetValue(((wxTextCtrl *)ctrl)->GetValue());
-                        break;
-
-                    case wxGRID_COMBOBOX:
-                        ((wxComboBox *)m_cellEditCtrl)->
-                            SetValue(((wxComboBox *)ctrl)->GetValue());
-                        break;
-                }
-            }
-            else
+            if ( IsSelection() )
             {
-                // in the case when in-place editing is turned off we just want to
-                // echo the text changes in the cell but not yet update the grid table
-                //
-                switch ( m_editCtrlType )
-                {
-                    case wxGRID_TEXTCTRL:
-                        DrawCellValue( m_currentCellCoords, ((wxTextCtrl *)ctrl)->GetValue() );
-                        break;
-
-                    case wxGRID_COMBOBOX:
-                        DrawCellValue( m_currentCellCoords, ((wxComboBox *)ctrl)->GetValue() );
-                        break;
-                }
+                SendEvent( EVT_GRID_RANGE_SELECT, -1, -1, event );
             }
         }
+
+        m_dragLastPos = -1;
     }
 
-    m_inOnText = FALSE;
-}
 
-void wxGrid::OnGridScroll( wxScrollEvent& ev )
-{
-    // propagate the event up and see if it gets processed
+    // ------------ Right button down
     //
-    wxWindow *parent = GetParent();
-    wxScrollEvent scrollEvt( ev );
-    if (parent->GetEventHandler()->ProcessEvent( scrollEvt )) return;
-
-    HideCellEditControl();
-
-    if ( ev.GetEventObject() == m_horizScrollBar )
+    else if ( event.RightDown() )
     {
-        if ( ev.GetPosition() != m_scrollPosX )
+        if ( !SendEvent( EVT_GRID_CELL_RIGHT_CLICK,
+                         coords.GetRow(),
+                         coords.GetCol(),
+                         event ) )
         {
-            SetHorizontalScrollPos( ev.GetPosition() );
-        }
+            // no default action at the moment
+        }        
     }
-    else
+
+    
+    // ------------ Right double click
+    //
+    else if ( event.RightDClick() )
     {
-        if ( ev.GetPosition() != m_scrollPosY )
+        if ( !SendEvent( EVT_GRID_CELL_RIGHT_DCLICK,
+                         coords.GetRow(),
+                         coords.GetCol(),
+                         event ) )
         {
-            SetVerticalScrollPos( ev.GetPosition() );
-        }
+            // no default action at the moment
+        }        
     }
-
-    ShowCellEditControl();
 }
 
 
-void wxGrid::SelectCell( const wxGridCellCoords& coords )
+//
+// ------ interaction with data model
+//
+bool wxGrid::ProcessTableMessage( wxGridTableMessage& msg )
 {
-    if ( SendEvent( EVT_GRID_SELECT_CELL, coords.GetRow(), coords.GetCol() ) )
+    switch ( msg.GetId() )
     {
-        // the event has been intercepted - do nothing
-        return;
-    }
+        case wxGRIDTABLE_REQUEST_VIEW_GET_VALUES:
+            return GetModelValues();
 
-    wxClientDC dc( this );
+        case wxGRIDTABLE_REQUEST_VIEW_SEND_VALUES:
+            return SetModelValues();
 
-    if ( m_currentCellCoords != wxGridNoCellCoords )
-    {
-        HideCurrentCellHighlight( dc );
-        HideCellEditControl();
-        SaveEditControlValue();
+        case wxGRIDTABLE_NOTIFY_ROWS_INSERTED:
+        case wxGRIDTABLE_NOTIFY_ROWS_APPENDED:
+        case wxGRIDTABLE_NOTIFY_ROWS_DELETED:
+        case wxGRIDTABLE_NOTIFY_COLS_INSERTED:
+        case wxGRIDTABLE_NOTIFY_COLS_APPENDED:
+        case wxGRIDTABLE_NOTIFY_COLS_DELETED:
+            return Redimension( msg );
+
+        default:
+            return FALSE;
     }
+}
 
-    m_currentCellCoords = coords;
 
-    SetEditControlValue();
-    if ( IsOnScreen() )
-    {
-        ShowCellEditControl();
-        ShowCurrentCellHighlight( dc );
-    }
 
-    if ( IsSelection() )
+// The behaviour of this function depends on the grid table class
+// Clear() function.  For the default wxGridStringTable class the
+// behavious is to replace all cell contents with wxEmptyString but
+// not to change the number of rows or cols.
+//
+void wxGrid::ClearGrid()
+{
+    if ( m_table )
     {
-        ClearSelection();
+        m_table->Clear();
+        SetEditControlValue();
         if ( !GetBatchCount() ) Refresh();
     }
 }
 
 
-void wxGrid::ShowCellEditControl()
+bool wxGrid::InsertRows( int pos, int numRows, bool WXUNUSED(updateLabels) )
 {
-    wxRect rect;
+    // TODO: something with updateLabels flag
 
-    if ( IsCellEditControlEnabled() )
+    if ( !m_created )
     {
-        if ( !IsVisible( m_currentCellCoords ) )
-        {
-            return;
-        }
-        else
-        {
-            rect = CellToRect( m_currentCellCoords );
+        wxLogError( wxT("Called wxGrid::InsertRows() before calling CreateGrid()") );
+        return FALSE;
+    }
 
-            m_cellEditCtrl->SetSize( rect );
-            m_cellEditCtrl->Show( TRUE );
+    if ( m_table )
+    {
+        bool ok = m_table->InsertRows( pos, numRows );
 
-            switch ( m_editCtrlType )
+        // the table will have sent the results of the insert row
+        // operation to this view object as a grid table message
+        //
+        if ( ok )
+        {
+            if ( m_numCols == 0 )
             {
-                case wxGRID_TEXTCTRL:
-                    ((wxTextCtrl *) m_cellEditCtrl)->SetInsertionPointEnd();
-                    break;
-
-                case wxGRID_CHECKBOX:
-                    // TODO: anything ???
-                    //
-                    break;
-
-                case wxGRID_CHOICE:
-                    // TODO: anything ???
-                    //
-                    break;
+                m_table->AppendCols( WXGRID_DEFAULT_NUMBER_COLS );
+                //
+                // TODO: perhaps instead of appending the default number of cols
+                // we should remember what the last non-zero number of cols was ?
+                //
+            }
 
-                case wxGRID_COMBOBOX:
-                    // TODO: anything ???
-                    //
-                    break;
+            if ( m_currentCellCoords == wxGridNoCellCoords )
+            {
+                // if we have just inserted cols into an empty grid the current
+                // cell will be undefined...
+                //
+                SetCurrentCell( 0, 0 );
             }
 
-            m_cellEditCtrl->SetFocus();
+            ClearSelection();
+            if ( !GetBatchCount() ) Refresh();
         }
+
+        SetEditControlValue();
+        return ok;
+    }
+    else
+    {
+        return FALSE;
     }
 }
 
 
-void wxGrid::HideCellEditControl()
+bool wxGrid::AppendRows( int numRows, bool WXUNUSED(updateLabels) )
 {
-    if ( IsCellEditControlEnabled() )
+    // TODO: something with updateLabels flag
+
+    if ( !m_created )
     {
-        m_cellEditCtrl->Show( FALSE );
+        wxLogError( wxT("Called wxGrid::AppendRows() before calling CreateGrid()") );
+        return FALSE;
+    }
+
+    if ( m_table && m_table->AppendRows( numRows ) )
+    {
+        if ( m_currentCellCoords == wxGridNoCellCoords )
+        {
+            // if we have just inserted cols into an empty grid the current
+            // cell will be undefined...
+            //
+            SetCurrentCell( 0, 0 );
+        }
+
+        // the table will have sent the results of the append row
+        // operation to this view object as a grid table message
+        //
+        ClearSelection();
+        if ( !GetBatchCount() ) Refresh();
+        return TRUE;
+    }
+    else
+    {
+        return FALSE;
     }
 }
 
-void wxGrid::SetEditControlValue( const wxString& value )
+
+bool wxGrid::DeleteRows( int pos, int numRows, bool WXUNUSED(updateLabels) )
 {
-    if ( m_table )
+    // TODO: something with updateLabels flag
+
+    if ( !m_created )
     {
-        wxString s;
-        if ( !value )
-            s = GetCellValue(m_currentCellCoords);
+        wxLogError( wxT("Called wxGrid::DeleteRows() before calling CreateGrid()") );
+        return FALSE;
+    }
+
+    if ( m_table && m_table->DeleteRows( pos, numRows ) )
+    {
+        // the table will have sent the results of the delete row
+        // operation to this view object as a grid table message
+        //
+        if ( m_numRows > 0 )
+            SetEditControlValue();
         else
-            s = value;
+            HideCellEditControl();
 
-        if ( IsTopEditControlEnabled() )
-        {
-            switch ( m_editCtrlType )
-            {
-                case wxGRID_TEXTCTRL:
-                    ((wxGridTextCtrl *)m_topEditCtrl)->SetStartValue(s);
-                    break;
+        ClearSelection();
+        if ( !GetBatchCount() ) Refresh();
+        return TRUE;
+    }
+    else
+    {
+        return FALSE;
+    }
+}
 
-                case wxGRID_CHECKBOX:
-                    // TODO: implement this
-                    //
-                    break;
 
-                case wxGRID_CHOICE:
-                    // TODO: implement this
-                    //
-                    break;
+bool wxGrid::InsertCols( int pos, int numCols, bool WXUNUSED(updateLabels) )
+{
+    // TODO: something with updateLabels flag
 
-                case wxGRID_COMBOBOX:
-                    // TODO: implement this
-                    //
-                    break;
-            }
-        }
+    if ( !m_created )
+    {
+        wxLogError( wxT("Called wxGrid::InsertCols() before calling CreateGrid()") );
+        return FALSE;
+    }
 
-        if ( IsCellEditControlEnabled() )
+    if ( m_table )
+    {
+        HideCellEditControl();
+        bool ok = m_table->InsertCols( pos, numCols );
+
+        // the table will have sent the results of the insert col
+        // operation to this view object as a grid table message
+        //
+        if ( ok )
         {
-            switch ( m_editCtrlType )
+            if ( m_currentCellCoords == wxGridNoCellCoords )
             {
-                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;
+                // if we have just inserted cols into an empty grid the current
+                // cell will be undefined...
+                //
+                SetCurrentCell( 0, 0 );
             }
+
+            ClearSelection();
+            if ( !GetBatchCount() ) Refresh();
         }
+
+        SetEditControlValue();
+        return ok;
+    }
+    else
+    {
+        return FALSE;
     }
 }
 
-void wxGrid::SaveEditControlValue()
+
+bool wxGrid::AppendCols( int numCols, bool WXUNUSED(updateLabels) )
 {
-    if ( m_table )
+    // TODO: something with updateLabels flag
+
+    if ( !m_created )
     {
-        wxWindow *ctrl = (wxWindow *)NULL;
+        wxLogError( wxT("Called wxGrid::AppendCols() before calling CreateGrid()") );
+        return FALSE;
+    }
 
-        if ( IsCellEditControlEnabled() )
-        {
-            ctrl = m_cellEditCtrl;
-        }
-        else if ( IsTopEditControlEnabled() )
+    if ( m_table && m_table->AppendCols( numCols ) )
+    {
+        // the table will have sent the results of the append col
+        // operation to this view object as a grid table message
+        //
+        if ( m_currentCellCoords == wxGridNoCellCoords )
         {
-            ctrl = m_topEditCtrl;
-        }
-        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;
-
-            case wxGRID_CHOICE:
-                // TODO: implement this
-                //
-                break;
-
-            case wxGRID_COMBOBOX:
-                // TODO: implement this
-                //
-                break;
+            // if we have just inserted cols into an empty grid the current
+            // cell will be undefined...
+            //
+            SetCurrentCell( 0, 0 );
         }
 
-        if ( valueChanged )
-        {
-            SendEvent( EVT_GRID_CELL_CHANGE,
-                       m_currentCellCoords.GetRow(),
-                       m_currentCellCoords.GetCol() );
-        }
+        ClearSelection();
+        if ( !GetBatchCount() ) Refresh();
+        return TRUE;
     }
-}
-
-
-int wxGrid::XYToArea( int x, int y )
-{
-    if ( x > m_left && x < m_right &&
-         y > m_top && y < m_bottom )
+    else
     {
-        if ( y < m_top + m_colLabelHeight )
-        {
-            if ( x > m_left + m_rowLabelWidth )
-            {
-                return WXGRID_COLLABEL;
-            }
-            else
-            {
-                return WXGRID_CORNERLABEL;
-            }
-        }
-        else if ( x <= m_left + m_rowLabelWidth )
-        {
-            return WXGRID_ROWLABEL;
-        }
-        else
-        {
-            return WXGRID_CELL;
-        }
+        return FALSE;
     }
-
-    return WXGRID_NOAREA;
-}
-
-
-void wxGrid::XYToCell( int x, int y, wxGridCellCoords& coords )
-{
-    coords.SetRow( YToRow(y) );
-    coords.SetCol( XToCol(x) );
 }
 
 
-int wxGrid::YToRow( int y )
+bool wxGrid::DeleteCols( int pos, int numCols, bool WXUNUSED(updateLabels) )
 {
-    int i;
+    // TODO: something with updateLabels flag
 
-    if ( y > m_top + m_colLabelHeight )
+    if ( !m_created )
     {
-        for ( i = m_scrollPosY;  i < m_numRows;  i++ )
-        {
-            if ( y < m_rowBottoms[i] )
-            {
-                return i;
-            }
-        }
+        wxLogError( wxT("Called wxGrid::DeleteCols() before calling CreateGrid()") );
+        return FALSE;
     }
 
-    return -1;
-}
-
-
-int wxGrid::XToCol( int x )
-{
-    int i;
+    if ( m_table && m_table->DeleteCols( pos, numCols ) )
+    {
+        // the table will have sent the results of the delete col
+        // operation to this view object as a grid table message
+        //
+        if ( m_numCols > 0 )
+            SetEditControlValue();
+        else
+            HideCellEditControl();
 
-    if ( x > m_left + m_rowLabelWidth )
+        ClearSelection();
+        if ( !GetBatchCount() ) Refresh();
+        return TRUE;
+    }
+    else
     {
-        for ( i = m_scrollPosX;  i < m_numCols;  i++ )
-        {
-            if ( x < m_colRights[i] )
-            {
-                return i;
-            }
-        }
+        return FALSE;
     }
-
-    return -1;
 }
 
 
-// return the row number that that the y coord is near the edge of, or
-// -1 if not near an edge
+
+//
+// ----- event handlers
 //
-int wxGrid::YToEdgeOfRow( int y )
-{
-    int i, d;
 
-    if ( y > m_top + m_colLabelHeight )
+// Generate a grid event based on a mouse event and
+// return the result of ProcessEvent()
+//
+bool wxGrid::SendEvent( const wxEventType type,
+                        int row, int col,
+                        wxMouseEvent& mouseEv )
+{
+    if ( type == EVT_GRID_ROW_SIZE ||
+         type == EVT_GRID_COL_SIZE )
     {
-        for ( i = m_scrollPosY;  i < m_numRows;  i++ )
-        {
-            if ( m_rowHeights[i] > WXGRID_LABEL_EDGE_ZONE )
-            {
-                d = abs( y - m_rowBottoms[i] );
-                {
-                    if ( d < WXGRID_LABEL_EDGE_ZONE ) return i;
-                }
-            }
-        }
+        int rowOrCol = (row == -1 ? col : row);
+
+        wxGridSizeEvent gridEvt( GetId(),
+                                 type,
+                                 this,
+                                 rowOrCol,
+                                 mouseEv.GetX(), mouseEv.GetY(),
+                                 mouseEv.ControlDown(),
+                                 mouseEv.ShiftDown(),
+                                 mouseEv.AltDown(),
+                                 mouseEv.MetaDown() );
+
+        return GetEventHandler()->ProcessEvent(gridEvt);
     }
+    else if ( type == EVT_GRID_RANGE_SELECT )
+    {
+        wxGridRangeSelectEvent gridEvt( GetId(),
+                                        type,
+                                        this,
+                                        m_selectedTopLeft,
+                                        m_selectedBottomRight,
+                                        mouseEv.ControlDown(),
+                                        mouseEv.ShiftDown(),
+                                        mouseEv.AltDown(),
+                                        mouseEv.MetaDown() );
 
-    return -1;
+        return GetEventHandler()->ProcessEvent(gridEvt);
+    }
+    else
+    {
+        wxGridEvent gridEvt( GetId(),
+                             type,
+                             this,
+                             row, col,
+                             mouseEv.GetX(), mouseEv.GetY(),
+                             mouseEv.ControlDown(),
+                             mouseEv.ShiftDown(),
+                             mouseEv.AltDown(),
+                             mouseEv.MetaDown() );
 
+        return GetEventHandler()->ProcessEvent(gridEvt);
+    }
 }
 
 
-// return the col number that that the x coord is near the edge of, or
-// -1 if not near an edge
+// Generate a grid event of specified type and return the result
+// of ProcessEvent().
 //
-int wxGrid::XToEdgeOfCol( int x )
+bool wxGrid::SendEvent( const wxEventType type,
+                        int row, int col )
 {
-    int i, d;
-
-    if ( x > m_left + m_rowLabelWidth )
+    if ( type == EVT_GRID_ROW_SIZE ||
+         type == EVT_GRID_COL_SIZE )
     {
-        for ( i = m_scrollPosX;  i < m_numCols;  i++ )
-        {
-            if ( m_colWidths[i] > WXGRID_LABEL_EDGE_ZONE )
-            {
-                d = abs( x - m_colRights[i] );
-                {
-                    if ( d < WXGRID_LABEL_EDGE_ZONE ) return i;
-                }
-            }
-        }
-    }
+        int rowOrCol = (row == -1 ? col : row);
 
-    return -1;
+        wxGridSizeEvent gridEvt( GetId(),
+                                 type,
+                                 this,
+                                 rowOrCol );
+
+        return GetEventHandler()->ProcessEvent(gridEvt);
+    }
+    else
+    {
+        wxGridEvent gridEvt( GetId(),
+                             type,
+                             this,
+                             row, col );
 
+        return GetEventHandler()->ProcessEvent(gridEvt);
+    }
 }
 
 
-wxRect wxGrid::CellToRect( int row, int col )
+void wxGrid::OnPaint( wxPaintEvent& WXUNUSED(event) )
 {
-    wxRect rect( -1, -1, -1, -1 );
+    wxPaintDC dc( this );
 
-    if ( row >= m_scrollPosY  &&  col >= m_scrollPosX )
+    if ( m_currentCellCoords == wxGridNoCellCoords  &&
+         m_numRows && m_numCols )
     {
-        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 ];
+        m_currentCellCoords.Set(0, 0);
+        SetEditControlValue();
+        ShowCellEditControl();
     }
-
-    return rect;
 }
 
 
-bool wxGrid::MoveCursorUp()
+// This is just here to make sure that CalcDimensions gets called when
+// the grid view is resized... then the size event is skipped to allow
+// the box sizers to handle everything
+//
+void wxGrid::OnSize( wxSizeEvent& event )
 {
-    if ( m_currentCellCoords != wxGridNoCellCoords  &&
-         m_currentCellCoords.GetRow() > 0 )
-    {
-        SelectCell( m_currentCellCoords.GetRow() - 1,
-                      m_currentCellCoords.GetCol() );
-
-        if ( !IsVisible( m_currentCellCoords ) )
-            MakeCellVisible( m_currentCellCoords );
-
-        return TRUE;
-    }
-
-    return FALSE;
+    CalcDimensions();
+    event.Skip();
 }
 
-bool wxGrid::MoveCursorDown()
-{
-    // TODO: allow for scrolling
-    //
-    if ( m_currentCellCoords != wxGridNoCellCoords  &&
-         m_currentCellCoords.GetRow() < m_numRows-1 )
-    {
-        SelectCell( m_currentCellCoords.GetRow() + 1,
-                      m_currentCellCoords.GetCol() );
-
-        if ( !IsVisible( m_currentCellCoords ) )
-            MakeCellVisible( m_currentCellCoords );
-
-        return TRUE;
-    }
-
-    return FALSE;
-}
 
-bool wxGrid::MoveCursorLeft()
+void wxGrid::OnKeyDown( wxKeyEvent& event )
 {
-    if ( m_currentCellCoords != wxGridNoCellCoords  &&
-         m_currentCellCoords.GetCol() > 0 )
+    if ( m_inOnKeyDown )
     {
-        SelectCell( m_currentCellCoords.GetRow(),
-                      m_currentCellCoords.GetCol() - 1 );
-
-        if ( !IsVisible( m_currentCellCoords ) )
-            MakeCellVisible( m_currentCellCoords );
-
-        return TRUE;
+        // shouldn't be here - we are going round in circles...
+        //
+        wxLogFatalError( wxT("wxGrid::OnKeyDown called while alread active") );
     }
 
-    return FALSE;
-}
+    m_inOnKeyDown = TRUE;
 
-bool wxGrid::MoveCursorRight()
-{
-    if ( m_currentCellCoords != wxGridNoCellCoords  &&
-         m_currentCellCoords.GetCol() < m_numCols - 1 )
+    // propagate the event up and see if it gets processed
+    //
+    wxWindow *parent = GetParent();
+    wxKeyEvent keyEvt( event );
+    keyEvt.SetEventObject( parent );
+
+    if ( !parent->GetEventHandler()->ProcessEvent( keyEvt ) )
     {
-        SelectCell( m_currentCellCoords.GetRow(),
-                      m_currentCellCoords.GetCol() + 1 );
+        // try local handlers
+        //
+        switch ( event.KeyCode() )
+        {
+            case WXK_UP:
+                if ( event.ControlDown() )
+                {
+                    MoveCursorUpBlock();
+                }
+                else
+                {
+                    MoveCursorUp();
+                }
+                break;
 
-        if ( !IsVisible( m_currentCellCoords ) )
-            MakeCellVisible( m_currentCellCoords );
+            case WXK_DOWN:
+                if ( event.ControlDown() )
+                {
+                    MoveCursorDownBlock();
+                }
+                else
+                {
+                    MoveCursorDown();
+                }
+                break;
 
-        return TRUE;
+            case WXK_LEFT:
+                if ( event.ControlDown() )
+                {
+                    MoveCursorLeftBlock();
+                }
+                else
+                {
+                    MoveCursorLeft();
+                }
+                break;
+
+            case WXK_RIGHT:
+                if ( event.ControlDown() )
+                {
+                    MoveCursorRightBlock();
+                }
+                else
+                {
+                    MoveCursorRight();
+                }
+                break;
+
+            case WXK_RETURN:
+                MoveCursorDown();
+                break;
+
+            case WXK_HOME:
+                if ( event.ControlDown() )
+                {
+                    MakeCellVisible( 0, 0 );
+                    SetCurrentCell( 0, 0 );
+                }
+                else
+                {
+                    event.Skip();
+                }
+                break;
+
+            case WXK_END:
+                if ( event.ControlDown() )
+                {
+                    MakeCellVisible( m_numRows-1, m_numCols-1 );
+                    SetCurrentCell( m_numRows-1, m_numCols-1 );
+                }
+                else
+                {
+                    event.Skip();
+                }
+                break;
+
+            case WXK_PRIOR:
+                MovePageUp();
+                break;
+
+            case WXK_NEXT:
+                MovePageDown();
+                break;
+
+            default:
+                // now try the cell edit control
+                //
+                if ( IsCellEditControlEnabled() )
+                {
+                    event.SetEventObject( m_cellEditCtrl );
+                    m_cellEditCtrl->GetEventHandler()->ProcessEvent( event );
+                }
+                break;
+        }
     }
 
-    return FALSE;
+    m_inOnKeyDown = FALSE;
 }
 
-bool wxGrid::MovePageUp()
+
+void wxGrid::SetCurrentCell( const wxGridCellCoords& coords )
 {
-    if ( m_currentCellCoords != wxGridNoCellCoords  &&
-         m_scrollPosY > 0 )
+    if ( SendEvent( EVT_GRID_SELECT_CELL, coords.GetRow(), coords.GetCol() ) )
     {
-        int row = m_currentCellCoords.GetRow();
-        int y = m_rowBottoms[ row ] - m_rowHeights[ row ];
-        while ( row > 0 )
-        {
-            if ( y + m_rowHeights[row-1] > m_bottom ) break;
-            y += m_rowHeights[ --row ];
-        }
-        SetVerticalScrollPos( row );
+        // the event has been intercepted - do nothing
+        return;
+    }
 
-        SelectCell( row, m_currentCellCoords.GetCol() );
-        return TRUE;
+    wxClientDC dc( m_gridWin );
+    PrepareDC( dc );
+
+    if ( m_currentCellCoords != wxGridNoCellCoords )
+    {
+        // HideCurrentCellHighlight( dc );
+        HideCellEditControl();
+        SaveEditControlValue();
     }
 
-    return FALSE;
+    m_currentCellCoords = coords;
+
+    SetEditControlValue();
+    ShowCellEditControl();
+    // ShowCurrentCellHighlight( dc );
+
+    if ( IsSelection() )
+    {
+        wxRect r( SelectionToDeviceRect() );
+        ClearSelection();
+        if ( !GetBatchCount() ) m_gridWin->Refresh( TRUE, &r );
+    }
 }
 
-bool wxGrid::MovePageDown()
+
+//
+// ------ functions to get/send data (see also public functions)
+//
+
+bool wxGrid::GetModelValues()
 {
-    if ( m_currentCellCoords != wxGridNoCellCoords  &&
-         m_scrollPosY + m_wholeRowsVisible < m_numRows )
+    if ( m_table )
     {
-        if ( m_wholeRowsVisible > 0 )
-        {
-            SetVerticalScrollPos( m_scrollPosY + m_wholeRowsVisible );
-        }
-        else if ( m_scrollPosY < m_numRows - 1 )
-        {
-            SetVerticalScrollPos( m_scrollPosY + 1 );
-        }
-        else
-        {
-            return FALSE;
-        }
-
-        // m_scrollPosY will have been updated
+        // all we need to do is repaint the grid
         //
-        SelectCell( m_scrollPosY, m_currentCellCoords.GetCol() );
+        m_gridWin->Refresh();
         return TRUE;
     }
 
     return FALSE;
 }
 
-bool wxGrid::MoveCursorUpBlock()
+
+bool wxGrid::SetModelValues()
 {
-    if ( m_table &&
-         m_currentCellCoords != wxGridNoCellCoords  &&
-         m_currentCellCoords.GetRow() > 0 )
-    {
-        int row = m_currentCellCoords.GetRow();
-        int col = m_currentCellCoords.GetCol();
+    int row, col;
 
-        if ( m_table->IsEmptyCell(row, col) )
-        {
-            // starting in an empty cell: find the next block of
-            // non-empty cells
-            //
-            while ( row > 0 )
-            {
-                row-- ;
-                if ( !(m_table->IsEmptyCell(row, col)) ) break;
-            }
-        }
-        else if ( m_table->IsEmptyCell(row-1, col) )
-        {
-            // starting at the top of a block: find the next block
-            //
-            row--;
-            while ( row > 0 )
-            {
-                row-- ;
-                if ( !(m_table->IsEmptyCell(row, col)) ) break;
-            }
-        }
-        else
+    if ( m_table )
+    {
+        for ( row = 0;  row < m_numRows;  row++ )
         {
-            // starting within a block: find the top of the block
-            //
-            while ( row > 0 )
+            for ( col = 0;  col < m_numCols;  col++ )
             {
-                row-- ;
-                if ( m_table->IsEmptyCell(row, col) )
-                {
-                    row++ ;
-                    break;
-                }
+                m_table->SetValue( row, col, GetCellValue(row, col) );
             }
         }
 
-        SelectCell( row, col );
-
-        if ( !IsVisible( m_currentCellCoords ) )
-            MakeCellVisible( m_currentCellCoords );
-
         return TRUE;
     }
 
     return FALSE;
 }
 
-bool wxGrid::MoveCursorDownBlock()
+
+
+// Note - this function only draws cells that are in the list of
+// exposed cells (usually set from the update region by
+// CalcExposedCells)
+//
+void wxGrid::DrawGridCellArea( wxDC& dc )
 {
-    if ( m_table &&
-         m_currentCellCoords != wxGridNoCellCoords  &&
-         m_currentCellCoords.GetRow() < m_numRows-1 )
+    if ( !m_numRows || !m_numCols ) return;
+    
+    size_t i;
+    size_t numCells = m_cellsExposed.GetCount();
+                         
+    for ( i = 0;  i < numCells;  i++ )
     {
-        int row = m_currentCellCoords.GetRow();
-        int col = m_currentCellCoords.GetCol();
+        DrawCell( dc, m_cellsExposed[i] );
+    }
+}
 
-        if ( m_table->IsEmptyCell(row, col) )
-        {
-            // starting in an empty cell: find the next block of
-            // non-empty cells
-            //
-            while ( row < m_numRows-1 )
-            {
-                row++ ;
-                if ( !(m_table->IsEmptyCell(row, col)) ) break;
-            }
-        }
-        else if ( m_table->IsEmptyCell(row+1, col) )
-        {
-            // starting at the bottom of a block: find the next block
-            //
-            row++;
-            while ( row < m_numRows-1 )
-            {
-                row++ ;
-                if ( !(m_table->IsEmptyCell(row, col)) ) break;
-            }
-        }
-        else
-        {
-            // starting within a block: find the bottom of the block
-            //
-            while ( row < m_numRows-1 )
-            {
-                row++ ;
-                if ( m_table->IsEmptyCell(row, col) )
-                {
-                    row-- ;
-                    break;
-                }
-            }
-        }
 
-        SelectCell( row, col );
+void wxGrid::DrawCell( wxDC& dc, const wxGridCellCoords& coords )
+{
+    if ( m_colWidths[coords.GetCol()] <=0  ||
+         m_rowHeights[coords.GetRow()] <= 0 ) return;
+    
+    if ( m_gridLinesEnabled )
+        DrawCellBorder( dc, coords );
 
-        if ( !IsVisible( m_currentCellCoords ) )
-            MakeCellVisible( m_currentCellCoords );
+    DrawCellBackground( dc, coords );
 
-        return TRUE;
-    }
+    // TODO: separate functions here for different kinds of cells ?
+    // e.g. text, image
+    //
+    DrawCellValue( dc, coords );
+}
 
-    return FALSE;
+
+void wxGrid::DrawCellBorder( wxDC& dc, const wxGridCellCoords& coords )
+{
+    if ( m_colWidths[coords.GetCol()] <=0  ||
+         m_rowHeights[coords.GetRow()] <= 0 ) return;
+    
+    dc.SetPen( wxPen(GetGridLineColour(), 1, wxSOLID) );
+    int row = coords.GetRow();
+    int col = coords.GetCol();
+    
+    // right hand border
+    //
+    dc.DrawLine( m_colRights[col], m_rowBottoms[row] - m_rowHeights[row],
+                 m_colRights[col], m_rowBottoms[row] );
+
+    // bottom border
+    //
+    dc.DrawLine( m_colRights[col] - m_colWidths[col], m_rowBottoms[row],
+                 m_colRights[col], m_rowBottoms[row] );
 }
 
-bool wxGrid::MoveCursorLeftBlock()
+
+void wxGrid::DrawCellBackground( wxDC& dc, const wxGridCellCoords& coords )
 {
-    if ( m_table &&
-         m_currentCellCoords != wxGridNoCellCoords  &&
-         m_currentCellCoords.GetCol() > 0 )
-    {
-        int row = m_currentCellCoords.GetRow();
-        int col = m_currentCellCoords.GetCol();
+    if ( m_colWidths[coords.GetCol()] <=0  ||
+         m_rowHeights[coords.GetRow()] <= 0 ) return;
+    
+    int row = coords.GetRow();
+    int col = coords.GetCol();
 
-        if ( m_table->IsEmptyCell(row, col) )
-        {
-            // starting in an empty cell: find the next block of
-            // non-empty cells
-            //
-            while ( col > 0 )
-            {
-                col-- ;
-                if ( !(m_table->IsEmptyCell(row, col)) ) break;
-            }
-        }
-        else if ( m_table->IsEmptyCell(row, col-1) )
-        {
-            // starting at the left of a block: find the next block
-            //
-            col--;
-            while ( col > 0 )
-            {
-                col-- ;
-                if ( !(m_table->IsEmptyCell(row, col)) ) break;
-            }
-        }
-        else
-        {
-            // starting within a block: find the left of the block
-            //
-            while ( col > 0 )
-            {
-                col-- ;
-                if ( m_table->IsEmptyCell(row, col) )
-                {
-                    col++ ;
-                    break;
-                }
-            }
-        }
-
-        SelectCell( row, col );
-
-        if ( !IsVisible( m_currentCellCoords ) )
-            MakeCellVisible( m_currentCellCoords );
+    dc.SetBackgroundMode( wxSOLID );
 
-        return TRUE;
+    if ( IsInSelection( coords ) )
+    {
+        // TODO: improve this
+        //
+        dc.SetBrush( *wxBLACK_BRUSH );
     }
-
-    return FALSE;
-}
-
-bool wxGrid::MoveCursorRightBlock()
-{
-    if ( m_table &&
-         m_currentCellCoords != wxGridNoCellCoords  &&
-         m_currentCellCoords.GetCol() < m_numCols-1 )
+    else
     {
-        int row = m_currentCellCoords.GetRow();
-        int col = m_currentCellCoords.GetCol();
-
-        if ( m_table->IsEmptyCell(row, col) )
-        {
-            // starting in an empty cell: find the next block of
-            // non-empty cells
-            //
-            while ( col < m_numCols-1 )
-            {
-                col++ ;
-                if ( !(m_table->IsEmptyCell(row, col)) ) break;
-            }
-        }
-        else if ( m_table->IsEmptyCell(row, col+1) )
-        {
-            // starting at the right of a block: find the next block
-            //
-            col++;
-            while ( col < m_numCols-1 )
-            {
-                col++ ;
-                if ( !(m_table->IsEmptyCell(row, col)) ) break;
-            }
-        }
-        else
-        {
-            // starting within a block: find the right of the block
-            //
-            while ( col < m_numCols-1 )
-            {
-                col++ ;
-                if ( m_table->IsEmptyCell(row, col) )
-                {
-                    col-- ;
-                    break;
-                }
-            }
-        }
-
-        SelectCell( row, col );
-
-        if ( !IsVisible( m_currentCellCoords ) )
-            MakeCellVisible( m_currentCellCoords );
-
-        return TRUE;
+        dc.SetBrush( wxBrush(GetCellBackgroundColour(row, col), wxSOLID) );
     }
 
-    return FALSE;
-}
-
-
-
-//
-// ----- grid drawing functions
-//
-
-void wxGrid::DrawLabelAreas( wxDC& dc )
-{
-    int cw, ch;
-    GetClientSize(&cw, &ch);
-
-    dc.SetPen(*wxTRANSPARENT_PEN);
-    dc.SetBrush( wxBrush(GetLabelBackgroundColour(), wxSOLID) );
-
-    dc.DrawRectangle( m_left, m_top,
-                      cw - m_left, m_colLabelHeight );
+    dc.SetPen( *wxTRANSPARENT_PEN );
 
-    dc.DrawRectangle( m_left, m_top,
-                      m_rowLabelWidth, ch - m_top );
+    dc.DrawRectangle( m_colRights[col] - m_colWidths[col] + 1,
+                      m_rowBottoms[row] - m_rowHeights[row] + 1,
+                      m_colWidths[col]-1,
+                      m_rowHeights[row]-1 );
 }
 
 
-void wxGrid::DrawColLabels( wxDC& dc )
+void wxGrid::DrawCellValue( wxDC& dc, const wxGridCellCoords& coords )
 {
-    int cw, ch;
-    GetClientSize(&cw, &ch);
-
-    if (m_colLabelHeight == 0) return;
+    if ( m_colWidths[coords.GetCol()] <=0  ||
+         m_rowHeights[coords.GetRow()] <= 0 ) return;
+    
+    int row = coords.GetRow();
+    int col = coords.GetCol();
 
-    DrawColLabelBorders( dc );
-
-    wxRect rect;
-    rect.y = m_top + 1;
-    rect.height = m_colLabelHeight - 1;
-
-    int labelLeft = m_left + m_rowLabelWidth;
-    int i;
+    dc.SetBackgroundMode( wxTRANSPARENT );
 
-    for ( i = m_scrollPosX;  i < m_numCols;  i++ )
+    if ( IsInSelection( row, col ) )
+    {
+        // TODO: improve this
+        //
+        dc.SetTextBackground( wxColour(0, 0, 0) );
+        dc.SetTextForeground( wxColour(255, 255, 255) );
+    }
+    else
     {
-        if ( labelLeft > cw) break;
+        dc.SetTextBackground( GetCellBackgroundColour(row, col) );
+        dc.SetTextForeground( GetCellTextColour(row, col) );
+    }
+    dc.SetFont( GetCellFont(row, col) );
 
-        rect.x = 1 + labelLeft;
-        rect.width = m_colWidths[i];
-        DrawColLabel( dc, rect, i );
+    int hAlign, vAlign;
+    GetCellAlignment( row, col, &hAlign, &vAlign );
 
-        labelLeft += m_colWidths[i];
-    }
+    wxRect rect;
+    rect.SetX( m_colRights[col] - m_colWidths[col] + 2 );
+    rect.SetY( m_rowBottoms[row] - m_rowHeights[row] + 2 );
+    rect.SetWidth( m_colWidths[col] - 4 );
+    rect.SetHeight( m_rowHeights[row] - 4 );
+    
+    DrawTextRectangle( dc, GetCellValue( row, col ), rect, hAlign, vAlign );
 }
 
 
-void wxGrid::DrawColLabelBorders( wxDC& dc )
+
+// TODO: remove this ???
+// This is used to redraw all grid lines e.g. when the grid line colour
+// has been changed
+//
+void wxGrid::DrawAllGridLines( wxDC& dc )
 {
-    if ( m_colLabelHeight <= 0 ) return;
+    if ( !m_gridLinesEnabled || 
+         !m_numRows || 
+         !m_numCols ) return;
 
-    int i;
     int cw, ch;
-    GetClientSize( &cw, &ch );
-
-    dc.SetPen( *wxBLACK_PEN );
+    m_gridWin->GetClientSize(&cw, &ch);
 
-    // horizontal lines
+    // virtual coords of visible area
     //
-    dc.DrawLine( m_left, m_top, cw, m_top );
+    int top, bottom, left, right;
+    CalcUnscrolledPosition( 0, 0, &left, &top );
+    CalcUnscrolledPosition( cw, ch, &right, &bottom );
 
-    dc.DrawLine( m_left, m_top + m_colLabelHeight,
-                 cw,     m_top + m_colLabelHeight );
+    dc.SetPen( wxPen(GetGridLineColour(), 1, wxSOLID) );
 
-    // vertical lines
+    // horizontal grid lines
     //
-    int colLeft = m_left + m_rowLabelWidth;
-    for ( i = m_scrollPosX;  i <= m_numCols;  i++ )
+    int i;    
+    for ( i = 0; i <= m_numRows; i++ )
     {
-        if (colLeft > cw) break;
-
-        dc.DrawLine( colLeft, m_top,
-                     colLeft, m_top + m_colLabelHeight);
-
-        if ( i < m_numCols ) colLeft += m_colWidths[i];
+        if ( m_rowBottoms[i] > bottom )
+        {
+            break;
+        }
+        else if ( m_rowBottoms[i] >= top )
+        {
+            dc.DrawLine( left, m_rowBottoms[i], right, m_rowBottoms[i] );
+        }
     }
 
-    // Draw white highlights for a 3d effect
-    //
-    dc.SetPen( *wxWHITE_PEN );
 
-    colLeft = m_left + m_rowLabelWidth;
-    for ( i = m_scrollPosX; i < m_numCols; i++ )
+    // vertical grid lines
+    //
+    for ( i = 0; i <= m_numCols; i++ )
     {
-        if (colLeft > cw) break;
-
-        dc.DrawLine(colLeft + 1, m_top + 1,
-                    colLeft + m_colWidths[i], m_top + 1);
+        if ( m_colRights[i] > right )
+        {
+            break;
+        }
+        else if ( m_colRights[i] >= left )
+        {
+            dc.DrawLine( m_colRights[i], top, m_colRights[i], bottom );
+        }
+    }
+}
 
-        dc.DrawLine(colLeft + 1, m_top + 1,
-                    colLeft + 1, m_top + m_colLabelHeight);
 
-        colLeft += m_colWidths[i];
-    }
+void wxGrid::DrawRowLabels( wxDC& dc )
+{
+    if ( !m_numRows || !m_numCols ) return;
+    
+    size_t i;
+    size_t numLabels = m_rowLabelsExposed.GetCount();
+                         
+    for ( i = 0;  i < numLabels;  i++ )
+    {
+        DrawRowLabel( dc, m_rowLabelsExposed[i] );
+    }    
 }
 
 
-void wxGrid::DrawColLabel( wxDC& dc, const wxRect& rect, int col )
+void wxGrid::DrawRowLabel( wxDC& dc, int row )
 {
-    wxRect rect2;
-    rect2 = rect;
-    rect2.x += 3;
-    rect2.y += 2;
-    rect2.width -= 5;
-    rect2.height -= 4;
+    if ( m_rowHeights[row] <= 0 ) return;
+    
+    // draw the label's horizontal border (the vertical border is
+    // provided by the cell area window margin)
+    //
+    dc.SetPen( *wxBLACK_PEN );
 
+    dc.DrawLine( 0, m_rowBottoms[row]+1,
+                 m_rowLabelWidth, m_rowBottoms[row]+1 );
+
+    dc.SetPen( *wxWHITE_PEN );
+
+    dc.DrawLine( 0, m_rowBottoms[row]+2,
+                 m_rowLabelWidth, m_rowBottoms[row]+2 );
+                 
     dc.SetBackgroundMode( wxTRANSPARENT );
-    dc.SetTextBackground( GetLabelBackgroundColour() );
     dc.SetTextForeground( GetLabelTextColour() );
     dc.SetFont( GetLabelFont() );
 
     int hAlign, vAlign;
-    GetColLabelAlignment( &hAlign, &vAlign );
-    DrawTextRectangle( dc, GetColLabelValue( col ), rect2, hAlign, vAlign );
+    GetRowLabelAlignment( &hAlign, &vAlign );
+    
+    wxRect rect;
+    rect.SetX( 2 );
+    rect.SetY( m_rowBottoms[row] - m_rowHeights[row] + 2 );
+    rect.SetWidth( m_rowLabelWidth - 4 );
+    rect.SetHeight( m_rowHeights[row] - 4 );
+    DrawTextRectangle( dc, GetRowLabelValue( row ), rect, hAlign, vAlign );    
 }
 
 
-void wxGrid::DrawRowLabels( wxDC& dc )
+void wxGrid::DrawColLabels( wxDC& dc )
 {
-    int cw, ch;
-    GetClientSize(&cw, &ch);
-
-    if (m_rowLabelWidth == 0) return;
-
-    DrawRowLabelBorders( dc );
-
-    wxRect rect;
-    rect.x = m_left + 1;
-    rect.width = m_rowLabelWidth - 1;
-
-    int labelTop = m_top + m_colLabelHeight;
-    int i;
-
-    for ( i = m_scrollPosY;  i < m_numRows;  i++ )
+    if ( !m_numRows || !m_numCols ) return;
+    
+    size_t i;
+    size_t numLabels = m_colLabelsExposed.GetCount();
+                         
+    for ( i = 0;  i < numLabels;  i++ )
     {
-        if ( labelTop > ch ) break;
-
-        rect.y = 1 + labelTop;
-        rect.height = m_rowHeights[i];
-        DrawRowLabel( dc, rect, i );
-
-        labelTop += m_rowHeights[i];
-    }
+        DrawColLabel( dc, m_colLabelsExposed[i] );
+    }    
 }
 
 
-void wxGrid::DrawRowLabelBorders( wxDC& dc )
+void wxGrid::DrawColLabel( wxDC& dc, int col )
 {
-    if ( m_rowLabelWidth <= 0 ) return;
-
-    int i;
-    int cw, ch;
-    GetClientSize( &cw, &ch );
-
-    dc.SetPen( *wxBLACK_PEN );
-
-    // vertical lines
+    if ( m_colWidths[col] <= 0 ) return;
+    
+    // draw the label's vertical border (the horizontal border is
+    // provided by the cell area window margin)
     //
-    dc.DrawLine( m_left, m_top, m_left, ch );
-
-    dc.DrawLine( m_left + m_rowLabelWidth, m_top,
-                 m_left + m_rowLabelWidth, ch );
-
-    // horizontal lines
-    //
-    int rowTop = m_top + m_colLabelHeight;
-    for ( i = m_scrollPosY;  i <= m_numRows;  i++ )
-    {
-        if ( rowTop > ch ) break;
-
-        dc.DrawLine( m_left, rowTop,
-                     m_left + m_rowLabelWidth, rowTop );
+    dc.SetPen( *wxBLACK_PEN );
 
-        if ( i < m_numRows ) rowTop += m_rowHeights[i];
-    }
+    dc.DrawLine( m_colRights[col]+1, 0,
+                 m_colRights[col]+1, m_colLabelHeight );
 
-    // Draw white highlights for a 3d effect
-    //
     dc.SetPen( *wxWHITE_PEN );
 
-    rowTop = m_top + m_colLabelHeight;
-    for ( i = m_scrollPosY; i < m_numRows; i++ )
-    {
-        if ( rowTop > ch ) break;
-
-        dc.DrawLine( m_left + 1, rowTop + 1,
-                     m_left + m_rowLabelWidth, rowTop + 1 );
-
-        dc.DrawLine( m_left + 1, rowTop + 1,
-                     m_left + 1, rowTop + m_rowHeights[i] );
-
-        rowTop += m_rowHeights[i];
-    }
-}
-
-
-void wxGrid::DrawRowLabel( wxDC& dc, const wxRect& rect, int row )
-{
-    wxRect rect2;
-    rect2 = rect;
-    rect2.x += 3;
-    rect2.y += 2;
-    rect2.width -= 5;
-    rect2.height -= 4;
+    dc.DrawLine( m_colRights[col]+2, 0,
+                 m_colRights[col]+2, m_colLabelHeight );
 
     dc.SetBackgroundMode( wxTRANSPARENT );
-    dc.SetTextBackground( GetLabelBackgroundColour() );
     dc.SetTextForeground( GetLabelTextColour() );
     dc.SetFont( GetLabelFont() );
 
     int hAlign, vAlign;
-    GetRowLabelAlignment( &hAlign, &vAlign );
-    DrawTextRectangle( dc, GetRowLabelValue( row ), rect2, hAlign, vAlign );
+    GetColLabelAlignment( &hAlign, &vAlign );
+    
+    wxRect rect;
+    rect.SetX( m_colRights[col] - m_colWidths[col] + 2 );
+    rect.SetY( 2 );
+    rect.SetWidth( m_colWidths[col] - 4 );
+    rect.SetHeight( m_colLabelHeight - 4 );
+    DrawTextRectangle( dc, GetColLabelValue( col ), rect, hAlign, vAlign );    
 }
 
 
-void wxGrid::DrawCellArea( wxDC& dc )
+void wxGrid::DrawTextRectangle( wxDC& dc,
+                                const wxString& value,
+                                const wxRect& rect,
+                                int horizAlign,
+                                int vertAlign )
 {
-  int cw, ch;
-  GetClientSize(&cw, &ch);
+    long textWidth, textHeight;
+    long lineWidth, lineHeight;
+    wxArrayString lines;
 
-  dc.SetPen( *wxTRANSPARENT_PEN );
-  dc.SetBrush( wxBrush(GetDefaultCellBackgroundColour(), wxSOLID) );
+    dc.SetClippingRegion( rect );
+    StringToLines( value, lines );
+    if ( lines.GetCount() )
+    {
+        GetTextBoxSize( dc, lines, &textWidth, &textHeight );
+        dc.GetTextExtent( lines[0], &lineWidth, &lineHeight );
 
-  int left = m_left + m_rowLabelWidth + 1;
-  int top  = m_top + m_colLabelHeight + 1;
+        float x, y;
+        switch ( horizAlign )
+        {
+            case wxRIGHT:
+                x = rect.x + (rect.width - textWidth - 1);
+                break;
 
-  dc.DrawRectangle( left, top, cw - left, ch - top );
-}
+            case wxCENTRE:
+                x = rect.x + ((rect.width - textWidth)/2);
+                break;
 
+            case wxLEFT:
+            default:
+                x = rect.x + 1;
+                break;
+        }
 
-void wxGrid::DrawGridLines( wxDC& dc )
-{
-    if ( !m_gridLinesEnabled || !m_numRows || !m_numCols ) return;
-
-    int i;
-    int cw, ch;
-    GetClientSize(&cw, &ch);
-
-    dc.SetPen( wxPen(GetGridLineColour(), 1, wxSOLID) );
-
-    // horizontal grid lines
-    //
-    int rowTop = m_top + m_colLabelHeight + m_rowHeights[m_scrollPosY];
-    for ( i = m_scrollPosY + 1; i <= m_numRows; i++ )
-    {
-        if ( rowTop > ch ) break;
-
-        dc.DrawLine( m_left + m_rowLabelWidth + 1, rowTop,
-                     m_right, rowTop);
-
-        if ( i < m_numRows ) rowTop += m_rowHeights[i];
-    }
-
-
-    // vertical grid lines
-    //
-    int colLeft = m_left + m_rowLabelWidth + m_colWidths[m_scrollPosX];
-    for ( i = m_scrollPosX + 1; i <= m_numCols; i++ )
-    {
-        if ( colLeft > cw ) break;
-
-        dc.DrawLine( colLeft, m_top + m_colLabelHeight + 1,
-                     colLeft, m_bottom );
-
-        if ( i < m_numCols ) colLeft += m_colWidths[i];
-    }
-}
-
-
-void wxGrid::DrawCells( wxDC& dc )
-{
-    if ( !m_numRows || !m_numCols ) return;
-
-    int row, col;
-
-    int cw, ch;
-    GetClientSize( &cw, &ch );
-
-    wxRect rect;
-
-    if ( m_table )
-    {
-        rect.y = m_top + m_colLabelHeight;
-        for ( row = m_scrollPosY;  row < m_numRows;  row++ )
-        {
-            if ( rect.y > ch ) break;
-
-            rect.height = m_rowHeights[ row ];
-            rect.x = m_left + m_rowLabelWidth;
-
-            for ( col = m_scrollPosX;  col < m_numCols;  col++ )
-            {
-                if ( rect.x > cw ) break;
-
-                rect.width = m_colWidths[col];
-                DrawCellBackground( dc, rect, row, col );
-                DrawCellValue( dc, rect, row, col );
-                rect.x += rect.width;
-            }
-            rect.y += rect.height;
-        }
-    }
-}
-
-
-void wxGrid::DrawCellBackground( wxDC& dc, const wxRect& rect, int row, int col )
-{
-    wxRect rect2;
-    rect2 = rect;
-    rect2.x += 1;
-    rect2.y += 1;
-    rect2.width -= 2;
-    rect2.height -= 2;
-
-    dc.SetBackgroundMode( wxSOLID );
-
-    if ( IsInSelection( row, col ) )
-    {
-        // TODO: improve this
-        //
-        dc.SetBrush( *wxBLACK_BRUSH );
-    }
-    else
-    {
-        dc.SetBrush( wxBrush(GetCellBackgroundColour(row, col), wxSOLID) );
-    }
-    dc.SetPen( *wxTRANSPARENT_PEN );
-    dc.DrawRectangle( rect2 );
-}
-
-
-// This draws a text value in the given cell.  If useValueArg is FALSE
-// (the default) then the grid table value will be used
-//
-void wxGrid::DrawCellValue( wxDC& dc, const wxRect& rect, int row, int col,
-                            const wxString& value, bool useValueArg )
-{
-    wxRect rect2;
-    rect2 = rect;
-    rect2.x += 3;
-    rect2.y += 2;
-    rect2.width -= 5;
-    rect2.height -= 4;
-
-    dc.SetBackgroundMode( wxTRANSPARENT );
-
-    if ( IsInSelection( row, col ) )
-    {
-        // TODO: improve this
-        //
-        dc.SetTextBackground( wxColour(0, 0, 0) );
-        dc.SetTextForeground( wxColour(255, 255, 255) );
-    }
-    else
-    {
-        dc.SetTextBackground( GetCellBackgroundColour(row, col) );
-        dc.SetTextForeground( GetCellTextColour(row, col) );
-    }
-    dc.SetFont( GetCellFont(row, col) );
-
-    int hAlign, vAlign;
-    GetCellAlignment( row, col, &hAlign, &vAlign );
-
-    if ( useValueArg )
-    {
-        DrawTextRectangle( dc, value, rect2, hAlign, vAlign );
-    }
-    else
-    {
-        DrawTextRectangle( dc, GetCellValue( row, col ), rect2, hAlign, vAlign );
-    }
-}
-
-
-// this is used to echo text being entered into the top edit control when
-// in-place editing is turned off
-//
-void wxGrid::DrawCellValue( const wxGridCellCoords& coords, const wxString& value )
-{
-    if ( IsVisible( coords ) )
-    {
-        int row = coords.GetRow();
-        int col = coords.GetCol();
-        wxRect rect;
-        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 ];
-
-        wxClientDC dc( this );
-        DrawCellBackground( dc, rect, row, col );
-        DrawCellValue( dc, rect, row, col, value, TRUE );
-    }
-}
-
-
-void wxGrid::DrawCellHighlight( wxDC& dc, int row, int col )
-{
-    // TODO: bounds checking on row, col ?
-    //
-
-    if ( row >= m_scrollPosY  &&  col >= m_scrollPosX )
-    {
-        long x, y;
-
-        int cw, ch;
-        GetClientSize( &cw, &ch );
-
-        x = m_colRights[col] - m_colWidths[col];
-        if ( x >= cw ) return;
-
-        y = m_rowBottoms[row] - m_rowHeights[row];
-        if ( y >= ch ) return;
-
-        dc.SetLogicalFunction( wxINVERT );
-        dc.SetPen( wxPen(GetCellHighlightColour(), 2, wxSOLID) );
-        dc.SetBrush( *wxTRANSPARENT_BRUSH );
-
-        dc.DrawRectangle( x-2, y-2,
-                          m_colWidths[col] + 6,
-                          m_rowHeights[row] + 6 );
-
-        dc.SetLogicalFunction( wxCOPY );
-    }
-}
-
-
-// This function is handy when you just want to update one or a few
-// cells.  For example, it is used by SetCellValue()
-//
-void wxGrid::DrawCell( int row, int col )
-{
-    if ( !GetBatchCount() )
-    {
-        if ( !IsVisible( wxGridCellCoords(row, col) ) ) return;
-
-        int cw, ch;
-        GetClientSize( &cw, &ch );
-
-        wxRect rect( CellToRect( row, col ) );
-
-        if ( m_table )
-        {
-            wxClientDC dc( this );
-            DrawCellBackground( dc, rect, row, col );
-            DrawCellValue( dc, rect, row, col );
-        }
-    }
-}
-
-
-// this is just to make other code more obvious
-//
-void wxGrid::HideCurrentCellHighlight( wxDC& dc )
-{
-    if ( m_currentCellHighlighted  &&
-         m_currentCellCoords != wxGridNoCellCoords )
-    {
-        DrawCellHighlight( dc, m_currentCellCoords );
-        m_currentCellHighlighted = FALSE;
-    }
-}
-
-
-// this is just to make other code more obvious
-//
-void wxGrid::ShowCurrentCellHighlight( wxDC& dc )
-{
-    if ( !m_currentCellHighlighted  &&
-         m_currentCellCoords != wxGridNoCellCoords )
-    {
-        DrawCellHighlight( dc, m_currentCellCoords );
-        m_currentCellHighlighted = TRUE;
-    }
-}
-
-
-void wxGrid::DrawTextRectangle( wxDC& dc,
-                                const wxString& value,
-                                const wxRect& rect,
-                                int horizAlign,
-                                int vertAlign )
-{
-    long textWidth, textHeight;
-    long lineWidth, lineHeight;
-    wxArrayString lines;
-
-    // see if we are already clipping
-    //
-    wxRect clipRect;
-    dc.GetClippingBox( clipRect );
-
-    bool alreadyClipping = TRUE;
-    wxRect intersectRect;
-
-    if ( clipRect.x == 0 && clipRect.y == 0 &&
-         clipRect.width == 0 && clipRect.height == 0)
-    {
-        alreadyClipping = FALSE;
-        intersectRect = rect;
-    }
-    else
-    {
-        // Find the intersection of the clipping rectangle and our
-        // rectangle
-        //
-        wxRegion region( rect );
-        region.Intersect( clipRect );
-        if ( region.IsEmpty() )
-        {
-            // nothing to do
-            //
-            return;
-        }
-        intersectRect = region.GetBox();
-    }
-
-    if ( alreadyClipping ) dc.DestroyClippingRegion();
-
-    dc.SetClippingRegion( intersectRect );
-
-    StringToLines( value, lines );
-    if ( lines.GetCount() )
-    {
-        GetTextBoxSize( dc, lines, &textWidth, &textHeight );
-        dc.GetTextExtent( lines[0], &lineWidth, &lineHeight );
-
-        float x, y;
-        switch ( horizAlign )
-        {
-            case wxRIGHT:
-                x = rect.x + (rect.width - textWidth - 1);
-                break;
-
-            case wxCENTRE:
-                x = rect.x + ((rect.width - textWidth)/2);
-                break;
-
-            case wxLEFT:
-            default:
-                x = rect.x + 1;
-                break;
-        }
-
-        switch ( vertAlign )
-        {
-            case wxBOTTOM:
-                y = rect.y + (rect.height - textHeight - 1);
-                break;
+        switch ( vertAlign )
+        {
+            case wxBOTTOM:
+                y = rect.y + (rect.height - textHeight - 1);
+                break;
 
             case wxCENTRE:
                 y = rect.y + ((rect.height - textHeight)/2);
@@ -3302,7 +2833,6 @@ void wxGrid::DrawTextRectangle( wxDC& dc,
     }
 
     dc.DestroyClippingRegion();
-    if (alreadyClipping) dc.SetClippingRegion( clipRect );
 }
 
 
@@ -3368,355 +2898,811 @@ void wxGrid::GetTextBoxSize( wxDC& dc,
 
 
 //
-// ------ functions to get/send data (see also public functions)
+// ------ Edit control functions
 //
 
-bool wxGrid::GetModelValues()
+
+void wxGrid::EnableEditing( bool edit )
 {
-    if ( m_table )
+    // TODO: improve this ?
+    //
+    if ( edit != m_editable )
     {
-        // all we need to do is repaint the grid
-        //
-        Refresh();
-        return TRUE;
+        m_editable = edit;
+        if ( !m_editable ) HideCellEditControl();
+        m_cellEditCtrlEnabled = m_editable;
+        if ( m_editable ) ShowCellEditControl();
     }
-
-    return FALSE;
 }
 
 
-bool wxGrid::SetModelValues()
+void wxGrid::EnableCellEditControl( bool enable )
 {
-    int row, col;
-
-    if ( m_table )
+    if ( m_cellEditCtrl &&
+         enable != m_cellEditCtrlEnabled )
     {
-        for ( row = m_scrollPosY;  row < m_numRows;  row++ )
+        m_cellEditCtrlEnabled = enable;
+        
+        if ( m_cellEditCtrlEnabled )
         {
-            for ( col = m_scrollPosX;  col < m_numCols;  col++ )
-            {
-                m_table->SetValue( row, col, GetCellValue(row, col) );
-            }
+            SetEditControlValue();
+            ShowCellEditControl();
+            // ShowCurrentCellHighlight( dc );
+        }
+        else
+        {
+            // HideCurrentCellHighlight( dc );
+            HideCellEditControl();
+            SaveEditControlValue();
         }
-
-        return TRUE;
     }
-
-    return FALSE;
 }
 
 
+// TODO: not implemented at the moment
+// Do we want it ?
 //
-// ------ public functions
-//
-
-bool wxGrid::CreateGrid( int numRows, int numCols )
+void wxGrid::EnableTopEditControl( bool enable )
 {
-    if ( m_created )
-    {
-        wxLogError( wxT("wxGrid::CreateGrid(numRows, numCols) called more than once") );
-        return FALSE;
-    }
-    else
-    {
-        m_numRows = numRows;
-        m_numCols = numCols;
-
-        m_table = new wxGridStringTable( m_numRows, m_numCols );
-        m_table->SetView( this );
-        Init();
-        m_created = TRUE;
-    }
-
-    return m_created;
+    // TODO: do we want this here or should the top edit
+    // control be an add-on class ?
 }
 
 
-// The behaviour of this function depends on the grid table class
-// Clear() function.  For the default wxGridStringTable class the
-// behavious is to replace all cell contents with wxEmptyString but
-// not to change the number of rows or cols.
-//
-void wxGrid::ClearGrid()
+void wxGrid::ShowCellEditControl()
 {
-    if ( m_table )
+    wxRect rect;
+
+    if ( IsCellEditControlEnabled() )
     {
-        m_table->Clear();
-        SetEditControlValue();
-        if ( !GetBatchCount() ) Refresh();
+        if ( !IsVisible( m_currentCellCoords ) )
+        {
+            return;
+        }
+        else
+        {
+            rect = CellToRect( m_currentCellCoords );
+
+            // convert to scrolled coords
+            //
+            int left, top, right, bottom;
+            CalcScrolledPosition( rect.GetLeft(), rect.GetTop(), &left, &top );
+            CalcScrolledPosition( rect.GetRight(), rect.GetBottom(), &right, &bottom );
+        
+            int cw, ch;
+            m_gridWin->GetClientSize( &cw, &ch );
+        
+            rect.SetLeft( wxMax(0, left) );
+            rect.SetTop( wxMax(0, top) );
+            
+            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;
+            }
+
+            m_cellEditCtrl->SetFocus();
+        }
     }
 }
 
 
-bool wxGrid::InsertRows( int pos, int numRows, bool WXUNUSED(updateLabels) )
+void wxGrid::HideCellEditControl()
 {
-    // TODO: something with updateLabels flag
-
-    if ( !m_created )
+    if ( IsCellEditControlEnabled() )
     {
-        wxLogError( wxT("Called wxGrid::InsertRows() before calling CreateGrid()") );
-        return FALSE;
+        m_cellEditCtrl->Show( FALSE );
     }
+}
 
+
+void wxGrid::SetEditControlValue( const wxString& value )
+{
     if ( m_table )
     {
-        bool ok = m_table->InsertRows( pos, numRows );
+        wxString s;
+        if ( !value )
+            s = GetCellValue(m_currentCellCoords);
+        else
+            s = value;
 
-        // the table will have sent the results of the insert row
-        // operation to this view object as a grid table message
+        // TODO: no top edit control implemented at the moment...
+        // Do we want it in this class ?
         //
-        if ( ok )
+        if ( IsTopEditControlEnabled() )
         {
-            if ( m_numCols == 0 )
+            switch ( m_editCtrlType )
             {
-                m_table->AppendCols( WXGRID_DEFAULT_NUMBER_COLS );
-                //
-                // TODO: perhaps instead of appending the default number of cols
-                // we should remember what the last non-zero number of cols was ?
-                //
+                case wxGRID_TEXTCTRL:
+                    ((wxGridTextCtrl *)m_topEditCtrl)->SetStartValue(s);
+                    break;
+
+                case wxGRID_CHECKBOX:
+                    // TODO: implement this
+                    //
+                    break;
+
+                case wxGRID_CHOICE:
+                    // TODO: implement this
+                    //
+                    break;
+
+                case wxGRID_COMBOBOX:
+                    // TODO: implement this
+                    //
+                    break;
             }
+        }
 
-            if ( m_currentCellCoords == wxGridNoCellCoords )
+        if ( IsCellEditControlEnabled() )
+        {
+            switch ( m_editCtrlType )
             {
-                // if we have just inserted cols into an empty grid the current
-                // cell will be undefined...
-                //
-                SelectCell( 0, 0 );
-            }
+                case wxGRID_TEXTCTRL:
+                    ((wxGridTextCtrl *)m_cellEditCtrl)->SetStartValue(s);
+                    break;
 
-            if ( !GetBatchCount() ) Refresh();
-        }
+                case wxGRID_CHECKBOX:
+                    // TODO: implement this
+                    //
+                    break;
 
-        SetEditControlValue();
-        return ok;
-    }
-    else
-    {
-        return FALSE;
+                case wxGRID_CHOICE:
+                    // TODO: implement this
+                    //
+                    break;
+
+                case wxGRID_COMBOBOX:
+                    // TODO: implement this
+                    //
+                    break;
+            }
+        }
     }
 }
 
-bool wxGrid::AppendRows( int numRows, bool WXUNUSED(updateLabels) )
-{
-    // TODO: something with updateLabels flag
 
-    if ( !m_created )
+void wxGrid::SaveEditControlValue()
+{
+    if ( m_table )
     {
-        wxLogError( wxT("Called wxGrid::AppendRows() before calling CreateGrid()") );
-        return FALSE;
-    }
+        wxWindow *ctrl = (wxWindow *)NULL;
 
-    if ( m_table && m_table->AppendRows( numRows ) )
-    {
-        if ( m_currentCellCoords == wxGridNoCellCoords )
+        if ( IsCellEditControlEnabled() )
         {
-            // if we have just inserted cols into an empty grid the current
-            // cell will be undefined...
-            //
-            SelectCell( 0, 0 );
+            ctrl = m_cellEditCtrl;
+        }
+        else if ( IsTopEditControlEnabled() )
+        {
+            ctrl = m_topEditCtrl;
+        }
+        else
+        {
+            return;
         }
 
-        // the table will have sent the results of the append row
-        // operation to this view object as a grid table message
-        //
-        if ( !GetBatchCount() ) Refresh();
-        return TRUE;
-    }
-    else
-    {
-        return FALSE;
+        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;
+
+            case wxGRID_CHOICE:
+                // TODO: implement this
+                //
+                break;
+
+            case wxGRID_COMBOBOX:
+                // TODO: implement this
+                //
+                break;
+        }
+
+        if ( valueChanged )
+        {
+            SendEvent( EVT_GRID_CELL_CHANGE,
+                       m_currentCellCoords.GetRow(),
+                       m_currentCellCoords.GetCol() );
+        }
     }
 }
 
-bool wxGrid::DeleteRows( int pos, int numRows, bool WXUNUSED(updateLabels) )
+
+//
+// ------ Grid location functions 
+//  Note that all of these functions work with the logical coordinates of 
+//  grid cells and labels so you will need to convert from device
+//  coordinates for mouse events etc.
+//
+
+void wxGrid::XYToCell( int x, int y, wxGridCellCoords& coords )
 {
-    // TODO: something with updateLabels flag
+    coords.SetRow( YToRow(y) );
+    coords.SetCol( XToCol(x) );
+}
 
-    if ( !m_created )
-    {
-        wxLogError( wxT("Called wxGrid::DeleteRows() before calling CreateGrid()") );
-        return FALSE;
-    }
 
-    if ( m_table && m_table->DeleteRows( pos, numRows ) )
-    {
-        // the table will have sent the results of the delete row
-        // operation to this view object as a grid table message
-        //
-        if ( m_numRows > 0 )
-            SetEditControlValue();
-        else
-            HideCellEditControl();
+int wxGrid::YToRow( int y )
+{
+    int i;
 
-        if ( !GetBatchCount() ) Refresh();
-        return TRUE;
-    }
-    else
+    for ( i = 0;  i < m_numRows;  i++ )
     {
-        return FALSE;
+        if ( y < m_rowBottoms[i] ) return i;
     }
+
+    return -1;
 }
 
-bool wxGrid::InsertCols( int pos, int numCols, bool WXUNUSED(updateLabels) )
+
+int wxGrid::XToCol( int x )
 {
-    // TODO: something with updateLabels flag
+    int i;
 
-    if ( !m_created )
+    for ( i = 0;  i < m_numCols;  i++ )
     {
-        wxLogError( wxT("Called wxGrid::InsertCols() before calling CreateGrid()") );
-        return FALSE;
+        if ( x < m_colRights[i] ) return i;
     }
 
-    if ( m_table )
-    {
-        HideCellEditControl();
-        bool ok = m_table->InsertCols( pos, numCols );
+    return -1;
+}
 
-        // the table will have sent the results of the insert col
-        // operation to this view object as a grid table message
-        //
-        if ( ok )
+
+// return the row number that that the y coord is near the edge of, or
+// -1 if not near an edge
+//
+int wxGrid::YToEdgeOfRow( int y )
+{
+    int i, d;
+
+    for ( i = 0;  i < m_numRows;  i++ )
+    {
+        if ( m_rowHeights[i] > WXGRID_LABEL_EDGE_ZONE )
         {
-            if ( m_currentCellCoords == wxGridNoCellCoords )
+            d = abs( y - m_rowBottoms[i] );
             {
-                // if we have just inserted cols into an empty grid the current
-                // cell will be undefined...
-                //
-                SelectCell( 0, 0 );
+                if ( d < WXGRID_LABEL_EDGE_ZONE ) return i;
             }
-
-            if ( !GetBatchCount() ) Refresh();
         }
-
-        SetEditControlValue();
-        return ok;
     }
-    else
+
+    return -1;
+}
+
+
+// return the col number that that the x coord is near the edge of, or
+// -1 if not near an edge
+//
+int wxGrid::XToEdgeOfCol( int x )
+{
+    int i, d;
+
+    for ( i = 0;  i < m_numCols;  i++ )
     {
-        return FALSE;
+        if ( m_colWidths[i] > WXGRID_LABEL_EDGE_ZONE )
+        {
+            d = abs( x - m_colRights[i] );
+            {
+                if ( d < WXGRID_LABEL_EDGE_ZONE ) return i;
+            }
+        }
     }
+
+    return -1;
 }
 
-bool wxGrid::AppendCols( int numCols, bool WXUNUSED(updateLabels) )
+
+wxRect wxGrid::CellToRect( int row, int col )
 {
-    // TODO: something with updateLabels flag
+    wxRect rect( -1, -1, -1, -1 );
 
-    if ( !m_created )
+    if ( row >= 0  &&  row < m_numRows  &&
+         col >= 0  &&  col < m_numCols )
     {
-        wxLogError( wxT("Called wxGrid::AppendCols() before calling CreateGrid()") );
-        return FALSE;
+        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 ];
     }
 
-    if ( m_table && m_table->AppendCols( numCols ) )
+    return rect;
+}
+
+
+bool wxGrid::IsVisible( int row, int col, bool wholeCellVisible )
+{
+    // get the cell rectangle in logical coords
+    //
+    wxRect r( CellToRect( row, col ) );
+    
+    // convert to device coords
+    //
+    int left, top, right, bottom;
+    CalcScrolledPosition( r.GetLeft(), r.GetTop(), &left, &top );
+    CalcScrolledPosition( r.GetRight(), r.GetBottom(), &right, &bottom );
+    
+    // check against the client area of the grid window
+    //
+    int cw, ch;
+    m_gridWin->GetClientSize( &cw, &ch );
+    
+    if ( wholeCellVisible )
     {
-        // the table will have sent the results of the append col
-        // operation to this view object as a grid table message
+        // is the cell wholly visible ?
         //
-        if ( m_currentCellCoords == wxGridNoCellCoords )
+        return ( left >= 0  &&  right <= cw  &&
+                 top >= 0  &&  bottom <= ch );
+    }
+    else
+    {
+        // is the cell partly visible ?
+        //
+        return ( ((left >=0 && left < cw) || (right > 0 && right <= cw))  &&
+                 ((top >=0 && top < ch) || (bottom > 0 && bottom <= ch)) );
+    }
+}
+
+
+// make the specified cell location visible by doing a minimal amount
+// of scrolling
+//
+void wxGrid::MakeCellVisible( int row, int col )
+{
+    int i;
+    int xpos = -1, ypos = -1;    
+
+    if ( row >= 0  &&  row < m_numRows  &&
+         col >= 0  &&  col < m_numCols )
+    {
+        // get the cell rectangle in logical coords
+        //
+        wxRect r( CellToRect( row, col ) );
+        
+        // convert to device coords
+        //
+        int left, top, right, bottom;
+        CalcScrolledPosition( r.GetLeft(), r.GetTop(), &left, &top );
+        CalcScrolledPosition( r.GetRight(), r.GetBottom(), &right, &bottom );
+        
+        int cw, ch;
+        m_gridWin->GetClientSize( &cw, &ch );
+        
+        if ( top < 0 )
         {
-            // if we have just inserted cols into an empty grid the current
-            // cell will be undefined...
-            //
-            SelectCell( 0, 0 );
+            ypos = r.GetTop();
         }
-        if ( !GetBatchCount() ) Refresh();
+        else if ( bottom > ch )
+        {
+            int h = r.GetHeight();
+            ypos = r.GetTop();
+            for ( i = row-1;  i >= 0;  i-- )
+            {
+                if ( h + m_rowHeights[i] > ch ) break;
+
+                h += m_rowHeights[i];
+                ypos -= m_rowHeights[i];
+            }
+        }
+
+        if ( left < 0 )
+        {
+            xpos = r.GetLeft();
+        }
+        else if ( right > cw )
+        {
+            int w = r.GetWidth();
+            xpos = r.GetLeft();
+            for ( i = col-1;  i >= 0;  i-- )
+            {
+                if ( w + m_colWidths[i] > cw ) break;
+
+                w += m_colWidths[i];
+                xpos -= m_colWidths[i];
+            }
+        }
+
+        if ( xpos != -1  ||  ypos != -1 )
+        {
+            if ( xpos != -1 ) xpos = xpos/10;
+            if ( ypos != -1 ) ypos = ypos/10;
+            Scroll( xpos, ypos );
+            AdjustScrollbars();
+        }
+    }
+}
+
+
+//
+// ------ Grid cursor movement functions
+//
+
+bool wxGrid::MoveCursorUp()
+{
+    if ( m_currentCellCoords != wxGridNoCellCoords  &&
+         m_currentCellCoords.GetRow() > 0 )
+    {
+        MakeCellVisible( m_currentCellCoords.GetRow() - 1,
+                        m_currentCellCoords.GetCol() );
+        
+        SetCurrentCell( m_currentCellCoords.GetRow() - 1,
+                        m_currentCellCoords.GetCol() );
+
         return TRUE;
     }
-    else
+
+    return FALSE;
+}
+
+
+bool wxGrid::MoveCursorDown()
+{
+    // TODO: allow for scrolling
+    //
+    if ( m_currentCellCoords != wxGridNoCellCoords  &&
+         m_currentCellCoords.GetRow() < m_numRows-1 )
     {
-        return FALSE;
+        MakeCellVisible( m_currentCellCoords.GetRow() + 1,
+                        m_currentCellCoords.GetCol() );
+        
+        SetCurrentCell( m_currentCellCoords.GetRow() + 1,
+                        m_currentCellCoords.GetCol() );
+
+        return TRUE;
     }
+
+    return FALSE;
 }
 
-bool wxGrid::DeleteCols( int pos, int numCols, bool WXUNUSED(updateLabels) )
+
+bool wxGrid::MoveCursorLeft()
 {
-    // TODO: something with updateLabels flag
+    if ( m_currentCellCoords != wxGridNoCellCoords  &&
+         m_currentCellCoords.GetCol() > 0 )
+    {
+        MakeCellVisible( m_currentCellCoords.GetRow(),
+                        m_currentCellCoords.GetCol() - 1 );
+        
+        SetCurrentCell( m_currentCellCoords.GetRow(),
+                        m_currentCellCoords.GetCol() - 1 );
 
-    if ( !m_created )
+        return TRUE;
+    }
+
+    return FALSE;
+}
+
+
+bool wxGrid::MoveCursorRight()
+{
+    if ( m_currentCellCoords != wxGridNoCellCoords  &&
+         m_currentCellCoords.GetCol() < m_numCols - 1 )
     {
-        wxLogError( wxT("Called wxGrid::DeleteCols() before calling CreateGrid()") );
-        return FALSE;
+        MakeCellVisible( m_currentCellCoords.GetRow(),
+                        m_currentCellCoords.GetCol() + 1 );
+        
+        SetCurrentCell( m_currentCellCoords.GetRow(),
+                        m_currentCellCoords.GetCol() + 1 );
+
+        return TRUE;
     }
 
-    if ( m_table && m_table->DeleteCols( pos, numCols ) )
+    return FALSE;
+}
+
+
+bool wxGrid::MovePageUp()
+{
+    if ( m_currentCellCoords == wxGridNoCellCoords ) return FALSE;
+    
+    int row = m_currentCellCoords.GetRow();
+    if ( row > 0 )
     {
-        // the table will have sent the results of the delete col
-        // operation to this view object as a grid table message
-        //
-        if ( m_numCols > 0 )
-            SetEditControlValue();
-        else
-            HideCellEditControl();
+        int cw, ch;
+        m_gridWin->GetClientSize( &cw, &ch );
+        
+        int y = m_rowBottoms[ row ] - m_rowHeights[ row ];
+        int newRow = YToRow( y - ch + 1 );
+        if ( newRow == -1 )
+        {
+            newRow = 0;
+        }
+        else if ( newRow == row ) 
+        {
+            newRow = row - 1;
+        }
 
-        if ( !GetBatchCount() ) Refresh();
+        MakeCellVisible( newRow, m_currentCellCoords.GetCol() );
+        SetCurrentCell( newRow, m_currentCellCoords.GetCol() );
+        
         return TRUE;
     }
-    else
+
+    return FALSE;
+}
+
+bool wxGrid::MovePageDown()
+{
+    if ( m_currentCellCoords == wxGridNoCellCoords ) return FALSE;
+    
+    int row = m_currentCellCoords.GetRow();
+    if ( row < m_numRows )
     {
-        return FALSE;
+        int cw, ch;
+        m_gridWin->GetClientSize( &cw, &ch );
+        
+        int y = m_rowBottoms[ row ] - m_rowHeights[ row ];
+        int newRow = YToRow( y + ch );
+        if ( newRow == -1 )
+        {
+            newRow = m_numRows - 1;
+        }
+        else if ( newRow == row ) 
+        {
+            newRow = row + 1;
+        }
+
+        MakeCellVisible( newRow, m_currentCellCoords.GetCol() );
+        SetCurrentCell( newRow, m_currentCellCoords.GetCol() );
+        
+        return TRUE;
     }
+
+    return FALSE;
 }
 
+bool wxGrid::MoveCursorUpBlock()
+{
+    if ( m_table &&
+         m_currentCellCoords != wxGridNoCellCoords  &&
+         m_currentCellCoords.GetRow() > 0 )
+    {
+        int row = m_currentCellCoords.GetRow();
+        int col = m_currentCellCoords.GetCol();
+
+        if ( m_table->IsEmptyCell(row, col) )
+        {
+            // starting in an empty cell: find the next block of
+            // non-empty cells
+            //
+            while ( row > 0 )
+            {
+                row-- ;
+                if ( !(m_table->IsEmptyCell(row, col)) ) break;
+            }
+        }
+        else if ( m_table->IsEmptyCell(row-1, col) )
+        {
+            // starting at the top of a block: find the next block
+            //
+            row--;
+            while ( row > 0 )
+            {
+                row-- ;
+                if ( !(m_table->IsEmptyCell(row, col)) ) break;
+            }
+        }
+        else
+        {
+            // starting within a block: find the top of the block
+            //
+            while ( row > 0 )
+            {
+                row-- ;
+                if ( m_table->IsEmptyCell(row, col) )
+                {
+                    row++ ;
+                    break;
+                }
+            }
+        }
 
+        MakeCellVisible( row, col );
+        SetCurrentCell( row, col );
 
+        return TRUE;
+    }
 
-// ------ control panel and cell edit control
-//
+    return FALSE;
+}
 
-void wxGrid::EnableEditing( bool edit )
+bool wxGrid::MoveCursorDownBlock()
 {
-    // TODO: improve this ?
-    //
-    if ( edit != m_editable )
+    if ( m_table &&
+         m_currentCellCoords != wxGridNoCellCoords  &&
+         m_currentCellCoords.GetRow() < m_numRows-1 )
     {
-        m_editable = edit;
-        if ( !m_editable ) HideCellEditControl();
-        m_topEditCtrlEnabled = m_editable;
-        m_cellEditCtrlEnabled = m_editable;
-        if ( !m_editable ) ShowCellEditControl();
+        int row = m_currentCellCoords.GetRow();
+        int col = m_currentCellCoords.GetCol();
+
+        if ( m_table->IsEmptyCell(row, col) )
+        {
+            // starting in an empty cell: find the next block of
+            // non-empty cells
+            //
+            while ( row < m_numRows-1 )
+            {
+                row++ ;
+                if ( !(m_table->IsEmptyCell(row, col)) ) break;
+            }
+        }
+        else if ( m_table->IsEmptyCell(row+1, col) )
+        {
+            // starting at the bottom of a block: find the next block
+            //
+            row++;
+            while ( row < m_numRows-1 )
+            {
+                row++ ;
+                if ( !(m_table->IsEmptyCell(row, col)) ) break;
+            }
+        }
+        else
+        {
+            // starting within a block: find the bottom of the block
+            //
+            while ( row < m_numRows-1 )
+            {
+                row++ ;
+                if ( m_table->IsEmptyCell(row, col) )
+                {
+                    row-- ;
+                    break;
+                }
+            }
+        }
+
+        MakeCellVisible( row, col );
+        SetCurrentCell( row, col );
+
+        return TRUE;
     }
-}
 
+    return FALSE;
+}
 
-void wxGrid::EnableTopEditControl( bool enable )
+bool wxGrid::MoveCursorLeftBlock()
 {
-    if ( enable != m_topEditCtrlEnabled )
+    if ( m_table &&
+         m_currentCellCoords != wxGridNoCellCoords  &&
+         m_currentCellCoords.GetCol() > 0 )
     {
-        HideCellEditControl();
-        m_topEditCtrlEnabled = enable;
-        CalcDimensions();
-        m_topEditCtrl->Show( enable );
+        int row = m_currentCellCoords.GetRow();
+        int col = m_currentCellCoords.GetCol();
+
+        if ( m_table->IsEmptyCell(row, col) )
+        {
+            // starting in an empty cell: find the next block of
+            // non-empty cells
+            //
+            while ( col > 0 )
+            {
+                col-- ;
+                if ( !(m_table->IsEmptyCell(row, col)) ) break;
+            }
+        }
+        else if ( m_table->IsEmptyCell(row, col-1) )
+        {
+            // starting at the left of a block: find the next block
+            //
+            col--;
+            while ( col > 0 )
+            {
+                col-- ;
+                if ( !(m_table->IsEmptyCell(row, col)) ) break;
+            }
+        }
+        else
+        {
+            // starting within a block: find the left of the block
+            //
+            while ( col > 0 )
+            {
+                col-- ;
+                if ( m_table->IsEmptyCell(row, col) )
+                {
+                    col++ ;
+                    break;
+                }
+            }
+        }
 
-        if ( m_currentCellCoords != wxGridNoCellCoords )
-          SetEditControlValue();
+        MakeCellVisible( row, col );
+        SetCurrentCell( row, col );
 
-        ShowCellEditControl();
-        if ( !GetBatchCount() ) Refresh();
+        return TRUE;
     }
+
+    return FALSE;
 }
 
-void wxGrid::EnableCellEditControl( bool enable )
+bool wxGrid::MoveCursorRightBlock()
 {
-    if ( m_cellEditCtrl &&
-         enable != m_cellEditCtrlEnabled )
+    if ( m_table &&
+         m_currentCellCoords != wxGridNoCellCoords  &&
+         m_currentCellCoords.GetCol() < m_numCols-1 )
     {
-        wxClientDC dc( this );
+        int row = m_currentCellCoords.GetRow();
+        int col = m_currentCellCoords.GetCol();
 
-        HideCurrentCellHighlight( dc );
-        HideCellEditControl();
-        SaveEditControlValue();
+        if ( m_table->IsEmptyCell(row, col) )
+        {
+            // starting in an empty cell: find the next block of
+            // non-empty cells
+            //
+            while ( col < m_numCols-1 )
+            {
+                col++ ;
+                if ( !(m_table->IsEmptyCell(row, col)) ) break;
+            }
+        }
+        else if ( m_table->IsEmptyCell(row, col+1) )
+        {
+            // starting at the right of a block: find the next block
+            //
+            col++;
+            while ( col < m_numCols-1 )
+            {
+                col++ ;
+                if ( !(m_table->IsEmptyCell(row, col)) ) break;
+            }
+        }
+        else
+        {
+            // starting within a block: find the right of the block
+            //
+            while ( col < m_numCols-1 )
+            {
+                col++ ;
+                if ( m_table->IsEmptyCell(row, col) )
+                {
+                    col-- ;
+                    break;
+                }
+            }
+        }
 
-        m_cellEditCtrlEnabled = enable;
+        MakeCellVisible( row, col );
+        SetCurrentCell( row, col );
 
-        SetEditControlValue();
-        ShowCellEditControl();
-        ShowCurrentCellHighlight( dc );
+        return TRUE;
     }
+
+    return FALSE;
 }
 
 
+
 //
-// ------ grid formatting functions
+// ------ Label values and formatting
 //
 
 void wxGrid::GetRowLabelAlignment( int *horiz, int *vert )
@@ -3761,36 +3747,53 @@ wxString wxGrid::GetColLabelValue( int col )
 
 void wxGrid::SetRowLabelSize( int width )
 {
-    m_rowLabelWidth = wxMax( 0, width );
-    CalcDimensions();
-    ShowCellEditControl();
-    if ( !GetBatchCount() ) Refresh();
+    // TODO: how to do this with the box sizers ?
 }
 
 void wxGrid::SetColLabelSize( int height )
 {
-    m_colLabelHeight = wxMax( 0, height );
-    CalcDimensions();
-    ShowCellEditControl();
-    if ( !GetBatchCount() ) Refresh();
+    // TODO: how to do this with the box sizers ?
 }
 
 void wxGrid::SetLabelBackgroundColour( const wxColour& colour )
 {
-    m_labelBackgroundColour = colour;
-    if ( !GetBatchCount() ) Refresh();
+    if ( m_labelBackgroundColour != colour )
+    {
+        m_labelBackgroundColour = colour;
+        m_rowLabelWin->SetBackgroundColour( colour );
+        m_colLabelWin->SetBackgroundColour( colour );
+        m_cornerLabelWin->SetBackgroundColour( colour );
+
+        if ( !GetBatchCount() )
+        {
+            m_rowLabelWin->Refresh();
+            m_colLabelWin->Refresh();
+            m_cornerLabelWin->Refresh();
+        }
+    }
 }
 
 void wxGrid::SetLabelTextColour( const wxColour& colour )
 {
-    m_labelTextColour = colour;
-    if ( !GetBatchCount() ) Refresh();
+    if ( m_labelTextColour != colour )
+    {
+        m_labelTextColour = colour;
+        if ( !GetBatchCount() )
+        {
+            m_rowLabelWin->Refresh();
+            m_colLabelWin->Refresh();
+        }
+    }
 }
 
 void wxGrid::SetLabelFont( const wxFont& font )
 {
     m_labelFont = font;
-    if ( !GetBatchCount() ) Refresh();
+    if ( !GetBatchCount() )
+    {
+        m_rowLabelWin->Refresh();
+        m_colLabelWin->Refresh();
+    }
 }
 
 void wxGrid::SetRowLabelAlignment( int horiz, int vert )
@@ -3805,7 +3808,11 @@ void wxGrid::SetRowLabelAlignment( int horiz, int vert )
         m_rowLabelVertAlign = vert;
     }
 
-    if ( !GetBatchCount() ) Refresh();
+    if ( !GetBatchCount() )
+    {
+        m_rowLabelWin->Refresh();
+        m_colLabelWin->Refresh();
+    }        
 }
 
 void wxGrid::SetColLabelAlignment( int horiz, int vert )
@@ -3820,7 +3827,11 @@ void wxGrid::SetColLabelAlignment( int horiz, int vert )
         m_colLabelVertAlign = vert;
     }
 
-    if ( !GetBatchCount() ) Refresh();
+    if ( !GetBatchCount() )
+    {
+        m_rowLabelWin->Refresh();
+        m_colLabelWin->Refresh();
+    }        
 }
 
 void wxGrid::SetRowLabelValue( int row, const wxString& s )
@@ -3828,7 +3839,12 @@ void wxGrid::SetRowLabelValue( int row, const wxString& s )
     if ( m_table )
     {
         m_table->SetRowLabelValue( row, s );
-        if ( !GetBatchCount() ) Refresh();
+        if ( !GetBatchCount() )
+        {
+            // TODO: Optimize this
+            //
+            m_rowLabelWin->Refresh();
+        }
     }
 }
 
@@ -3837,16 +3853,25 @@ void wxGrid::SetColLabelValue( int col, const wxString& s )
     if ( m_table )
     {
         m_table->SetColLabelValue( col, s );
-        if ( !GetBatchCount() ) Refresh();
+        if ( !GetBatchCount() )
+        {
+            // TODO: optimize this
+            //
+            m_colLabelWin->Refresh();
+        }
     }
 }
 
 void wxGrid::SetGridLineColour( const wxColour& colour )
 {
-    m_gridLineColour = colour;
-
-    wxClientDC dc( this );
-    DrawGridLines( dc );
+    if ( m_gridLineColour != colour )
+    {
+        m_gridLineColour = colour;
+        
+        wxClientDC dc( m_gridWin );
+        PrepareDC( dc );
+        DrawAllGridLines( dc );
+    }
 }
 
 void wxGrid::EnableGridLines( bool enable )
@@ -3854,7 +3879,20 @@ void wxGrid::EnableGridLines( bool enable )
     if ( enable != m_gridLinesEnabled )
     {
         m_gridLinesEnabled = enable;
-        if ( !GetBatchCount() ) Refresh();
+
+        if ( !GetBatchCount() )
+        {
+            if ( enable )
+            {
+                wxClientDC dc( m_gridWin );
+                PrepareDC( dc );
+                DrawAllGridLines( dc );
+            }
+            else
+            {
+                m_gridWin->Refresh();
+            }
+        }
     }
 }
 
@@ -3956,30 +3994,34 @@ void wxGrid::SetDefaultRowSize( int height, bool resizeExistingRows )
 
     if ( resizeExistingRows )
     {
-        // TODO: what do we do about events here ?
-        // Generate an event for each resize ?
-        //
         int row;
+        int bottom = 0;
         for ( row = 0;  row < m_numRows;  row++ )
         {
             m_rowHeights[row] = m_defaultRowHeight;
+            bottom += m_defaultRowHeight;
+            m_rowBottoms[row] = bottom;
         }
-        m_sumRowHeights = m_defaultRowHeight * m_numRows;
         CalcDimensions();
-        if ( !GetBatchCount() ) Refresh();
     }
 }
 
 void wxGrid::SetRowSize( int row, int height )
 {
+    int i;
+    
     if ( row >= 0  &&  row < m_numRows )
     {
-        m_sumRowHeights -= m_rowHeights[row];
-        m_rowHeights[row] = wxMax( 0, height );
-        m_sumRowHeights += m_rowHeights[row];
+        int h = wxMax( 0, height );
+        int diff = h - m_rowHeights[row];
+        
+        m_rowHeights[row] = h;
+        for ( i = row;  i < m_numRows;  i++ )
+        {
+            m_rowBottoms[i] += diff;
+        }
         CalcDimensions();
-        if ( !GetBatchCount() ) Refresh();
-
+        
         // Note: we are ending the event *after* doing
         // default processing in this case
         //
@@ -3998,30 +4040,34 @@ void wxGrid::SetDefaultColSize( int width, bool resizeExistingCols )
 
     if ( resizeExistingCols )
     {
-        // TODO: what do we do about events here ?
-        // Generate an event for each resize ?
-        //
         int col;
+        int right = 0;
         for ( col = 0;  col < m_numCols;  col++ )
         {
             m_colWidths[col] = m_defaultColWidth;
+            right += m_defaultColWidth;
+            m_colRights[col] = right;
         }
-        m_sumColWidths = m_defaultColWidth * m_numCols;
         CalcDimensions();
-        if ( !GetBatchCount() ) Refresh();
     }
 }
 
 void wxGrid::SetColSize( int col, int width )
 {
+    int i;
+    
     if ( col >= 0  &&  col < m_numCols )
     {
-        m_sumColWidths -= m_colWidths[col];
-        m_colWidths[col] = wxMax( 0, width );
-        m_sumColWidths += m_colWidths[col];
-        CalcDimensions();
-        if ( !GetBatchCount() ) Refresh();
+        int w = wxMax( 0, width );
+        int diff = w - m_colWidths[col];
+        m_colWidths[col] = w;
 
+        for ( i = col;  i < m_numCols;  i++ )
+        {
+            m_colRights[i] += diff;
+        }
+        CalcDimensions();
+        
         // Note: we are ending the event *after* doing
         // default processing in this case
         //
@@ -4089,6 +4135,7 @@ void wxGrid::SetCellAlignment( int WXUNUSED(row), int WXUNUSED(col), int WXUNUSE
 }
 
 
+
 //
 // ------ cell value accessor functions
 //
@@ -4098,146 +4145,34 @@ void wxGrid::SetCellValue( int row, int col, const wxString& s )
     if ( m_table )
     {
         m_table->SetValue( row, col, s.c_str() );
-        DrawCell( row, col );
+        if ( !GetBatchCount() )
+        {
+            wxClientDC dc( m_gridWin );
+            PrepareDC( dc );
+            DrawCell( dc, wxGridCellCoords(row, col) );
+        }
+        
+#if 0  // TODO: edit in place
+        
         if ( m_currentCellCoords.GetRow() == row &&
              m_currentCellCoords.GetCol() == col )
         {
             SetEditControlValue( s );
         }
-    }
-}
-
-
-
-//
-// ------ interaction with data model
-//
-bool wxGrid::ProcessTableMessage( wxGridTableMessage& msg )
-{
-    switch ( msg.GetId() )
-    {
-        case wxGRIDTABLE_REQUEST_VIEW_GET_VALUES:
-            return GetModelValues();
-
-        case wxGRIDTABLE_REQUEST_VIEW_SEND_VALUES:
-            return SetModelValues();
-
-        case wxGRIDTABLE_NOTIFY_ROWS_INSERTED:
-        case wxGRIDTABLE_NOTIFY_ROWS_APPENDED:
-        case wxGRIDTABLE_NOTIFY_ROWS_DELETED:
-        case wxGRIDTABLE_NOTIFY_COLS_INSERTED:
-        case wxGRIDTABLE_NOTIFY_COLS_APPENDED:
-        case wxGRIDTABLE_NOTIFY_COLS_DELETED:
-            return Redimension( msg );
-
-        default:
-            return FALSE;
-    }
-}
-
-
-//
-// ------ Grid location functions
-//
-//  (see also inline functions in grid.h)
-
-
-// check to see if a cell location is wholly visible
-//
-bool wxGrid::IsVisible( const wxGridCellCoords& coords )
-{
-    return ( coords.GetRow() >= m_scrollPosY  &&
-             coords.GetRow() < m_scrollPosY + m_wholeRowsVisible  &&
-             coords.GetCol() >= m_scrollPosX  &&
-             coords.GetCol() < m_scrollPosX + m_wholeColsVisible );
-}
-
-
-// make the specified cell location visible by doing a minimal amount
-// of scrolling
-//
-void wxGrid::MakeCellVisible( int row, int col )
-{
-    int lastX = m_scrollPosX;
-    int lastY = m_scrollPosY;
-
-    if ( row >= 0  &&  row < m_numRows  &&
-         col >= 0  &&  col < m_numCols )
-    {
-        if ( row < m_scrollPosY )
-        {
-            SetVerticalScrollPos( row );
-        }
-        else if ( row >= m_scrollPosY + m_wholeRowsVisible )
-        {
-            int i;
-            int h = m_rowBottoms[row];
-            for ( i = m_scrollPosY; i < m_numRows && h > m_bottom; i++ )
-            {
-                h -= m_rowHeights[i];
-            }
-            SetVerticalScrollPos( i );
-        }
-
-        if ( col < m_scrollPosX )
-        {
-            SetHorizontalScrollPos( col );
-        }
-        else if ( col >= m_scrollPosX + m_wholeColsVisible )
-        {
-            int i;
-            int w = m_colRights[col];
-            for ( i = m_scrollPosX; i < m_numCols && w > m_right; i++ )
-            {
-                w -= m_colWidths[i];
-            }
-            SetHorizontalScrollPos( i );
-        }
-
-        if ( m_scrollPosX != lastX  ||  m_scrollPosY != lastY )
-        {
-            // The cell was not visible before but not it is
-            //
-            ShowCellEditControl();
-        }
-    }
-    else
-    {
-        // TODO: log an error
-    }
-}
-
-
-void wxGrid::SetVerticalScrollPos( int topMostRow )
-{
-    if ( m_vertScrollBar && topMostRow != m_scrollPosY )
-    {
-        m_scrollPosY = topMostRow;
-
-        CalcDimensions();
-        Refresh();
-    }
-}
-
-
-void wxGrid::SetHorizontalScrollPos( int leftMostCol )
-{
-    if ( m_horizScrollBar && leftMostCol != m_scrollPosX )
-    {
-        m_scrollPosX = leftMostCol;
+#endif
 
-        CalcDimensions();
-        Refresh();
     }
 }
 
 
 //
-// ------ block, row and col selection
+// ------ Block, row and col selection
 //
 
 void wxGrid::SelectRow( int row, bool addToSelected )
 {
+    wxRect r;
+    
     if ( IsSelection() && addToSelected )
     {
         if ( m_selectedTopLeft.GetRow() > row )
@@ -4249,18 +4184,23 @@ void wxGrid::SelectRow( int row, bool addToSelected )
             m_selectedBottomRight.SetRow( row );
 
         m_selectedBottomRight.SetCol( m_numCols - 1 );
+
+        // TODO: optimize this so that we only refresh the newly
+        // selected cells
+        //
+        r = SelectionToDeviceRect();
+        if ( r != wxGridNoCellRect ) m_gridWin->Refresh( TRUE, &r );
     }
     else
     {
+        r = SelectionToDeviceRect();
         ClearSelection();
+        if ( r != wxGridNoCellRect ) m_gridWin->Refresh( TRUE, &r );
+        
         m_selectedTopLeft.Set( row, 0 );
         m_selectedBottomRight.Set( row, m_numCols-1 );
-    }
-
-    if ( !GetBatchCount() )
-    {
-        wxRect rect( SelectionToRect() );
-        if ( rect != wxGridNoCellRect ) Refresh( TRUE, &rect );
+        r = SelectionToDeviceRect();
+        m_gridWin->Refresh( TRUE, &r );
     }
 
     wxGridRangeSelectEvent gridEvt( GetId(),
@@ -4275,7 +4215,9 @@ void wxGrid::SelectRow( int row, bool addToSelected )
 
 void wxGrid::SelectCol( int col, bool addToSelected )
 {
-    if ( addToSelected && m_selectedTopLeft != wxGridNoCellCoords )
+    wxRect r;
+    
+    if ( IsSelection() && addToSelected )
     {
         if ( m_selectedTopLeft.GetCol() > col )
             m_selectedTopLeft.SetCol( col );
@@ -4286,18 +4228,23 @@ void wxGrid::SelectCol( int col, bool addToSelected )
             m_selectedBottomRight.SetCol( col );
 
         m_selectedBottomRight.SetRow( m_numRows - 1 );
+
+        // TODO: optimize this so that we only refresh the newly
+        // selected cells
+        //
+        r = SelectionToDeviceRect();
+        if ( r != wxGridNoCellRect ) m_gridWin->Refresh( TRUE, &r );
     }
     else
     {
+        r = SelectionToDeviceRect();
         ClearSelection();
+        if ( r != wxGridNoCellRect ) m_gridWin->Refresh( TRUE, &r );
+        
         m_selectedTopLeft.Set( 0, col );
         m_selectedBottomRight.Set( m_numRows-1, col );
-    }
-
-    if ( !GetBatchCount() )
-    {
-        wxRect rect( SelectionToRect() );
-        if ( rect != wxGridNoCellRect ) Refresh( TRUE, &rect );
+        r = SelectionToDeviceRect();
+        m_gridWin->Refresh( TRUE, &r );
     }
 
     wxGridRangeSelectEvent gridEvt( GetId(),
@@ -4330,16 +4277,14 @@ void wxGrid::SelectBlock( int topRow, int leftCol, int bottomRow, int rightCol )
 
     m_selectedTopLeft.Set( topRow, leftCol );
     m_selectedBottomRight.Set( bottomRow, rightCol );
-
-    if ( !GetBatchCount() )
-    {
-        wxRect rect( SelectionToRect() );
-        if ( rect != wxGridNoCellRect ) Refresh( TRUE, &rect );
-    }
+    
+    wxRect r;
+    r = SelectionToDeviceRect();
+    m_gridWin->Refresh( TRUE, &r );
 
     // only generate an event if the block is not being selected by
     // dragging the mouse (in which case the event will be generated in
-    // OnMouse) }
+    // the mouse event handler)
     if ( !m_isDragging )
     {
         wxGridRangeSelectEvent gridEvt( GetId(),
@@ -4357,27 +4302,21 @@ void wxGrid::SelectAll()
     m_selectedTopLeft.Set( 0, 0 );
     m_selectedBottomRight.Set( m_numRows-1, m_numCols-1 );
 
-    if ( !GetBatchCount() ) Refresh();
+    m_gridWin->Refresh();
 }
 
 
 void wxGrid::ClearSelection()
 {
-    if ( IsSelection() )
-    {
-        wxRect rect( SelectionToRect() );
-        if ( rect != wxGridNoCellRect )
-        {
-            Refresh( TRUE, &rect );
-        }
-
-        m_selectedTopLeft = wxGridNoCellCoords;
-        m_selectedBottomRight = wxGridNoCellCoords;
-    }
+    m_selectedTopLeft = wxGridNoCellCoords;
+    m_selectedBottomRight = wxGridNoCellCoords;
 }
 
 
-wxRect wxGrid::SelectionToRect()
+// This function returns the rectangle that encloses the selected cells
+// in device coords clipped to the client size of the grid window.
+//
+wxRect wxGrid::SelectionToDeviceRect()
 {
     wxRect rect;
     wxRect cellRect;
@@ -4391,7 +4330,7 @@ wxRect wxGrid::SelectionToRect()
         }
         else
         {
-            rect = wxRect( m_left, m_top, 0, 0 );
+            rect = wxRect( 0, 0, 0, 0 );
         }
 
         cellRect = CellToRect( m_selectedBottomRight );
@@ -4403,14 +4342,30 @@ wxRect wxGrid::SelectionToRect()
         {
             return wxGridNoCellRect;
         }
+
+        // convert to scrolled coords
+        //
+        int left, top, right, bottom;
+        CalcScrolledPosition( rect.GetLeft(), rect.GetTop(), &left, &top );
+        CalcScrolledPosition( rect.GetRight(), rect.GetBottom(), &right, &bottom );
+        
+        int cw, ch;
+        m_gridWin->GetClientSize( &cw, &ch );
+        
+        rect.SetLeft( wxMax(0, left) );
+        rect.SetTop( wxMax(0, top) );
+        rect.SetRight( wxMin(cw, right) );
+        rect.SetBottom( wxMin(ch, bottom) );
+    }
+    else
+    {
+        return wxGridNoCellRect;
     }
 
     return rect;
 }
 
 
-
-
 //
 // ------ Grid event classes
 //