default:
// additionally accept 'e' as in '1e+6'
if ( (keycode < 128) &&
- (isdigit(keycode) || tolower(keycode) == wxT('e')) )
+ (isdigit(keycode) || tolower(keycode) == 'e') )
return TRUE;
}
}
m_startValue = grid->GetTable()->GetValue(row, col);
- Combo()->SetValue(m_startValue);
- size_t count = m_choices.GetCount();
- for (size_t i=0; i<count; i++)
+ if (m_allowOthers)
+ Combo()->SetValue(m_startValue);
+ else
{
- if (m_startValue == m_choices[i])
- {
- Combo()->SetSelection(i);
- break;
- }
+ // find the right position, or default to the first if not found
+ int pos = Combo()->FindString(m_startValue);
+ if (pos == -1)
+ pos = 0;
+ Combo()->SetSelection(pos);
}
Combo()->SetInsertionPointEnd();
Combo()->SetFocus();
grid->GetTable()->SetValue(row, col, value);
m_startValue = wxEmptyString;
- Combo()->SetValue(m_startValue);
+ if (m_allowOthers)
+ Combo()->SetValue(m_startValue);
+ else
+ Combo()->SetSelection(0);
return changed;
}
bool isSelected)
{
wxRect rect = rectCell;
+ rect.Inflate(-1);
+
+ // erase only this cells background, overflow cells should have been erased
+ wxGridCellRenderer::Draw(grid, attr, dc, rectCell, row, col, isSelected);
+
+ int hAlign, vAlign;
+ attr.GetAlignment(&hAlign, &vAlign);
+
+ int overflowCols = 0;
if (attr.GetOverflow())
{
int i, c_cols, c_rows;
for (i = col+cell_cols; i < cols; i++)
{
- // check w/ anchor cell for multicell block
- grid.GetCellSize(row, i, &c_rows, &c_cols);
- if (c_rows > 0) c_rows = 0;
- if (grid.GetTable()->IsEmptyCell(row+c_rows, i))
+ bool is_empty = TRUE;
+ for (int j=row; j<row+cell_rows; j++)
{
+ // check w/ anchor cell for multicell block
+ grid.GetCellSize(j, i, &c_rows, &c_cols);
+ if (c_rows > 0) c_rows = 0;
+ if (!grid.GetTable()->IsEmptyCell(j+c_rows, i))
+ {
+ is_empty = FALSE;
+ break;
+ }
+ }
+ if (is_empty)
rect.width += grid.GetColSize(i);
- if (rect.width >= best_width) break;
+ else
+ {
+ i--;
+ break;
}
- else break;
+ if (rect.width >= best_width) break;
}
+ overflowCols = i - col - cell_cols + 1;
+ if (overflowCols >= cols) overflowCols = cols - 1;
}
- }
- // erase only this cells background, overflow cells should have been erased
- wxGridCellRenderer::Draw(grid, attr, dc, rectCell, row, col, isSelected);
+ if (overflowCols > 0) // redraw overflow cells w/ proper hilight
+ {
+ hAlign = wxALIGN_LEFT; // if oveflowed then it's left aligned
+ wxRect clip = rect;
+ clip.x += rectCell.width;
+ // draw each overflow cell individually
+ int col_end = col+cell_cols+overflowCols;
+ if (col_end >= grid.GetNumberCols())
+ col_end = grid.GetNumberCols() - 1;
+ for (int i = col+cell_cols; i <= col_end; i++)
+ {
+ clip.width = grid.GetColSize(i) - 1;
+ dc.DestroyClippingRegion();
+ dc.SetClippingRegion(clip);
- // now we only have to draw the text
- SetTextColoursAndFont(grid, attr, dc, isSelected);
+ SetTextColoursAndFont(grid, attr, dc,
+ grid.IsInSelection(row,i));
- int hAlign, vAlign;
- attr.GetAlignment(&hAlign, &vAlign);
+ grid.DrawTextRectangle(dc, grid.GetCellValue(row, col),
+ rect, hAlign, vAlign);
+ clip.x += grid.GetColSize(i) - 1;
+ }
- rect.Inflate(-1);
+ rect = rectCell;
+ rect.Inflate(-1);
+ rect.width++;
+ dc.DestroyClippingRegion();
+ }
+ }
+
+ // now we only have to draw the text
+ SetTextColoursAndFont(grid, attr, dc, isSelected);
grid.DrawTextRectangle(dc, grid.GetCellValue(row, col),
rect, hAlign, vAlign);
{
if ( m_precision == -1 )
{
- // default width/precision
- m_format = _T("%f");
- }
+ // default width/precision
+ m_format = _T("%f");
+ }
else
{
m_format.Printf(_T("%%.%df"), m_precision);
if ( pos >= curNumRows )
{
- wxString errmsg;
- errmsg.Printf(wxT("Called wxGridStringTable::DeleteRows(pos=%d, N=%d)\nPos value is invalid for present table with %d rows"),
- pos, numRows, curNumRows );
- wxFAIL_MSG( errmsg );
+ wxFAIL_MSG( wxString::Format
+ (
+ wxT("Called wxGridStringTable::DeleteRows(pos=%lu, N=%lu)\nPos value is invalid for present table with %lu rows"),
+ (unsigned long)pos,
+ (unsigned long)numRows,
+ (unsigned long)curNumRows
+ ) );
+
return FALSE;
}
if ( numRows >= curNumRows )
{
- m_data.Empty(); // don't release memory just yet
+ m_data.Clear();
}
else
{
if ( pos >= curNumCols )
{
- wxString errmsg;
- errmsg.Printf( wxT("Called wxGridStringTable::DeleteCols(pos=%d, N=%d)...\nPos value is invalid for present table with %d cols"),
- pos, numCols, curNumCols );
- wxFAIL_MSG( errmsg );
+ wxFAIL_MSG( wxString::Format
+ (
+ wxT("Called wxGridStringTable::DeleteCols(pos=%lu, N=%lu)\nPos value is invalid for present table with %lu cols"),
+ (unsigned long)pos,
+ (unsigned long)numCols,
+ (unsigned long)curNumCols
+ ) );
return FALSE;
}
// Internal helper macros for simpler use of that function
static int CoordToRowOrCol(int coord, int defaultDist, int minDist,
- const wxArrayInt& BorderArray, bool maxOnOverflow);
+ const wxArrayInt& BorderArray, int nMax,
+ bool maxOnOverflow);
#define internalXToCol(x) CoordToRowOrCol(x, m_defaultColWidth, \
WXGRID_MIN_COL_WIDTH, \
- m_colRights, TRUE)
+ m_colRights, m_numCols, TRUE)
#define internalYToRow(y) CoordToRowOrCol(y, m_defaultRowHeight, \
WXGRID_MIN_ROW_HEIGHT, \
- m_rowBottoms, TRUE)
+ m_rowBottoms, m_numRows, TRUE)
/////////////////////////////////////////////////////////////////////
IMPLEMENT_DYNAMIC_CLASS( wxGrid, wxScrolledWindow )
m_selection->SetSelectionMode( selmode );
}
+wxGrid::wxGridSelectionModes wxGrid::GetSelectionMode() const
+{
+ wxCHECK_MSG( m_created, wxGrid::wxGridSelectCells,
+ wxT("Called wxGrid::GetSelectionMode() before calling CreateGrid()") );
+
+ return m_selection->GetSelectionMode();
+}
+
bool wxGrid::SetTable( wxGridTableBase *table, bool takeOwnership,
wxGrid::wxGridSelectionModes selmode )
{
// init attr cache
m_attrCache.row = -1;
+ m_attrCache.col = -1;
+ m_attrCache.attr = NULL;
// TODO: something better than this ?
//
m_rowBottoms.Alloc( m_numRows );
int rowBottom = 0;
-
+
m_rowHeights.Add( m_defaultRowHeight, m_numRows );
for ( int i = 0; i < m_numRows; i++ )
// removed, not only if the cell "underneath" it actually changes.
// For now, I intentionally do not save the editor's content as the
// cell it might want to save that stuff to might no longer exist.
- DisableCellEditControl();
+ HideCellEditControl();
#if 0
// if we were using the default widths/heights so far, we must change them
// now
{
if ( !event.ShiftDown() && !event.ControlDown() )
ClearSelection();
- else if ( m_selection )
+ if ( m_selection )
{
if ( event.ShiftDown() )
{
//
else if ( event.Moving() && !event.IsButton() )
{
+ if( coords.GetRow() < 0 || coords.GetCol() < 0 )
+ {
+ // out of grid cell area
+ ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL);
+ return;
+ }
+
int dragRow = YToEdgeOfRow( y );
int dragCol = XToEdgeOfCol( x );
wxPaintDC dc(this); // needed to prevent zillions of paint events on MSW
}
-void wxGrid::Refresh(bool eraseb, wxRect* rect)
+void wxGrid::Refresh(bool eraseb, const wxRect* rect)
{
// Don't do anything if between Begin/EndBatch...
// EndBatch() will do all this on the last nested one anyway.
if (! GetBatchCount())
{
+ // Refresh to get correct scrolled position:
wxScrolledWindow::Refresh(eraseb,rect);
- int off_x=0 ,off_y=0;
- wxRect * anotherrect = NULL ;
-
if (rect)
{
+ int rect_x, rect_y, rectWidth, rectHeight;
+ int width_label, width_cell, height_label, height_cell;
+ int x, y;
+
//Copy rectangle can get scroll offsets..
- anotherrect = new wxRect(*rect);
- CalcScrolledPosition( 0, 0, &off_x, &off_y );
- }
- //Corner label Doesn't move from the origin.
- m_cornerLabelWin->Refresh(eraseb,rect);
+ rect_x = rect->GetX();
+ rect_y = rect->GetY();
+ rectWidth = rect->GetWidth();
+ rectHeight = rect->GetHeight();
- //Move Rect down for row labels...
- if (rect)
- rect->Offset(0,off_y);
- m_rowLabelWin->Refresh(eraseb,rect);
+ width_label = m_rowLabelWidth - rect_x;
+ if (width_label > rectWidth) width_label = rectWidth;
- //Move rect copy along for col labels...
- if (anotherrect)
- anotherrect->Offset(off_x,0);
- m_colLabelWin->Refresh(eraseb,anotherrect);
+ height_label = m_colLabelHeight - rect_y;
+ if (height_label > rectHeight) height_label = rectHeight;
- //Move main rect along (so it's down and across!)
- // for cell window.
- if (rect)
- rect->Offset(off_x,0);
- m_gridWin->Refresh(eraseb,rect);
+ if (rect_x > m_rowLabelWidth)
+ {
+ x = rect_x - m_rowLabelWidth;
+ width_cell = rectWidth;
+ }
+ else
+ {
+ x = 0;
+ width_cell = rectWidth - (m_rowLabelWidth - rect_x);
+ }
+
+ if (rect_y > m_colLabelHeight)
+ {
+ y = rect_y - m_colLabelHeight;
+ height_cell = rectHeight;
+ }
+ else
+ {
+ y = 0;
+ height_cell = rectHeight - (m_colLabelHeight - rect_y);
+ }
+
+ // Paint corner label part intersecting rect.
+ if ( width_label > 0 && height_label > 0 )
+ {
+ wxRect anotherrect(rect_x, rect_y, width_label, height_label);
+ m_cornerLabelWin->Refresh(eraseb, &anotherrect);
+ }
+
+ // Paint col labels part intersecting rect.
+ if ( width_cell > 0 && height_label > 0 )
+ {
+ wxRect anotherrect(x, rect_y, width_cell, height_label);
+ m_colLabelWin->Refresh(eraseb, &anotherrect);
+ }
+
+ // Paint row labels part intersecting rect.
+ if ( width_label > 0 && height_cell > 0 )
+ {
+ wxRect anotherrect(rect_x, y, width_label, height_cell);
+ m_rowLabelWin->Refresh(eraseb, &anotherrect);
+ }
+
+ // Paint cell area part intersecting rect.
+ if ( width_cell > 0 && height_cell > 0 )
+ {
+ wxRect anotherrect(x, y, width_cell, height_cell);
+ m_gridWin->Refresh(eraseb, &anotherrect);
+ }
+ }
+ else
+ {
+ m_cornerLabelWin->Refresh(eraseb, NULL);
+ m_colLabelWin->Refresh(eraseb, NULL);
+ m_rowLabelWin->Refresh(eraseb, NULL);
+ m_gridWin->Refresh(eraseb, NULL);
+ }
}
}
wxRect rect;
rect = BlockToDeviceRect( wxGridCellCoords ( topRow, leftCol ),
wxGridCellCoords ( bottomRow, rightCol ) );
- m_gridWin->Refresh( FALSE, &rect );
+ m_gridWin->Refresh( FALSE, &rect );
}
// Now handle changing an existing selection area.
else if ( m_selectingTopLeft != updateTopLeft ||
bool wxGrid::GetModelValues()
{
+ // Hide the editor, so it won't hide a changed value.
+ HideCellEditControl();
+
if ( m_table )
{
// all we need to do is repaint the grid
{
int row, col;
+ // Disable the editor, so it won't hide a changed value.
+ // Do we also want to save the current value of the editor first?
+ // I think so ...
+ DisableCellEditControl();
+
if ( m_table )
{
for ( row = 0; row < m_numRows; row++ )
{
if ( !m_numRows || !m_numCols ) return;
- int i, j, k, l, numCells = cells.GetCount();
+ int i, numCells = cells.GetCount();
int row, col, cell_rows, cell_cols;
wxGridCellCoordsArray redrawCells;
{
wxGridCellCoords cell(row+cell_rows, col+cell_cols);
bool marked = FALSE;
- for ( j = 0; j < numCells; j++ )
+ for ( int j = 0; j < numCells; j++ )
{
if ( cell == cells[j] )
{
if (!marked)
{
int count = redrawCells.GetCount();
- for (j = 0; j < count; j++)
+ for (int j = 0; j < count; j++)
{
if ( cell == redrawCells[j] )
{
// If this cell is empty, find cell to left that might want to overflow
if (m_table && m_table->IsEmptyCell(row, col))
{
- for ( l = 0; l < cell_rows; l++ )
+ for ( int l = 0; l < cell_rows; l++ )
{
- for (j = col-1; j >= 0; j--)
+ // find a cell in this row to left alreay marked for repaint
+ int left = col;
+ for (int k = 0; k < int(redrawCells.GetCount()); k++)
+ if ((redrawCells[k].GetCol() < left) &&
+ (redrawCells[k].GetRow() == row))
+ left=redrawCells[k].GetCol();
+
+ if (left == col) left = 0; // oh well
+
+ for (int j = col-1; j >= left; j--)
{
if (!m_table->IsEmptyCell(row+l, j))
{
wxGridCellCoords cell(row+l, j);
bool marked = FALSE;
- for (k = 0; k < numCells; k++)
+ for (int k = 0; k < numCells; k++)
{
if ( cell == cells[k] )
{
if (!marked)
{
int count = redrawCells.GetCount();
- for (k = 0; k < count; k++)
+ for (int k = 0; k < count; k++)
{
if ( cell == redrawCells[k] )
{
editor->Show( TRUE, attr );
// resize editor to overflow into righthand cells if allowed
+ int maxWidth = rect.width;
wxString value = GetCellValue(row, col);
if ( (value != wxEmptyString) && (attr->GetOverflow()) )
{
- wxClientDC dc(m_gridWin);
- wxCoord y = 0, best_width = 0;
- dc.SetFont(attr->GetFont());
- dc.GetTextExtent(value, &best_width, &y);
-
- int cell_rows, cell_cols;
- attr->GetSize( &cell_rows, &cell_cols );
+ int y;
+ GetTextExtent(value, &maxWidth, &y,
+ NULL, NULL, &attr->GetFont());
+ if (maxWidth < rect.width) maxWidth = rect.width;
+ }
+ int client_right = m_gridWin->GetClientSize().GetWidth();
+ if (rect.x+maxWidth > client_right)
+ maxWidth = client_right - rect.x;
- if ((best_width > rect.width) && (col < m_numCols) && m_table)
+ if ((maxWidth > rect.width) && (col < m_numCols) && m_table)
+ {
+ GetCellSize( row, col, &cell_rows, &cell_cols );
+ // may have changed earlier
+ for (int i = col+cell_cols; i < m_numCols; i++)
{
- int i;
- for (i = col+cell_cols; i < m_numCols; i++)
- {
- if (m_table->IsEmptyCell(row,i))
- {
- rect.width += GetColWidth(i);
- if (rect.width >= best_width) break;
- }
- else
- break;
- }
+ int c_rows, c_cols;
+ GetCellSize( row, i, &c_rows, &c_cols );
+ // looks weird going over a multicell
+ if (m_table->IsEmptyCell(row,i) &&
+ (rect.width < maxWidth) && (c_rows == 1))
+ rect.width += GetColWidth(i);
+ else
+ break;
}
+ if (rect.GetRight() > client_right)
+ rect.SetRight(client_right-1);
}
editor->SetSize( rect );
editor->DecRef();
attr->DecRef();
- }
+ }
}
}
// of m_rowBottoms/m_ColRights to speed up the search!
static int CoordToRowOrCol(int coord, int defaultDist, int minDist,
- const wxArrayInt& BorderArray, bool maxOnOverflow)
+ const wxArrayInt& BorderArray, int nMax,
+ bool maxOnOverflow)
{
if (!defaultDist)
defaultDist = 1;
size_t i_max = coord / defaultDist,
i_min = 0;
+
if (BorderArray.IsEmpty())
{
- return i_max;
+ if((int) i_max < nMax)
+ return i_max;
+ return maxOnOverflow ? nMax - 1 : -1;
}
if ( i_max >= BorderArray.GetCount())
int wxGrid::YToRow( int y )
{
return CoordToRowOrCol(y, m_defaultRowHeight,
- WXGRID_MIN_ROW_HEIGHT, m_rowBottoms, FALSE);
+ WXGRID_MIN_ROW_HEIGHT, m_rowBottoms, m_numRows, FALSE);
}
int wxGrid::XToCol( int x )
{
return CoordToRowOrCol(x, m_defaultColWidth,
- WXGRID_MIN_COL_WIDTH, m_colRights, FALSE);
+ WXGRID_MIN_COL_WIDTH, m_colRights, m_numCols, FALSE);
}
void wxGrid::CacheAttr(int row, int col, wxGridCellAttr *attr) const
{
- wxGrid *self = (wxGrid *)this; // const_cast
+ if ( attr != NULL )
+ {
+ wxGrid *self = (wxGrid *)this; // const_cast
- self->ClearAttrCache();
- self->m_attrCache.row = row;
- self->m_attrCache.col = col;
- self->m_attrCache.attr = attr;
- wxSafeIncRef(attr);
+ self->ClearAttrCache();
+ self->m_attrCache.row = row;
+ self->m_attrCache.col = col;
+ self->m_attrCache.attr = attr;
+ wxSafeIncRef(attr);
+ }
}
bool wxGrid::LookupAttr(int row, int col, wxGridCellAttr **attr) const
// round up the size to a multiple of scroll step - this ensures that we
// won't get the scrollbars if we're sized exactly to this width
- wxSize sizeFit(GetScrollX(size.x) * GRID_SCROLL_LINE_X,
- GetScrollY(size.y) * GRID_SCROLL_LINE_Y);
+ // CalcDimension adds m_extraWidth + 1 etc. to calculate the necessary
+ // scrollbar steps
+ wxSize sizeFit(GetScrollX(size.x + m_extraWidth + 1) * GRID_SCROLL_LINE_X,
+ GetScrollY(size.y + m_extraHeight + 1) * GRID_SCROLL_LINE_Y);
- // distribute the extra space between teh columns/rows to avoid having
+ // distribute the extra space between the columns/rows to avoid having
// extra white space
- wxCoord diff = sizeFit.x - size.x;
- if ( diff )
+
+ // Remove the extra m_extraWidth + 1 added above
+ wxCoord diff = sizeFit.x - size.x + (m_extraWidth + 1);
+ if ( diff && m_numCols )
{
// try to resize the columns uniformly
wxCoord diffPerCol = diff / m_numCols;
}
// same for rows
- diff = sizeFit.y - size.y;
- if ( diff )
+ diff = sizeFit.y - size.y - (m_extraHeight + 1);
+ if ( diff && m_numRows )
{
// try to resize the columns uniformly
wxCoord diffPerRow = diff / m_numRows;
col <= m_selectingBottomRight.GetCol() )) );
}
+wxGridCellCoordsArray wxGrid::GetSelectedCells() const
+{
+ if (!m_selection) { wxGridCellCoordsArray a; return a; }
+ return m_selection->m_cellSelection;
+}
+wxGridCellCoordsArray wxGrid::GetSelectionBlockTopLeft() const
+{
+ if (!m_selection) { wxGridCellCoordsArray a; return a; }
+ return m_selection->m_blockSelectionTopLeft;
+}
+wxGridCellCoordsArray wxGrid::GetSelectionBlockBottomRight() const
+{
+ if (!m_selection) { wxGridCellCoordsArray a; return a; }
+ return m_selection->m_blockSelectionBottomRight;
+}
+wxArrayInt wxGrid::GetSelectedRows() const
+{
+ if (!m_selection) { wxArrayInt a; return a; }
+ return m_selection->m_rowSelection;
+}
+wxArrayInt wxGrid::GetSelectedCols() const
+{
+ if (!m_selection) { wxArrayInt a; return a; }
+ return m_selection->m_colSelection;
+}
+
+
void wxGrid::ClearSelection()
{
m_selectingTopLeft = wxGridNoCellCoords;