+IMPLEMENT_DYNAMIC_CLASS( wxGridRowLabelWindow, wxWindow )
+
+BEGIN_EVENT_TABLE( wxGridRowLabelWindow, wxWindow )
+ EVT_PAINT( wxGridRowLabelWindow::OnPaint )
+ EVT_MOUSEWHEEL( wxGridRowLabelWindow::OnMouseWheel)
+ EVT_MOUSE_EVENTS( wxGridRowLabelWindow::OnMouseEvent )
+ EVT_KEY_DOWN( wxGridRowLabelWindow::OnKeyDown )
+ EVT_KEY_UP( wxGridRowLabelWindow::OnKeyUp )
+ EVT_CHAR ( wxGridRowLabelWindow::OnChar )
+END_EVENT_TABLE()
+
+wxGridRowLabelWindow::wxGridRowLabelWindow( wxGrid *parent,
+ wxWindowID id,
+ const wxPoint &pos, const wxSize &size )
+ : wxWindow( parent, id, pos, size, wxWANTS_CHARS|wxBORDER_NONE|wxFULL_REPAINT_ON_RESIZE )
+{
+ m_owner = parent;
+}
+
+void wxGridRowLabelWindow::OnPaint( wxPaintEvent& WXUNUSED(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 );
+
+ int x, y;
+ m_owner->CalcUnscrolledPosition( 0, 0, &x, &y );
+ dc.SetDeviceOrigin( 0, -y );
+
+ wxArrayInt rows = m_owner->CalcRowLabelsExposed( GetUpdateRegion() );
+ m_owner->DrawRowLabels( dc , rows );
+}
+
+
+void wxGridRowLabelWindow::OnMouseEvent( wxMouseEvent& event )
+{
+ m_owner->ProcessRowLabelMouseEvent( event );
+}
+
+
+void wxGridRowLabelWindow::OnMouseWheel( wxMouseEvent& event )
+{
+ m_owner->GetEventHandler()->ProcessEvent(event);
+}
+
+
+// This seems to be required for wxMotif otherwise the mouse
+// cursor must be in the cell edit control to get key events
+//
+void wxGridRowLabelWindow::OnKeyDown( wxKeyEvent& event )
+{
+ if ( !m_owner->GetEventHandler()->ProcessEvent( event ) ) event.Skip();
+}
+
+void wxGridRowLabelWindow::OnKeyUp( wxKeyEvent& event )
+{
+ if ( !m_owner->GetEventHandler()->ProcessEvent( event ) ) event.Skip();
+}
+
+void wxGridRowLabelWindow::OnChar( wxKeyEvent& event )
+{
+ if ( !m_owner->GetEventHandler()->ProcessEvent( event ) ) event.Skip();
+}
+
+
+
+//////////////////////////////////////////////////////////////////////
+
+IMPLEMENT_DYNAMIC_CLASS( wxGridColLabelWindow, wxWindow )
+
+BEGIN_EVENT_TABLE( wxGridColLabelWindow, wxWindow )
+ EVT_PAINT( wxGridColLabelWindow::OnPaint )
+ EVT_MOUSEWHEEL( wxGridColLabelWindow::OnMouseWheel)
+ EVT_MOUSE_EVENTS( wxGridColLabelWindow::OnMouseEvent )
+ EVT_KEY_DOWN( wxGridColLabelWindow::OnKeyDown )
+ EVT_KEY_UP( wxGridColLabelWindow::OnKeyUp )
+ EVT_CHAR ( wxGridColLabelWindow::OnChar )
+END_EVENT_TABLE()
+
+wxGridColLabelWindow::wxGridColLabelWindow( wxGrid *parent,
+ wxWindowID id,
+ const wxPoint &pos, const wxSize &size )
+ : wxWindow( parent, id, pos, size, wxWANTS_CHARS|wxBORDER_NONE|wxFULL_REPAINT_ON_RESIZE )
+{
+ m_owner = parent;
+}
+
+void wxGridColLabelWindow::OnPaint( wxPaintEvent& WXUNUSED(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 );
+
+ int x, y;
+ m_owner->CalcUnscrolledPosition( 0, 0, &x, &y );
+ dc.SetDeviceOrigin( -x, 0 );
+
+ wxArrayInt cols = m_owner->CalcColLabelsExposed( GetUpdateRegion() );
+ m_owner->DrawColLabels( dc , cols );
+}
+
+
+void wxGridColLabelWindow::OnMouseEvent( wxMouseEvent& event )
+{
+ m_owner->ProcessColLabelMouseEvent( event );
+}
+
+void wxGridColLabelWindow::OnMouseWheel( wxMouseEvent& event )
+{
+ m_owner->GetEventHandler()->ProcessEvent(event);
+}
+
+
+// This seems to be required for wxMotif otherwise the mouse
+// cursor must be in the cell edit control to get key events
+//
+void wxGridColLabelWindow::OnKeyDown( wxKeyEvent& event )
+{
+ if ( !m_owner->GetEventHandler()->ProcessEvent( event ) ) event.Skip();
+}
+
+void wxGridColLabelWindow::OnKeyUp( wxKeyEvent& event )
+{
+ if ( !m_owner->GetEventHandler()->ProcessEvent( event ) ) event.Skip();
+}
+
+void wxGridColLabelWindow::OnChar( wxKeyEvent& event )
+{
+ if ( !m_owner->GetEventHandler()->ProcessEvent( event ) ) event.Skip();
+}
+
+
+//////////////////////////////////////////////////////////////////////
+
+IMPLEMENT_DYNAMIC_CLASS( wxGridCornerLabelWindow, wxWindow )
+
+BEGIN_EVENT_TABLE( wxGridCornerLabelWindow, wxWindow )
+ EVT_MOUSEWHEEL( wxGridCornerLabelWindow::OnMouseWheel)
+ EVT_MOUSE_EVENTS( wxGridCornerLabelWindow::OnMouseEvent )
+ EVT_PAINT( wxGridCornerLabelWindow::OnPaint)
+ EVT_KEY_DOWN( wxGridCornerLabelWindow::OnKeyDown )
+ EVT_KEY_UP( wxGridCornerLabelWindow::OnKeyUp )
+ EVT_CHAR ( wxGridCornerLabelWindow::OnChar )
+END_EVENT_TABLE()
+
+wxGridCornerLabelWindow::wxGridCornerLabelWindow( wxGrid *parent,
+ wxWindowID id,
+ const wxPoint &pos, const wxSize &size )
+ : wxWindow( parent, id, pos, size, wxWANTS_CHARS|wxBORDER_NONE|wxFULL_REPAINT_ON_RESIZE )
+{
+ m_owner = parent;
+}
+
+void wxGridCornerLabelWindow::OnPaint( wxPaintEvent& WXUNUSED(event) )
+{
+ wxPaintDC dc(this);
+
+ int client_height = 0;
+ int client_width = 0;
+ GetClientSize( &client_width, &client_height );
+
+ // VZ: any reason for this ifdef? (FIXME)
+#ifdef __WXGTK__
+ wxRect rect;
+ rect.SetX( 1 );
+ rect.SetY( 1 );
+ rect.SetWidth( client_width - 2 );
+ rect.SetHeight( client_height - 2 );
+
+ wxRendererNative::Get().DrawHeaderButton( this, dc, rect, 0 );
+#else // !__WXGTK__
+ dc.SetPen( wxPen(wxSystemSettings::GetColour(wxSYS_COLOUR_3DDKSHADOW),1, wxSOLID) );
+ dc.DrawLine( client_width-1, client_height-1, client_width-1, 0 );
+ dc.DrawLine( client_width-1, client_height-1, 0, client_height-1 );
+ dc.DrawLine( 0, 0, client_width, 0 );
+ dc.DrawLine( 0, 0, 0, client_height );
+
+ dc.SetPen( *wxWHITE_PEN );
+ dc.DrawLine( 1, 1, client_width-1, 1 );
+ dc.DrawLine( 1, 1, 1, client_height-1 );
+#endif // __WXGTK__/!__WXGTK__
+}
+
+
+void wxGridCornerLabelWindow::OnMouseEvent( wxMouseEvent& event )
+{
+ m_owner->ProcessCornerLabelMouseEvent( event );
+}
+
+
+void wxGridCornerLabelWindow::OnMouseWheel( wxMouseEvent& event )
+{
+ m_owner->GetEventHandler()->ProcessEvent(event);
+}
+
+// This seems to be required for wxMotif otherwise the mouse
+// cursor must be in the cell edit control to get key events
+//
+void wxGridCornerLabelWindow::OnKeyDown( wxKeyEvent& event )
+{
+ if ( !m_owner->GetEventHandler()->ProcessEvent( event ) ) event.Skip();
+}
+
+void wxGridCornerLabelWindow::OnKeyUp( wxKeyEvent& event )
+{
+ if ( !m_owner->GetEventHandler()->ProcessEvent( event ) ) event.Skip();
+}
+
+void wxGridCornerLabelWindow::OnChar( wxKeyEvent& event )
+{
+ if ( !m_owner->GetEventHandler()->ProcessEvent( event ) ) event.Skip();
+}
+
+
+//////////////////////////////////////////////////////////////////////
+
+IMPLEMENT_DYNAMIC_CLASS( wxGridWindow, wxWindow )
+
+BEGIN_EVENT_TABLE( wxGridWindow, wxWindow )
+ EVT_PAINT( wxGridWindow::OnPaint )
+ EVT_MOUSEWHEEL( wxGridWindow::OnMouseWheel)
+ EVT_MOUSE_EVENTS( wxGridWindow::OnMouseEvent )
+ EVT_KEY_DOWN( wxGridWindow::OnKeyDown )
+ EVT_KEY_UP( wxGridWindow::OnKeyUp )
+ EVT_CHAR ( wxGridWindow::OnChar )
+ EVT_SET_FOCUS( wxGridWindow::OnFocus )
+ EVT_KILL_FOCUS( wxGridWindow::OnFocus )
+ EVT_ERASE_BACKGROUND( wxGridWindow::OnEraseBackground )
+END_EVENT_TABLE()
+
+wxGridWindow::wxGridWindow( wxGrid *parent,
+ wxGridRowLabelWindow *rowLblWin,
+ wxGridColLabelWindow *colLblWin,
+ wxWindowID id,
+ const wxPoint &pos,
+ const wxSize &size )
+ : wxWindow( parent, id, pos, size, wxWANTS_CHARS | wxBORDER_NONE | wxCLIP_CHILDREN|wxFULL_REPAINT_ON_RESIZE,
+ wxT("grid window") )
+
+{
+ m_owner = parent;
+ m_rowLabelWin = rowLblWin;
+ m_colLabelWin = colLblWin;
+}
+
+
+void wxGridWindow::OnPaint( wxPaintEvent &WXUNUSED(event) )
+{
+ wxPaintDC dc( this );
+ m_owner->PrepareDC( dc );
+ wxRegion reg = GetUpdateRegion();
+ wxGridCellCoordsArray DirtyCells = m_owner->CalcCellsExposed( reg );
+ m_owner->DrawGridCellArea( dc , DirtyCells);
+#if WXGRID_DRAW_LINES
+ m_owner->DrawAllGridLines( dc, reg );
+#endif
+ m_owner->DrawGridSpace( dc );
+ m_owner->DrawHighlight( dc , DirtyCells );
+}
+
+
+void wxGridWindow::ScrollWindow( int dx, int dy, const wxRect *rect )
+{
+ wxWindow::ScrollWindow( dx, dy, rect );
+ m_rowLabelWin->ScrollWindow( 0, dy, rect );
+ m_colLabelWin->ScrollWindow( dx, 0, rect );
+}
+
+
+void wxGridWindow::OnMouseEvent( wxMouseEvent& event )
+{
+ if (event.ButtonDown(wxMOUSE_BTN_LEFT) && FindFocus() != this)
+ SetFocus();
+
+ m_owner->ProcessGridCellMouseEvent( event );
+}
+
+void wxGridWindow::OnMouseWheel( wxMouseEvent& event )
+{
+ m_owner->GetEventHandler()->ProcessEvent(event);
+}
+
+// This seems to be required for wxMotif/wxGTK otherwise the mouse
+// cursor must be in the cell edit control to get key events
+//
+void wxGridWindow::OnKeyDown( wxKeyEvent& event )
+{
+ if ( !m_owner->GetEventHandler()->ProcessEvent( event ) ) event.Skip();
+}
+
+void wxGridWindow::OnKeyUp( wxKeyEvent& event )
+{
+ if ( !m_owner->GetEventHandler()->ProcessEvent( event ) ) event.Skip();
+}
+
+void wxGridWindow::OnChar( wxKeyEvent& event )
+{
+ if ( !m_owner->GetEventHandler()->ProcessEvent( event ) ) event.Skip();
+}
+
+void wxGridWindow::OnEraseBackground( wxEraseEvent& WXUNUSED(event) )
+{
+}
+
+void wxGridWindow::OnFocus(wxFocusEvent& event)
+{
+ if ( !m_owner->GetEventHandler()->ProcessEvent( event ) )
+ event.Skip();
+}
+
+//////////////////////////////////////////////////////////////////////
+
+// Internal Helper function for computing row or column from some
+// (unscrolled) coordinate value, using either
+// m_defaultRowHeight/m_defaultColWidth or binary search on array
+// of m_rowBottoms/m_ColRights to speed up the search!
+
+// Internal helper macros for simpler use of that function
+
+static int CoordToRowOrCol(int coord, int defaultDist, int minDist,
+ const wxArrayInt& BorderArray, int nMax,
+ bool clipToMinMax);
+
+#define internalXToCol(x) CoordToRowOrCol(x, m_defaultColWidth, \
+ m_minAcceptableColWidth, \
+ m_colRights, m_numCols, true)
+#define internalYToRow(y) CoordToRowOrCol(y, m_defaultRowHeight, \
+ m_minAcceptableRowHeight, \
+ m_rowBottoms, m_numRows, true)
+/////////////////////////////////////////////////////////////////////
+
+#if wxUSE_EXTENDED_RTTI
+WX_DEFINE_FLAGS( wxGridStyle )
+
+wxBEGIN_FLAGS( wxGridStyle )
+ // new style border flags, we put them first to
+ // use them for streaming out
+ wxFLAGS_MEMBER(wxBORDER_SIMPLE)
+ wxFLAGS_MEMBER(wxBORDER_SUNKEN)
+ wxFLAGS_MEMBER(wxBORDER_DOUBLE)
+ wxFLAGS_MEMBER(wxBORDER_RAISED)
+ wxFLAGS_MEMBER(wxBORDER_STATIC)
+ wxFLAGS_MEMBER(wxBORDER_NONE)
+
+ // old style border flags
+ wxFLAGS_MEMBER(wxSIMPLE_BORDER)
+ wxFLAGS_MEMBER(wxSUNKEN_BORDER)
+ wxFLAGS_MEMBER(wxDOUBLE_BORDER)
+ wxFLAGS_MEMBER(wxRAISED_BORDER)
+ wxFLAGS_MEMBER(wxSTATIC_BORDER)
+ wxFLAGS_MEMBER(wxBORDER)
+
+ // standard window styles
+ wxFLAGS_MEMBER(wxTAB_TRAVERSAL)
+ wxFLAGS_MEMBER(wxCLIP_CHILDREN)
+ wxFLAGS_MEMBER(wxTRANSPARENT_WINDOW)
+ wxFLAGS_MEMBER(wxWANTS_CHARS)
+ wxFLAGS_MEMBER(wxFULL_REPAINT_ON_RESIZE)
+ wxFLAGS_MEMBER(wxALWAYS_SHOW_SB )
+ wxFLAGS_MEMBER(wxVSCROLL)
+ wxFLAGS_MEMBER(wxHSCROLL)
+
+wxEND_FLAGS( wxGridStyle )
+
+IMPLEMENT_DYNAMIC_CLASS_XTI(wxGrid, wxScrolledWindow,"wx/grid.h")
+
+wxBEGIN_PROPERTIES_TABLE(wxGrid)
+ wxHIDE_PROPERTY( Children )
+ wxPROPERTY_FLAGS( WindowStyle , wxGridStyle , long , SetWindowStyleFlag , GetWindowStyleFlag , EMPTY_MACROVALUE, 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // style
+wxEND_PROPERTIES_TABLE()
+
+wxBEGIN_HANDLERS_TABLE(wxGrid)
+wxEND_HANDLERS_TABLE()
+
+wxCONSTRUCTOR_5( wxGrid , wxWindow* , Parent , wxWindowID , Id , wxPoint , Position , wxSize , Size , long , WindowStyle )
+
+/*
+ TODO : Expose more information of a list's layout etc. via appropriate objects (\81Ã la NotebookPageInfo)
+*/
+#else
+IMPLEMENT_DYNAMIC_CLASS( wxGrid, wxScrolledWindow )
+#endif
+
+BEGIN_EVENT_TABLE( wxGrid, wxScrolledWindow )
+ EVT_PAINT( wxGrid::OnPaint )
+ EVT_SIZE( wxGrid::OnSize )
+ EVT_KEY_DOWN( wxGrid::OnKeyDown )
+ EVT_KEY_UP( wxGrid::OnKeyUp )
+ EVT_CHAR ( wxGrid::OnChar )
+ EVT_ERASE_BACKGROUND( wxGrid::OnEraseBackground )
+END_EVENT_TABLE()
+
+wxGrid::wxGrid()
+{
+ // in order to make sure that a size event is not
+ // trigerred in a unfinished state
+ m_cornerLabelWin = NULL ;
+ m_rowLabelWin = NULL ;
+ m_colLabelWin = NULL ;
+ m_gridWin = NULL ;
+}
+
+wxGrid::wxGrid( wxWindow *parent,
+ wxWindowID id,
+ const wxPoint& pos,
+ const wxSize& size,
+ long style,
+ const wxString& name )
+ : wxScrolledWindow( parent, id, pos, size, (style | wxWANTS_CHARS), name ),
+ m_colMinWidths(GRID_HASH_SIZE),
+ m_rowMinHeights(GRID_HASH_SIZE)
+{
+ Create();
+ SetBestFittingSize(size);
+}
+
+bool wxGrid::Create(wxWindow *parent, wxWindowID id,
+ const wxPoint& pos, const wxSize& size,
+ long style, const wxString& name)
+{
+ if (!wxScrolledWindow::Create(parent, id, pos, size,
+ style | wxWANTS_CHARS , name))
+ return false;
+
+ m_colMinWidths = wxLongToLongHashMap(GRID_HASH_SIZE) ;
+ m_rowMinHeights = wxLongToLongHashMap(GRID_HASH_SIZE) ;
+
+ Create() ;
+ SetBestFittingSize(size);
+
+ return true;
+}
+
+
+wxGrid::~wxGrid()
+{
+ // Must do this or ~wxScrollHelper will pop the wrong event handler
+ SetTargetWindow(this);
+ ClearAttrCache();
+ wxSafeDecRef(m_defaultCellAttr);
+
+#ifdef DEBUG_ATTR_CACHE
+ size_t total = gs_nAttrCacheHits + gs_nAttrCacheMisses;
+ wxPrintf(_T("wxGrid attribute cache statistics: "
+ "total: %u, hits: %u (%u%%)\n"),
+ total, gs_nAttrCacheHits,
+ total ? (gs_nAttrCacheHits*100) / total : 0);
+#endif
+
+ if (m_ownTable)
+ delete m_table;
+
+ delete m_typeRegistry;
+ delete m_selection;
+}
+
+
+//
+// ----- internal init and update functions
+//
+
+// NOTE: If using the default visual attributes works everywhere then this can
+// be removed as well as the #else cases below.
+#define _USE_VISATTR 0
+
+#if _USE_VISATTR
+#include "wx/listbox.h"
+#endif
+
+void wxGrid::Create()
+{
+ m_created = false; // set to true by CreateGrid
+
+ m_table = (wxGridTableBase *) NULL;
+ m_ownTable = false;
+
+ m_cellEditCtrlEnabled = false;
+
+ m_defaultCellAttr = new wxGridCellAttr();
+
+ // Set default cell attributes
+ m_defaultCellAttr->SetDefAttr(m_defaultCellAttr);
+ m_defaultCellAttr->SetKind(wxGridCellAttr::Default);
+ m_defaultCellAttr->SetFont(GetFont());
+ m_defaultCellAttr->SetAlignment(wxALIGN_LEFT, wxALIGN_TOP);
+ m_defaultCellAttr->SetRenderer(new wxGridCellStringRenderer);
+ m_defaultCellAttr->SetEditor(new wxGridCellTextEditor);
+
+#if _USE_VISATTR
+ wxVisualAttributes gva = wxListBox::GetClassDefaultAttributes();
+ wxVisualAttributes lva = wxPanel::GetClassDefaultAttributes();
+
+ m_defaultCellAttr->SetTextColour(gva.colFg);
+ m_defaultCellAttr->SetBackgroundColour(gva.colBg);
+
+#else
+ m_defaultCellAttr->SetTextColour(
+ wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT));
+ m_defaultCellAttr->SetBackgroundColour(
+ wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW));
+#endif
+
+ m_numRows = 0;
+ m_numCols = 0;
+ m_currentCellCoords = wxGridNoCellCoords;
+
+ m_rowLabelWidth = WXGRID_DEFAULT_ROW_LABEL_WIDTH;
+ m_colLabelHeight = WXGRID_DEFAULT_COL_LABEL_HEIGHT;
+
+ // create the type registry
+ m_typeRegistry = new wxGridTypeRegistry;
+ m_selection = NULL;
+
+ // subwindow components that make up the wxGrid
+ m_cornerLabelWin = new wxGridCornerLabelWindow( this,
+ wxID_ANY,
+ wxDefaultPosition,
+ wxDefaultSize );
+
+ m_rowLabelWin = new wxGridRowLabelWindow( this,
+ wxID_ANY,
+ wxDefaultPosition,
+ wxDefaultSize );
+
+ m_colLabelWin = new wxGridColLabelWindow( this,
+ wxID_ANY,
+ wxDefaultPosition,
+ wxDefaultSize );
+
+ m_gridWin = new wxGridWindow( this,
+ m_rowLabelWin,
+ m_colLabelWin,
+ wxID_ANY,
+ wxDefaultPosition,
+ wxDefaultSize );
+
+ SetTargetWindow( m_gridWin );
+
+#if _USE_VISATTR
+ wxColour gfg = gva.colFg;
+ wxColour gbg = gva.colBg;
+ wxColour lfg = lva.colFg;
+ wxColour lbg = lva.colBg;
+#else
+ wxColour gfg = wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOWTEXT );
+ wxColour gbg = wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOW );
+ wxColour lfg = wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOWTEXT );
+ wxColour lbg = wxSystemSettings::GetColour( wxSYS_COLOUR_BTNFACE );
+#endif
+ m_cornerLabelWin->SetOwnForegroundColour(lfg);
+ m_cornerLabelWin->SetOwnBackgroundColour(lbg);
+ m_rowLabelWin->SetOwnForegroundColour(lfg);
+ m_rowLabelWin->SetOwnBackgroundColour(lbg);
+ m_colLabelWin->SetOwnForegroundColour(lfg);
+ m_colLabelWin->SetOwnBackgroundColour(lbg);
+
+ m_gridWin->SetOwnForegroundColour(gfg);
+ m_gridWin->SetOwnBackgroundColour(gbg);
+
+ Init();
+}
+
+
+bool wxGrid::CreateGrid( int numRows, int numCols,
+ wxGrid::wxGridSelectionModes selmode )
+{
+ wxCHECK_MSG( !m_created,
+ false,
+ wxT("wxGrid::CreateGrid or wxGrid::SetTable called more than once") );
+
+ m_numRows = numRows;
+ m_numCols = numCols;
+
+ m_table = new wxGridStringTable( m_numRows, m_numCols );
+ m_table->SetView( this );
+ m_ownTable = true;
+ m_selection = new wxGridSelection( this, selmode );
+
+ CalcDimensions();
+
+ m_created = true;
+
+ return m_created;
+}
+
+void wxGrid::SetSelectionMode(wxGrid::wxGridSelectionModes selmode)
+{
+ wxCHECK_RET( m_created,
+ wxT("Called wxGrid::SetSelectionMode() before calling CreateGrid()") );
+
+ m_selection->SetSelectionMode( selmode );
+}
+
+wxGrid::wxGridSelectionModes wxGrid::GetSelectionMode() const
+{
+ wxCHECK_MSG( m_created, wxGrid::wxGridSelectCells,
+ wxT("Called wxGrid::GetSelectionMode() before calling CreateGrid()") );
+
+ return m_selection->GetSelectionMode();
+}
+
+bool wxGrid::SetTable( wxGridTableBase *table, bool takeOwnership,
+ wxGrid::wxGridSelectionModes selmode )
+{
+ if ( m_created )
+ {
+ // stop all processing
+ m_created = false;
+
+ if (m_ownTable)
+ {
+ wxGridTableBase *t=m_table;
+ m_table=0;
+ delete t;
+ }
+ delete m_selection;
+
+ m_table=0;
+ m_selection=0;
+ m_numRows=0;
+ m_numCols=0;
+ }
+ if (table)
+ {
+ m_numRows = table->GetNumberRows();
+ m_numCols = table->GetNumberCols();
+
+ m_table = table;
+ m_table->SetView( this );
+ if (takeOwnership)
+ m_ownTable = true;
+ m_selection = new wxGridSelection( this, selmode );
+
+ CalcDimensions();
+
+ m_created = true;
+ }
+
+ return m_created;
+}
+
+
+void wxGrid::Init()
+{
+ m_rowLabelWidth = WXGRID_DEFAULT_ROW_LABEL_WIDTH;
+ m_colLabelHeight = WXGRID_DEFAULT_COL_LABEL_HEIGHT;
+
+ if ( m_rowLabelWin )
+ {
+ m_labelBackgroundColour = m_rowLabelWin->GetBackgroundColour();
+ }
+ else
+ {
+ m_labelBackgroundColour = wxColour( _T("WHITE") );
+ }
+
+ m_labelTextColour = wxColour( _T("BLACK") );
+
+ // init attr cache
+ m_attrCache.row = -1;
+ m_attrCache.col = -1;
+ m_attrCache.attr = NULL;
+
+ // TODO: something better than this ?
+ //
+ m_labelFont = this->GetFont();
+ m_labelFont.SetWeight( wxBOLD );
+
+ m_rowLabelHorizAlign = wxALIGN_CENTRE;
+ m_rowLabelVertAlign = wxALIGN_CENTRE;
+
+ m_colLabelHorizAlign = wxALIGN_CENTRE;
+ m_colLabelVertAlign = wxALIGN_CENTRE;
+ m_colLabelTextOrientation = wxHORIZONTAL;
+
+ m_defaultColWidth = WXGRID_DEFAULT_COL_WIDTH;
+ m_defaultRowHeight = m_gridWin->GetCharHeight();
+
+ m_minAcceptableColWidth = WXGRID_MIN_COL_WIDTH;
+ m_minAcceptableRowHeight = WXGRID_MIN_ROW_HEIGHT;
+
+#if defined(__WXMOTIF__) || defined(__WXGTK__) // see also text ctrl sizing in ShowCellEditControl()
+ m_defaultRowHeight += 8;
+#else
+ m_defaultRowHeight += 4;
+#endif
+
+ m_gridLineColour = wxColour( 192,192,192 );
+ m_gridLinesEnabled = true;
+ m_cellHighlightColour = *wxBLACK;
+ m_cellHighlightPenWidth = 2;
+ m_cellHighlightROPenWidth = 1;
+
+ m_cursorMode = WXGRID_CURSOR_SELECT_CELL;
+ m_winCapture = (wxWindow *)NULL;
+ m_canDragRowSize = true;
+ m_canDragColSize = true;
+ m_canDragGridSize = true;
+ m_canDragCell = false;
+ m_dragLastPos = -1;
+ m_dragRowOrCol = -1;
+ m_isDragging = false;
+ m_startDragPos = wxDefaultPosition;
+
+ m_waitForSlowClick = false;
+
+ m_rowResizeCursor = wxCursor( wxCURSOR_SIZENS );
+ m_colResizeCursor = wxCursor( wxCURSOR_SIZEWE );
+
+ m_currentCellCoords = wxGridNoCellCoords;
+
+ m_selectingTopLeft = wxGridNoCellCoords;
+ m_selectingBottomRight = wxGridNoCellCoords;
+ m_selectionBackground = wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHT);
+ m_selectionForeground = wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT);
+
+ m_editable = true; // default for whole grid
+
+ m_inOnKeyDown = false;
+ m_batchCount = 0;
+
+ m_extraWidth =
+ m_extraHeight = 0;
+
+ m_scrollLineX = GRID_SCROLL_LINE_X;
+ m_scrollLineY = GRID_SCROLL_LINE_Y;
+}
+
+// ----------------------------------------------------------------------------
+// the idea is to call these functions only when necessary because they create
+// quite big arrays which eat memory mostly unnecessary - in particular, if
+// default widths/heights are used for all rows/columns, we may not use these
+// arrays at all
+//
+// with some extra code, it should be possible to only store the
+// widths/heights different from default ones but this will be done later...
+// ----------------------------------------------------------------------------
+
+void wxGrid::InitRowHeights()
+{
+ m_rowHeights.Empty();
+ m_rowBottoms.Empty();
+
+ m_rowHeights.Alloc( m_numRows );
+ m_rowBottoms.Alloc( m_numRows );
+
+ int rowBottom = 0;
+
+ m_rowHeights.Add( m_defaultRowHeight, m_numRows );
+
+ for ( int i = 0; i < m_numRows; i++ )
+ {
+ rowBottom += m_defaultRowHeight;
+ m_rowBottoms.Add( rowBottom );
+ }
+}
+
+void wxGrid::InitColWidths()
+{
+ m_colWidths.Empty();
+ m_colRights.Empty();
+
+ m_colWidths.Alloc( m_numCols );
+ m_colRights.Alloc( m_numCols );
+ int colRight = 0;
+
+ m_colWidths.Add( m_defaultColWidth, m_numCols );
+
+ for ( int i = 0; i < m_numCols; i++ )
+ {
+ colRight += m_defaultColWidth;
+ m_colRights.Add( colRight );
+ }
+}
+
+int wxGrid::GetColWidth(int col) const
+{
+ return m_colWidths.IsEmpty() ? m_defaultColWidth : m_colWidths[col];
+}
+
+int wxGrid::GetColLeft(int col) const
+{
+ return m_colRights.IsEmpty() ? col * m_defaultColWidth
+ : m_colRights[col] - m_colWidths[col];
+}
+
+int wxGrid::GetColRight(int col) const
+{
+ return m_colRights.IsEmpty() ? (col + 1) * m_defaultColWidth
+ : m_colRights[col];
+}
+
+int wxGrid::GetRowHeight(int row) const
+{
+ return m_rowHeights.IsEmpty() ? m_defaultRowHeight : m_rowHeights[row];
+}
+
+int wxGrid::GetRowTop(int row) const
+{
+ return m_rowBottoms.IsEmpty() ? row * m_defaultRowHeight
+ : m_rowBottoms[row] - m_rowHeights[row];
+}
+
+int wxGrid::GetRowBottom(int row) const
+{
+ return m_rowBottoms.IsEmpty() ? (row + 1) * m_defaultRowHeight
+ : m_rowBottoms[row];
+}
+
+void wxGrid::CalcDimensions()
+{
+ int cw, ch;
+ GetClientSize( &cw, &ch );
+
+ if ( m_rowLabelWin->IsShown() )
+ cw -= m_rowLabelWidth;
+ if ( m_colLabelWin->IsShown() )
+ ch -= m_colLabelHeight;
+
+ // grid total size
+ int w = m_numCols > 0 ? GetColRight(m_numCols - 1) + m_extraWidth + 1 : 0;
+ int h = m_numRows > 0 ? GetRowBottom(m_numRows - 1) + m_extraHeight + 1 : 0;
+
+ // take into account editor if shown
+ if( IsCellEditControlShown() )
+ {
+ int w2, h2;
+ int r = m_currentCellCoords.GetRow();
+ int c = m_currentCellCoords.GetCol();
+ int x = GetColLeft(c);
+ int y = GetRowTop(r);
+
+ // how big is the editor
+ wxGridCellAttr* attr = GetCellAttr(r, c);
+ wxGridCellEditor* editor = attr->GetEditor(this, r, c);
+ editor->GetControl()->GetSize(&w2, &h2);
+ w2 += x;
+ h2 += y;
+ if( w2 > w ) w = w2;
+ if( h2 > h ) h = h2;
+ editor->DecRef();
+ attr->DecRef();
+ }
+
+ // preserve (more or less) the previous position
+ int x, y;
+ GetViewStart( &x, &y );
+
+ // ensure the position is valid for the new scroll ranges
+ if ( x >= w )
+ x = wxMax( w - 1, 0 );
+ if ( y >= h )
+ y = wxMax( h - 1, 0 );
+
+ // do set scrollbar parameters
+ SetScrollbars( m_scrollLineX, m_scrollLineY,
+ GetScrollX(w), GetScrollY(h), x, y,
+ GetBatchCount() != 0);
+
+ // if our OnSize() hadn't been called (it would if we have scrollbars), we
+ // still must reposition the children
+ CalcWindowSizes();
+}
+
+
+void wxGrid::CalcWindowSizes()
+{
+ // escape if the window is has not been fully created yet
+
+ if ( m_cornerLabelWin == NULL )
+ return ;
+
+ int cw, ch;
+ GetClientSize( &cw, &ch );
+
+ if ( m_cornerLabelWin && m_cornerLabelWin->IsShown() )
+ m_cornerLabelWin->SetSize( 0, 0, m_rowLabelWidth, m_colLabelHeight );
+
+ if ( m_colLabelWin && m_colLabelWin->IsShown() )
+ m_colLabelWin->SetSize( m_rowLabelWidth, 0, cw-m_rowLabelWidth, m_colLabelHeight);
+
+ if ( m_rowLabelWin && m_rowLabelWin->IsShown() )
+ m_rowLabelWin->SetSize( 0, m_colLabelHeight, m_rowLabelWidth, ch-m_colLabelHeight);
+
+ if ( m_gridWin && m_gridWin->IsShown() )
+ m_gridWin->SetSize( m_rowLabelWidth, m_colLabelHeight, cw-m_rowLabelWidth, ch-m_colLabelHeight);
+}
+
+
+// this is called when the grid table sends a message to say that it
+// has been redimensioned
+//
+bool wxGrid::Redimension( wxGridTableMessage& msg )
+{
+ int i;
+ bool result = false;
+
+ // Clear the attribute cache as the attribute might refer to a different
+ // cell than stored in the cache after adding/removing rows/columns.
+ ClearAttrCache();
+ // By the same reasoning, the editor should be dismissed if columns are
+ // added or removed. And for consistency, it should IMHO always be
+ // removed, not only if the cell "underneath" it actually changes.
+ // For now, I intentionally do not save the editor's content as the
+ // cell it might want to save that stuff to might no longer exist.
+ HideCellEditControl();
+#if 0
+ // if we were using the default widths/heights so far, we must change them
+ // now
+ if ( m_colWidths.IsEmpty() )
+ {
+ InitColWidths();
+ }
+
+ if ( m_rowHeights.IsEmpty() )
+ {
+ InitRowHeights();
+ }
+#endif
+
+ switch ( msg.GetId() )
+ {
+ case wxGRIDTABLE_NOTIFY_ROWS_INSERTED:
+ {
+ size_t pos = msg.GetCommandInt();
+ int numRows = msg.GetCommandInt2();
+
+ m_numRows += numRows;
+
+ if ( !m_rowHeights.IsEmpty() )
+ {
+ m_rowHeights.Insert( m_defaultRowHeight, pos, numRows );
+ m_rowBottoms.Insert( 0, pos, 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;
+ }
+ }
+ if ( m_currentCellCoords == wxGridNoCellCoords )
+ {
+ // if we have just inserted cols into an empty grid the current
+ // cell will be undefined...
+ //
+ SetCurrentCell( 0, 0 );
+ }
+
+ if ( m_selection )
+ m_selection->UpdateRows( pos, numRows );
+ wxGridCellAttrProvider * attrProvider = m_table->GetAttrProvider();
+ if (attrProvider)
+ attrProvider->UpdateAttrRows( pos, numRows );
+
+ if ( !GetBatchCount() )
+ {
+ CalcDimensions();
+ m_rowLabelWin->Refresh();
+ }
+ }
+ result = true;
+ break;
+
+ case wxGRIDTABLE_NOTIFY_ROWS_APPENDED:
+ {
+ int numRows = msg.GetCommandInt();
+ int oldNumRows = m_numRows;
+ m_numRows += numRows;
+
+ if ( !m_rowHeights.IsEmpty() )
+ {
+ m_rowHeights.Add( m_defaultRowHeight, numRows );
+ m_rowBottoms.Add( 0, 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;
+ }
+ }
+ if ( m_currentCellCoords == wxGridNoCellCoords )
+ {
+ // if we have just inserted cols into an empty grid the current
+ // cell will be undefined...
+ //
+ SetCurrentCell( 0, 0 );
+ }
+ if ( !GetBatchCount() )
+ {
+ CalcDimensions();
+ m_rowLabelWin->Refresh();
+ }
+ }
+ result = true;
+ break;
+
+ case wxGRIDTABLE_NOTIFY_ROWS_DELETED:
+ {
+ size_t pos = msg.GetCommandInt();
+ int numRows = msg.GetCommandInt2();
+ m_numRows -= numRows;
+
+ if ( !m_rowHeights.IsEmpty() )
+ {
+ m_rowHeights.RemoveAt( pos, numRows );
+ m_rowBottoms.RemoveAt( pos, numRows );
+
+ int h = 0;
+ for ( i = 0; i < m_numRows; i++ )
+ {
+ h += m_rowHeights[i];
+ m_rowBottoms[i] = h;
+ }
+ }
+ if ( !m_numRows )
+ {
+ m_currentCellCoords = wxGridNoCellCoords;
+ }
+ else
+ {
+ if ( m_currentCellCoords.GetRow() >= m_numRows )
+ m_currentCellCoords.Set( 0, 0 );
+ }
+
+ if ( m_selection )
+ m_selection->UpdateRows( pos, -((int)numRows) );
+ wxGridCellAttrProvider * attrProvider = m_table->GetAttrProvider();
+ if (attrProvider) {
+ attrProvider->UpdateAttrRows( pos, -((int)numRows) );
+// ifdef'd out following patch from Paul Gammans
+#if 0
+ // No need to touch column attributes, unless we
+ // removed _all_ rows, in this case, we remove
+ // all column attributes.
+ // I hate to do this here, but the
+ // needed data is not available inside UpdateAttrRows.
+ if ( !GetNumberRows() )
+ attrProvider->UpdateAttrCols( 0, -GetNumberCols() );
+#endif
+ }
+ if ( !GetBatchCount() )
+ {
+ CalcDimensions();
+ m_rowLabelWin->Refresh();
+ }
+ }
+ result = true;
+ break;
+
+ case wxGRIDTABLE_NOTIFY_COLS_INSERTED:
+ {
+ size_t pos = msg.GetCommandInt();
+ int numCols = msg.GetCommandInt2();
+ m_numCols += numCols;
+
+ if ( !m_colWidths.IsEmpty() )
+ {
+ m_colWidths.Insert( m_defaultColWidth, pos, numCols );
+ m_colRights.Insert( 0, pos, 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;
+ }
+ }
+ if ( m_currentCellCoords == wxGridNoCellCoords )
+ {
+ // if we have just inserted cols into an empty grid the current
+ // cell will be undefined...
+ //
+ SetCurrentCell( 0, 0 );
+ }
+
+ if ( m_selection )
+ m_selection->UpdateCols( pos, numCols );
+ wxGridCellAttrProvider * attrProvider = m_table->GetAttrProvider();
+ if (attrProvider)
+ attrProvider->UpdateAttrCols( pos, numCols );
+ if ( !GetBatchCount() )
+ {
+ CalcDimensions();
+ m_colLabelWin->Refresh();
+ }
+
+ }
+ result = true;
+ break;
+
+ case wxGRIDTABLE_NOTIFY_COLS_APPENDED:
+ {
+ int numCols = msg.GetCommandInt();
+ int oldNumCols = m_numCols;
+ m_numCols += numCols;
+ if ( !m_colWidths.IsEmpty() )
+ {
+ m_colWidths.Add( m_defaultColWidth, numCols );
+ m_colRights.Add( 0, 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;
+ }
+ }
+ if ( m_currentCellCoords == wxGridNoCellCoords )
+ {
+ // if we have just inserted cols into an empty grid the current
+ // cell will be undefined...
+ //
+ SetCurrentCell( 0, 0 );
+ }
+ if ( !GetBatchCount() )
+ {
+ CalcDimensions();
+ m_colLabelWin->Refresh();
+ }
+ }
+ result = true;
+ break;
+
+ case wxGRIDTABLE_NOTIFY_COLS_DELETED:
+ {
+ size_t pos = msg.GetCommandInt();
+ int numCols = msg.GetCommandInt2();
+ m_numCols -= numCols;
+
+ if ( !m_colWidths.IsEmpty() )
+ {
+ m_colWidths.RemoveAt( pos, numCols );
+ m_colRights.RemoveAt( pos, numCols );
+
+ int w = 0;
+ for ( i = 0; i < m_numCols; i++ )
+ {
+ w += m_colWidths[i];
+ m_colRights[i] = w;
+ }
+ }
+ if ( !m_numCols )
+ {
+ m_currentCellCoords = wxGridNoCellCoords;
+ }
+ else
+ {
+ if ( m_currentCellCoords.GetCol() >= m_numCols )
+ m_currentCellCoords.Set( 0, 0 );
+ }
+
+ if ( m_selection )
+ m_selection->UpdateCols( pos, -((int)numCols) );
+ wxGridCellAttrProvider * attrProvider = m_table->GetAttrProvider();
+ if (attrProvider) {
+ attrProvider->UpdateAttrCols( pos, -((int)numCols) );
+// ifdef'd out following patch from Paul Gammans
+#if 0
+ // No need to touch row attributes, unless we
+ // removed _all_ columns, in this case, we remove
+ // all row attributes.
+ // I hate to do this here, but the
+ // needed data is not available inside UpdateAttrCols.
+ if ( !GetNumberCols() )
+ attrProvider->UpdateAttrRows( 0, -GetNumberRows() );
+#endif
+ }
+ if ( !GetBatchCount() )
+ {
+ CalcDimensions();
+ m_colLabelWin->Refresh();
+ }
+ }
+ result = true;
+ break;
+ }
+
+ if (result && !GetBatchCount() )
+ m_gridWin->Refresh();
+ return result;
+}
+
+
+wxArrayInt wxGrid::CalcRowLabelsExposed( const wxRegion& reg )
+{
+ wxRegionIterator iter( reg );
+ wxRect r;
+
+ wxArrayInt rowlabels;
+
+ int top, 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;
+ m_gridWin->GetClientSize( &cw, &ch );
+ if ( r.GetTop() > ch ) r.SetTop( 0 );
+ r.SetBottom( wxMin( r.GetBottom(), ch ) );
+#endif
+
+ // 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;
+ for ( row = internalYToRow(top); row < m_numRows; row++ )
+ {
+ if ( GetRowBottom(row) < top )
+ continue;
+
+ if ( GetRowTop(row) > bottom )
+ break;
+
+ rowlabels.Add( row );
+ }
+
+ ++iter;
+ }
+
+ return rowlabels;
+}
+
+
+wxArrayInt wxGrid::CalcColLabelsExposed( const wxRegion& reg )
+{
+ wxRegionIterator iter( reg );
+ wxRect r;
+
+ wxArrayInt colLabels;
+
+ int left, right;
+ 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;
+ 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;
+ for ( col = internalXToCol(left); col < m_numCols; col++ )
+ {
+ if ( GetColRight(col) < left )
+ continue;
+
+ if ( GetColLeft(col) > right )
+ break;
+
+ colLabels.Add( col );
+ }
+
+ ++iter;
+ }
+ return colLabels;
+}
+
+
+wxGridCellCoordsArray wxGrid::CalcCellsExposed( const wxRegion& reg )
+{
+ wxRegionIterator iter( reg );
+ wxRect r;
+
+ wxGridCellCoordsArray cellsExposed;
+
+ 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;
+ 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
+
+ // logical bounds of update region
+ //
+ CalcUnscrolledPosition( r.GetLeft(), r.GetTop(), &left, &top );
+ CalcUnscrolledPosition( r.GetRight(), r.GetBottom(), &right, &bottom );
+
+ // find the cells within these bounds
+ //
+ int row, col;
+ for ( row = internalYToRow(top); row < m_numRows; row++ )
+ {
+ if ( GetRowBottom(row) <= top )
+ continue;
+
+ if ( GetRowTop(row) > bottom )
+ break;
+
+ for ( col = internalXToCol(left); col < m_numCols; col++ )
+ {
+ if ( GetColRight(col) <= left )
+ continue;
+
+ if ( GetColLeft(col) > right )
+ break;
+
+ cellsExposed.Add( wxGridCellCoords( row, col ) );
+ }
+ }
+
+ ++iter;
+ }
+
+ return cellsExposed;
+}
+
+
+void wxGrid::ProcessRowLabelMouseEvent( wxMouseEvent& event )
+{
+ int x, y, row;
+ wxPoint pos( event.GetPosition() );
+ CalcUnscrolledPosition( pos.x, pos.y, &x, &y );
+
+ if ( event.Dragging() )
+ {
+ if (!m_isDragging)
+ {
+ m_isDragging = true;
+ m_rowLabelWin->CaptureMouse();
+ }
+
+ if ( event.LeftIsDown() )
+ {
+ switch( m_cursorMode )
+ {
+ case WXGRID_CURSOR_RESIZE_ROW:
+ {
+ int cw, ch, left, dummy;
+ m_gridWin->GetClientSize( &cw, &ch );
+ CalcUnscrolledPosition( 0, 0, &left, &dummy );
+
+ wxClientDC dc( m_gridWin );
+ PrepareDC( dc );
+ y = wxMax( y,
+ GetRowTop(m_dragRowOrCol) +
+ GetRowMinimalHeight(m_dragRowOrCol) );
+ dc.SetLogicalFunction(wxINVERT);
+ if ( m_dragLastPos >= 0 )
+ {
+ dc.DrawLine( left, m_dragLastPos, left+cw, m_dragLastPos );
+ }
+ dc.DrawLine( left, y, left+cw, y );
+ m_dragLastPos = y;
+ }
+ break;
+
+ case WXGRID_CURSOR_SELECT_ROW:
+ {
+ if ( (row = YToRow( y )) >= 0 )
+ {
+ if ( m_selection )
+ {
+ m_selection->SelectRow( row,
+ event.ControlDown(),
+ event.ShiftDown(),
+ event.AltDown(),
+ event.MetaDown() );
+ }
+ }
+ }
+ break;
+
+ // default label to suppress warnings about "enumeration value
+ // 'xxx' not handled in switch
+ default:
+ break;
+ }
+ }
+ return;
+ }
+
+ if ( m_isDragging && (event.Entering() || event.Leaving()) )
+ return;
+
+ if (m_isDragging)
+ {
+ if (m_rowLabelWin->HasCapture()) m_rowLabelWin->ReleaseMouse();
+ m_isDragging = false;
+ }
+
+ // ------------ Entering or leaving the window
+ //
+ if ( event.Entering() || event.Leaving() )
+ {
+ ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL, m_rowLabelWin);
+ }
+
+
+ // ------------ Left button pressed
+ //
+ else if ( event.LeftDown() )
+ {
+ // 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 ( row >= 0 &&
+ !SendEvent( wxEVT_GRID_LABEL_LEFT_CLICK, row, -1, event ) )
+ {
+ if ( !event.ShiftDown() && !event.ControlDown() )
+ ClearSelection();
+ if ( m_selection )
+ {
+ if ( event.ShiftDown() )
+ {
+ m_selection->SelectBlock( m_currentCellCoords.GetRow(),
+ 0,
+ row,
+ GetNumberCols() - 1,
+ event.ControlDown(),
+ event.ShiftDown(),
+ event.AltDown(),
+ event.MetaDown() );
+ }
+ else
+ {
+ m_selection->SelectRow( row,
+ event.ControlDown(),
+ event.ShiftDown(),
+ event.AltDown(),
+ event.MetaDown() );
+ }
+ }
+
+ ChangeCursorMode(WXGRID_CURSOR_SELECT_ROW, m_rowLabelWin);
+ }
+ }
+ else
+ {
+ // starting to drag-resize a row
+ //
+ if ( CanDragRowSize() )
+ ChangeCursorMode(WXGRID_CURSOR_RESIZE_ROW, m_rowLabelWin);
+ }
+ }
+
+
+ // ------------ Left double click
+ //
+ else if (event.LeftDClick() )
+ {
+ int row = YToEdgeOfRow(y);
+ if ( row < 0 )
+ {
+ row = YToRow(y);
+ if ( row >=0 &&
+ !SendEvent( wxEVT_GRID_LABEL_LEFT_DCLICK, row, -1, event ) )
+ {
+ // no default action at the moment
+ }
+ }
+ else
+ {
+ // adjust row height depending on label text
+ AutoSizeRowLabelSize( row );
+
+ ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL, m_colLabelWin);
+ m_dragLastPos = -1;
+ }
+ }
+
+
+ // ------------ Left button released
+ //
+ else if ( event.LeftUp() )
+ {
+ if ( m_cursorMode == WXGRID_CURSOR_RESIZE_ROW )
+ {
+ DoEndDragResizeRow();
+
+ // Note: we are ending the event *after* doing
+ // default processing in this case
+ //
+ SendEvent( wxEVT_GRID_ROW_SIZE, m_dragRowOrCol, -1, event );
+ }
+
+ ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL, m_rowLabelWin);
+ m_dragLastPos = -1;
+ }
+
+
+ // ------------ Right button down
+ //
+ else if ( event.RightDown() )
+ {
+ row = YToRow(y);
+ if ( row >=0 &&
+ !SendEvent( wxEVT_GRID_LABEL_RIGHT_CLICK, row, -1, event ) )
+ {
+ // no default action at the moment
+ }
+ }
+
+
+ // ------------ Right double click
+ //
+ else if ( event.RightDClick() )
+ {
+ row = YToRow(y);
+ if ( row >= 0 &&
+ !SendEvent( wxEVT_GRID_LABEL_RIGHT_DCLICK, row, -1, event ) )
+ {
+ // no default action at the moment
+ }
+ }
+
+
+ // ------------ No buttons down and mouse moving
+ //
+ else if ( event.Moving() )
+ {
+ m_dragRowOrCol = YToEdgeOfRow( y );
+ if ( m_dragRowOrCol >= 0 )
+ {
+ if ( m_cursorMode == WXGRID_CURSOR_SELECT_CELL )
+ {
+ // don't capture the mouse yet
+ if ( CanDragRowSize() )
+ ChangeCursorMode(WXGRID_CURSOR_RESIZE_ROW, m_rowLabelWin, false);
+ }
+ }
+ else if ( m_cursorMode != WXGRID_CURSOR_SELECT_CELL )
+ {
+ ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL, m_rowLabelWin, false);
+ }
+ }
+}
+
+
+void wxGrid::ProcessColLabelMouseEvent( wxMouseEvent& event )
+{
+ int x, y, col;
+ wxPoint pos( event.GetPosition() );
+ CalcUnscrolledPosition( pos.x, pos.y, &x, &y );
+
+ if ( event.Dragging() )
+ {
+ if (!m_isDragging)
+ {
+ m_isDragging = true;
+ m_colLabelWin->CaptureMouse();
+ }
+
+ if ( event.LeftIsDown() )
+ {
+ switch( m_cursorMode )
+ {
+ case WXGRID_CURSOR_RESIZE_COL:
+ {
+ int cw, ch, dummy, top;
+ m_gridWin->GetClientSize( &cw, &ch );
+ CalcUnscrolledPosition( 0, 0, &dummy, &top );
+
+ wxClientDC dc( m_gridWin );
+ PrepareDC( dc );
+
+ x = wxMax( x, GetColLeft(m_dragRowOrCol) +
+ GetColMinimalWidth(m_dragRowOrCol));
+ dc.SetLogicalFunction(wxINVERT);
+ if ( m_dragLastPos >= 0 )
+ {
+ dc.DrawLine( m_dragLastPos, top, m_dragLastPos, top+ch );
+ }
+ dc.DrawLine( x, top, x, top+ch );
+ m_dragLastPos = x;
+ }
+ break;
+
+ case WXGRID_CURSOR_SELECT_COL:
+ {
+ if ( (col = XToCol( x )) >= 0 )
+ {
+ if ( m_selection )
+ {
+ m_selection->SelectCol( col,
+ event.ControlDown(),
+ event.ShiftDown(),
+ event.AltDown(),
+ event.MetaDown() );
+ }
+ }
+ }
+ break;
+
+ // default label to suppress warnings about "enumeration value
+ // 'xxx' not handled in switch
+ default:
+ break;
+ }
+ }
+ return;
+ }
+
+ if ( m_isDragging && (event.Entering() || event.Leaving()) )
+ return;
+
+ if (m_isDragging)
+ {
+ if (m_colLabelWin->HasCapture()) m_colLabelWin->ReleaseMouse();
+ m_isDragging = false;
+ }
+
+ // ------------ Entering or leaving the window
+ //
+ if ( event.Entering() || event.Leaving() )
+ {
+ ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL, m_colLabelWin);
+ }
+
+
+ // ------------ Left button pressed
+ //
+ else if ( event.LeftDown() )
+ {
+ // don't send a label click event for a hit on the