home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / wxos2240.zip / wxWindows-2.4.0 / src / generic / gridg.cpp < prev    next >
C/C++ Source or Header  |  2002-09-06  |  80KB  |  2,859 lines

  1. /////////////////////////////////////////////////////////////////////////////
  2. // Name:        gridg.cpp
  3. // Purpose:     wxGenericGrid
  4. // Author:      Julian Smart
  5. // Modified by: Michael Bedward
  6. //                Added edit in place facility, 20 Apr 1999
  7. //                Added cursor key control, 29 Jun 1999
  8. //              Gerhard Gruber
  9. //                Added keyboard navigation, client data, other fixes
  10. // Created:     04/01/98
  11. // RCS-ID:      $Id: gridg.cpp,v 1.41 2002/09/06 14:42:47 JS Exp $
  12. // Copyright:   (c) Julian Smart and Markus Holzem
  13. // Licence:     wxWindows license
  14. /////////////////////////////////////////////////////////////////////////////
  15.  
  16. #ifdef __GNUG__
  17.     #pragma implementation "gridg.h"
  18.     #pragma interface
  19. #endif
  20.  
  21. // For compilers that support precompilation, includes "wx/wx.h".
  22. #include "wx/wxprec.h"
  23.  
  24. #ifdef __BORLANDC__
  25.     #pragma hdrstop
  26. #endif
  27.  
  28. #if wxUSE_GRID && !(wxUSE_NEW_GRID)
  29.  
  30. #ifndef WX_PRECOMP
  31.     #include "wx/utils.h"
  32.     #include "wx/dcclient.h"
  33.     #include "wx/dcmemory.h"
  34.     #include "wx/textctrl.h"
  35.     #include "wx/settings.h"
  36. #endif
  37.  
  38. #include <string.h>
  39.  
  40. #include "wx/string.h"
  41.  
  42. #include "wx/generic/gridg.h"
  43.  
  44.  
  45. // Values used to adjust the size of the in-place-edit control, and other
  46. // goodies.  Per-platform tweaks should be done here.
  47. #ifdef __WXMSW__
  48. #define wxIPE_ADJUST            -2
  49. #define wxIPE_STYLE             wxNO_BORDER
  50. #define wxIPE_HIGHLIGHT         1
  51. #define wxUSE_DOUBLE_BUFFERING  1
  52. #endif
  53.  
  54. #ifdef __WXPM__
  55. #define wxIPE_ADJUST            -1
  56. #define wxIPE_STYLE             wxNO_BORDER
  57. #define wxIPE_HIGHLIGHT         1
  58. #define wxUSE_DOUBLE_BUFFERING  1
  59. #endif
  60.  
  61. #ifdef __WXGTK__
  62. #define wxIPE_ADJUST            -1
  63. #define wxIPE_STYLE             wxNO_BORDER
  64. #define wxIPE_HIGHLIGHT         0
  65. #define wxUSE_DOUBLE_BUFFERING  1
  66. #endif
  67.  
  68. #ifdef __WXMOTIF__
  69. #define wxIPE_ADJUST            2
  70. #define wxIPE_STYLE             wxNO_BORDER
  71. #define wxIPE_HIGHLIGHT         0
  72. #define wxUSE_DOUBLE_BUFFERING  0
  73. #endif
  74.  
  75. #ifndef wxIPE_ADJUST
  76. #define wxIPE_ADJUST            2
  77. #define wxIPE_STYLE             wxNO_BORDER
  78. #define wxIPE_HIGHLIGHT         0
  79. #define wxUSE_DOUBLE_BUFFERING  0
  80. #endif
  81.  
  82.  
  83.  
  84. #define wxGRID_DRAG_NONE       0
  85. #define wxGRID_DRAG_LEFT_RIGHT 1
  86. #define wxGRID_DRAG_UP_DOWN    2
  87.  
  88. IMPLEMENT_DYNAMIC_CLASS(wxGenericGrid, wxPanel)
  89. IMPLEMENT_DYNAMIC_CLASS(wxGridEvent, wxEvent)
  90.  
  91. BEGIN_EVENT_TABLE(wxGenericGrid, wxPanel)
  92.     EVT_SIZE(wxGenericGrid::OnSize)
  93.     EVT_PAINT(wxGenericGrid::OnPaint)
  94.     EVT_ERASE_BACKGROUND(wxGenericGrid::OnEraseBackground)
  95.     EVT_MOUSE_EVENTS(wxGenericGrid::OnMouseEvent)
  96.     EVT_TEXT(wxGRID_TEXT_CTRL, wxGenericGrid::OnText)
  97.     EVT_TEXT(wxGRID_EDIT_IN_PLACE_TEXT_CTRL, wxGenericGrid::OnTextInPlace)
  98.     EVT_TEXT_ENTER(wxGRID_TEXT_CTRL, wxGenericGrid::OnTextEnter)
  99.     EVT_TEXT_ENTER(wxGRID_EDIT_IN_PLACE_TEXT_CTRL, wxGenericGrid::OnTextInPlaceEnter)
  100.     EVT_COMMAND_SCROLL(wxGRID_HSCROLL, wxGenericGrid::OnGridScroll)
  101.     EVT_COMMAND_SCROLL(wxGRID_VSCROLL, wxGenericGrid::OnGridScroll)
  102.  
  103.     // default wxGridEvent handlers
  104.     EVT_GRID_SELECT_CELL(wxGenericGrid::_OnSelectCell)
  105.     EVT_GRID_CREATE_CELL(wxGenericGrid::_OnCreateCell)
  106.     EVT_GRID_CHANGE_LABELS(wxGenericGrid::_OnChangeLabels)
  107.     EVT_GRID_CHANGE_SEL_LABEL(wxGenericGrid::_OnChangeSelectionLabel)
  108.     EVT_GRID_CELL_CHANGE(wxGenericGrid::_OnCellChange)
  109.     EVT_GRID_CELL_LCLICK(wxGenericGrid::_OnCellLeftClick)
  110.     EVT_GRID_CELL_RCLICK(wxGenericGrid::_OnCellRightClick)
  111.     EVT_GRID_LABEL_LCLICK(wxGenericGrid::_OnLabelLeftClick)
  112.     EVT_GRID_LABEL_RCLICK(wxGenericGrid::_OnLabelRightClick)
  113.  
  114. END_EVENT_TABLE()
  115.  
  116.  
  117. wxGenericGrid::wxGenericGrid()
  118. {
  119.   m_viewWidth = 0;
  120.   m_viewHeight = 0;
  121.   m_batchCount = 0;
  122.   m_hScrollBar = (wxScrollBar *) NULL;
  123.   m_vScrollBar = (wxScrollBar *) NULL;
  124.   m_cellTextColour = *wxBLACK;
  125.   m_cellBackgroundColour = *wxWHITE;
  126.   m_labelTextColour = *wxBLACK;
  127. //  m_labelBackgroundColour = *wxLIGHT_GREY;
  128.   m_labelBackgroundColour = wxSystemSettings::GetColour( wxSYS_COLOUR_BTNFACE );
  129.   m_labelBackgroundBrush = wxNullBrush;
  130.   m_labelTextFont = wxNullFont;
  131.   m_cellTextFont = wxNullFont;
  132.   m_textItem = (wxTextCtrl *) NULL;
  133.   m_currentRectVisible = FALSE;
  134.   m_editable = TRUE;
  135.  
  136.   m_editInPlace = FALSE;
  137.   m_inOnTextInPlace = FALSE;
  138.   m_inScroll = FALSE;
  139.  
  140. #if defined(__WIN95__)
  141.   m_scrollWidth = wxSystemSettings::GetMetric(wxSYS_VSCROLL_X);
  142. #elif defined(__WXGTK__)
  143.   m_scrollWidth = wxSystemSettings::GetMetric(wxSYS_VSCROLL_X);
  144. #else
  145.   m_scrollWidth = 16;
  146. #endif
  147.   m_dragStatus = wxGRID_DRAG_NONE;
  148.   m_dragRowOrCol = 0;
  149.   m_dragStartPosition = 0;
  150.   m_dragLastPosition = 0;
  151.   m_divisionPen = wxNullPen;
  152.   m_highlightPen = wxNullPen;
  153.   m_leftOfSheet = wxGRID_DEFAULT_SHEET_LEFT;
  154.   m_topOfSheet = wxGRID_DEFAULT_SHEET_TOP;
  155.   m_cellHeight = wxGRID_DEFAULT_CELL_HEIGHT;
  156.   m_totalGridWidth = 0;
  157.   m_totalGridHeight = 0;
  158.   m_colWidths = (short *) NULL;
  159.   m_rowHeights = (short *) NULL;
  160.   m_verticalLabelWidth = wxGRID_DEFAULT_VERTICAL_LABEL_WIDTH;
  161.   m_horizontalLabelHeight = wxGRID_DEFAULT_HORIZONAL_LABEL_HEIGHT;
  162.   m_verticalLabelAlignment = wxCENTRE;
  163.   m_horizontalLabelAlignment = wxCENTRE;
  164.   m_editControlPosition.x = wxGRID_DEFAULT_EDIT_X;
  165.   m_editControlPosition.y = wxGRID_DEFAULT_EDIT_Y;
  166.   m_editControlPosition.width = wxGRID_DEFAULT_EDIT_WIDTH;
  167.   m_editControlPosition.height = wxGRID_DEFAULT_EDIT_HEIGHT;
  168.   m_wCursorRow = 0;
  169.   m_wCursorColumn = 0;
  170.   m_scrollPosX = 0;
  171.   m_scrollPosY = 0;
  172.   m_editCreated = FALSE;
  173.   m_totalRows = 0;
  174.   m_totalCols = 0;
  175.   m_gridCells = (wxGridCell ***) NULL;
  176.   m_rowLabelCells = (wxGridCell **) NULL;
  177.   m_colLabelCells = (wxGridCell **) NULL;
  178.   m_textItem = (wxTextCtrl *) NULL;
  179. }
  180.  
  181. bool wxGenericGrid::Create(wxWindow *parent,
  182.                            wxWindowID id,
  183.                            const wxPoint& pos,
  184.                            const wxSize& size,
  185.                            long style,
  186.                            const wxString& name)
  187. {
  188.   m_viewWidth = 0;
  189.   m_viewHeight = 0;
  190.   m_batchCount = 0;
  191.   m_editingPanel = (wxPanel *) NULL;
  192.   m_hScrollBar = (wxScrollBar *) NULL;
  193.   m_vScrollBar = (wxScrollBar *) NULL;
  194.   m_cellTextColour = *wxBLACK;
  195.   m_cellBackgroundColour = *wxWHITE;
  196.   m_labelTextColour = *wxBLACK;
  197. //  m_labelBackgroundColour = *wxLIGHT_GREY;
  198.   m_labelBackgroundColour = wxSystemSettings::GetColour( wxSYS_COLOUR_BTNFACE );
  199.   m_labelBackgroundBrush = wxNullBrush;
  200.   m_labelTextFont = * wxTheFontList->FindOrCreateFont(10, wxSWISS, wxNORMAL, wxBOLD);
  201.   m_cellTextFont = * wxTheFontList->FindOrCreateFont(10, wxSWISS, wxNORMAL, wxNORMAL);
  202.   m_textItem = (wxTextCtrl *) NULL;
  203.   m_currentRectVisible = FALSE;
  204.   m_editable = TRUE;
  205.   m_editInPlace = FALSE;
  206.   m_inOnTextInPlace = FALSE;
  207.   m_inScroll = FALSE;
  208. #if defined(__WIN95__)
  209.   m_scrollWidth = wxSystemSettings::GetMetric(wxSYS_VSCROLL_X);
  210. #elif defined(__WXGTK__)
  211.   m_scrollWidth = wxSystemSettings::GetMetric(wxSYS_VSCROLL_X);
  212. #else
  213.   m_scrollWidth = 16;
  214. #endif
  215.   m_dragStatus = wxGRID_DRAG_NONE;
  216.   m_dragRowOrCol = 0;
  217.   m_dragStartPosition = 0;
  218.   m_dragLastPosition = 0;
  219.   m_divisionPen = * wxThePenList->FindOrCreatePen(wxT("LIGHT GREY"), 1, wxSOLID);
  220.   m_highlightPen = * wxBLACK_PEN;
  221.   m_doubleBufferingBitmap = (wxBitmap *) NULL;
  222.  
  223.   if (!m_horizontalSashCursor.Ok())
  224.   {
  225.     m_horizontalSashCursor = wxCursor(wxCURSOR_SIZEWE);
  226.     m_verticalSashCursor = wxCursor(wxCURSOR_SIZENS);
  227.   }
  228.  
  229.   SetLabelBackgroundColour(m_labelBackgroundColour);
  230.  
  231.   m_leftOfSheet = wxGRID_DEFAULT_SHEET_LEFT;
  232.   m_topOfSheet = wxGRID_DEFAULT_SHEET_TOP;
  233.   m_cellHeight = wxGRID_DEFAULT_CELL_HEIGHT;
  234.   m_totalGridWidth = 0;
  235.   m_totalGridHeight = 0;
  236.   m_colWidths = (short *) NULL;
  237.   m_rowHeights = (short *) NULL;
  238.  
  239.   m_verticalLabelWidth = wxGRID_DEFAULT_VERTICAL_LABEL_WIDTH;
  240.   m_horizontalLabelHeight = wxGRID_DEFAULT_HORIZONAL_LABEL_HEIGHT;
  241.   m_verticalLabelAlignment = wxCENTRE;
  242.   m_horizontalLabelAlignment = wxCENTRE;
  243.   m_editControlPosition.x = wxGRID_DEFAULT_EDIT_X;
  244.   m_editControlPosition.y = wxGRID_DEFAULT_EDIT_Y;
  245.   m_editControlPosition.width = wxGRID_DEFAULT_EDIT_WIDTH;
  246.   m_editControlPosition.height = wxGRID_DEFAULT_EDIT_HEIGHT;
  247.  
  248.   m_wCursorRow = 0;
  249.   m_wCursorColumn = 0;
  250.  
  251.   m_scrollPosX = 0;
  252.   m_scrollPosY = 0;
  253.  
  254.   /* Store the rect. coordinates for the current cell */
  255.   SetCurrentRect(m_wCursorRow, m_wCursorColumn);
  256.  
  257.   m_editCreated = FALSE;
  258.  
  259.   m_totalRows = 0;
  260.   m_totalCols = 0;
  261.   m_gridCells = (wxGridCell ***) NULL;
  262.   m_rowLabelCells = (wxGridCell **) NULL;
  263.   m_colLabelCells = (wxGridCell **) NULL;
  264.   m_textItem = (wxTextCtrl *) NULL;
  265.  
  266.   wxPanel::Create(parent, id, pos, size, style, name);
  267.  
  268.   m_editingPanel = new wxPanel(this);
  269.  
  270.   m_textItem = new wxTextCtrl(m_editingPanel, wxGRID_TEXT_CTRL, wxT(""),
  271.                               wxPoint(m_editControlPosition.x, m_editControlPosition.y),
  272.                               wxSize(m_editControlPosition.width, -1),
  273.                               wxTE_PROCESS_ENTER);
  274.   m_textItem->Show(TRUE);
  275.   m_textItem->SetFocus();
  276.   int controlW, controlH;
  277.  
  278.   m_textItem->GetSize(&controlW, &controlH);
  279.   m_editControlPosition.height = controlH;
  280.  
  281.   m_topOfSheet = m_editControlPosition.y + controlH + 2;
  282.  
  283.   m_editCreated = TRUE;
  284.  
  285.   m_hScrollBar = new wxScrollBar(this, wxGRID_HSCROLL, wxPoint(0, 0), wxSize(20, 100), wxHORIZONTAL);
  286.   m_vScrollBar = new wxScrollBar(this, wxGRID_VSCROLL, wxPoint(0, 0), wxSize(100, 20), wxVERTICAL);
  287.  
  288. //  SetSize(pos.x, pos.y, size.x, size.y);
  289.  
  290.   m_inPlaceTextItem = new wxTextCtrl( (wxPanel*)this, wxGRID_EDIT_IN_PLACE_TEXT_CTRL, wxT(""),
  291.                                       wxPoint( m_currentRect.x-wxIPE_ADJUST, m_currentRect.y-wxIPE_ADJUST ),
  292.                                       wxSize( m_currentRect.width+wxIPE_ADJUST*2, m_currentRect.height+wxIPE_ADJUST*2 ),
  293.                                       wxNO_BORDER | wxTE_PROCESS_ENTER );
  294.   m_inPlaceTextItem->Show(m_editInPlace);
  295.   if ( m_editInPlace )
  296.     m_inPlaceTextItem->SetFocus();
  297.  
  298.   return TRUE;
  299. }
  300.  
  301. wxGenericGrid::~wxGenericGrid()
  302. {
  303.   ClearGrid();
  304. }
  305.  
  306. void wxGenericGrid::ClearGrid()
  307. {
  308.   int i,j;
  309.   if (m_gridCells)
  310.   {
  311.     for (i = 0; i < m_totalRows; i++)
  312.     {
  313.       for (j = 0; j < m_totalCols; j++)
  314.         if (m_gridCells[i][j])
  315.           delete m_gridCells[i][j];
  316.       delete[] m_gridCells[i];
  317.     }
  318.     delete[] m_gridCells;
  319.     m_gridCells = (wxGridCell ***) NULL;
  320.   }
  321.   if (m_colWidths)
  322.     delete[] m_colWidths;
  323.   m_colWidths = (short *) NULL;
  324.   if (m_rowHeights)
  325.     delete[] m_rowHeights;
  326.   m_rowHeights = (short *) NULL;
  327.  
  328.   if (m_rowLabelCells)
  329.   {
  330.     for (i = 0; i < m_totalRows; i++)
  331.       delete m_rowLabelCells[i];
  332.     delete[] m_rowLabelCells;
  333.     m_rowLabelCells = (wxGridCell **) NULL;
  334.   }
  335.   if (m_colLabelCells)
  336.   {
  337.     for (i = 0; i < m_totalCols; i++)
  338.       delete m_colLabelCells[i];
  339.     delete[] m_colLabelCells;
  340.     m_colLabelCells = (wxGridCell **) NULL;
  341.   }
  342.   if (m_doubleBufferingBitmap)
  343.   {
  344.     delete m_doubleBufferingBitmap;
  345.     m_doubleBufferingBitmap = (wxBitmap *) NULL;
  346.   }
  347. }
  348.  
  349. bool wxGenericGrid::CreateGrid(int nRows, int nCols, wxString **cellValues, short *widths,
  350.      short defaultWidth, short defaultHeight)
  351. {
  352.   m_totalRows = nRows;
  353.   m_totalCols = nCols;
  354.  
  355.   int i,j;
  356.   m_colWidths = new short[nCols];
  357.   m_rowHeights = new short[nRows];
  358.   for (i = 0; i < nCols; i++)
  359.     if (widths)
  360.       m_colWidths[i] = widths[i];
  361.     else
  362.       m_colWidths[i] = defaultWidth;
  363.   for (i = 0; i < nRows; i++)
  364.     m_rowHeights[i] = defaultHeight;
  365.  
  366.   m_gridCells = new wxGridCell **[nRows];
  367.  
  368.   for (i = 0; i < nRows; i++)
  369.     m_gridCells[i] = new wxGridCell *[nCols];
  370.  
  371.   for (i = 0; i < nRows; i++)
  372.     for (j = 0; j < nCols; j++)
  373.       if (cellValues)
  374.       {
  375.         //m_gridCells[i][j] = OnCreateCell();
  376.         wxGridEvent g_evt(GetId(), wxEVT_GRID_CREATE_CELL, this, i, j);
  377.         GetEventHandler()->ProcessEvent(g_evt);
  378.         m_gridCells[i][j] = g_evt.m_cell;
  379.         m_gridCells[i][j]->SetTextValue(cellValues[i][j]);
  380.       }
  381.       else
  382.         m_gridCells[i][j] = (wxGridCell *) NULL;
  383.  
  384.   m_rowLabelCells = new wxGridCell *[nRows];
  385.   for (i = 0; i < nRows; i++)
  386.     m_rowLabelCells[i] = new wxGridCell(this);
  387.   m_colLabelCells = new wxGridCell *[nCols];
  388.   for (i = 0; i < nCols; i++)
  389.     m_colLabelCells[i] = new wxGridCell(this);
  390.  
  391.   m_wCursorRow = m_wCursorColumn = 0;
  392.   SetCurrentRect(0, 0);
  393.  
  394.   // Need to determine various dimensions
  395.   UpdateDimensions();
  396.  
  397.   // Number of 'lines'
  398.   int objectSizeX = m_totalCols;
  399.   int pageSizeX = 1;
  400.   int viewLengthX = m_totalCols;
  401.  
  402. /*
  403.   m_hScrollBar->SetViewLength(viewLengthX);
  404.   m_hScrollBar->SetObjectLength(objectSizeX);
  405.   m_hScrollBar->SetPageSize(pageSizeX);
  406. */
  407.   m_hScrollBar->SetScrollbar(m_hScrollBar->GetThumbPosition(), pageSizeX, objectSizeX, viewLengthX);
  408.  
  409.   int objectSizeY = m_totalRows;
  410.   int pageSizeY = 1;
  411.   int viewLengthY = m_totalRows;
  412.  
  413. /*
  414.   m_vScrollBar->SetViewLength(viewLengthY);
  415.   m_vScrollBar->SetObjectLength(objectSizeY);
  416.   m_vScrollBar->SetPageSize(pageSizeY);
  417. */
  418.  
  419.   m_vScrollBar->SetScrollbar(m_vScrollBar->GetThumbPosition(), pageSizeY, objectSizeY, viewLengthY);
  420.  
  421.   AdjustScrollbars();
  422.  
  423.   //OnChangeLabels();
  424.   wxGridEvent g_evt(GetId(), wxEVT_GRID_CHANGE_LABELS, this);
  425.   GetEventHandler()->ProcessEvent(g_evt);
  426.  
  427.   //OnChangeSelectionLabel();
  428.   wxGridEvent g_evt2(GetId(), wxEVT_GRID_CHANGE_SEL_LABEL, this);
  429.   GetEventHandler()->ProcessEvent(g_evt2);
  430.  
  431.   return TRUE;
  432. }
  433.  
  434. // Need to determine various dimensions
  435. void wxGenericGrid::UpdateDimensions()
  436. {
  437.   int canvasWidth, canvasHeight;
  438.   GetSize(&canvasWidth, &canvasHeight);
  439.  
  440.   if (m_editCreated && m_editable)
  441.   {
  442.     int controlW, controlH;
  443.     GetTextItem()->GetSize(&controlW, &controlH);
  444.     m_topOfSheet = m_editControlPosition.y + controlH + 2;
  445.   }
  446.   else
  447.     m_topOfSheet = 0;
  448.   m_rightOfSheet = m_leftOfSheet + m_verticalLabelWidth;
  449.   int i;
  450.   for (i = m_scrollPosX; i < m_totalCols; i++)
  451.   {
  452.     if (m_rightOfSheet > canvasWidth)
  453.       break;
  454.     else
  455.       m_rightOfSheet += m_colWidths[i];
  456.   }
  457.   m_bottomOfSheet = m_topOfSheet + m_horizontalLabelHeight;
  458.   for (i = m_scrollPosY; i < m_totalRows; i++)
  459.   {
  460.     if (m_bottomOfSheet > canvasHeight)
  461.       break;
  462.     else
  463.       m_bottomOfSheet += m_rowHeights[i];
  464.   }
  465.  
  466.   m_totalGridWidth = m_leftOfSheet + m_verticalLabelWidth;
  467.   for (i = 0; i < m_totalCols; i++)
  468.   {
  469.     m_totalGridWidth += m_colWidths[i];
  470.   }
  471.   m_totalGridHeight = m_topOfSheet + m_horizontalLabelHeight;
  472.   for (i = 0; i < m_totalRows; i++)
  473.   {
  474.     m_totalGridHeight += m_rowHeights[i];
  475.   }
  476. }
  477.  
  478. wxGridCell *wxGenericGrid::GetCell(int row, int col) const
  479. {
  480.   if (!m_gridCells)
  481.     return (wxGridCell *) NULL;
  482.  
  483.   if ((row >= m_totalRows) || (col >= m_totalCols))
  484.     return (wxGridCell *) NULL;
  485.  
  486.   wxGridCell *cell = m_gridCells[row][col];
  487.   if (!cell)
  488.   {
  489.     // m_gridCells[row][col] = OnCreateCell();
  490.     wxGridEvent g_evt(GetId(), wxEVT_GRID_CREATE_CELL, (wxGenericGrid*) this, row, col);
  491.     GetEventHandler()->ProcessEvent(g_evt);
  492.     m_gridCells[row][col] = g_evt.m_cell;
  493.     return m_gridCells[row][col];
  494.   }
  495.   else
  496.     return cell;
  497. }
  498.  
  499. void wxGenericGrid::SetGridClippingRegion(wxDC *dc)
  500. {
  501.   int m_scrollWidthHoriz = 0;
  502.   int m_scrollWidthVert = 0;
  503.   int cw, ch;
  504.   GetClientSize(&cw, &ch);
  505.  
  506.   if (m_hScrollBar && m_hScrollBar->IsShown())
  507.     m_scrollWidthHoriz = m_scrollWidth;
  508.   if (m_vScrollBar && m_vScrollBar->IsShown())
  509.     m_scrollWidthVert = m_scrollWidth;
  510.  
  511.   // Don't paint over the scrollbars
  512.   dc->SetClippingRegion(m_leftOfSheet, m_topOfSheet,
  513.      cw - m_scrollWidthVert - m_leftOfSheet, ch - m_scrollWidthHoriz - m_topOfSheet);
  514. }
  515.  
  516. void wxGenericGrid::OnPaint(wxPaintEvent& WXUNUSED(event))
  517. {
  518.   int w, h;
  519.   GetClientSize(&w, &h);
  520.  
  521.   bool useDoubleBuffering = (bool) wxUSE_DOUBLE_BUFFERING;
  522.   if (useDoubleBuffering)
  523.   {
  524.     // Reuse the old bitmap if possible
  525.  
  526.     if (!m_doubleBufferingBitmap ||
  527.        (m_doubleBufferingBitmap->GetWidth() < w || m_doubleBufferingBitmap->GetHeight() < h))
  528.     {
  529.         if (m_doubleBufferingBitmap)
  530.             delete m_doubleBufferingBitmap;
  531.         m_doubleBufferingBitmap = new wxBitmap(w, h);
  532.     }
  533.     if (!m_doubleBufferingBitmap || !m_doubleBufferingBitmap->Ok())
  534.     {
  535.         // If we couldn't create a new bitmap, perhaps because resources were low,
  536.         // then don't complain, just don't double-buffer
  537.         if (m_doubleBufferingBitmap)
  538.             delete m_doubleBufferingBitmap;
  539.         m_doubleBufferingBitmap = (wxBitmap *) NULL;
  540.         useDoubleBuffering = FALSE;
  541.     }
  542.   }
  543.  
  544.   if (useDoubleBuffering)
  545.   {
  546.     wxPaintDC paintDC(this);
  547.     wxMemoryDC dc(& paintDC);
  548.     dc.SelectObject(* m_doubleBufferingBitmap);
  549.  
  550.     PaintGrid(dc);
  551.  
  552.     int vertScrollBarWidth = m_scrollWidth;
  553.     int horizScrollBarHeight = m_scrollWidth;
  554.     if (m_vScrollBar && !m_vScrollBar->IsShown())
  555.       vertScrollBarWidth = 0;
  556.     if (m_hScrollBar && !m_hScrollBar->IsShown())
  557.       horizScrollBarHeight = 0;
  558.  
  559.     paintDC.Blit(m_leftOfSheet, m_topOfSheet, w - vertScrollBarWidth - m_leftOfSheet, h - horizScrollBarHeight - m_topOfSheet,
  560.       &dc, m_leftOfSheet, m_topOfSheet, wxCOPY);
  561.  
  562.     dc.SelectObject(wxNullBitmap);
  563.   }
  564.   else
  565.   {
  566.     wxPaintDC dc(this);
  567.     PaintGrid(dc);
  568.   }
  569. }
  570.  
  571. void wxGenericGrid::PaintGrid(wxDC& dc)
  572. {
  573.     dc.BeginDrawing();
  574.     dc.SetOptimization(FALSE);
  575.  
  576.     SetGridClippingRegion(& dc);
  577.  
  578.     DrawLabelAreas(& dc);
  579.  
  580.     DrawEditableArea(& dc);
  581.     DrawColumnLabels(& dc);
  582.     DrawRowLabels(& dc);
  583.     DrawCells(& dc);
  584.     DrawGridLines(& dc);
  585.  
  586.     /* Hilight present cell */
  587.     SetCurrentRect(m_wCursorRow, m_wCursorColumn);
  588.     if (m_currentRectVisible && (wxIPE_HIGHLIGHT || !(m_editable && m_editInPlace)))
  589.       HighlightCell(& dc, TRUE);
  590.  
  591.     dc.DestroyClippingRegion();
  592.     dc.SetOptimization(TRUE);
  593.     dc.EndDrawing();
  594. }
  595.  
  596. // Erase (some of) the background.
  597. // Currently, a Windows-only optimisation.
  598. void wxGenericGrid::OnEraseBackground(wxEraseEvent& WXUNUSED(event) )
  599. {
  600.     wxClientDC dc(this);
  601.     dc.BeginDrawing();
  602.     dc.SetOptimization(FALSE);
  603.  
  604.     int w, h;
  605.     GetClientSize(& w, & h);
  606.     dc.SetBrush(*wxLIGHT_GREY_BRUSH);
  607.     dc.SetPen(*wxLIGHT_GREY_PEN);
  608.  
  609.     if (m_hScrollBar && m_hScrollBar->IsShown() && m_vScrollBar && m_vScrollBar->IsShown())
  610.     {
  611.         dc.DrawRectangle(w - m_scrollWidth, h - m_scrollWidth, m_scrollWidth, m_scrollWidth);
  612.     }
  613.  
  614.     dc.SetOptimization(TRUE);
  615.     dc.EndDrawing();
  616. }
  617.  
  618.  
  619. void wxGenericGrid::DrawLabelAreas(wxDC *dc)
  620. {
  621.   int cw, ch;
  622.   GetClientSize(&cw, &ch);
  623.  
  624.   dc->SetPen(*wxTRANSPARENT_PEN);
  625. //  dc->SetBrush(*dc->GetBackground());
  626.  
  627.   // Should blank out any area which isn't going to be painted over.
  628. //  dc->DrawRectangle(m_leftOfSheet, m_bottomOfSheet, cw - m_leftOfSheet, ch - m_bottomOfSheet);
  629. //  dc->DrawRectangle(m_rightOfSheet, m_topOfSheet, cw - m_rightOfSheet, ch - m_topOfSheet);
  630.  
  631.   // Paint the label areas
  632.   dc->SetBrush(m_labelBackgroundBrush);
  633. //  dc->DrawRectangle(m_leftOfSheet, m_topOfSheet, m_rightOfSheet - m_leftOfSheet + 1, m_horizontalLabelHeight + 1);
  634.   dc->DrawRectangle(m_leftOfSheet, m_topOfSheet, cw-m_leftOfSheet, m_horizontalLabelHeight + 1);
  635. //  dc->DrawRectangle(m_leftOfSheet, m_topOfSheet, m_verticalLabelWidth + 1, m_bottomOfSheet - m_topOfSheet + 1);
  636.   dc->DrawRectangle(m_leftOfSheet, m_topOfSheet, m_verticalLabelWidth + 1, ch-m_topOfSheet);
  637. }
  638.  
  639. void wxGenericGrid::DrawEditableArea(wxDC *dc)
  640. {
  641.   int cw, ch;
  642.   GetClientSize(&cw, &ch);
  643.  
  644.   dc->SetPen(*wxTRANSPARENT_PEN);
  645.   dc->SetBrush(*wxTheBrushList->FindOrCreateBrush(m_cellBackgroundColour, wxSOLID));
  646. //  dc->DrawRectangle(m_leftOfSheet+m_verticalLabelWidth, m_topOfSheet+m_horizontalLabelHeight,
  647. //      m_rightOfSheet-(m_leftOfSheet+m_verticalLabelWidth) + 1, m_bottomOfSheet - (m_topOfSheet+m_horizontalLabelHeight) + 1);
  648.   dc->DrawRectangle(m_leftOfSheet+m_verticalLabelWidth, m_topOfSheet+m_horizontalLabelHeight,
  649.       cw-(m_leftOfSheet+m_verticalLabelWidth), ch - (m_topOfSheet+m_horizontalLabelHeight));
  650. }
  651.  
  652. void wxGenericGrid::DrawGridLines(wxDC *dc)
  653. {
  654.   int cw, ch;
  655.   GetClientSize(&cw, &ch);
  656.  
  657.   int i;
  658.  
  659.   if (m_divisionPen.Ok())
  660.   {
  661.     dc->SetPen(m_divisionPen);
  662.  
  663.     int heightCount = m_topOfSheet + m_horizontalLabelHeight;
  664.  
  665.     // Draw horizontal grey lines for cells
  666.     for (i = m_scrollPosY; i < (m_totalRows+1); i++)
  667.     {
  668.       if (heightCount > ch)
  669.         break;
  670.       else
  671.       {
  672.         dc->DrawLine(m_leftOfSheet, heightCount,
  673.                    cw, heightCount);
  674.         if (i < m_totalRows)
  675.           heightCount += m_rowHeights[i];
  676.       }
  677.     }
  678.   }
  679.  
  680.   if (m_verticalLabelWidth > 0)
  681.   {
  682.     dc->SetPen(*wxBLACK_PEN);
  683.  
  684.     // Draw horizontal black lines for row labels
  685.     int heightCount = m_topOfSheet + m_horizontalLabelHeight;
  686.     for (i = m_scrollPosY; i < (m_totalRows+1); i++)
  687.     {
  688.       if (heightCount > ch)
  689.         break;
  690.       else
  691.       {
  692.         dc->DrawLine(m_leftOfSheet, heightCount,
  693.                      m_verticalLabelWidth, heightCount);
  694.         if (i < m_totalRows)
  695.           heightCount += m_rowHeights[i];
  696.       }
  697.     }
  698.     // Draw a black vertical line for row number cells
  699.     dc->DrawLine(m_leftOfSheet + m_verticalLabelWidth, m_topOfSheet,
  700.       m_leftOfSheet + m_verticalLabelWidth, ch);
  701.     // First vertical line
  702.     dc->DrawLine(m_leftOfSheet, m_topOfSheet, m_leftOfSheet, ch);
  703.  
  704.     dc->SetPen(*wxWHITE_PEN);
  705.  
  706.     // Draw highlights on row labels
  707.     heightCount = m_topOfSheet + m_horizontalLabelHeight;
  708.     for (i = m_scrollPosY; i < m_totalRows; i++)
  709.     {
  710.       if (heightCount > ch)
  711.         break;
  712.       else
  713.       {
  714.         dc->DrawLine(m_leftOfSheet+1, heightCount+1,
  715.                      m_verticalLabelWidth, heightCount+1);
  716.         dc->DrawLine(m_leftOfSheet+1, heightCount+1,
  717.                      m_leftOfSheet+1, heightCount + m_rowHeights[i] - 1);
  718.         heightCount += m_rowHeights[i];
  719.       }
  720.     }
  721.     // Last one - down to the floor.
  722.     dc->DrawLine(m_leftOfSheet+1, heightCount+1,
  723.                  m_verticalLabelWidth, heightCount+1);
  724.     dc->DrawLine(m_leftOfSheet+1, heightCount+1,
  725.                    m_leftOfSheet+1, ch);
  726.  
  727.   }
  728.  
  729.   if (m_divisionPen.Ok())
  730.   {
  731.     dc->SetPen(m_divisionPen);
  732.  
  733.     // Draw vertical grey lines for cells
  734.     int widthCount = m_leftOfSheet + m_verticalLabelWidth;
  735.     for (i = m_scrollPosX; i < m_totalCols; i++)
  736.     {
  737.       if (widthCount > cw)
  738.         break;
  739.       else
  740.       {
  741.         // Skip the first one
  742.         if (i != m_scrollPosX)
  743.         {
  744.          dc->DrawLine(widthCount, m_topOfSheet + m_horizontalLabelHeight,
  745.                        widthCount, m_bottomOfSheet);
  746.         }
  747.         widthCount += m_colWidths[i];
  748.       }
  749.     }
  750.     // Last one
  751.     dc->DrawLine(widthCount, m_topOfSheet + m_horizontalLabelHeight,
  752.                     widthCount, m_bottomOfSheet);
  753.   }
  754.  
  755.   dc->SetPen(*wxBLACK_PEN);
  756.  
  757.   // Draw two black horizontal lines for column number cells
  758.   dc->DrawLine(
  759.           m_leftOfSheet, m_topOfSheet,
  760.           cw, m_topOfSheet);
  761.   dc->DrawLine(m_leftOfSheet,  m_topOfSheet + m_horizontalLabelHeight,
  762.                cw, m_topOfSheet + m_horizontalLabelHeight);
  763.  
  764.   if (m_horizontalLabelHeight > 0)
  765.   {
  766.     int widthCount = m_leftOfSheet + m_verticalLabelWidth;
  767.  
  768.     // Draw black vertical lines for column number cells
  769.     for (i = m_scrollPosX; i < m_totalCols; i++)
  770.     {
  771.       if (widthCount > cw)
  772.         break;
  773.       else
  774.       {
  775.         dc->DrawLine(widthCount, m_topOfSheet,
  776.                       widthCount, m_topOfSheet + m_horizontalLabelHeight);
  777.         widthCount += m_colWidths[i];
  778.       }
  779.     }
  780.  
  781.     // Last one
  782.     dc->DrawLine(widthCount, m_topOfSheet,
  783.                     widthCount, m_topOfSheet + m_horizontalLabelHeight);
  784.  
  785.     // Draw highlights
  786.     dc->SetPen(*wxWHITE_PEN);
  787.     widthCount = m_leftOfSheet + m_verticalLabelWidth;
  788.  
  789.     for (i = m_scrollPosX; i < m_totalCols; i++)
  790.     {
  791.       if (widthCount > cw)
  792.         break;
  793.       else
  794.       {
  795.         dc->DrawLine(widthCount+1, m_topOfSheet+1,
  796.                      widthCount+m_colWidths[i], m_topOfSheet+1);
  797.         dc->DrawLine(widthCount+1, m_topOfSheet+1,
  798.                      widthCount+1, m_topOfSheet+m_horizontalLabelHeight);
  799.         widthCount += m_colWidths[i];
  800.       }
  801.     }
  802.     // Last one - to the right side of the canvas.
  803.     dc->DrawLine(widthCount+1, m_topOfSheet+1,
  804.                    cw, m_topOfSheet+1);
  805.     dc->DrawLine(widthCount+1, m_topOfSheet+1,
  806.                    widthCount+1, m_topOfSheet+m_horizontalLabelHeight);
  807.  
  808.   }
  809. }
  810.  
  811. void wxGenericGrid::DrawColumnLabels(wxDC *dc)
  812. {
  813.   int cw, ch;
  814.   GetClientSize(&cw, &ch);
  815.  
  816.   if (m_horizontalLabelHeight == 0)
  817.     return;
  818.  
  819.   int i;
  820.   wxRect rect;
  821.  
  822.   // Draw letters for columns
  823.   rect.y = m_topOfSheet + 1;
  824.   rect.height = m_horizontalLabelHeight - 1;
  825.  
  826.   dc->SetTextBackground(m_labelBackgroundColour);
  827.   dc->SetBackgroundMode(wxTRANSPARENT);
  828. //  dc->SetTextForeground(m_labelTextColour);
  829.  
  830.   int widthCount = m_leftOfSheet + m_verticalLabelWidth;
  831.   for (i = m_scrollPosX; i < m_totalCols; i++)
  832.   {
  833.      if (widthCount > cw)
  834.        break;
  835.      else
  836.      {
  837.        rect.x = 1 + widthCount;
  838.        rect.width = m_colWidths[i];
  839.        DrawColumnLabel(dc, &rect, i);
  840.  
  841.        widthCount += m_colWidths[i];
  842.      }
  843.   }
  844. }
  845.  
  846. void wxGenericGrid::DrawColumnLabel(wxDC *dc, wxRect *rect, int col)
  847. {
  848.   wxGridCell *cell = GetLabelCell(wxHORIZONTAL, col);
  849.   if (cell)
  850.   {
  851.     wxRect rect2;
  852.     rect2 = *rect;
  853.     rect2.x += 3;
  854.     rect2.y += 2;
  855.     rect2.width -= 5;
  856.     rect2.height -= 4;
  857.     dc->SetTextForeground(GetLabelTextColour());
  858.     dc->SetFont(GetLabelTextFont());
  859.         if ( !cell->GetTextValue().IsNull() )
  860.             DrawTextRect(dc, cell->GetTextValue(), &rect2, GetLabelAlignment(wxHORIZONTAL));
  861.   }
  862. }
  863.  
  864. void wxGenericGrid::DrawRowLabels(wxDC *dc)
  865. {
  866.   int cw, ch;
  867.   GetClientSize(&cw, &ch);
  868.  
  869.   if (m_verticalLabelWidth == 0)
  870.     return;
  871.  
  872.   int i;
  873.   wxRect rect;
  874.  
  875.   // Draw numbers for rows
  876.   rect.x = m_leftOfSheet;
  877.   rect.width = m_verticalLabelWidth;
  878.  
  879.   int heightCount = m_topOfSheet + m_horizontalLabelHeight;
  880.  
  881.   dc->SetTextBackground(m_labelBackgroundColour);
  882.   dc->SetBackgroundMode(wxTRANSPARENT);
  883.  
  884.   for (i = m_scrollPosY; i < m_totalRows; i++)
  885.   {
  886.      if (heightCount > ch)
  887.        break;
  888.      else
  889.      {
  890.        rect.y = 1 + heightCount;
  891.        rect.height = m_rowHeights[i];
  892.        DrawRowLabel(dc, &rect, i);
  893.  
  894.        heightCount += m_rowHeights[i];
  895.      }
  896.   }
  897. }
  898.  
  899. void wxGenericGrid::DrawRowLabel(wxDC *dc, wxRect *rect, int row)
  900. {
  901.   wxGridCell *cell = GetLabelCell(wxVERTICAL, row);
  902.   if (cell)
  903.   {
  904.     wxRect rect2;
  905.     rect2 = *rect;
  906.     rect2.x += 3;
  907.     rect2.y += 2;
  908.     rect2.width -= 5;
  909.     rect2.height -= 4;
  910.     dc->SetTextForeground(GetLabelTextColour());
  911.     dc->SetFont(GetLabelTextFont());
  912.         if ( !cell->GetTextValue().IsNull() )
  913.             DrawTextRect(dc, cell->GetTextValue(), &rect2, GetLabelAlignment(wxVERTICAL));
  914.   }
  915. }
  916.  
  917. void wxGenericGrid::DrawCells(wxDC *dc)
  918. {
  919.   int cw, ch;
  920.   GetClientSize(&cw, &ch);
  921.  
  922.   int i,j;
  923.  
  924.   // Draw value corresponding to each cell
  925.   for (i = m_scrollPosY; i < m_totalRows; i++)
  926.   {
  927.     for (j = m_scrollPosX; j < m_totalCols; j++)
  928.     {
  929.       SetCurrentRect(i, j, cw, ch);
  930.       if (m_currentRectVisible)
  931.       {
  932.         DrawCellBackground(dc, &m_currentRect, i, j);
  933.         DrawCellValue(dc, &m_currentRect, i, j);
  934.       }
  935.       if (m_currentRect.x > cw)
  936.         break;
  937.     }
  938.     if (m_currentRect.y > ch)
  939.       break;
  940.   }
  941.   dc->SetBackgroundMode(wxSOLID);
  942.   dc->SetPen(*wxBLACK_PEN);
  943. }
  944.  
  945. void wxGenericGrid::DrawCellBackground(wxDC *dc, wxRect *rect, int row, int col)
  946. {
  947.   wxGridCell *cell = GetCell(row, col);
  948.   if (cell)
  949.   {
  950.     dc->SetBrush(cell->GetBackgroundBrush());
  951.     dc->SetPen(*wxTRANSPARENT_PEN);
  952.  
  953. #if 0    // In wxWin 2.0 the dc code is exact. RR.
  954. #ifdef __WXMOTIF__
  955.     dc->DrawRectangle(rect->x+1, rect->y+1, rect->width-1, rect->height-1);
  956. #else
  957.     dc->DrawRectangle(rect->x+1, rect->y+1, rect->width, rect->height);
  958. #endif
  959. #endif
  960.  
  961.     dc->DrawRectangle(rect->x+1, rect->y+1, rect->width-1, rect->height-1);
  962.  
  963.     dc->SetPen(*wxBLACK_PEN);
  964.   }
  965. }
  966.  
  967. void wxGenericGrid::DrawCellValue(wxDC *dc, wxRect *rect, int row, int col)
  968. {
  969.   wxGridCell *cell = GetCell(row, col);
  970.   if (cell)
  971.   {
  972.     wxBitmap *bitmap = cell->GetCellBitmap();
  973.     wxRect rect2;
  974.     rect2 = *rect;
  975.     rect2.x += 3;
  976.     rect2.y += 2;
  977.     rect2.width -= 5;
  978.     rect2.height -= 4;
  979.  
  980.     if (bitmap)
  981.     {
  982.       DrawBitmapRect(dc, bitmap, &rect2, cell->GetAlignment());
  983.     }
  984.     else
  985.     {
  986.       dc->SetBackgroundMode(wxTRANSPARENT);
  987.       dc->SetTextForeground(cell->GetTextColour());
  988.       dc->SetFont(cell->GetFont());
  989.  
  990.           if ( !cell->GetTextValue().IsNull() )
  991.               DrawTextRect(dc, cell->GetTextValue(), &rect2, cell->GetAlignment());
  992.     }
  993.   }
  994. }
  995.  
  996. void wxGenericGrid::AdjustScrollbars()
  997. {
  998.   int cw, ch;
  999.   GetClientSize(&cw, &ch);
  1000.  
  1001.   // We find the view size by seeing how many rows/cols fit on
  1002.   // the current view.
  1003.   // BUT... this means that the scrollbar should be adjusted every time
  1004.   // it's scrolled, as well as when sized, because with variable size rows/cols,
  1005.   // the number of rows/col visible on the view differs according to what bit
  1006.   // you're looking at. The object length is always the same, but the
  1007.   // view length differs.
  1008.  
  1009.   // Since this may not be known until the end of this function, we should probably call AdjustScrollbars
  1010.   // twice.
  1011.   int vertScrollBarWidth = m_scrollWidth;
  1012.   int horizScrollBarHeight = m_scrollWidth;
  1013.   if (m_vScrollBar && !m_vScrollBar->IsShown())
  1014.     vertScrollBarWidth = 0;
  1015.   if (m_hScrollBar && !m_hScrollBar->IsShown())
  1016.     horizScrollBarHeight = 0;
  1017.  
  1018.   int noHorizSteps = 0;
  1019.   int noVertSteps = 0;
  1020.  
  1021.   if (m_totalGridWidth + vertScrollBarWidth > cw)
  1022.   {
  1023.     int widthCount = 0;
  1024.  
  1025.     int i;
  1026.     int nx = 0;
  1027.     for (i = m_scrollPosX ; i < m_totalCols; i++)
  1028.     {
  1029.       widthCount += m_colWidths[i];
  1030.       // A partial bit doesn't count, we still have to scroll to see the
  1031.       // rest of it
  1032.       if (widthCount + m_leftOfSheet + m_verticalLabelWidth > (cw-vertScrollBarWidth))
  1033.         break;
  1034.       else
  1035.            nx ++;
  1036.     }
  1037.  
  1038.     noHorizSteps += nx;
  1039.   }
  1040.   m_viewWidth = noHorizSteps;
  1041.  
  1042.   if (m_totalGridHeight + horizScrollBarHeight > ch)
  1043.   {
  1044.     int heightCount = 0;
  1045.  
  1046.     int i;
  1047.     int ny = 0;
  1048.     for (i = m_scrollPosY ; i < m_totalRows; i++)
  1049.     {
  1050.       heightCount += m_rowHeights[i];
  1051.       // A partial bit doesn't count, we still have to scroll to see the
  1052.       // rest of it
  1053.       if (heightCount + m_topOfSheet + m_horizontalLabelHeight > (ch-horizScrollBarHeight))
  1054.         break;
  1055.       else
  1056.         ny ++;
  1057.     }
  1058.  
  1059.     noVertSteps += ny;
  1060.   }
  1061.  
  1062.   m_viewHeight = noVertSteps;
  1063.  
  1064.   if (m_totalGridWidth + vertScrollBarWidth <= cw)
  1065.   {
  1066.     if ( m_hScrollBar )
  1067.         m_hScrollBar->Show(FALSE);
  1068.     SetScrollPosX(0);
  1069.   }
  1070.   else
  1071.   {
  1072.       if ( m_hScrollBar )
  1073.           m_hScrollBar->Show(TRUE);
  1074.   }
  1075.  
  1076.   if (m_totalGridHeight + horizScrollBarHeight <= ch)
  1077.   {
  1078.       if ( m_vScrollBar )
  1079.           m_vScrollBar->Show(FALSE);
  1080.       SetScrollPosY(0);
  1081.   }
  1082.   else
  1083.   {
  1084.       if ( m_vScrollBar )
  1085.           m_vScrollBar->Show(TRUE);
  1086.   }
  1087.  
  1088.   UpdateDimensions(); // Necessary in case m_scrollPosX/Y changed
  1089.  
  1090.   vertScrollBarWidth = m_scrollWidth;
  1091.   horizScrollBarHeight = m_scrollWidth;
  1092.   if (m_vScrollBar && !m_vScrollBar->IsShown())
  1093.     vertScrollBarWidth = 0;
  1094.   if (m_hScrollBar && !m_hScrollBar->IsShown())
  1095.     horizScrollBarHeight = 0;
  1096.  
  1097.   if (m_hScrollBar && m_hScrollBar->IsShown())
  1098.   {
  1099.     int nCols = GetCols();
  1100.     m_hScrollBar->SetScrollbar(m_hScrollBar->GetThumbPosition(), wxMax(noHorizSteps, 1), (noHorizSteps == 0) ? 1 : nCols, wxMax(noHorizSteps, 1));
  1101.  
  1102. /*
  1103.     m_hScrollBar->SetSize(m_leftOfSheet, ch - m_scrollWidth -2,   // why -2 ? Robert.
  1104.       cw - vertScrollBarWidth - m_leftOfSheet, m_scrollWidth);
  1105. */
  1106.     m_hScrollBar->SetSize(m_leftOfSheet, ch - m_scrollWidth,
  1107.       cw - vertScrollBarWidth - m_leftOfSheet, m_scrollWidth);
  1108.  
  1109.   }
  1110.  
  1111.   if (m_vScrollBar && m_vScrollBar->IsShown())
  1112.   {
  1113.     int nRows = GetRows();
  1114.  
  1115.     m_vScrollBar->SetScrollbar(m_vScrollBar->GetThumbPosition(), wxMax(noVertSteps, 1), (noVertSteps == 0) ? 1 : nRows, wxMax(noVertSteps, 1));
  1116.     m_vScrollBar->SetSize(cw - m_scrollWidth, m_topOfSheet,
  1117.        m_scrollWidth, ch - m_topOfSheet - horizScrollBarHeight);
  1118.   }
  1119. }
  1120.  
  1121. void wxGenericGrid::OnSize(wxSizeEvent& WXUNUSED(event) )
  1122. {
  1123.   if (!m_vScrollBar || !m_hScrollBar)
  1124.           return;
  1125.  
  1126.   AdjustScrollbars();
  1127.  
  1128.   int cw, ch;
  1129.   GetClientSize(&cw, &ch);
  1130.  
  1131.   if (m_editCreated && m_editingPanel && GetTextItem() && GetTextItem()->IsShown())
  1132.   {
  1133.     m_editingPanel->SetSize(0, 0, cw, m_editControlPosition.height + m_editControlPosition.y + 2);
  1134.     GetTextItem()->SetSize(m_editControlPosition.x, m_editControlPosition.y,
  1135.       cw - 2*m_editControlPosition.x, m_editControlPosition.height);
  1136.   }
  1137. }
  1138.  
  1139. bool wxGenericGrid::CellHitTest(int x, int y, int *row, int *col)
  1140. {
  1141.       // Find the selected cell and call OnSelectCell
  1142.       if (x >= (m_leftOfSheet + m_verticalLabelWidth) && y >= (m_topOfSheet + m_horizontalLabelHeight) &&
  1143.           x <= m_rightOfSheet && y <= m_bottomOfSheet)
  1144.       {
  1145.          // Calculate the cell number from x and y
  1146.          x -= (m_verticalLabelWidth + m_leftOfSheet);
  1147.          y -= (m_topOfSheet + m_horizontalLabelHeight);
  1148.  
  1149.          int i;
  1150.  
  1151.          // Now we need to do a hit test for which row we're on
  1152.          int currentHeight = 0;
  1153.          for (i = m_scrollPosY; i < m_totalRows; i++)
  1154.          {
  1155.             if (y >= currentHeight && y <= (currentHeight + m_rowHeights[i]))
  1156.             {
  1157.               *row = i;
  1158.               break;
  1159.             }
  1160.             currentHeight += m_rowHeights[i];
  1161.          }
  1162.  
  1163.          // Now we need to do a hit test for which column we're on
  1164.          int currentWidth = 0;
  1165.          for (i = m_scrollPosX; i < m_totalCols; i++)
  1166.          {
  1167.             if (x >= currentWidth && x <= (currentWidth + m_colWidths[i]))
  1168.             {
  1169.               *col = i;
  1170.               break;
  1171.             }
  1172.             currentWidth += m_colWidths[i];
  1173.          }
  1174.          return TRUE;
  1175.        }
  1176.   return FALSE;
  1177. }
  1178.  
  1179. bool wxGenericGrid::LabelSashHitTest(int x, int y, int *orientation, int *rowOrCol, int *startPos)
  1180. {
  1181.   int i;
  1182.   int tolerance = 3;
  1183.  
  1184.   if (x >= (m_leftOfSheet + m_verticalLabelWidth) && y >= m_topOfSheet &&
  1185.       x <= m_rightOfSheet && y <= (m_topOfSheet + m_horizontalLabelHeight))
  1186.   {
  1187.     // We may be on a column label sash.
  1188.     int currentWidth = m_leftOfSheet + m_verticalLabelWidth;
  1189.     for (i = m_scrollPosX; i < m_totalCols; i++)
  1190.     {
  1191.       if (x >= (currentWidth + m_colWidths[i] - tolerance) && x <= (currentWidth + m_colWidths[i] + tolerance))
  1192.       {
  1193.         *orientation = wxHORIZONTAL;
  1194.         *rowOrCol = i;
  1195.         *startPos = currentWidth;
  1196.         return TRUE;
  1197.       }
  1198.       currentWidth += m_colWidths[i];
  1199.     }
  1200.     return FALSE;
  1201.   }
  1202.   else if (x >= m_leftOfSheet && y >= (m_topOfSheet + m_horizontalLabelHeight) &&
  1203.       x <= (m_leftOfSheet + m_verticalLabelWidth) && y <= m_bottomOfSheet)
  1204.   {
  1205.     // We may be on a row label sash.
  1206.     int currentHeight = m_topOfSheet + m_horizontalLabelHeight;
  1207.     for (i = m_scrollPosY; i < m_totalRows; i++)
  1208.     {
  1209.       if (y >= (currentHeight + m_rowHeights[i] - tolerance) && y <= (currentHeight + m_rowHeights[i] + tolerance))
  1210.       {
  1211.         *orientation = wxVERTICAL;
  1212.         *rowOrCol = i;
  1213.         *startPos = currentHeight;
  1214.         return TRUE;
  1215.       }
  1216.       currentHeight += m_rowHeights[i];
  1217.     }
  1218.     return FALSE;
  1219.   }
  1220.   return FALSE;
  1221. }
  1222.  
  1223. bool wxGenericGrid::LabelHitTest(int x, int y, int *row, int *col)
  1224. {
  1225.       // Find the selected label
  1226.       if (x >= m_leftOfSheet && y >= m_topOfSheet &&
  1227.           x <= m_rightOfSheet && y <= m_bottomOfSheet)
  1228.       {
  1229.          // Calculate the cell number from x and y
  1230.          x -= m_leftOfSheet;
  1231.          y -= m_topOfSheet;
  1232.  
  1233.          int i;
  1234.  
  1235.          // Now we need to do a hit test for which row we're on
  1236.          int currentHeight = m_horizontalLabelHeight;
  1237.          for (i = m_scrollPosY; i < m_totalRows; i++)
  1238.          {
  1239.             if (y >= currentHeight && y <= (currentHeight + m_rowHeights[i]))
  1240.             {
  1241.               *row = i;
  1242.               break;
  1243.             }
  1244.             currentHeight += m_rowHeights[i];
  1245.          }
  1246.          if (y >= 0 && y <= m_horizontalLabelHeight)
  1247.          {
  1248.              *row = -1;
  1249.          }
  1250.  
  1251.          // Now we need to do a hit test for which column we're on
  1252.          int currentWidth = m_verticalLabelWidth;
  1253.          for (i = m_scrollPosX; i < m_totalCols; i++)
  1254.          {
  1255.             if (x >= currentWidth && x <= (currentWidth + m_colWidths[i]))
  1256.             {
  1257.               *col = i;
  1258.               break;
  1259.             }
  1260.             currentWidth += m_colWidths[i];
  1261.          }
  1262.          if (x >= 0 && x <= m_verticalLabelWidth)
  1263.          {
  1264.              *col = -1;
  1265.          }
  1266.  
  1267.          if ((*col == -1) || (*row == -1))
  1268.          {
  1269.              return TRUE;
  1270.          }
  1271.        }
  1272.   return FALSE;
  1273. }
  1274.  
  1275. void wxGenericGrid::OnMouseEvent(wxMouseEvent& ev)
  1276. {
  1277.   if (ev.LeftDown())
  1278.   {
  1279.     wxClientDC dc(this);
  1280.     dc.BeginDrawing();
  1281.  
  1282.     int row, col;
  1283.     if (CellHitTest((int)ev.GetX(), (int)ev.GetY(), &row, &col))
  1284.     {
  1285.       OnSelectCellImplementation(& dc, row, col);
  1286.  
  1287.       //OnCellLeftClick(row, col, (int)ev.GetX(), (int)ev.GetY(), ev.ControlDown(), ev.ShiftDown());
  1288.       wxGridEvent g_evt(GetId(), wxEVT_GRID_CELL_LCLICK, this,
  1289.                         row, col, (int)ev.GetX(), (int)ev.GetY(),
  1290.                         ev.ControlDown(), ev.ShiftDown());
  1291.       GetEventHandler()->ProcessEvent(g_evt);
  1292.  
  1293.     }
  1294.     if (LabelHitTest((int)ev.GetX(), (int)ev.GetY(), &row, &col))
  1295.     {
  1296.       //OnLabelLeftClick(row, col, (int)ev.GetX(), (int)ev.GetY(), ev.ControlDown(), ev.ShiftDown());
  1297.       wxGridEvent g_evt(GetId(), wxEVT_GRID_LABEL_LCLICK, this,
  1298.                         row, col, (int)ev.GetX(), (int)ev.GetY(),
  1299.                         ev.ControlDown(), ev.ShiftDown());
  1300.       GetEventHandler()->ProcessEvent(g_evt);
  1301.  
  1302.     }
  1303.     dc.EndDrawing();
  1304.   }
  1305.   else if (ev.Dragging() && ev.LeftIsDown())
  1306.   {
  1307.     switch (m_dragStatus)
  1308.     {
  1309.       case wxGRID_DRAG_NONE:
  1310.       {
  1311.         int orientation;
  1312.         if (LabelSashHitTest((int)ev.GetX(), (int)ev.GetY(), &orientation, &m_dragRowOrCol, &m_dragStartPosition))
  1313.         {
  1314.           if (orientation == wxHORIZONTAL)
  1315.           {
  1316.             m_dragStatus = wxGRID_DRAG_LEFT_RIGHT;
  1317.             SetCursor(m_horizontalSashCursor);
  1318.             m_dragLastPosition = (int)ev.GetX();
  1319.           }
  1320.           else
  1321.           {
  1322.             m_dragStatus = wxGRID_DRAG_UP_DOWN;
  1323.             SetCursor(m_verticalSashCursor);
  1324.             m_dragLastPosition = (int)ev.GetY();
  1325.           }
  1326.           wxClientDC dc(this);
  1327.           dc.BeginDrawing();
  1328.           dc.SetLogicalFunction(wxINVERT);
  1329.           if (orientation == wxHORIZONTAL)
  1330.             dc.DrawLine((int)ev.GetX(), m_topOfSheet, (int)ev.GetX(), m_bottomOfSheet);
  1331.           else
  1332.             dc.DrawLine(m_leftOfSheet, (int)ev.GetY(), m_rightOfSheet, (int)ev.GetY());
  1333.           dc.EndDrawing();
  1334.  
  1335.           CaptureMouse();
  1336.         }
  1337.         break;
  1338.       }
  1339.       case wxGRID_DRAG_LEFT_RIGHT:
  1340.       {
  1341.         wxClientDC dc(this);
  1342.         dc.BeginDrawing();
  1343.         dc.SetLogicalFunction(wxINVERT);
  1344.         dc.DrawLine(m_dragLastPosition, m_topOfSheet, m_dragLastPosition, m_bottomOfSheet);
  1345.  
  1346.         dc.DrawLine((int)ev.GetX(), m_topOfSheet, (int)ev.GetX(), m_bottomOfSheet);
  1347.         dc.EndDrawing();
  1348.  
  1349.         m_dragLastPosition = (int)ev.GetX();
  1350.         SetCursor(m_horizontalSashCursor);
  1351.         break;
  1352.       }
  1353.       case wxGRID_DRAG_UP_DOWN:
  1354.       {
  1355.         wxClientDC dc(this);
  1356.         dc.BeginDrawing();
  1357.         dc.SetLogicalFunction(wxINVERT);
  1358.         dc.DrawLine(m_leftOfSheet, m_dragLastPosition, m_rightOfSheet, m_dragLastPosition);
  1359.  
  1360.         dc.DrawLine(m_leftOfSheet, (int)ev.GetY(), m_rightOfSheet, (int)ev.GetY());
  1361.         dc.EndDrawing();
  1362.  
  1363.         m_dragLastPosition = (int)ev.GetY();
  1364.         SetCursor(m_verticalSashCursor);
  1365.         break;
  1366.       }
  1367.     }
  1368.   }
  1369.   else if (ev.Moving())
  1370.   {
  1371.     int rowOrCol, orientation, startPos;
  1372.     if (LabelSashHitTest((int)ev.GetX(), (int)ev.GetY(), &orientation, &rowOrCol, &startPos))
  1373.     {
  1374.       if (orientation == wxHORIZONTAL)
  1375.         SetCursor(m_horizontalSashCursor);
  1376.        else
  1377.         SetCursor(m_verticalSashCursor);
  1378.     }
  1379.     else
  1380.       SetCursor(*wxSTANDARD_CURSOR);
  1381.   }
  1382.   else if (ev.LeftUp())
  1383.   {
  1384.     switch (m_dragStatus)
  1385.     {
  1386.       case wxGRID_DRAG_LEFT_RIGHT:
  1387.       {
  1388.         wxClientDC dc(this);
  1389.         dc.BeginDrawing();
  1390.         dc.SetLogicalFunction(wxINVERT);
  1391.         dc.DrawLine(m_dragLastPosition, m_topOfSheet, m_dragLastPosition, m_bottomOfSheet);
  1392.         dc.SetLogicalFunction(wxCOPY);
  1393.         dc.EndDrawing();
  1394.  
  1395.         ReleaseMouse();
  1396.         if (ev.GetX() > m_dragStartPosition)
  1397.         {
  1398.           m_colWidths[m_dragRowOrCol] = (short)(ev.GetX() - m_dragStartPosition);
  1399.           UpdateDimensions();
  1400.           AdjustScrollbars();
  1401.           Refresh();
  1402.         }
  1403.         SetCursor(*wxSTANDARD_CURSOR);
  1404.         int cw, ch;
  1405.         GetClientSize(&cw, &ch);
  1406.                 wxSizeEvent evt;
  1407.         OnSize(evt);
  1408.         break;
  1409.       }
  1410.       case wxGRID_DRAG_UP_DOWN:
  1411.       {
  1412.         wxClientDC dc(this);
  1413.         dc.BeginDrawing();
  1414.         dc.SetLogicalFunction(wxINVERT);
  1415.         dc.DrawLine(m_leftOfSheet, m_dragLastPosition, m_rightOfSheet, m_dragLastPosition);
  1416.         dc.SetLogicalFunction(wxCOPY);
  1417.         dc.EndDrawing();
  1418.  
  1419.         ReleaseMouse();
  1420.         if (ev.GetY() > m_dragStartPosition)
  1421.         {
  1422.           m_rowHeights[m_dragRowOrCol] = (short)(ev.GetY() - m_dragStartPosition);
  1423.           UpdateDimensions();
  1424.           AdjustScrollbars();
  1425.           Refresh();
  1426.         }
  1427.         SetCursor(*wxSTANDARD_CURSOR);
  1428.         break;
  1429.       }
  1430.     }
  1431.     m_dragStatus = wxGRID_DRAG_NONE;
  1432.   }
  1433.   else if (ev.RightDown())
  1434.   {
  1435.     int row, col;
  1436.     if (CellHitTest((int)ev.GetX(), (int)ev.GetY(), &row, &col))
  1437.     {
  1438.       //OnCellRightClick(row, col, (int)ev.GetX(), (int)ev.GetY(), ev.ControlDown(), ev.ShiftDown());
  1439.       wxGridEvent g_evt(GetId(), wxEVT_GRID_CELL_RCLICK, this,
  1440.                         row, col, (int)ev.GetX(), (int)ev.GetY(),
  1441.                         ev.ControlDown(), ev.ShiftDown());
  1442.       GetEventHandler()->ProcessEvent(g_evt);
  1443.  
  1444.     }
  1445.     if (LabelHitTest((int)ev.GetX(), (int)ev.GetY(), &row, &col))
  1446.     {
  1447.       //OnLabelRightClick(row, col, (int)ev.GetX(), (int)ev.GetY(), ev.ControlDown(), ev.ShiftDown());
  1448.       wxGridEvent g_evt(GetId(), wxEVT_GRID_LABEL_RCLICK, this,
  1449.                         row, col, (int)ev.GetX(), (int)ev.GetY(),
  1450.                         ev.ControlDown(), ev.ShiftDown());
  1451.       GetEventHandler()->ProcessEvent(g_evt);
  1452.     }
  1453.   }
  1454. }
  1455.  
  1456. void wxGenericGrid::OnSelectCellImplementation(wxDC *dc, int row, int col)
  1457. {
  1458.   m_wCursorColumn = col;
  1459.   m_wCursorRow = row;
  1460.  
  1461.   //OnChangeSelectionLabel();
  1462.   wxGridEvent g_evt(GetId(), wxEVT_GRID_CHANGE_SEL_LABEL, this);
  1463.   GetEventHandler()->ProcessEvent(g_evt);
  1464.  
  1465.   SetGridClippingRegion(dc);
  1466.  
  1467.   // Remove the highlight from the old cell
  1468.   if ( m_currentRectVisible && (wxIPE_HIGHLIGHT || !(m_editable && m_editInPlace)))
  1469.     {
  1470.       HighlightCell(dc, FALSE);
  1471.     }
  1472.  
  1473.  
  1474.   // Highlight the new cell and copy its content to the edit control
  1475.   SetCurrentRect(m_wCursorRow, m_wCursorColumn);
  1476.   wxGridCell *cell = GetCell(m_wCursorRow, m_wCursorColumn);
  1477.   if (cell)
  1478.   {
  1479.         if ( cell->GetTextValue().IsNull() )
  1480.                 m_textItem->SetValue(wxT(""));
  1481.         else
  1482.             m_textItem->SetValue(cell->GetTextValue());
  1483.   }
  1484.  
  1485.   SetGridClippingRegion(dc);
  1486.  
  1487.  
  1488.   if ( m_editable && m_editInPlace )
  1489.     {
  1490.       int x, y, width, height;
  1491.       if ( m_currentRect.x <= 0 )
  1492.         {
  1493.           x = 0;
  1494.           width = m_currentRect.width + wxIPE_ADJUST;
  1495.         }
  1496.       else
  1497.         {
  1498.           x = m_currentRect.x - wxIPE_ADJUST;
  1499.           width = m_currentRect.width + wxIPE_ADJUST*2;
  1500.         }
  1501.  
  1502.       if ( m_currentRect.y <= 0 )
  1503.         {
  1504.           y = 0;
  1505.           height = m_currentRect.height + wxIPE_ADJUST;
  1506.         }
  1507.       else
  1508.         {
  1509.           y = m_currentRect.y - wxIPE_ADJUST;
  1510.           height = m_currentRect.height + wxIPE_ADJUST*2;
  1511.         }
  1512.  
  1513.       m_inPlaceTextItem->SetSize( x, y, width, height );
  1514.  
  1515.       if ( cell ) {
  1516.           m_inPlaceTextItem->SetFont( cell->GetFont() );
  1517.           m_inPlaceTextItem->SetBackgroundColour(cell->GetBackgroundColour());
  1518.           m_inPlaceTextItem->SetForegroundColour(cell->GetTextColour());
  1519.  
  1520.           if ( cell->GetTextValue().IsNull() ) {
  1521.               m_inPlaceTextItem->SetValue( wxT("") );
  1522.           }
  1523.           else {
  1524.               m_inPlaceTextItem->SetValue( cell->GetTextValue() );
  1525.           }
  1526.       }
  1527.  
  1528.       m_inPlaceTextItem->Show(TRUE);
  1529.       m_inPlaceTextItem->SetFocus();
  1530. #if defined(__VISAGECPP__)
  1531.       {
  1532.           int                       highlight = wxIPE_HIGHLIGHT;
  1533.           if (highlight != 0)
  1534.               HighlightCell(dc, TRUE);
  1535.       }
  1536. #else
  1537.       if (wxIPE_HIGHLIGHT != 0)
  1538.           HighlightCell(dc, TRUE);
  1539. #endif
  1540.     }
  1541.   else if (!wxIPE_HIGHLIGHT)
  1542.     {
  1543.       // 1) Why isn't this needed for Windows??
  1544.       // Probably because of the SetValue?? JS.
  1545.       // 2) Arrrrrgh. This isn't needed anywhere,
  1546.       // of course. One hour of debugging... RR.
  1547.       //
  1548.       // 3) It *is* needed for Motif - michael
  1549.       //
  1550.       // 4) It *seems* to be needed whenever
  1551.       //    wxIPE_HIGHLIGHT is not set (i.e.
  1552.       //    for both wxGTK and wxMOTIF)... SN.
  1553.       if (!(m_editable && m_editInPlace)))
  1554.           HighlightCell(dc, TRUE);
  1555.     }
  1556.  
  1557.   dc->DestroyClippingRegion();
  1558.  
  1559.   OnSelectCell(row, col);
  1560.   wxGridEvent g_evt2(GetId(), wxEVT_GRID_SELECT_CELL, this, row, col);
  1561.   GetEventHandler()->ProcessEvent(g_evt2);
  1562. }
  1563.  
  1564. wxGridCell *wxGenericGrid::OnCreateCell()
  1565. {
  1566.   return new wxGridCell(this);
  1567. }
  1568.  
  1569. void wxGenericGrid::OnChangeLabels()
  1570. {
  1571.   char buf[100];
  1572.   int i;
  1573.   for (i = 0; i < m_totalRows; i++)
  1574.   {
  1575.     sprintf(buf, wxT("%d"), i+1);
  1576.     SetLabelValue(wxVERTICAL, buf, i);
  1577.   }
  1578.   // A...Z,AA...ZZ,AAA...ZZZ, etc.
  1579.   for (i = 0; i < m_totalCols; i++)
  1580.   {
  1581.     int j;
  1582.     int noTimes = (i/26 + 1);
  1583.     int ch = (i % 26) + 65;
  1584.     buf[0] = 0;
  1585.     for (j = 0; j < noTimes; j++)
  1586.     {
  1587.       char buf2[20];
  1588.       sprintf(buf2, wxT("%c"), (char)ch);
  1589.       strcat(buf, buf2);
  1590.     }
  1591.     SetLabelValue(wxHORIZONTAL, buf, i);
  1592.   }
  1593. }
  1594.  
  1595. void wxGenericGrid::OnChangeSelectionLabel()
  1596. {
  1597.   if (!GetEditable())
  1598.     return;
  1599.  
  1600.   wxString rowLabel(GetLabelValue(wxVERTICAL, GetCursorRow()));
  1601.   wxString colLabel(GetLabelValue(wxHORIZONTAL, GetCursorColumn()));
  1602.  
  1603.   wxString newLabel = colLabel + rowLabel;
  1604.   if ((newLabel.Length() > 0) && (newLabel.Length() <= 8) && GetTextItem())
  1605.   {
  1606. //    GetTextItem()->SetLabel(newLabel);
  1607.   }
  1608. }
  1609.  
  1610. void wxGenericGrid::HighlightCell(wxDC *dc, bool doHighlight)
  1611. {
  1612.   wxPen savePen = dc->GetPen();
  1613.   if (doHighlight)
  1614.       dc->SetPen(m_highlightPen);
  1615.   else
  1616.       dc->SetPen(*wxThePenList->FindOrCreatePen(m_cellBackgroundColour, 1, wxSOLID));
  1617.  
  1618.   // Top
  1619.   dc->DrawLine( m_currentRect.x + 1,
  1620.                 m_currentRect.y + 1,
  1621.                 m_currentRect.x + m_currentRect.width - 1,
  1622.                 m_currentRect.y + 1);
  1623.   // Right
  1624.   dc->DrawLine( m_currentRect.x + m_currentRect.width - 1,
  1625.                 m_currentRect.y + 1,
  1626.                 m_currentRect.x + m_currentRect.width - 1,
  1627.                 m_currentRect.y + m_currentRect.height - 1 );
  1628.   // Bottom
  1629.   dc->DrawLine( m_currentRect.x + m_currentRect.width - 1,
  1630.                 m_currentRect.y + m_currentRect.height - 1,
  1631.                 m_currentRect.x + 1,
  1632.                 m_currentRect.y + m_currentRect.height - 1);
  1633.   // Left
  1634.   dc->DrawLine( m_currentRect.x + 1,
  1635.                 m_currentRect.y + m_currentRect.height - 1,
  1636.                 m_currentRect.x + 1,
  1637.                 m_currentRect.y + 1);
  1638.  
  1639.   dc->SetPen(savePen);
  1640. }
  1641.  
  1642. void wxGenericGrid::DrawCellText()
  1643. {
  1644.   if (!m_currentRectVisible)
  1645.     return;
  1646.  
  1647.   wxGridCell *cell = GetCell(GetCursorRow(), GetCursorColumn());
  1648.   if (!cell)
  1649.     return;
  1650.  
  1651.   wxClientDC dc(this);
  1652.   dc.BeginDrawing();
  1653.  
  1654.   SetGridClippingRegion(& dc);
  1655.  
  1656.   dc.SetBackgroundMode(wxTRANSPARENT);
  1657.   dc.SetBrush(cell->GetBackgroundBrush());
  1658.  
  1659.   wxString editValue = m_textItem->GetValue();
  1660.  
  1661.   wxRect rect;
  1662.   rect = m_currentRect;
  1663.   rect.x += 3;
  1664.   rect.y += 2;
  1665.   rect.width -= 5;
  1666.   rect.height -= 4;
  1667.  
  1668.   // FIXME: what's this string of spaces supposed to represent?
  1669.   DrawTextRect(& dc, wxT("                                    "), &rect, wxLEFT);
  1670.   DrawTextRect(& dc, editValue, &rect, cell->GetAlignment());
  1671.  
  1672.   dc.DestroyClippingRegion();
  1673.  
  1674.   dc.SetBackgroundMode(wxSOLID);
  1675.  
  1676.   dc.EndDrawing();
  1677. }
  1678.  
  1679. void wxGenericGrid::SetCurrentRect(int Row, int Column, int canvasW, int canvasH)
  1680. {
  1681.   int currentWidth = m_leftOfSheet + m_verticalLabelWidth;
  1682.   int i;
  1683.   for (i = m_scrollPosX; i < Column; i++)
  1684.     currentWidth += m_colWidths[i];
  1685.  
  1686.   int currentHeight = m_topOfSheet + m_horizontalLabelHeight;
  1687.   for (i = m_scrollPosY; i < Row; i++)
  1688.     currentHeight += m_rowHeights[i];
  1689.  
  1690.   m_currentRect.x = currentWidth;
  1691.   m_currentRect.y = currentHeight;
  1692.   m_currentRect.width = m_colWidths ? (m_colWidths[Column]) : 0;
  1693.   m_currentRect.height = m_rowHeights ? (m_rowHeights[Row]) : 0;
  1694.  
  1695.   if (Row < m_scrollPosY || Column < m_scrollPosX)
  1696.     m_currentRectVisible = FALSE;
  1697.   else if ((canvasW != -1 && canvasH != -1) && (m_currentRect.x > canvasW || m_currentRect.y > canvasH))
  1698.     m_currentRectVisible = FALSE;
  1699.   else m_currentRectVisible = TRUE;
  1700. }
  1701.  
  1702. static bool wxRectIntersection(wxRect *rect1, wxRect *rect2, wxRect *rect3)
  1703. {
  1704.   int x2_1 = rect1->x + rect1->width;
  1705.   int y2_1 = rect1->y + rect1->height;
  1706.  
  1707.   int x2_2 = rect2->x + rect2->width;
  1708.   int y2_2 = rect2->y + rect2->height;
  1709.  
  1710.   int x2_3, y2_3;
  1711.  
  1712.   // Check for intersection
  1713.   if ((rect1->x > x2_2) || (rect2->x > x2_1) ||
  1714.       (rect1->y > y2_2) || (rect2->y > y2_1))
  1715.   {
  1716.     // No intersection
  1717.     rect3->x = rect3->y = rect3->width = rect3->height = 0;
  1718.     return FALSE;
  1719.   }
  1720.  
  1721.   if (rect1->x > rect2->x)
  1722.     rect3->x = rect1->x;
  1723.   else
  1724.     rect3->x = rect2->x;
  1725.   if (rect1->y > rect2->y)
  1726.     rect3->y = rect1->y;
  1727.   else
  1728.     rect3->y = rect2->y;
  1729.  
  1730.   if (x2_1 > x2_2)
  1731.     x2_3 = x2_2;
  1732.   else
  1733.     x2_3 = x2_1;
  1734.   if (y2_1 > y2_2)
  1735.     y2_3 = y2_2;
  1736.   else
  1737.     y2_3 = y2_1;
  1738.  
  1739.   rect3->width = (int)(x2_3 - rect3->x);
  1740.   rect3->height = (int)(y2_3 - rect3->y);
  1741.   return TRUE;
  1742. }
  1743.  
  1744. void wxGenericGrid::DrawTextRect(wxDC *dc, const wxString& text, wxRect *rect, int flag)
  1745. {
  1746.   dc->BeginDrawing();
  1747.  
  1748.   // Ultimately, this functionality should be built into wxWindows,
  1749.   // and optimized for each platform. E.g. on Windows, use DrawText
  1750.   // passing a clipping rectangle, so that the wxWindows clipping region
  1751.   // does not have to be used to implement this.
  1752.  
  1753.   // If we're already clipping, we need to find the intersection
  1754.   // between current clipping area and text clipping area.
  1755.  
  1756.   wxRect clipRect;
  1757.   wxRect clipRect2;
  1758.   long clipX, clipY, clipW, clipH;
  1759.   dc->GetClippingBox(&clipX, &clipY, &clipW, &clipH);
  1760.   clipRect.x = (int)clipX; clipRect.y = (int)clipY;
  1761.   clipRect.width = (int)clipW; clipRect.height = (int)clipH;
  1762.  
  1763.   bool alreadyClipping = TRUE;
  1764.  
  1765.   if (clipRect.x == 0 && clipRect.y == 0 && clipRect.width == 0 && clipRect.height == 0)
  1766.   {
  1767.     alreadyClipping = FALSE;
  1768.     clipRect2.x = rect->x; clipRect2.y = rect->y;
  1769.     clipRect2.width = rect->width; clipRect2.height = rect->height;
  1770.   }
  1771.   else
  1772.   {
  1773.     // Find intersection.
  1774.     if (!wxRectIntersection(rect, &clipRect, &clipRect2))
  1775.       return;
  1776.   }
  1777.  
  1778.   if (alreadyClipping)
  1779.     dc->DestroyClippingRegion();
  1780.  
  1781.   dc->SetClippingRegion(clipRect2.x, clipRect2.y, clipRect2.width, clipRect2.height);
  1782.   long textWidth, textHeight;
  1783.  
  1784.   dc->GetTextExtent(text, &textWidth, &textHeight);
  1785.  
  1786.   // Do alignment
  1787.   float x,y;
  1788.   switch (flag)
  1789.   {
  1790.     case wxRIGHT:
  1791.     {
  1792.       x = (rect->x + rect->width - textWidth - (float)1.0);
  1793.       y = (rect->y + (rect->height - textHeight)/(float)2.0);
  1794.       break;
  1795.     }
  1796.     case wxCENTRE:
  1797.     {
  1798.       x = (rect->x + (rect->width - textWidth)/(float)2.0);
  1799.       y = (rect->y + (rect->height - textHeight)/(float)2.0);
  1800.       break;
  1801.     }
  1802.     case wxLEFT:
  1803.     default:
  1804.     {
  1805.       x = (rect->x + (float)1.0);
  1806.       y = (rect->y + (rect->height - textHeight)/(float)2.0);
  1807.       break;
  1808.     }
  1809.   }
  1810.   dc->DrawText(text, (long)x, (long)y );
  1811.  
  1812.   dc->DestroyClippingRegion();
  1813.  
  1814.   // Restore old clipping
  1815.   if (alreadyClipping)
  1816.     dc->SetClippingRegion(clipRect.x, clipRect.y, clipRect.width, clipRect.height);
  1817.  
  1818.   dc->EndDrawing();
  1819. }
  1820.  
  1821. void wxGenericGrid::DrawBitmapRect(wxDC *dc, wxBitmap *bitmap, wxRect *rect, int flag)
  1822. {
  1823.   dc->BeginDrawing();
  1824.  
  1825.   // Ultimately, this functionality should be built into wxWindows,
  1826.   // and optimized for each platform. E.g. on Windows, use DrawText
  1827.   // passing a clipping rectangle, so that the wxWindows clipping region
  1828.   // does not have to be used to implement this.
  1829.  
  1830.   // If we're already clipping, we need to find the intersection
  1831.   // between current clipping area and text clipping area.
  1832.  
  1833.   wxRect clipRect;
  1834.   wxRect clipRect2;
  1835.   long clipX, clipY, clipW, clipH;
  1836.   dc->GetClippingBox(&clipX, &clipY, &clipW, &clipH);
  1837.   clipRect.x = (int)clipX; clipRect.y = (int)clipY;
  1838.   clipRect.width = (int)clipW; clipRect.height = (int)clipH;
  1839.  
  1840.   bool alreadyClipping = TRUE;
  1841.  
  1842.   if (clipRect.x == 0 && clipRect.y == 0 && clipRect.width == 0 && clipRect.height == 0)
  1843.   {
  1844.     alreadyClipping = FALSE;
  1845.     clipRect2.x = rect->x; clipRect2.y = rect->y;
  1846.     clipRect2.width = rect->width; clipRect2.height = rect->height;
  1847.   }
  1848.   else
  1849.   {
  1850.     // Find intersection.
  1851.     if (!wxRectIntersection(rect, &clipRect, &clipRect2))
  1852.       return;
  1853.   }
  1854.  
  1855.   if (alreadyClipping)
  1856.     dc->DestroyClippingRegion();
  1857.  
  1858.   dc->SetClippingRegion(clipRect2.x, clipRect2.y, clipRect2.width, clipRect2.height);
  1859.   float bitmapWidth, bitmapHeight;
  1860.  
  1861.   bitmapWidth = bitmap->GetWidth();
  1862.   bitmapHeight = bitmap->GetHeight();
  1863.  
  1864.   // Do alignment
  1865.   long x,y;
  1866.   switch (flag)
  1867.   {
  1868.     case wxRIGHT:
  1869.     {
  1870.       x = (long)(rect->x + rect->width - bitmapWidth - 1);
  1871.       y = (long)(rect->y + (rect->height - bitmapHeight)/2.0);
  1872.       break;
  1873.     }
  1874.     case wxCENTRE:
  1875.     {
  1876.       x = (long)(rect->x + (rect->width - bitmapWidth)/2.0);
  1877.       y = (long)(rect->y + (rect->height - bitmapHeight)/2.0);
  1878.       break;
  1879.     }
  1880.     case wxLEFT:
  1881.     default:
  1882.     {
  1883.       x = (long)(rect->x + 1);
  1884.       y = (long)(rect->y + (rect->height - bitmapHeight)/2.0);
  1885.       break;
  1886.     }
  1887.   }
  1888.   wxMemoryDC dcTemp;
  1889.   dcTemp.SelectObject(*bitmap);
  1890.  
  1891.   dc->Blit( (long)x, (long)y, (long)bitmapWidth, (long)bitmapHeight, &dcTemp, 0, 0);
  1892.   dcTemp.SelectObject(wxNullBitmap);
  1893.  
  1894.   dc->DestroyClippingRegion();
  1895.  
  1896.   // Restore old clipping
  1897.   if (alreadyClipping)
  1898.     dc->SetClippingRegion(clipRect.x, clipRect.y, clipRect.width, clipRect.height);
  1899.  
  1900.   dc->EndDrawing();
  1901. }
  1902.  
  1903. void wxGenericGrid::OnActivate(bool active)
  1904. {
  1905.   if (active)
  1906.   {
  1907.     // Edit control should always have the focus
  1908.     if (GetTextItem() && GetEditable())
  1909.     {
  1910.       GetTextItem()->SetFocus();
  1911.       wxGridCell *cell = GetCell(GetCursorRow(), GetCursorColumn());
  1912.       if (cell)
  1913.         GetTextItem()->SetValue(cell->GetTextValue());
  1914.     }
  1915.   }
  1916. }
  1917.  
  1918. void wxGenericGrid::SetCellValue(const wxString& val, int row, int col)
  1919. {
  1920.   wxGridCell *cell = GetCell(row, col);
  1921.   if (cell)
  1922.   {
  1923.     cell->SetTextValue(val);
  1924.  
  1925.     RefreshCell(row, col, TRUE);
  1926.   }
  1927. }
  1928.  
  1929. void wxGenericGrid::RefreshCell(int row, int col, bool setText)
  1930. {
  1931.     // Don't refresh within a pair of batch brackets
  1932.     if (GetBatchCount() > 0)
  1933.         return;
  1934.  
  1935.     int cw, ch;
  1936.     GetClientSize(&cw, &ch);
  1937.  
  1938.     SetCurrentRect(row, col, cw, ch);
  1939.     if (m_currentRectVisible)
  1940.     {
  1941.       wxGridCell *cell = GetCell(row, col);
  1942.  
  1943.       bool currentPos = FALSE;
  1944.       if (row == m_wCursorRow && col == m_wCursorColumn && GetTextItem() && GetTextItem()->IsShown() && setText)
  1945.       {
  1946.         GetTextItem()->SetValue(cell->GetTextValue());
  1947.         currentPos = TRUE;
  1948.       }
  1949.       // Gets refreshed anyway in MSW
  1950. #ifdef __WXMSW__
  1951.       if (!currentPos)
  1952. #endif
  1953.       {
  1954.         wxClientDC dc(this);
  1955.         dc.BeginDrawing();
  1956.         DrawCellBackground(& dc, &m_currentRect, row, col);
  1957.         DrawCellValue(& dc, &m_currentRect, row, col);
  1958.         dc.EndDrawing();
  1959.       }
  1960.     }
  1961. }
  1962.  
  1963. wxString& wxGenericGrid::GetCellValue(int row, int col) const
  1964. {
  1965.   static wxString emptyString(wxT(""));
  1966.  
  1967.   wxGridCell *cell = GetCell(row, col);
  1968.   if (cell)
  1969.     return cell->GetTextValue();
  1970.   else
  1971.     return emptyString;
  1972. }
  1973.  
  1974. void wxGenericGrid::SetColumnWidth(int col, int width)
  1975. {
  1976.   if (col <= m_totalCols)
  1977.     m_colWidths[col] = width;
  1978. }
  1979.  
  1980. int wxGenericGrid::GetColumnWidth(int col) const
  1981. {
  1982.   if (col <= m_totalCols)
  1983.     return m_colWidths[col];
  1984.   else
  1985.     return 0;
  1986. }
  1987.  
  1988. void wxGenericGrid::SetRowHeight(int row, int height)
  1989. {
  1990.   if (row <= m_totalRows)
  1991.     m_rowHeights[row] = height;
  1992. }
  1993.  
  1994. int wxGenericGrid::GetRowHeight(int row) const
  1995. {
  1996.   if (row <= m_totalRows)
  1997.     return m_rowHeights[row];
  1998.   else
  1999.     return 0;
  2000. }
  2001.  
  2002. void wxGenericGrid::SetLabelSize(int orientation, int sz)
  2003. {
  2004.   if (orientation == wxHORIZONTAL)
  2005.     m_horizontalLabelHeight = sz;
  2006.   else
  2007.     m_verticalLabelWidth = sz;
  2008.   UpdateDimensions();
  2009.   SetCurrentRect(GetCursorRow(), GetCursorColumn());
  2010. }
  2011.  
  2012. int wxGenericGrid::GetLabelSize(int orientation) const
  2013. {
  2014.   if (orientation == wxHORIZONTAL)
  2015.     return m_horizontalLabelHeight;
  2016.   else
  2017.     return m_verticalLabelWidth;
  2018. }
  2019.  
  2020. wxGridCell *wxGenericGrid::GetLabelCell(int orientation, int pos) const
  2021. {
  2022.   if (orientation == wxHORIZONTAL)
  2023.   {
  2024.     if (m_colLabelCells && pos < m_totalCols)
  2025.       return m_colLabelCells[pos];
  2026.     else
  2027.       return (wxGridCell *) NULL;
  2028.   }
  2029.   else
  2030.   {
  2031.     if (m_rowLabelCells && pos < m_totalRows)
  2032.       return m_rowLabelCells[pos];
  2033.     else
  2034.       return (wxGridCell *) NULL;
  2035.   }
  2036. }
  2037.  
  2038. void wxGenericGrid::SetLabelValue(int orientation, const wxString& val, int pos)
  2039. {
  2040.   wxGridCell *cell = GetLabelCell(orientation, pos);
  2041.   if (cell)
  2042.     cell->SetTextValue(val);
  2043. }
  2044.  
  2045. wxString& wxGenericGrid::GetLabelValue(int orientation, int pos) const
  2046. {
  2047.   static wxString emptyString = wxT("");
  2048.   wxGridCell *cell = GetLabelCell(orientation, pos);
  2049.   if (cell)
  2050.     return cell->GetTextValue();
  2051.   else
  2052.     return emptyString;
  2053. }
  2054.  
  2055. void wxGenericGrid::SetLabelAlignment(int orientation, int align)
  2056. {
  2057.   if (orientation == wxHORIZONTAL)
  2058.     m_horizontalLabelAlignment = align;
  2059.   else
  2060.     m_verticalLabelAlignment = align;
  2061.   UpdateDimensions();
  2062.   SetCurrentRect(GetCursorRow(), GetCursorColumn());
  2063. }
  2064.  
  2065. int wxGenericGrid::GetLabelAlignment(int orientation) const
  2066. {
  2067.   if (orientation == wxHORIZONTAL)
  2068.     return m_horizontalLabelAlignment;
  2069.   else
  2070.     return m_verticalLabelAlignment;
  2071. }
  2072.  
  2073. void wxGenericGrid::SetLabelTextColour(const wxColour& colour)
  2074. {
  2075.   m_labelTextColour = colour;
  2076.  
  2077. }
  2078.  
  2079. void wxGenericGrid::SetLabelBackgroundColour(const wxColour& colour)
  2080. {
  2081.   m_labelBackgroundColour = colour;
  2082.   m_labelBackgroundBrush = * wxTheBrushList->FindOrCreateBrush(m_labelBackgroundColour, wxSOLID);
  2083. }
  2084.  
  2085. void wxGenericGrid::SetEditable(bool edit)
  2086. {
  2087.   m_editable = edit;
  2088.   if (edit)
  2089.   {
  2090.     int controlW, controlH;
  2091.     m_textItem->GetSize(&controlW, &controlH);
  2092.     m_editControlPosition.height = controlH;
  2093.  
  2094.     m_topOfSheet = m_editControlPosition.x + controlH + 2;
  2095.     if (m_textItem)
  2096.     {
  2097.       m_editingPanel->Show(TRUE);
  2098.       m_textItem->Show(TRUE);
  2099.       m_textItem->SetFocus();
  2100.     }
  2101.  
  2102.     if (m_inPlaceTextItem)
  2103.       {
  2104.         m_inPlaceTextItem->Show(TRUE);
  2105.         m_inPlaceTextItem->SetFocus();
  2106.       }
  2107.   }
  2108.   else
  2109.   {
  2110.     m_topOfSheet = 0;
  2111.     if (m_textItem)
  2112.     {
  2113.       m_textItem->Show(FALSE);
  2114.       m_editingPanel->Show(FALSE);
  2115.     }
  2116.  
  2117.     if ( m_inPlaceTextItem )
  2118.       {
  2119.         m_inPlaceTextItem->Show(FALSE);
  2120.       }
  2121.   }
  2122.   UpdateDimensions();
  2123.   SetCurrentRect(GetCursorRow(), GetCursorColumn());
  2124.  
  2125.   int cw, ch;
  2126.   GetClientSize(&cw, &ch);
  2127.   wxSizeEvent evt;
  2128.   OnSize(evt);
  2129. /*
  2130.   int cw, ch;
  2131.   int m_scrollWidth = 16;
  2132.   GetClientSize(&cw, &ch);
  2133.  
  2134.   if (m_vScrollBar)
  2135.     m_vScrollBar->SetSize(cw - m_scrollWidth, m_topOfSheet,
  2136.        m_scrollWidth, ch - m_topOfSheet - m_scrollWidth);
  2137. */
  2138. }
  2139.  
  2140.  
  2141. void wxGenericGrid::SetEditInPlace(bool edit)
  2142. {
  2143.   if ( m_editInPlace != edit )
  2144.     {
  2145.       m_editInPlace = edit;
  2146.  
  2147.       if ( m_editInPlace )  // switched on
  2148.         {
  2149.           if ( m_currentRectVisible && m_editable )
  2150.             {
  2151.               m_inPlaceTextItem->SetSize( m_currentRect.x-wxIPE_ADJUST,
  2152.                                           m_currentRect.y-wxIPE_ADJUST,
  2153.                                           m_currentRect.width+wxIPE_ADJUST*2,
  2154.                                           m_currentRect.height+wxIPE_ADJUST*2 );
  2155.  
  2156.               wxGridCell *cell = GetCell(m_wCursorRow, m_wCursorColumn);
  2157.  
  2158.               if ( cell ) {
  2159.                   m_inPlaceTextItem->SetFont( cell->GetFont() );
  2160.                   m_inPlaceTextItem->SetBackgroundColour(cell->GetBackgroundColour());
  2161.                   m_inPlaceTextItem->SetForegroundColour(cell->GetTextColour());
  2162.  
  2163.                   if ( cell->GetTextValue().IsNull() ) {
  2164.                       m_inPlaceTextItem->SetValue( wxT("") );
  2165.                   }
  2166.                   else {
  2167.                       m_inPlaceTextItem->SetValue( cell->GetTextValue() );
  2168.                   }
  2169.               }
  2170.  
  2171.               m_inPlaceTextItem->Show( TRUE );
  2172.               m_inPlaceTextItem->SetFocus();
  2173.             }
  2174.         }
  2175.       else  // switched off
  2176.         {
  2177.           m_inPlaceTextItem->Show( FALSE );
  2178.         }
  2179.     }
  2180. }
  2181.  
  2182.  
  2183. void wxGenericGrid::SetCellAlignment(int flag, int row, int col)
  2184. {
  2185.   wxGridCell *cell = GetCell(row, col);
  2186.   if (cell)
  2187.     cell->SetAlignment(flag);
  2188. }
  2189.  
  2190. int wxGenericGrid::GetCellAlignment(int row, int col) const
  2191. {
  2192.   wxGridCell *cell = GetCell(row, col);
  2193.   if (cell)
  2194.     return cell->GetAlignment();
  2195.   else
  2196.     return m_cellAlignment;
  2197. }
  2198.  
  2199. void wxGenericGrid::SetCellAlignment(int flag)
  2200. {
  2201.   m_cellAlignment = flag;
  2202.   int i,j;
  2203.   for (i = 0; i < GetRows(); i++)
  2204.     for (j = 0; j < GetCols(); j++)
  2205.       if (GetCell(i, j))
  2206.         GetCell(i, j)->SetAlignment(flag);
  2207. }
  2208.  
  2209. int wxGenericGrid::GetCellAlignment(void) const
  2210. {
  2211.   return m_cellAlignment;
  2212. }
  2213.  
  2214. void wxGenericGrid::SetCellBackgroundColour(const wxColour& col)
  2215. {
  2216.   m_cellBackgroundColour = col;
  2217.   int i,j;
  2218.   for (i = 0; i < GetRows(); i++)
  2219.     for (j = 0; j < GetCols(); j++)
  2220.       if (GetCell(i, j))
  2221.         GetCell(i, j)->SetBackgroundColour(col);
  2222. }
  2223.  
  2224. void wxGenericGrid::SetCellBackgroundColour(const wxColour& val, int row, int col)
  2225. {
  2226.   wxGridCell *cell = GetCell(row, col);
  2227.   if (cell)
  2228.   {
  2229.     cell->SetBackgroundColour(val);
  2230.     RefreshCell(row, col);
  2231.   }
  2232. }
  2233.  
  2234. wxColour& wxGenericGrid::GetCellBackgroundColour(int row, int col) const
  2235. {
  2236.   wxGridCell *cell = GetCell(row, col);
  2237.   if (cell)
  2238.     return cell->GetBackgroundColour();
  2239.   else
  2240.     return (wxColour&) m_cellBackgroundColour;
  2241. }
  2242.  
  2243. void wxGenericGrid::SetCellTextColour(const wxColour& val, int row, int col)
  2244. {
  2245.   wxGridCell *cell = GetCell(row, col);
  2246.   if (cell)
  2247.   {
  2248.     cell->SetTextColour(val);
  2249.     RefreshCell(row, col);
  2250.   }
  2251. }
  2252.  
  2253. void wxGenericGrid::SetCellTextFont(const wxFont& fnt, int row, int col)
  2254. {
  2255.   wxGridCell *cell = GetCell(row, col);
  2256.   if (cell)
  2257.   {
  2258.     cell->SetFont(fnt);
  2259.     RefreshCell(row, col);
  2260.   }
  2261. }
  2262.  
  2263. wxFont& wxGenericGrid::GetCellTextFont(int row, int col) const
  2264. {
  2265.   wxGridCell *cell = GetCell(row, col);
  2266.   if (cell)
  2267.     return (wxFont&) cell->GetFont();
  2268.   else
  2269.     return (wxFont&) m_cellTextFont;
  2270. }
  2271.  
  2272. wxColour& wxGenericGrid::GetCellTextColour(int row, int col) const
  2273. {
  2274.   wxGridCell *cell = GetCell(row, col);
  2275.   if (cell)
  2276.     return (wxColour&) cell->GetTextColour();
  2277.   else
  2278.     return (wxColour&) m_cellTextColour;
  2279. }
  2280.  
  2281. void wxGenericGrid::SetCellTextColour(const wxColour& val)
  2282. {
  2283.   m_cellTextColour = val;
  2284.   int i,j;
  2285.   for (i = 0; i < GetRows(); i++)
  2286.     for (j = 0; j < GetCols(); j++)
  2287.       if (GetCell(i, j))
  2288.         GetCell(i, j)->SetTextColour(val);
  2289. }
  2290.  
  2291. void wxGenericGrid::SetCellTextFont(const wxFont& fnt)
  2292. {
  2293.   m_cellTextFont = fnt;
  2294.   int i,j;
  2295.   for (i = 0; i < GetRows(); i++)
  2296.     for (j = 0; j < GetCols(); j++)
  2297.       if (GetCell(i, j))
  2298.         GetCell(i, j)->SetFont(fnt);
  2299. }
  2300.  
  2301. void wxGenericGrid::SetCellBitmap(wxBitmap *bitmap, int row, int col)
  2302. {
  2303.   wxGridCell *cell = GetCell(row, col);
  2304.   if (cell)
  2305.   {
  2306.     cell->SetCellBitmap(bitmap);
  2307.     RefreshCell(row, col);
  2308.   }
  2309. }
  2310.  
  2311. wxBitmap *wxGenericGrid::GetCellBitmap(int row, int col) const
  2312. {
  2313.   wxGridCell *cell = GetCell(row, col);
  2314.   if (cell)
  2315.   {
  2316.     return cell->GetCellBitmap();
  2317.   }
  2318.   else
  2319.     return (wxBitmap *) NULL;
  2320. }
  2321.  
  2322. bool wxGenericGrid::InsertCols(int pos, int n, bool updateLabels)
  2323. {
  2324.   if (pos > m_totalCols)
  2325.     return FALSE;
  2326.  
  2327.   if (!m_gridCells)
  2328.     return CreateGrid(1, n);
  2329.   else
  2330.   {
  2331.     int i, j;
  2332.     // Cells
  2333.     for (i = 0; i < m_totalRows; i++)
  2334.     {
  2335.       wxGridCell **cols = m_gridCells[i];
  2336.       wxGridCell **newCols = new wxGridCell *[m_totalCols + n];
  2337.       for (j = 0; j < pos; j++)
  2338.         newCols[j] = cols[j];
  2339.       for (j = pos; j < pos + n; j++)
  2340.         newCols[j] = new wxGridCell(this);
  2341.       for (j = pos + n; j < m_totalCols + n; j++)
  2342.         newCols[j] = cols[j - n];
  2343.  
  2344.       delete[] cols;
  2345.       m_gridCells[i] = newCols;
  2346.     }
  2347.  
  2348.     // Column widths
  2349.     short *newColWidths = new short[m_totalCols + n];
  2350.     for (j = 0; j < pos; j++)
  2351.       newColWidths[j] = m_colWidths[j];
  2352.     for (j = pos; j < pos + n; j++)
  2353.       newColWidths[j] = wxGRID_DEFAULT_CELL_WIDTH;
  2354.     for (j = pos + n; j < m_totalCols + n; j++)
  2355.       newColWidths[j] = m_colWidths[j - n];
  2356.     delete[] m_colWidths;
  2357.     m_colWidths = newColWidths;
  2358.  
  2359.     // Column labels
  2360.     wxGridCell **newLabels = new wxGridCell *[m_totalCols + n];
  2361.     for (j = 0; j < pos; j++)
  2362.       newLabels[j] = m_colLabelCells[j];
  2363.     for (j = pos; j < pos + n; j++)
  2364.       newLabels[j] = new wxGridCell(this);
  2365.     for (j = pos + n; j < m_totalCols + n; j++)
  2366.       newLabels[j] = m_colLabelCells[j - n];
  2367.  
  2368.     delete[] m_colLabelCells;
  2369.     m_colLabelCells = newLabels;
  2370.  
  2371.     m_totalCols += n;
  2372.  
  2373.     if (updateLabels) {
  2374.         //OnChangeLabels();
  2375.         wxGridEvent g_evt(GetId(), wxEVT_GRID_CHANGE_LABELS, this);
  2376.         GetEventHandler()->ProcessEvent(g_evt);
  2377.     }
  2378.  
  2379.     UpdateDimensions();
  2380.     AdjustScrollbars();
  2381.     return TRUE;
  2382.   }
  2383. }
  2384.  
  2385. bool wxGenericGrid::InsertRows(int pos, int n, bool updateLabels)
  2386. {
  2387.   if (pos > m_totalRows)
  2388.     return FALSE;
  2389.  
  2390.   if (!m_gridCells)
  2391.     return CreateGrid(n, 1);
  2392.   else
  2393.   {
  2394.     int i, j;
  2395.  
  2396.     wxGridCell ***rows = new wxGridCell **[m_totalRows + n];
  2397.  
  2398.     // Cells
  2399.     for (i = 0; i < pos; i++)
  2400.       rows[i] = m_gridCells[i];
  2401.  
  2402.     for (i = pos; i < pos + n; i++)
  2403.     {
  2404.       rows[i] = new wxGridCell *[m_totalCols];
  2405.       for (j = 0; j < m_totalCols; j++)
  2406.         rows[i][j] = new wxGridCell(this);
  2407.     }
  2408.  
  2409.     for (i = pos + n; i < m_totalRows + n; i++)
  2410.       rows[i] = m_gridCells[i - n];
  2411.  
  2412.     delete[] m_gridCells;
  2413.     m_gridCells = rows;
  2414.  
  2415.     // Row heights
  2416.     short *newRowHeights = new short[m_totalRows + n];
  2417.     for (i = 0; i < pos; i++)
  2418.       newRowHeights[i] = m_rowHeights[i];
  2419.     for (i = pos; i < pos + n; i++)
  2420.       newRowHeights[i] = wxGRID_DEFAULT_CELL_HEIGHT;
  2421.     for (i = pos + n; i < m_totalRows + n; i++)
  2422.       newRowHeights[i] = m_rowHeights[i - n];
  2423.     delete[] m_rowHeights;
  2424.     m_rowHeights = newRowHeights;
  2425.  
  2426.     // Column labels
  2427.     wxGridCell **newLabels = new wxGridCell *[m_totalRows + n];
  2428.     for (i = 0; i < pos; i++)
  2429.       newLabels[i] = m_rowLabelCells[i];
  2430.     for (i = pos; i < pos + n; i++)
  2431.       newLabels[i] = new wxGridCell(this);
  2432.     for (i = pos + n; i < m_totalRows + n; i++)
  2433.       newLabels[i] = m_rowLabelCells[i - n];
  2434.  
  2435.     delete[] m_rowLabelCells;
  2436.     m_rowLabelCells = newLabels;
  2437.  
  2438.     m_totalRows += n;
  2439.  
  2440.     if (updateLabels) {
  2441.         //OnChangeLabels();
  2442.           wxGridEvent g_evt(GetId(), wxEVT_GRID_CHANGE_LABELS, this);
  2443.           GetEventHandler()->ProcessEvent(g_evt);
  2444.     }
  2445.  
  2446.     UpdateDimensions();
  2447.     AdjustScrollbars();
  2448.     return TRUE;
  2449.   }
  2450. }
  2451.  
  2452. bool wxGenericGrid::AppendCols(int n, bool updateLabels)
  2453. {
  2454.   return InsertCols(GetCols(), n, updateLabels);
  2455. }
  2456.  
  2457. bool wxGenericGrid::AppendRows(int n, bool updateLabels)
  2458. {
  2459.   return InsertRows(GetRows(), n, updateLabels);
  2460. }
  2461.  
  2462. bool wxGenericGrid::DeleteRows(int pos, int n, bool updateLabels)
  2463. {
  2464.   if (pos > m_totalRows)
  2465.     return FALSE;
  2466.   if (!m_gridCells)
  2467.     return FALSE;
  2468.  
  2469.   int i;
  2470.  
  2471.   wxGridCell ***rows = new wxGridCell **[m_totalRows - n];
  2472.  
  2473.   // Cells
  2474.   for (i = 0; i < pos; i++)
  2475.     rows[i] = m_gridCells[i];
  2476.  
  2477.   for (i = pos + n; i < m_totalRows; i++)
  2478.     rows[i-n] = m_gridCells[i];
  2479.  
  2480.   delete[] m_gridCells;
  2481.   m_gridCells = rows;
  2482.  
  2483.   // Row heights
  2484.   short *newRowHeights = new short[m_totalRows - n];
  2485.   for (i = 0; i < pos; i++)
  2486.     newRowHeights[i] = m_rowHeights[i];
  2487.   for (i = pos + n; i < m_totalRows; i++)
  2488.     newRowHeights[i-n] = m_rowHeights[i];
  2489.   delete[] m_rowHeights;
  2490.   m_rowHeights = newRowHeights;
  2491.  
  2492.   // Column labels
  2493.   wxGridCell **newLabels = new wxGridCell *[m_totalRows - n];
  2494.   for (i = 0; i < pos; i++)
  2495.     newLabels[i] = m_rowLabelCells[i];
  2496.   for (i = pos + n; i < m_totalRows; i++)
  2497.     newLabels[i-n] = m_rowLabelCells[i];
  2498.  
  2499.   delete[] m_rowLabelCells;
  2500.   m_rowLabelCells = newLabels;
  2501.  
  2502.   m_totalRows -= n;
  2503.  
  2504.   if (updateLabels){
  2505.         //OnChangeLabels();
  2506.         wxGridEvent g_evt(GetId(), wxEVT_GRID_CHANGE_LABELS, this);
  2507.         GetEventHandler()->ProcessEvent(g_evt);
  2508.     }
  2509.   UpdateDimensions();
  2510.   AdjustScrollbars();
  2511.   return TRUE;
  2512. }
  2513.  
  2514. bool wxGenericGrid::DeleteCols(int pos, int n, bool updateLabels)
  2515. {
  2516.   if (pos + n > m_totalCols)
  2517.     return FALSE;
  2518.   if (!m_gridCells)
  2519.     return FALSE;
  2520.  
  2521.   int i, j;
  2522.  
  2523.   // Cells
  2524.   for (i = 0; i < m_totalRows; i++)
  2525.   {
  2526.       wxGridCell **cols = m_gridCells[i];
  2527.       wxGridCell **newCols = new wxGridCell *[m_totalCols - n];
  2528.       for (j = 0; j < pos; j++)
  2529.         newCols[j] = cols[j];
  2530.       for (j = pos; j < pos + n; j++)
  2531.         delete cols[j];
  2532.       for (j = pos + n; j < m_totalCols; j++)
  2533.         newCols[j-n] = cols[j];
  2534.  
  2535.       delete[] cols;
  2536.       m_gridCells[i] = newCols;
  2537.   }
  2538.  
  2539.   // Column widths
  2540.   short *newColWidths = new short[m_totalCols - n];
  2541.   for (j = 0; j < pos; j++)
  2542.     newColWidths[j] = m_colWidths[j];
  2543.   for (j = pos + n; j < m_totalCols; j++)
  2544.     newColWidths[j-n] = m_colWidths[j];
  2545.   delete[] m_colWidths;
  2546.   m_colWidths = newColWidths;
  2547.  
  2548.   // Column labels
  2549.   wxGridCell **newLabels = new wxGridCell *[m_totalCols - n];
  2550.   for (j = 0; j < pos; j++)
  2551.     newLabels[j] = m_colLabelCells[j];
  2552.   for (j = pos + n; j < m_totalCols; j++)
  2553.     newLabels[j-n] = m_colLabelCells[j];
  2554.  
  2555.   delete[] m_colLabelCells;
  2556.   m_colLabelCells = newLabels;
  2557.  
  2558.   m_totalCols -= n;
  2559.  
  2560.   if (updateLabels) {
  2561.         //OnChangeLabels();
  2562.         wxGridEvent g_evt(GetId(), wxEVT_GRID_CHANGE_LABELS, this);
  2563.         GetEventHandler()->ProcessEvent(g_evt);
  2564.     }
  2565.   UpdateDimensions();
  2566.   AdjustScrollbars();
  2567.   return TRUE;
  2568. }
  2569.  
  2570. void wxGenericGrid::SetGridCursor(int row, int col)
  2571. {
  2572.   if (row >= m_totalRows || col >= m_totalCols)
  2573.     return;
  2574.  
  2575.   if (row == GetCursorRow() && col == GetCursorColumn())
  2576.     return;
  2577.  
  2578.   wxClientDC dc(this);
  2579.   dc.BeginDrawing();
  2580.  
  2581.   SetGridClippingRegion(& dc);
  2582.  
  2583.   if (m_currentRectVisible && (wxIPE_HIGHLIGHT || !(m_editable && m_editInPlace)))
  2584.       HighlightCell(& dc, FALSE);
  2585.  
  2586.   m_wCursorRow = row;
  2587.   m_wCursorColumn = col;
  2588.  
  2589.   int cw, ch;
  2590.   GetClientSize(&cw, &ch);
  2591.  
  2592.   SetCurrentRect(row, col, cw, ch);
  2593.  
  2594.   if (m_currentRectVisible && (wxIPE_HIGHLIGHT || !(m_editable && m_editInPlace)))
  2595.       HighlightCell(& dc, TRUE);
  2596.  
  2597.   dc.DestroyClippingRegion();
  2598.   dc.EndDrawing();
  2599. }
  2600.  
  2601. // ----------------------------------------------------------------------------
  2602. // Grid cell
  2603. // ----------------------------------------------------------------------------
  2604.  
  2605. wxGridCell::wxGridCell(wxGenericGrid *window)
  2606. {
  2607.   cellBitmap = (wxBitmap *) NULL;
  2608.   font = wxNullFont;
  2609.   backgroundBrush = wxNullBrush;
  2610.   if (window)
  2611.     textColour = window->GetCellTextColour();
  2612.   else
  2613.     textColour.Set(0,0,0);
  2614.   if (window)
  2615.     backgroundColour = window->GetCellBackgroundColour();
  2616.   else
  2617.     backgroundColour.Set(255,255,255);
  2618.  
  2619.   if (window)
  2620.     font = window->GetCellTextFont();
  2621.   else
  2622.     font = * wxTheFontList->FindOrCreateFont(12, wxSWISS, wxNORMAL, wxNORMAL);
  2623.  
  2624.   SetBackgroundColour(backgroundColour);
  2625.  
  2626.   if (window)
  2627.     alignment = window->GetCellAlignment();
  2628.   else
  2629.     alignment = wxLEFT;
  2630.  
  2631.   cellData = (void *)NULL;
  2632. }
  2633.  
  2634. wxGridCell::~wxGridCell()
  2635. {
  2636. }
  2637.  
  2638. void wxGridCell::SetBackgroundColour(const wxColour& colour)
  2639. {
  2640.   backgroundColour = colour;
  2641.   backgroundBrush = * wxTheBrushList->FindOrCreateBrush(backgroundColour, wxSOLID);
  2642. }
  2643.  
  2644. void wxGenericGrid::OnText(wxCommandEvent& WXUNUSED(ev) )
  2645. {
  2646.   // michael - added this conditional to prevent change to
  2647.   // grid cell text when edit control is hidden but still has
  2648.   // focus
  2649.   //
  2650.   if ( m_editable )
  2651.     {
  2652.       wxGenericGrid *grid = this;
  2653.       wxGridCell *cell = grid->GetCell(grid->GetCursorRow(), grid->GetCursorColumn());
  2654.       if (cell && grid->CurrentCellVisible())
  2655.         {
  2656.           cell->SetTextValue(grid->GetTextItem()->GetValue());
  2657.           if ( m_editInPlace && !m_inOnTextInPlace )
  2658.             {
  2659.               m_inPlaceTextItem->SetValue( grid->GetTextItem()->GetValue() );
  2660.             }
  2661.  
  2662.           if (!m_editInPlace) {
  2663.               wxClientDC dc(grid);
  2664.  
  2665.               dc.BeginDrawing();
  2666.               grid->SetGridClippingRegion(& dc);
  2667.               grid->DrawCellBackground(& dc, &grid->GetCurrentRect(), grid->GetCursorRow(), grid->GetCursorColumn());
  2668.               grid->DrawCellValue(& dc, &grid->GetCurrentRect(), grid->GetCursorRow(), grid->GetCursorColumn());
  2669.               grid->HighlightCell(& dc, TRUE);
  2670.               dc.DestroyClippingRegion();
  2671.               dc.EndDrawing();
  2672.           }
  2673.  
  2674.           //grid->OnCellChange(grid->GetCursorRow(), grid->GetCursorColumn());
  2675.           wxGridEvent g_evt(GetId(), wxEVT_GRID_CELL_CHANGE, grid,
  2676.                             grid->GetCursorRow(), grid->GetCursorColumn());
  2677.           GetEventHandler()->ProcessEvent(g_evt);
  2678.  
  2679.           //    grid->DrawCellText();
  2680.         }
  2681.     }
  2682. }
  2683.  
  2684. void wxGenericGrid::OnTextEnter(wxCommandEvent& WXUNUSED(ev) )
  2685. {
  2686.   // move the cursor down the current row (if possible)
  2687.   // when the enter key has been pressed
  2688.   //
  2689.   if ( m_editable )
  2690.     {
  2691.       if ( GetCursorRow() < GetRows()-1 )
  2692.         {
  2693.           wxClientDC dc( this );
  2694.           dc.BeginDrawing();
  2695.           OnSelectCellImplementation(& dc,
  2696.                                      GetCursorRow()+1,
  2697.                                      GetCursorColumn() );
  2698.           dc.EndDrawing();
  2699.         }
  2700.     }
  2701. }
  2702.  
  2703. void wxGenericGrid::OnTextInPlace(wxCommandEvent& ev )
  2704. {
  2705.   if ( m_editable )
  2706.     {
  2707.       wxGenericGrid *grid = this;
  2708.       wxGridCell *cell = grid->GetCell(grid->GetCursorRow(), grid->GetCursorColumn());
  2709.       if (cell && grid->CurrentCellVisible())
  2710.         {
  2711.           m_inOnTextInPlace = TRUE;
  2712.           grid->GetTextItem()->SetValue( m_inPlaceTextItem->GetValue() );
  2713.           OnText( ev );
  2714.           m_inOnTextInPlace = FALSE;
  2715.         }
  2716.     }
  2717. }
  2718.  
  2719. void wxGenericGrid::OnTextInPlaceEnter(wxCommandEvent& WXUNUSED(ev) )
  2720. {
  2721.   // move the cursor down the current row (if possible)
  2722.   // when the enter key has been pressed
  2723.   //
  2724.   if ( m_editable )
  2725.     {
  2726.       if ( GetCursorRow() < GetRows()-1 )
  2727.         {
  2728.           wxClientDC dc( this );
  2729.           dc.BeginDrawing();
  2730.           OnSelectCellImplementation(& dc,
  2731.                                      GetCursorRow()+1,
  2732.                                      GetCursorColumn() );
  2733.           dc.EndDrawing();
  2734.         }
  2735.     }
  2736. }
  2737.  
  2738. void wxGenericGrid::OnGridScroll(wxScrollEvent& ev)
  2739. {
  2740.   if ( m_inScroll )
  2741.         return;
  2742.  
  2743.   if ( m_editInPlace ) m_inPlaceTextItem->Show(FALSE);
  2744.  
  2745.   m_inScroll = TRUE;
  2746.   wxGenericGrid *win = this;
  2747.  
  2748.   bool change = FALSE;
  2749.  
  2750.   if (ev.GetEventObject() == win->GetHorizScrollBar())
  2751.   {
  2752.     change = (ev.GetPosition() != m_scrollPosX);
  2753.     win->SetScrollPosX(ev.GetPosition());
  2754.   }
  2755.   else
  2756.   {
  2757.     change = (ev.GetPosition() != m_scrollPosY);
  2758.     win->SetScrollPosY(ev.GetPosition());
  2759.   }
  2760.  
  2761.   win->UpdateDimensions();
  2762.  
  2763.   win->SetCurrentRect(win->GetCursorRow(), win->GetCursorColumn());
  2764.  
  2765.   // Because rows and columns can be arbitrary sizes,
  2766.   // the scrollbars will need to be adjusted to reflect the
  2767.   // current view.
  2768.   AdjustScrollbars();
  2769.  
  2770.   if (change) win->Refresh(FALSE);
  2771.  
  2772.   if ( m_editInPlace && m_currentRectVisible )
  2773.     {
  2774.       m_inPlaceTextItem->SetSize( m_currentRect.x-wxIPE_ADJUST,
  2775.                                   m_currentRect.y-wxIPE_ADJUST,
  2776.                                   m_currentRect.width+wxIPE_ADJUST*2,
  2777.                                   m_currentRect.height+wxIPE_ADJUST*2 );
  2778.       m_inPlaceTextItem->Show( TRUE );
  2779.       m_inPlaceTextItem->SetFocus();
  2780.     }
  2781.  
  2782.   m_inScroll = FALSE;
  2783.  
  2784. }
  2785.  
  2786.  
  2787. //----------------------------------------------------------------------
  2788. // Default wxGridEvent handlers
  2789. //      (just redirect to the pre-existing virtual methods)
  2790.  
  2791. void wxGenericGrid::_OnSelectCell(wxGridEvent& ev)
  2792. {
  2793.     OnSelectCell(ev.m_row, ev.m_col);
  2794. }
  2795.  
  2796. void wxGenericGrid::_OnCreateCell(wxGridEvent& ev)
  2797. {
  2798.     ev.m_cell = OnCreateCell();
  2799. }
  2800.  
  2801. void wxGenericGrid::_OnChangeLabels(wxGridEvent& WXUNUSED(ev))
  2802. {
  2803.     OnChangeLabels();
  2804. }
  2805.  
  2806. void wxGenericGrid::_OnChangeSelectionLabel(wxGridEvent& WXUNUSED(ev))
  2807. {
  2808.     OnChangeSelectionLabel();
  2809. }
  2810.  
  2811. void wxGenericGrid::_OnCellChange(wxGridEvent& ev)
  2812. {
  2813.     OnCellChange(ev.m_row, ev.m_col);
  2814. }
  2815.  
  2816. void wxGenericGrid::_OnCellLeftClick(wxGridEvent& ev)
  2817. {
  2818.     OnCellLeftClick(ev.m_row, ev.m_col, ev.m_x, ev.m_y, ev.m_control, ev.m_shift);
  2819. }
  2820.  
  2821. void wxGenericGrid::_OnCellRightClick(wxGridEvent& ev)
  2822. {
  2823.     OnCellRightClick(ev.m_row, ev.m_col, ev.m_x, ev.m_y, ev.m_control, ev.m_shift);
  2824. }
  2825.  
  2826. void wxGenericGrid::_OnLabelLeftClick(wxGridEvent& ev)
  2827. {
  2828.     OnLabelLeftClick(ev.m_row, ev.m_col, ev.m_x, ev.m_y, ev.m_control, ev.m_shift);
  2829. }
  2830.  
  2831. void wxGenericGrid::_OnLabelRightClick(wxGridEvent& ev)
  2832. {
  2833.     OnLabelRightClick(ev.m_row, ev.m_col, ev.m_x, ev.m_y, ev.m_control, ev.m_shift);
  2834. }
  2835.  
  2836. void *wxGenericGrid::SetCellData(void *data, int row, int col)
  2837. {
  2838.     void *rc = NULL;
  2839.  
  2840.     wxGridCell *cell = GetCell(row, col);
  2841.     if ( cell )
  2842.         rc = cell->SetCellData(data);
  2843.  
  2844.     return rc;
  2845. }
  2846.  
  2847. void *wxGenericGrid::GetCellData(int row, int col)
  2848. {
  2849.     void *rc = NULL;
  2850.  
  2851.     wxGridCell *cell = GetCell(row, col);
  2852.     if ( cell )
  2853.         rc = cell->GetCellData();
  2854.  
  2855.     return rc;
  2856. }
  2857.  
  2858. #endif // wxUSE_GRID && !(wxUSE_NEW_GRID)
  2859.