#if wxUSE_GRID
+#include "wx/grid.h"
+
#ifndef WX_PRECOMP
#include "wx/utils.h"
#include "wx/dcclient.h"
#include "wx/tokenzr.h"
#include "wx/renderer.h"
-#include "wx/grid.h"
#include "wx/generic/gridsel.h"
+const wxChar wxGridNameStr[] = wxT("grid");
+
#if defined(__WXMOTIF__)
#define WXUNUSED_MOTIF(identifier) WXUNUSED(identifier)
#else
wxGridRowLabelWindow *rowLblWin,
wxGridColLabelWindow *colLblWin,
wxWindowID id, const wxPoint &pos, const wxSize &size );
- ~wxGridWindow() {}
+ virtual ~wxGridWindow() {}
void ScrollWindow( int dx, int dy, const wxRect *rect );
{
if ( wxGridCellEditor::IsAcceptedKey(event) )
{
- int keycode = event.GetKeyCode();
- printf("%d\n", keycode);
- // accept digits, 'e' as in '1e+6', also '-', '+', and '.'
- char tmpbuf[2];
- tmpbuf[0] = (char) keycode;
- tmpbuf[1] = '\0';
- wxString strbuf(tmpbuf, *wxConvCurrent);
+ const int keycode = event.GetKeyCode();
+ if ( isascii(keycode) )
+ {
+ char tmpbuf[2];
+ tmpbuf[0] = (char) keycode;
+ tmpbuf[1] = '\0';
+ wxString strbuf(tmpbuf, *wxConvCurrent);
#if wxUSE_INTL
- bool is_decimal_point =
- ( strbuf == wxLocale::GetInfo(wxLOCALE_DECIMAL_POINT,
- wxLOCALE_CAT_NUMBER) );
+ const wxString decimalPoint =
+ wxLocale::GetInfo(wxLOCALE_DECIMAL_POINT, wxLOCALE_CAT_NUMBER);
#else
- bool is_decimal_point = ( strbuf == _T(".") );
+ const wxString decimalPoint(_T('.'));
#endif
- if ( (keycode < 128) &&
- (wxIsdigit(keycode) || tolower(keycode) == 'e' ||
- is_decimal_point || keycode == '+' || keycode == '-') )
- {
- return true;
+ // accept digits, 'e' as in '1e+6', also '-', '+', and '.'
+ if ( wxIsdigit(keycode) ||
+ tolower(keycode) == 'e' ||
+ keycode == decimalPoint ||
+ keycode == '+' ||
+ keycode == '-' )
+ {
+ return true;
+ }
}
}
// wxGridCellBoolEditor
// ----------------------------------------------------------------------------
+// the default values for GetValue()
+wxString wxGridCellBoolEditor::ms_stringValues[2] = { _T(""), _T("1") };
+
void wxGridCellBoolEditor::Create(wxWindow* parent,
wxWindowID id,
wxEvtHandler* evtHandler)
else
{
wxString cellval( grid->GetTable()->GetValue(row, col) );
- m_startValue = !( !cellval || (cellval == wxT("0")) );
+
+ if ( cellval == ms_stringValues[false] )
+ m_startValue = false;
+ else if ( cellval == ms_stringValues[true] )
+ m_startValue = true;
+ else
+ {
+ // do not try to be smart here and convert it to true or false
+ // because we'll still overwrite it with something different and
+ // this risks to be very surprising for the user code, let them
+ // know about it
+ wxFAIL_MSG( _T("invalid value for a cell with bool editor!") );
+ }
}
CBox()->SetValue(m_startValue);
if ( changed )
{
- if (grid->GetTable()->CanGetValueAs(row, col, wxGRID_VALUE_BOOL))
- grid->GetTable()->SetValueAsBool(row, col, value);
+ wxGridTableBase * const table = grid->GetTable();
+ if ( table->CanGetValueAs(row, col, wxGRID_VALUE_BOOL) )
+ table->SetValueAsBool(row, col, value);
else
- grid->GetTable()->SetValue(row, col, value ? _T("1") : wxEmptyString);
+ table->SetValue(row, col, GetValue());
}
return changed;
}
}
-
-// return the value as "1" for true and the empty string for false
wxString wxGridCellBoolEditor::GetValue() const
{
- bool bSet = CBox()->GetValue();
- return bSet ? _T("1") : wxEmptyString;
+ return ms_stringValues[CBox()->GetValue()];
+}
+
+/* static */ void
+wxGridCellBoolEditor::UseStringValues(const wxString& valueTrue,
+ const wxString& valueFalse)
+{
+ ms_stringValues[false] = valueFalse;
+ ms_stringValues[true] = valueTrue;
+}
+
+/* static */ bool
+wxGridCellBoolEditor::IsTrueValue(const wxString& value)
+{
+ return value == ms_stringValues[true];
}
#endif // wxUSE_CHECKBOX
else
{
wxString cellval( grid.GetTable()->GetValue(row, col) );
- value = !( !cellval || (cellval == wxT("0")) );
+ value = wxGridCellBoolEditor::IsTrueValue(cellval);
}
if ( value )
if ( IsReadOnly() )
attr->SetReadOnly();
+ attr->SetOverflow( m_overflow == Overflow );
attr->SetKind( m_attrkind );
return attr;
int x, y;
m_owner->CalcUnscrolledPosition( 0, 0, &x, &y );
- dc.SetDeviceOrigin( 0, -y );
+ wxPoint pt = dc.GetDeviceOrigin();
+ dc.SetDeviceOrigin( pt.x, pt.y-y );
wxArrayInt rows = m_owner->CalcRowLabelsExposed( GetUpdateRegion() );
m_owner->DrawRowLabels( dc, rows );
int x, y;
m_owner->CalcUnscrolledPosition( 0, 0, &x, &y );
- dc.SetDeviceOrigin( -x, 0 );
+ wxPoint pt = dc.GetDeviceOrigin();
+ if (GetLayoutDirection() == wxLayout_RightToLeft)
+ dc.SetDeviceOrigin( pt.x+x, pt.y );
+ else
+ dc.SetDeviceOrigin( pt.x-x, pt.y );
wxArrayInt cols = m_owner->CalcColLabelsExposed( GetUpdateRegion() );
m_owner->DrawColLabels( dc, cols );
GetClientSize( &client_width, &client_height );
// VZ: any reason for this ifdef? (FIXME)
-#ifdef __WXGTK__
+#if 0
+def __WXGTK__
wxRect rect;
rect.SetX( 1 );
rect.SetY( 1 );
m_rowMinHeights(GRID_HASH_SIZE)
{
Create();
- SetBestFittingSize(size);
+ SetInitialSize(size);
}
bool wxGrid::Create(wxWindow *parent, wxWindowID id,
m_rowMinHeights = wxLongToLongHashMap(GRID_HASH_SIZE);
Create();
- SetBestFittingSize(size);
+ SetInitialSize(size);
return true;
}
total ? (gs_nAttrCacheHits*100) / total : 0);
#endif
- if (m_ownTable)
+ // if we own the table, just delete it, otherwise at least don't leave it
+ // with dangling view pointer
+ if ( m_ownTable )
delete m_table;
+ else if ( m_table && m_table->GetView() == this )
+ m_table->SetView(NULL);
delete m_typeRegistry;
delete m_selection;
// default widths/heights are used for all rows/columns, we may not use these
// arrays at all
//
-// with some extra code, it should be possible to only store the
-// widths/heights different from default ones but this will be done later...
+// with some extra code, it should be possible to only store the widths/heights
+// different from default ones (resulting in space savings for huge grids) but
+// this is not done currently
// ----------------------------------------------------------------------------
void wxGrid::InitRowHeights()
m_rowHeights.Alloc( m_numRows );
m_rowBottoms.Alloc( m_numRows );
- int rowBottom = 0;
-
m_rowHeights.Add( m_defaultRowHeight, m_numRows );
+ int rowBottom = 0;
for ( int i = 0; i < m_numRows; i++ )
{
rowBottom += m_defaultRowHeight;
m_colWidths.Alloc( m_numCols );
m_colRights.Alloc( m_numCols );
- int colRight = 0;
m_colWidths.Add( m_defaultColWidth, m_numCols );
+ int colRight = 0;
for ( int i = 0; i < m_numCols; i++ )
{
colRight = ( GetColPos( i ) + 1 ) * m_defaultColWidth;
void wxGrid::CalcDimensions()
{
- int cw, ch;
- GetClientSize( &cw, &ch );
+ // compute the size of the scrollable area
+ int w = m_numCols > 0 ? GetColRight(GetColAt(m_numCols - 1)) : 0;
+ int h = m_numRows > 0 ? GetRowBottom(m_numRows - 1) : 0;
- if ( m_rowLabelWin->IsShown() )
- cw -= m_rowLabelWidth;
- if ( m_colLabelWin->IsShown() )
- ch -= m_colLabelHeight;
-
- // grid total size
- int w = m_numCols > 0 ? GetColRight(GetColAt( m_numCols - 1 )) + m_extraWidth + 1 : 0;
- int h = m_numRows > 0 ? GetRowBottom(m_numRows - 1) + m_extraHeight + 1 : 0;
+ w += m_extraWidth;
+ h += m_extraHeight;
// take into account editor if shown
if ( IsCellEditControlShown() )
// do set scrollbar parameters
SetScrollbars( m_scrollLineX, m_scrollLineY,
- GetScrollX(w), GetScrollY(h), x, y,
+ GetScrollX(w), GetScrollY(h),
+ x, y,
GetBatchCount() != 0);
// if our OnSize() hadn't been called (it would if we have scrollbars), we
int cw, ch;
GetClientSize( &cw, &ch );
+ // this block of code tries to work around the following problem: the grid
+ // could have been just resized to have enough space to show the full grid
+ // window contents without the scrollbars, but its client size could be
+ // not big enough because the grid has the scrollbars right now and so the
+ // scrollbars would remain even though we don't need them any more
+ //
+ // to prevent this from happening, check if we have enough space for
+ // everything without the scrollbars and explicitly disable them then
+ wxSize size = GetSize() - GetWindowBorderSize();
+ if ( size != wxSize(cw, ch) )
+ {
+ // check if we have enough space for grid window after accounting for
+ // the fixed size elements
+ size.x -= m_rowLabelWidth;
+ size.y -= m_colLabelHeight;
+
+ const wxSize vsize = m_gridWin->GetVirtualSize();
+
+ if ( size.x >= vsize.x && size.y >= vsize.y )
+ {
+ // yes, we do, so remove the scrollbars and use the new client size
+ // (which should be the same as full window size - borders now)
+ SetScrollbars(0, 0, 0, 0);
+ GetClientSize(&cw, &ch);
+ }
+ }
+
if ( m_cornerLabelWin && m_cornerLabelWin->IsShown() )
m_cornerLabelWin->SetSize( 0, 0, m_rowLabelWidth, m_colLabelHeight );
if ( !parent->GetEventHandler()->ProcessEvent( keyEvt ) )
{
+ if (GetLayoutDirection() == wxLayout_RightToLeft)
+ {
+ if (event.GetKeyCode() == WXK_RIGHT)
+ event.m_keyCode = WXK_LEFT;
+ else if (event.GetKeyCode() == WXK_LEFT)
+ event.m_keyCode = WXK_RIGHT;
+ }
+
// try local handlers
switch ( event.GetKeyCode() )
{
return;
}
+#if !(defined(__WXMAC__) && wxMAC_USE_CORE_GRAPHICS)
wxClientDC dc( m_gridWin );
PrepareDC( dc );
+#endif
if ( m_currentCellCoords != wxGridNoCellCoords )
{
// Otherwise refresh redraws the highlight!
m_currentCellCoords = coords;
+#if defined(__WXMAC__) && wxMAC_USE_CORE_GRAPHICS
+ m_gridWin->Refresh(true /*, & r */);
+#else
DrawGridCellArea( dc, cells );
DrawAllGridLines( dc, r );
+#endif
}
}
m_currentCellCoords = coords;
wxGridCellAttr *attr = GetCellAttr( coords );
+#if !(defined(__WXMAC__) && wxMAC_USE_CORE_GRAPHICS)
DrawCellHighlight( dc, attr );
+#endif
attr->DecRef();
}
// edit control is erased by this code after being rendered.
// On wxMac (QD build only), the cell editor is a wxTextCntl and is rendered
// implicitly, causing this out-of order render.
-#if !defined(__WXMAC__) || wxMAC_USE_CORE_GRAPHICS
+#if !defined(__WXMAC__)
wxGridCellEditor *editor = attr->GetEditor(this, row, col);
editor->PaintBackground(rect, attr);
editor->DecRef();
int rightCol = GetColPos( internalXToCol(right) );
int bottomRow = internalYToRow(bottom);
-#ifndef __WXMAC__
- // CS: I don't know why suddenly unscrolled coordinates are used for clipping
+#if !defined(__WXMAC__) || wxMAC_USE_CORE_GRAPHICS
wxRegion clippedcells(0, 0, cw, ch);
int i, j, cell_rows, cell_cols;
wxRect rect;
- for (j=topRow; j<bottomRow; j++)
+ for (j=topRow; j<=bottomRow; j++)
{
int colPos;
- for (colPos=leftCol; colPos<rightCol; colPos++)
+ for (colPos=leftCol; colPos<=rightCol; colPos++)
{
i = GetColAt( colPos );
int i, j, cell_rows, cell_cols;
wxRect rect;
- for (j=topRow; j<bottomRow; j++)
+ for (j=topRow; j<=bottomRow; j++)
{
- for (i=leftCol; i<rightCol; i++)
+ for (i=leftCol; i<=rightCol; i++)
{
GetCellSize( j, i, &cell_rows, &cell_cols );
if ((cell_rows > 1) || (cell_cols > 1))
{
i = GetColAt( colPos );
- int colRight = GetColRight(i) - 1;
+ int colRight = GetColRight(i);
+#ifdef __WXGTK__
+ if (GetLayoutDirection() != wxLayout_RightToLeft)
+#endif
+ colRight--;
+
if ( colRight > right )
{
break;
wxRect rect;
-#ifdef __WXGTK20__
+#if 0
+def __WXGTK20__
rect.SetX( 1 );
rect.SetY( GetRowTop(row) + 1 );
rect.SetWidth( m_rowLabelWidth - 2 );
wxRect rect;
-#ifdef __WXGTK20__
+#if 0
+def __WXGTK20__
rect.SetX( colLeft + 1 );
rect.SetY( 1 );
rect.SetWidth( GetColWidth(col) - 2 );
continue;
}
- long lineWidth,
- lineHeight;
+ long lineWidth = 0,
+ lineHeight = 0;
dc.GetTextExtent(line, &lineWidth, &lineHeight);
switch ( horizAlign )
return GetColAt( maxPos );
}
-// return the row number that that the y coord is near the edge of, or
-// -1 if not near an edge
+// return the row number that that the y coord is near
+// the edge of, or -1 if not near an edge.
+// coords can only possibly be near an edge if
+// (a) the row/column is large enough to still allow for an "inner" area
+// that is _not_ nead the edge (i.e., if the height/width is smaller
+// than WXGRID_LABEL_EDGE_ZONE, coords are _never_ considered to be
+// near the edge).
+// and
+// (b) resizing rows/columns (the thing for which edge detection is
+// relevant at all) is enabled.
//
int wxGrid::YToEdgeOfRow( int y )
{
int i;
i = internalYToRow(y);
- if ( GetRowHeight(i) > WXGRID_LABEL_EDGE_ZONE )
+ if ( GetRowHeight(i) > WXGRID_LABEL_EDGE_ZONE && CanDragRowSize() )
{
// We know that we are in row i, test whether we are
// close enough to lower or upper border, respectively.
// return the col number that that the x coord is near the edge of, or
// -1 if not near an edge
+// See comment at YToEdgeOfRow for conditions on edge detection.
//
int wxGrid::XToEdgeOfCol( int x )
{
int i;
i = internalXToCol(x);
- if ( GetColWidth(i) > WXGRID_LABEL_EDGE_ZONE )
+ if ( GetColWidth(i) > WXGRID_LABEL_EDGE_ZONE && CanDragColSize() )
{
// We know that we are in column i; test whether we are
// close enough to right or left border, respectively.
int diff = h - m_rowHeights[row];
m_rowHeights[row] = h;
- int i;
- for ( i = row; i < m_numRows; i++ )
+ for ( int i = row; i < m_numRows; i++ )
{
m_rowBottoms[i] += diff;
}
int diff = w - m_colWidths[col];
m_colWidths[col] = w;
- int i;
- int colPos;
- for ( colPos = GetColPos( col ); colPos < m_numCols; colPos++ )
+ for ( int colPos = GetColPos(col); colPos < m_numCols; colPos++ )
{
- i = GetColAt( colPos );
- m_colRights[i] += diff;
+ m_colRights[GetColAt(colPos)] += diff;
}
if ( !GetBatchCount() )
if ( column )
{
- dc.GetTextExtent( GetColLabelValue(col), &w, &h );
+ dc.GetMultiLineTextExtent( GetColLabelValue(col), &w, &h );
if ( GetColLabelTextOrientation() == wxVERTICAL )
w = h;
}
else
- dc.GetTextExtent( GetRowLabelValue(row), &w, &h );
+ dc.GetMultiLineTextExtent( GetRowLabelValue(row), &w, &h );
extent = column ? w : h;
if ( extent > extentMax )
{
BeginBatch();
- wxSize size(SetOrCalcColumnSizes(false), SetOrCalcRowSizes(false));
-
- // 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
- // CalcDimension adds m_extraWidth + 1 etc. to calculate the necessary
- // scrollbar steps
- wxSize sizeFit(
- GetScrollX(size.x + m_extraWidth + 1) * m_scrollLineX,
- GetScrollY(size.y + m_extraHeight + 1) * m_scrollLineY );
+ // we need to round up the size of the scrollable area to a multiple of
+ // scroll step to ensure that we don't get the scrollbars when we're sized
+ // exactly to fit our contents
+ wxSize size(SetOrCalcColumnSizes(false) - m_rowLabelWidth + m_extraWidth,
+ SetOrCalcRowSizes(false) - m_colLabelHeight + m_extraHeight);
+ wxSize sizeFit(GetScrollX(size.x) * GetScrollLineX(),
+ GetScrollY(size.y) * GetScrollLineY());
// distribute the extra space between the columns/rows to avoid having
// extra white space
-
- // Remove the extra m_extraWidth + 1 added above
- wxCoord diff = sizeFit.x - size.x + (m_extraWidth + 1);
+ wxCoord diff = sizeFit.x - size.x;
if ( diff && m_numCols )
{
// try to resize the columns uniformly
}
// same for rows
- diff = sizeFit.y - size.y - (m_extraHeight + 1);
+ diff = sizeFit.y - size.y;
if ( diff && m_numRows )
{
// try to resize the columns uniformly
}
}
- EndBatch();
+ // we know that we're not going to have scrollbars so disable them now to
+ // avoid trouble in SetClientSize() which can otherwise set the correct
+ // client size but also leave space for (not needed any more) scrollbars
+ SetScrollbars(0, 0, 0, 0, 0, 0, true);
+ SetClientSize(sizeFit.x + m_rowLabelWidth, sizeFit.y + m_colLabelHeight);
- SetClientSize(sizeFit);
+ EndBatch();
}
void wxGrid::AutoSizeRowLabelSize( int row )
wxSize wxGrid::DoGetBestSize() const
{
- // don't set sizes, only calculate them
wxGrid *self = (wxGrid *)this; // const_cast
- int width, height;
- width = self->SetOrCalcColumnSizes(true);
- height = self->SetOrCalcRowSizes(true);
-
- if (!width)
- width = 100;
- if (!height)
- height = 80;
-
- // Round up to a multiple the scroll rate
- // NOTE: this still doesn't get rid of the scrollbars;
- // is there any magic incantation for that?
- int xpu, ypu;
- GetScrollPixelsPerUnit(&xpu, &ypu);
- if (xpu)
- width += 1 + xpu - (width % xpu);
- if (ypu)
- height += 1 + ypu - (height % ypu);
-
- // limit to 1/4 of the screen size
- int maxwidth, maxheight;
- wxDisplaySize( &maxwidth, &maxheight );
- maxwidth /= 2;
- maxheight /= 2;
- if ( width > maxwidth )
- width = maxwidth;
- if ( height > maxheight )
- height = maxheight;
-
- wxSize best(width, height);
+ // we do the same as in AutoSize() here with the exception that we don't
+ // change the column/row sizes, only calculate them
+ wxSize size(self->SetOrCalcColumnSizes(true) - m_rowLabelWidth + m_extraWidth,
+ self->SetOrCalcRowSizes(true) - m_colLabelHeight + m_extraHeight);
+ wxSize sizeFit(GetScrollX(size.x) * GetScrollLineX(),
+ GetScrollY(size.y) * GetScrollLineY());
// NOTE: This size should be cached, but first we need to add calls to
// InvalidateBestSize everywhere that could change the results of this
// calculation.
// CacheBestSize(size);
- return best;
+ return wxSize(sizeFit.x + m_rowLabelWidth, sizeFit.y + m_colLabelHeight)
+ + GetWindowBorderSize();
}
void wxGrid::Fit()