X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/ccdee36f75f1e988409a3455d1bfc3dedb957c9b..3201a1046ba71ba8e5ef2ed694fde34d12f743f3:/src/generic/grid.cpp diff --git a/src/generic/grid.cpp b/src/generic/grid.cpp index f1decc96ce..69debf7727 100644 --- a/src/generic/grid.cpp +++ b/src/generic/grid.cpp @@ -2,14 +2,14 @@ // Name: src/generic/grid.cpp // Purpose: wxGrid and related classes // Author: Michael Bedward (based on code by Julian Smart, Robin Dunn) -// Modified by: Robin Dunn, Vadim Zeitlin +// Modified by: Robin Dunn, Vadim Zeitlin, Santiago Palacios // Created: 1/08/1999 // RCS-ID: $Id$ // Copyright: (c) Michael Bedward (mbedward@ozemail.com.au) // Licence: wxWindows licence ///////////////////////////////////////////////////////////////////////////// -// For compilers that support precompilatixon, includes "wx/wx.h". +// For compilers that support precompilation, includes "wx/wx.h". #include "wx/wxprec.h" #ifdef __BORLANDC__ @@ -18,6 +18,8 @@ #if wxUSE_GRID +#include "wx/grid.h" + #ifndef WX_PRECOMP #include "wx/utils.h" #include "wx/dcclient.h" @@ -29,6 +31,7 @@ #include "wx/valtext.h" #include "wx/intl.h" #include "wx/math.h" + #include "wx/listbox.h" #endif #include "wx/textfile.h" @@ -36,9 +39,10 @@ #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 @@ -104,6 +108,7 @@ DEFINE_EVENT_TYPE(wxEVT_GRID_LABEL_LEFT_DCLICK) DEFINE_EVENT_TYPE(wxEVT_GRID_LABEL_RIGHT_DCLICK) DEFINE_EVENT_TYPE(wxEVT_GRID_ROW_SIZE) DEFINE_EVENT_TYPE(wxEVT_GRID_COL_SIZE) +DEFINE_EVENT_TYPE(wxEVT_GRID_COL_MOVE) DEFINE_EVENT_TYPE(wxEVT_GRID_RANGE_SELECT) DEFINE_EVENT_TYPE(wxEVT_GRID_CELL_CHANGE) DEFINE_EVENT_TYPE(wxEVT_GRID_SELECT_CELL) @@ -115,22 +120,48 @@ DEFINE_EVENT_TYPE(wxEVT_GRID_EDITOR_CREATED) // private classes // ---------------------------------------------------------------------------- -class WXDLLIMPEXP_ADV wxGridRowLabelWindow : public wxWindow +// common base class for various grid subwindows +class WXDLLIMPEXP_ADV wxGridSubwindow : public wxWindow +{ +public: + wxGridSubwindow() { m_owner = NULL; } + wxGridSubwindow(wxGrid *owner, + wxWindowID id, + const wxPoint& pos, + const wxSize& size, + int additionalStyle = 0, + const wxString& name = wxPanelNameStr) + : wxWindow(owner, id, pos, size, + wxBORDER_NONE | additionalStyle, + name) + { + m_owner = owner; + } + + virtual bool AcceptsFocus() const { return false; } + + wxGrid *GetOwner() { return m_owner; } + +protected: + void OnMouseCaptureLost(wxMouseCaptureLostEvent& event); + + wxGrid *m_owner; + + DECLARE_EVENT_TABLE() + DECLARE_NO_COPY_CLASS(wxGridSubwindow) +}; + +class WXDLLIMPEXP_ADV wxGridRowLabelWindow : public wxGridSubwindow { public: - wxGridRowLabelWindow() { m_owner = (wxGrid *)NULL; } + wxGridRowLabelWindow() { } wxGridRowLabelWindow( wxGrid *parent, wxWindowID id, const wxPoint &pos, const wxSize &size ); private: - wxGrid *m_owner; - void OnPaint( wxPaintEvent& event ); void OnMouseEvent( wxMouseEvent& event ); void OnMouseWheel( wxMouseEvent& event ); - void OnKeyDown( wxKeyEvent& event ); - void OnKeyUp( wxKeyEvent& ); - void OnChar( wxKeyEvent& ); DECLARE_DYNAMIC_CLASS(wxGridRowLabelWindow) DECLARE_EVENT_TABLE() @@ -138,22 +169,17 @@ private: }; -class WXDLLIMPEXP_ADV wxGridColLabelWindow : public wxWindow +class WXDLLIMPEXP_ADV wxGridColLabelWindow : public wxGridSubwindow { public: - wxGridColLabelWindow() { m_owner = (wxGrid *)NULL; } + wxGridColLabelWindow() { } wxGridColLabelWindow( wxGrid *parent, wxWindowID id, const wxPoint &pos, const wxSize &size ); private: - wxGrid *m_owner; - - void OnPaint( wxPaintEvent &event ); + void OnPaint( wxPaintEvent& event ); void OnMouseEvent( wxMouseEvent& event ); void OnMouseWheel( wxMouseEvent& event ); - void OnKeyDown( wxKeyEvent& event ); - void OnKeyUp( wxKeyEvent& ); - void OnChar( wxKeyEvent& ); DECLARE_DYNAMIC_CLASS(wxGridColLabelWindow) DECLARE_EVENT_TABLE() @@ -161,21 +187,16 @@ private: }; -class WXDLLIMPEXP_ADV wxGridCornerLabelWindow : public wxWindow +class WXDLLIMPEXP_ADV wxGridCornerLabelWindow : public wxGridSubwindow { public: - wxGridCornerLabelWindow() { m_owner = (wxGrid *)NULL; } + wxGridCornerLabelWindow() { } wxGridCornerLabelWindow( wxGrid *parent, wxWindowID id, const wxPoint &pos, const wxSize &size ); private: - wxGrid *m_owner; - void OnMouseEvent( wxMouseEvent& event ); void OnMouseWheel( wxMouseEvent& event ); - void OnKeyDown( wxKeyEvent& event ); - void OnKeyUp( wxKeyEvent& ); - void OnChar( wxKeyEvent& ); void OnPaint( wxPaintEvent& event ); DECLARE_DYNAMIC_CLASS(wxGridCornerLabelWindow) @@ -183,28 +204,25 @@ private: DECLARE_NO_COPY_CLASS(wxGridCornerLabelWindow) }; -class WXDLLIMPEXP_ADV wxGridWindow : public wxWindow +class WXDLLIMPEXP_ADV wxGridWindow : public wxGridSubwindow { public: wxGridWindow() { - m_owner = (wxGrid *)NULL; - m_rowLabelWin = (wxGridRowLabelWindow *)NULL; - m_colLabelWin = (wxGridColLabelWindow *)NULL; + m_rowLabelWin = NULL; + m_colLabelWin = NULL; } wxGridWindow( wxGrid *parent, wxGridRowLabelWindow *rowLblWin, wxGridColLabelWindow *colLblWin, wxWindowID id, const wxPoint &pos, const wxSize &size ); - ~wxGridWindow() {} void ScrollWindow( int dx, int dy, const wxRect *rect ); - wxGrid* GetOwner() { return m_owner; } + virtual bool AcceptsFocus() const { return true; } private: - wxGrid *m_owner; wxGridRowLabelWindow *m_rowLabelWin; wxGridColLabelWindow *m_colLabelWin; @@ -262,7 +280,6 @@ BEGIN_EVENT_TABLE( wxGridCellEditorEvtHandler, wxEvtHandler ) END_EVENT_TABLE() - // ---------------------------------------------------------------------------- // the internal data representation used by wxGridCellAttrProvider // ---------------------------------------------------------------------------- @@ -370,6 +387,7 @@ private: wxGridDataTypeInfoArray m_typeinfo; }; + // ---------------------------------------------------------------------------- // conditional compilation // ---------------------------------------------------------------------------- @@ -467,7 +485,7 @@ void wxGridCellEditor::PaintBackground(const wxRect& rectCell, gridWindow->GetOwner()->PrepareDC(dc); dc.SetPen(*wxTRANSPARENT_PEN); - dc.SetBrush(wxBrush(attr->GetBackgroundColour(), wxSOLID)); + dc.SetBrush(wxBrush(attr->GetBackgroundColour(), wxBRUSHSTYLE_SOLID)); dc.DrawRectangle(rectCell); // redraw the control we just painted over @@ -478,7 +496,7 @@ void wxGridCellEditor::Destroy() { if (m_control) { - m_control->PopEventHandler(true /* delete it*/); + m_control->PopEventHandler( true /* delete it*/ ); m_control->Destroy(); m_control = NULL; @@ -507,6 +525,7 @@ void wxGridCellEditor::Show(bool show, wxGridCellAttr *attr) m_fontOld = m_control->GetFont(); m_control->SetFont(attr->GetFont()); #endif + // can't do anything more in the base class version, the other // attributes may only be used by the derived classes } @@ -569,6 +588,12 @@ bool wxGridCellEditor::IsAcceptedKey(wxKeyEvent& event) int key = 0; bool keyOk = true; +#ifdef __WXGTK20__ + // If it's a F-Key or other special key then it shouldn't start the + // editor. + if (event.GetKeyCode() >= WXK_START) + return false; +#endif #if wxUSE_UNICODE // if the unicode key code is not really a unicode character (it may // be a function key or etc., the platforms appear to always give us a @@ -612,17 +637,27 @@ void wxGridCellTextEditor::Create(wxWindow* parent, wxWindowID id, wxEvtHandler* evtHandler) { + DoCreate(parent, id, evtHandler); +} + +void wxGridCellTextEditor::DoCreate(wxWindow* parent, + wxWindowID id, + wxEvtHandler* evtHandler, + long style) +{ + style |= wxTE_PROCESS_ENTER | + wxTE_PROCESS_TAB | + wxTE_AUTO_SCROLL | + wxNO_BORDER; + m_control = new wxTextCtrl(parent, id, wxEmptyString, - wxDefaultPosition, wxDefaultSize -#if defined(__WXMSW__) - , wxTE_PROCESS_TAB | wxTE_AUTO_SCROLL -#endif - ); + wxDefaultPosition, wxDefaultSize, + style); // set max length allowed in the textctrl, if the parameter was set - if (m_maxChars != 0) + if ( m_maxChars != 0 ) { - ((wxTextCtrl*)m_control)->SetMaxLength(m_maxChars); + Text()->SetMaxLength(m_maxChars); } wxGridCellEditor::Create(parent, id, evtHandler); @@ -631,8 +666,8 @@ void wxGridCellTextEditor::Create(wxWindow* parent, void wxGridCellTextEditor::PaintBackground(const wxRect& WXUNUSED(rectCell), wxGridCellAttr * WXUNUSED(attr)) { - // as we fill the entire client area, don't do anything here to minimize - // flicker + // as we fill the entire client area, + // don't do anything here to minimize flicker } void wxGridCellTextEditor::SetSize(const wxRect& rectOrig) @@ -651,27 +686,33 @@ void wxGridCellTextEditor::SetSize(const wxRect& rectOrig) rect.width -= 1; rect.height -= 1; } -#else // !GTK - int extra_x = ( rect.x > 2 ) ? 2 : 1; +#elif defined(__WXMSW__) + if ( rect.x == 0 ) + rect.x += 2; + else + rect.x += 3; + + if ( rect.y == 0 ) + rect.y += 2; + else + rect.y += 3; -// MB: treat MSW separately here otherwise the caret doesn't show -// when the editor is in the first row. -#if defined(__WXMSW__) - int extra_y = 2; + rect.width -= 2; + rect.height -= 2; #else + int extra_x = ( rect.x > 2 ) ? 2 : 1; int extra_y = ( rect.y > 2 ) ? 2 : 1; -#endif -#if defined(__WXMOTIF__) - extra_x *= 2; - extra_y *= 2; -#endif + #if defined(__WXMOTIF__) + extra_x *= 2; + extra_y *= 2; + #endif rect.SetLeft( wxMax(0, rect.x - extra_x) ); rect.SetTop( wxMax(0, rect.y - extra_y) ); rect.SetRight( rect.GetRight() + 2 * extra_x ); rect.SetBottom( rect.GetBottom() + 2 * extra_y ); -#endif // GTK/!GTK +#endif wxGridCellEditor::SetSize(rect); } @@ -706,6 +747,7 @@ bool wxGridCellTextEditor::EndEdit(int row, int col, wxGrid* grid) grid->GetTable()->SetValue(row, col, value); m_startValue = wxEmptyString; + // No point in setting the text of the hidden control //Text()->SetValue(m_startValue); @@ -798,13 +840,13 @@ void wxGridCellTextEditor::SetParameters(const wxString& params) else { long tmp; - if ( !params.ToLong(&tmp) ) + if ( params.ToLong(&tmp) ) { - wxLogDebug(_T("Invalid wxGridCellTextEditor parameter string '%s' ignored"), params.c_str()); + m_maxChars = (size_t)tmp; } else { - m_maxChars = (size_t)tmp; + wxLogDebug( _T("Invalid wxGridCellTextEditor parameter string '%s' ignored"), params.c_str() ); } } } @@ -848,7 +890,7 @@ void wxGridCellNumberEditor::Create(wxWindow* parent, #if wxUSE_VALIDATORS Text()->SetValidator(wxTextValidator(wxFILTER_NUMERIC)); -#endif // wxUSE_VALIDATORS +#endif } } @@ -1041,7 +1083,7 @@ void wxGridCellFloatEditor::Create(wxWindow* parent, #if wxUSE_VALIDATORS Text()->SetValidator(wxTextValidator(wxFILTER_NUMERIC)); -#endif // wxUSE_VALIDATORS +#endif } void wxGridCellFloatEditor::BeginEdit(int row, int col, wxGrid* grid) @@ -1176,27 +1218,30 @@ bool wxGridCellFloatEditor::IsAcceptedKey(wxKeyEvent& event) { 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; + } } } @@ -1211,6 +1256,9 @@ bool wxGridCellFloatEditor::IsAcceptedKey(wxKeyEvent& event) // wxGridCellBoolEditor // ---------------------------------------------------------------------------- +// the default values for GetValue() +wxString wxGridCellBoolEditor::ms_stringValues[2] = { _T(""), _T("1") }; + void wxGridCellBoolEditor::Create(wxWindow* parent, wxWindowID id, wxEvtHandler* evtHandler) @@ -1307,7 +1355,7 @@ void wxGridCellBoolEditor::Show(bool show, wxGridCellAttr *attr) void wxGridCellBoolEditor::BeginEdit(int row, int col, wxGrid* grid) { wxASSERT_MSG(m_control, - wxT("The wxGridCellEditor must be Created first!")); + wxT("The wxGridCellEditor must be created first!")); if (grid->GetTable()->CanGetValueAs(row, col, wxGRID_VALUE_BOOL)) { @@ -1316,7 +1364,19 @@ void wxGridCellBoolEditor::BeginEdit(int row, int col, wxGrid* grid) 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); @@ -1327,7 +1387,7 @@ bool wxGridCellBoolEditor::EndEdit(int row, int col, wxGrid* grid) { wxASSERT_MSG(m_control, - wxT("The wxGridCellEditor must be Created first!")); + wxT("The wxGridCellEditor must be created first!")); bool changed = false; bool value = CBox()->GetValue(); @@ -1336,10 +1396,11 @@ bool wxGridCellBoolEditor::EndEdit(int row, int col, 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; @@ -1348,7 +1409,7 @@ bool wxGridCellBoolEditor::EndEdit(int row, int col, void wxGridCellBoolEditor::Reset() { wxASSERT_MSG(m_control, - wxT("The wxGridCellEditor must be Created first!")); + wxT("The wxGridCellEditor must be created first!")); CBox()->SetValue(m_startValue); } @@ -1394,12 +1455,23 @@ void wxGridCellBoolEditor::StartingKey(wxKeyEvent& event) } } - -// 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 @@ -1443,10 +1515,16 @@ void wxGridCellChoiceEditor::Create(wxWindow* parent, wxWindowID id, wxEvtHandler* evtHandler) { + int style = wxTE_PROCESS_ENTER | + wxTE_PROCESS_TAB | + wxBORDER_NONE; + + if ( !m_allowOthers ) + style |= wxCB_READONLY; m_control = new wxComboBox(parent, id, wxEmptyString, wxDefaultPosition, wxDefaultSize, m_choices, - m_allowOthers ? 0 : wxCB_READONLY); + style); wxGridCellEditor::Create(parent, id, evtHandler); } @@ -1458,15 +1536,15 @@ void wxGridCellChoiceEditor::PaintBackground(const wxRect& rectCell, // flicker // TODO: It doesn't actually fill the client area since the height of a - // combo always defaults to the standard... Until someone has time to - // figure out the right rectangle to paint, just do it the normal way... + // combo always defaults to the standard. Until someone has time to + // figure out the right rectangle to paint, just do it the normal way. wxGridCellEditor::PaintBackground(rectCell, attr); } void wxGridCellChoiceEditor::BeginEdit(int row, int col, wxGrid* grid) { wxASSERT_MSG(m_control, - wxT("The wxGridCellEditor must be Created first!")); + wxT("The wxGridCellEditor must be created first!")); wxGridCellEditorEvtHandler* evtHandler = NULL; if (m_control) @@ -1481,8 +1559,9 @@ void wxGridCellChoiceEditor::BeginEdit(int row, int col, wxGrid* grid) if (m_allowOthers) { Combo()->SetValue(m_startValue); + Combo()->SetInsertionPointEnd(); } - else + else // the combobox is read-only { // find the right position, or default to the first if not found int pos = Combo()->FindString(m_startValue); @@ -1491,7 +1570,6 @@ void wxGridCellChoiceEditor::BeginEdit(int row, int col, wxGrid* grid) Combo()->SetSelection(pos); } - Combo()->SetInsertionPointEnd(); Combo()->SetFocus(); if (evtHandler) @@ -1638,6 +1716,7 @@ void wxGridCellEditorEvtHandler::OnChar(wxKeyEvent& event) event.Skip(); break; } + case WXK_END: { if ( wholeCellVisible ) @@ -1691,6 +1770,7 @@ void wxGridCellEditorEvtHandler::OnChar(wxKeyEvent& event) default: event.Skip(); + break; } } @@ -1723,23 +1803,28 @@ void wxGridCellRenderer::Draw(wxGrid& grid, int WXUNUSED(row), int WXUNUSED(col), bool isSelected) { - dc.SetBackgroundMode( wxSOLID ); + dc.SetBackgroundMode( wxBRUSHSTYLE_SOLID ); // grey out fields if the grid is disabled if ( grid.IsEnabled() ) { if ( isSelected ) { - dc.SetBrush( wxBrush(grid.GetSelectionBackground(), wxSOLID) ); + wxColour clr; + if ( grid.HasFocus() ) + clr = grid.GetSelectionBackground(); + else + clr = wxSystemSettings::GetColour(wxSYS_COLOUR_BTNSHADOW); + dc.SetBrush( wxBrush(clr, wxBRUSHSTYLE_SOLID) ); } else { - dc.SetBrush( wxBrush(attr.GetBackgroundColour(), wxSOLID) ); + dc.SetBrush( wxBrush(attr.GetBackgroundColour(), wxBRUSHSTYLE_SOLID) ); } } else { - dc.SetBrush(wxBrush(wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE), wxSOLID)); + dc.SetBrush(wxBrush(wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE), wxBRUSHSTYLE_SOLID)); } dc.SetPen( *wxTRANSPARENT_PEN ); @@ -1755,28 +1840,33 @@ void wxGridCellStringRenderer::SetTextColoursAndFont(const wxGrid& grid, wxDC& dc, bool isSelected) { - dc.SetBackgroundMode( wxTRANSPARENT ); + dc.SetBackgroundMode( wxBRUSHSTYLE_TRANSPARENT ); // TODO some special colours for attr.IsReadOnly() case? // different coloured text when the grid is disabled if ( grid.IsEnabled() ) { - if ( isSelected ) - { - dc.SetTextBackground( grid.GetSelectionBackground() ); - dc.SetTextForeground( grid.GetSelectionForeground() ); - } - else - { - dc.SetTextBackground( attr.GetBackgroundColour() ); - dc.SetTextForeground( attr.GetTextColour() ); - } + if ( isSelected ) + { + wxColour clr; + if ( grid.HasFocus() ) + clr = grid.GetSelectionBackground(); + else + clr = wxSystemSettings::GetColour(wxSYS_COLOUR_BTNSHADOW); + dc.SetTextBackground( clr ); + dc.SetTextForeground( grid.GetSelectionForeground() ); + } + else + { + dc.SetTextBackground( attr.GetBackgroundColour() ); + dc.SetTextForeground( attr.GetTextColour() ); + } } else { - dc.SetTextBackground(wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE)); - dc.SetTextForeground(wxSystemSettings::GetColour(wxSYS_COLOUR_GRAYTEXT)); + dc.SetTextBackground(wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE)); + dc.SetTextForeground(wxSystemSettings::GetColour(wxSYS_COLOUR_GRAYTEXT)); } dc.SetFont( attr.GetFont() ); @@ -1852,7 +1942,9 @@ void wxGridCellStringRenderer::Draw(wxGrid& grid, } if (is_empty) + { rect.width += grid.GetColSize(i); + } else { i--; @@ -1874,10 +1966,10 @@ void wxGridCellStringRenderer::Draw(wxGrid& grid, wxRect clip = rect; clip.x += rectCell.width; // draw each overflow cell individually - int col_end = col+cell_cols + overflowCols; + 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++) + for (int i = col + cell_cols; i <= col_end; i++) { clip.width = grid.GetColSize(i) - 1; dc.DestroyClippingRegion(); @@ -2123,8 +2215,7 @@ wxSize wxGridCellBoolRenderer::GetBestSize(wxGrid& grid, wxSize size = checkbox->GetBestSize(); wxCoord checkSize = size.y + 2 * wxGRID_CHECKMARK_MARGIN; - // FIXME wxGTK::wxCheckBox::GetBestSize() gives "wrong" result -#if defined(__WXGTK__) || defined(__WXMOTIF__) +#if defined(__WXMOTIF__) checkSize -= size.y / 2; #endif @@ -2153,12 +2244,12 @@ void wxGridCellBoolRenderer::Draw(wxGrid& grid, if ( size.x >= minSize || size.y >= minSize ) { // and even leave (at least) 1 pixel margin - size.x = size.y = minSize - 2; + size.x = size.y = minSize; } // draw a border around checkmark int vAlign, hAlign; - attr.GetAlignment(& hAlign, &vAlign); + attr.GetAlignment(&hAlign, &vAlign); wxRect rectBorder; if (hAlign == wxALIGN_CENTRE) @@ -2185,33 +2276,20 @@ void wxGridCellBoolRenderer::Draw(wxGrid& grid, bool value; if ( grid.GetTable()->CanGetValueAs(row, col, wxGRID_VALUE_BOOL) ) + { value = grid.GetTable()->GetValueAsBool(row, col); + } else { wxString cellval( grid.GetTable()->GetValue(row, col) ); - value = !( !cellval || (cellval == wxT("0")) ); + value = wxGridCellBoolEditor::IsTrueValue(cellval); } - if ( value ) - { - wxRect rectMark = rectBorder; - -#ifdef __WXMSW__ - // MSW DrawCheckMark() is weird (and should probably be changed...) - rectMark.Inflate(-wxGRID_CHECKMARK_MARGIN / 2); - rectMark.x++; - rectMark.y++; -#else - rectMark.Inflate(-wxGRID_CHECKMARK_MARGIN); -#endif - - dc.SetTextForeground(attr.GetTextColour()); - dc.DrawCheckMark(rectMark); - } + int flags = 0; + if (value) + flags |= wxCONTROL_CHECKED; - dc.SetBrush(*wxTRANSPARENT_BRUSH); - dc.SetPen(wxPen(attr.GetTextColour(), 1, wxSOLID)); - dc.DrawRectangle(rectBorder); + wxRendererNative::Get().DrawCheckBox( &grid, dc, rectBorder, flags ); } // ---------------------------------------------------------------------------- @@ -2264,6 +2342,7 @@ wxGridCellAttr *wxGridCellAttr::Clone() const if ( IsReadOnly() ) attr->SetReadOnly(); + attr->SetOverflow( m_overflow == Overflow ); attr->SetKind( m_attrkind ); return attr; @@ -2391,7 +2470,9 @@ void wxGridCellAttr::GetAlignment(int *hAlign, int *vAlign) const *vAlign = m_vAlign; } else if (m_defGridAttr && m_defGridAttr != this) + { m_defGridAttr->GetAlignment(hAlign, vAlign); + } else { wxFAIL_MSG(wxT("Missing default cell attribute")); @@ -2411,11 +2492,11 @@ void wxGridCellAttr::GetSize( int *num_rows, int *num_cols ) const // used, otherwise the default editor or renderer is fetched from the grid and // used. It should be the default for the data type of the cell. If it is // NULL (because the table has a type that the grid does not have in its -// registry,) then the grid's default editor or renderer is used. +// registry), then the grid's default editor or renderer is used. -wxGridCellRenderer* wxGridCellAttr::GetRenderer(wxGrid* grid, int row, int col) const +wxGridCellRenderer* wxGridCellAttr::GetRenderer(const wxGrid* grid, int row, int col) const { - wxGridCellRenderer *renderer; + wxGridCellRenderer *renderer = NULL; if ( m_renderer && this != m_defGridAttr ) { @@ -2431,14 +2512,10 @@ wxGridCellRenderer* wxGridCellAttr::GetRenderer(wxGrid* grid, int row, int col) // GetDefaultRendererForCell() will do IncRef() for us renderer = grid->GetDefaultRendererForCell(row, col); } - else - { - renderer = NULL; - } - if ( !renderer ) + if ( renderer == NULL ) { - if (m_defGridAttr && this != m_defGridAttr ) + if ( (m_defGridAttr != NULL) && (m_defGridAttr != this) ) { // if we still don't have one then use the grid default // (no need for IncRef() here neither) @@ -2461,9 +2538,9 @@ wxGridCellRenderer* wxGridCellAttr::GetRenderer(wxGrid* grid, int row, int col) } // same as above, except for s/renderer/editor/g -wxGridCellEditor* wxGridCellAttr::GetEditor(wxGrid* grid, int row, int col) const +wxGridCellEditor* wxGridCellAttr::GetEditor(const wxGrid* grid, int row, int col) const { - wxGridCellEditor *editor; + wxGridCellEditor *editor = NULL; if ( m_editor && this != m_defGridAttr ) { @@ -2479,14 +2556,10 @@ wxGridCellEditor* wxGridCellAttr::GetEditor(wxGrid* grid, int row, int col) cons // GetDefaultEditorForCell() will do IncRef() for us editor = grid->GetDefaultEditorForCell(row, col); } - else - { - editor = NULL; - } - if ( !editor ) + if ( editor == NULL ) { - if ( m_defGridAttr && this != m_defGridAttr ) + if ( (m_defGridAttr != NULL) && (m_defGridAttr != this) ) { // if we still don't have one then use the grid default // (no need for IncRef() here neither) @@ -2517,8 +2590,12 @@ void wxGridCellAttrData::SetAttr(wxGridCellAttr *attr, int row, int col) int n = FindIndex(row, col); if ( n == wxNOT_FOUND ) { - // add the attribute - m_attrs.Add(new wxGridCellWithAttr(row, col, attr)); + if ( attr ) + { + // add the attribute + m_attrs.Add(new wxGridCellWithAttr(row, col, attr)); + } + //else: nothing to do } else { @@ -2645,7 +2722,7 @@ int wxGridCellAttrData::FindIndex(int row, int col) const wxGridRowOrColAttrData::~wxGridRowOrColAttrData() { - size_t count = m_attrs.Count(); + size_t count = m_attrs.GetCount(); for ( size_t n = 0; n < count; n++ ) { m_attrs[n]->DecRef(); @@ -2671,9 +2748,13 @@ void wxGridRowOrColAttrData::SetAttr(wxGridCellAttr *attr, int rowOrCol) int i = m_rowsOrCols.Index(rowOrCol); if ( i == wxNOT_FOUND ) { - // add the attribute - m_rowsOrCols.Add(rowOrCol); - m_attrs.Add(attr); + if ( attr ) + { + // add the attribute + m_rowsOrCols.Add(rowOrCol); + m_attrs.Add(attr); + } + // nothing to remove } else { @@ -2886,7 +2967,7 @@ void wxGridCellAttrProvider::UpdateAttrCols( size_t pos, int numCols ) wxGridTypeRegistry::~wxGridTypeRegistry() { - size_t count = m_typeinfo.Count(); + size_t count = m_typeinfo.GetCount(); for ( size_t i = 0; i < count; i++ ) delete m_typeinfo[i]; } @@ -3204,7 +3285,7 @@ wxString wxGridTableBase::GetColLabelValue( int col ) // reverse the string... wxString s2; - for ( i = 0; i < n; i++ ) + for ( i = 0; i < n; i++ ) { s2 += s[n - i - 1]; } @@ -3373,9 +3454,9 @@ void wxGridStringTable::Clear() { numCols = m_data[0].GetCount(); - for ( row = 0; row < numRows; row++ ) + for ( row = 0; row < numRows; row++ ) { - for ( col = 0; col < numCols; col++ ) + for ( col = 0; col < numCols; col++ ) { m_data[row][col] = wxEmptyString; } @@ -3498,9 +3579,18 @@ bool wxGridStringTable::InsertCols( size_t pos, size_t numCols ) return AppendCols( numCols ); } - for ( row = 0; row < curNumRows; row++ ) + if ( !m_colLabels.IsEmpty() ) + { + m_colLabels.Insert( wxEmptyString, pos, numCols ); + + size_t i; + for ( i = pos; i < pos + numCols; i++ ) + m_colLabels[i] = wxGridTableBase::GetColLabelValue( i ); + } + + for ( row = 0; row < curNumRows; row++ ) { - for ( col = pos; col < pos + numCols; col++ ) + for ( col = pos; col < pos + numCols; col++ ) { m_data[row].Insert( wxEmptyString, col ); } @@ -3535,7 +3625,7 @@ bool wxGridStringTable::AppendCols( size_t numCols ) } #endif - for ( row = 0; row < curNumRows; row++ ) + for ( row = 0; row < curNumRows; row++ ) { m_data[row].Add( wxEmptyString, numCols ); } @@ -3572,12 +3662,28 @@ bool wxGridStringTable::DeleteCols( size_t pos, size_t numCols ) return false; } - if ( numCols > curNumCols - pos ) + int colID; + if ( GetView() ) + colID = GetView()->GetColAt( pos ); + else + colID = pos; + + if ( numCols > curNumCols - colID ) + { + numCols = curNumCols - colID; + } + + if ( !m_colLabels.IsEmpty() ) { - numCols = curNumCols - pos; + // m_colLabels stores just as many elements as it needs, e.g. if only + // the label of the first column had been set it would have only one + // element and not numCols, so account for it + int nToRm = m_colLabels.size() - colID; + if ( nToRm > 0 ) + m_colLabels.RemoveAt( colID, nToRm ); } - for ( row = 0; row < curNumRows; row++ ) + for ( row = 0; row < curNumRows; row++ ) { if ( numCols >= curNumCols ) { @@ -3585,7 +3691,7 @@ bool wxGridStringTable::DeleteCols( size_t pos, size_t numCols ) } else { - m_data[row].RemoveAt( pos, numCols ); + m_data[row].RemoveAt( colID, numCols ); } } @@ -3637,7 +3743,7 @@ void wxGridStringTable::SetRowLabelValue( int row, const wxString& value ) int n = m_rowLabels.GetCount(); int i; - for ( i = n; i <= row; i++ ) + for ( i = n; i <= row; i++ ) { m_rowLabels.Add( wxGridTableBase::GetRowLabelValue(i) ); } @@ -3653,7 +3759,7 @@ void wxGridStringTable::SetColLabelValue( int col, const wxString& value ) int n = m_colLabels.GetCount(); int i; - for ( i = n; i <= col; i++ ) + for ( i = n; i <= col; i++ ) { m_colLabels.Add( wxGridTableBase::GetColLabelValue(i) ); } @@ -3666,21 +3772,27 @@ void wxGridStringTable::SetColLabelValue( int col, const wxString& value ) ////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////// +BEGIN_EVENT_TABLE(wxGridSubwindow, wxWindow) + EVT_MOUSE_CAPTURE_LOST(wxGridSubwindow::OnMouseCaptureLost) +END_EVENT_TABLE() + +void wxGridSubwindow::OnMouseCaptureLost(wxMouseCaptureLostEvent& WXUNUSED(event)) +{ + m_owner->CancelMouseCapture(); +} + IMPLEMENT_DYNAMIC_CLASS( wxGridRowLabelWindow, wxWindow ) -BEGIN_EVENT_TABLE( wxGridRowLabelWindow, wxWindow ) +BEGIN_EVENT_TABLE( wxGridRowLabelWindow, wxGridSubwindow ) EVT_PAINT( wxGridRowLabelWindow::OnPaint ) - EVT_MOUSEWHEEL( wxGridRowLabelWindow::OnMouseWheel) + EVT_MOUSEWHEEL( wxGridRowLabelWindow::OnMouseWheel ) EVT_MOUSE_EVENTS( wxGridRowLabelWindow::OnMouseEvent ) - EVT_KEY_DOWN( wxGridRowLabelWindow::OnKeyDown ) - EVT_KEY_UP( wxGridRowLabelWindow::OnKeyUp ) - EVT_CHAR ( wxGridRowLabelWindow::OnChar ) END_EVENT_TABLE() wxGridRowLabelWindow::wxGridRowLabelWindow( wxGrid *parent, wxWindowID id, const wxPoint &pos, const wxSize &size ) - : wxWindow( parent, id, pos, size, wxWANTS_CHARS|wxBORDER_NONE|wxFULL_REPAINT_ON_RESIZE ) + : wxGridSubwindow(parent, id, pos, size) { m_owner = parent; } @@ -3697,10 +3809,11 @@ void wxGridRowLabelWindow::OnPaint( wxPaintEvent& WXUNUSED(event) ) 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 ); + m_owner->DrawRowLabels( dc, rows ); } void wxGridRowLabelWindow::OnMouseEvent( wxMouseEvent& event ) @@ -3710,47 +3823,23 @@ void wxGridRowLabelWindow::OnMouseEvent( wxMouseEvent& event ) void wxGridRowLabelWindow::OnMouseWheel( wxMouseEvent& event ) { - m_owner->GetEventHandler()->ProcessEvent(event); -} - -// This seems to be required for wxMotif otherwise the mouse -// cursor must be in the cell edit control to get key events -// -void wxGridRowLabelWindow::OnKeyDown( wxKeyEvent& event ) -{ - if ( !m_owner->GetEventHandler()->ProcessEvent( event ) ) - event.Skip(); -} - -void wxGridRowLabelWindow::OnKeyUp( wxKeyEvent& event ) -{ - if ( !m_owner->GetEventHandler()->ProcessEvent( event ) ) - event.Skip(); -} - -void wxGridRowLabelWindow::OnChar( wxKeyEvent& event ) -{ - if ( !m_owner->GetEventHandler()->ProcessEvent( event ) ) - event.Skip(); + m_owner->GetEventHandler()->ProcessEvent( event ); } ////////////////////////////////////////////////////////////////////// IMPLEMENT_DYNAMIC_CLASS( wxGridColLabelWindow, wxWindow ) -BEGIN_EVENT_TABLE( wxGridColLabelWindow, wxWindow ) +BEGIN_EVENT_TABLE( wxGridColLabelWindow, wxGridSubwindow ) EVT_PAINT( wxGridColLabelWindow::OnPaint ) - EVT_MOUSEWHEEL( wxGridColLabelWindow::OnMouseWheel) + EVT_MOUSEWHEEL( wxGridColLabelWindow::OnMouseWheel ) EVT_MOUSE_EVENTS( wxGridColLabelWindow::OnMouseEvent ) - EVT_KEY_DOWN( wxGridColLabelWindow::OnKeyDown ) - EVT_KEY_UP( wxGridColLabelWindow::OnKeyUp ) - EVT_CHAR ( wxGridColLabelWindow::OnChar ) END_EVENT_TABLE() wxGridColLabelWindow::wxGridColLabelWindow( wxGrid *parent, wxWindowID id, const wxPoint &pos, const wxSize &size ) - : wxWindow( parent, id, pos, size, wxWANTS_CHARS|wxBORDER_NONE|wxFULL_REPAINT_ON_RESIZE ) + : wxGridSubwindow(parent, id, pos, size) { m_owner = parent; } @@ -3767,10 +3856,14 @@ void wxGridColLabelWindow::OnPaint( wxPaintEvent& WXUNUSED(event) ) 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 ); + m_owner->DrawColLabels( dc, cols ); } void wxGridColLabelWindow::OnMouseEvent( wxMouseEvent& event ) @@ -3780,47 +3873,23 @@ void wxGridColLabelWindow::OnMouseEvent( wxMouseEvent& event ) void wxGridColLabelWindow::OnMouseWheel( wxMouseEvent& event ) { - m_owner->GetEventHandler()->ProcessEvent(event); -} - -// This seems to be required for wxMotif otherwise the mouse -// cursor must be in the cell edit control to get key events -// -void wxGridColLabelWindow::OnKeyDown( wxKeyEvent& event ) -{ - if ( !m_owner->GetEventHandler()->ProcessEvent( event ) ) - event.Skip(); -} - -void wxGridColLabelWindow::OnKeyUp( wxKeyEvent& event ) -{ - if ( !m_owner->GetEventHandler()->ProcessEvent( event ) ) - event.Skip(); -} - -void wxGridColLabelWindow::OnChar( wxKeyEvent& event ) -{ - if ( !m_owner->GetEventHandler()->ProcessEvent( event ) ) - event.Skip(); + m_owner->GetEventHandler()->ProcessEvent( event ); } ////////////////////////////////////////////////////////////////////// IMPLEMENT_DYNAMIC_CLASS( wxGridCornerLabelWindow, wxWindow ) -BEGIN_EVENT_TABLE( wxGridCornerLabelWindow, wxWindow ) - EVT_MOUSEWHEEL( wxGridCornerLabelWindow::OnMouseWheel) +BEGIN_EVENT_TABLE( wxGridCornerLabelWindow, wxGridSubwindow ) + EVT_MOUSEWHEEL( wxGridCornerLabelWindow::OnMouseWheel ) EVT_MOUSE_EVENTS( wxGridCornerLabelWindow::OnMouseEvent ) - EVT_PAINT( wxGridCornerLabelWindow::OnPaint) - EVT_KEY_DOWN( wxGridCornerLabelWindow::OnKeyDown ) - EVT_KEY_UP( wxGridCornerLabelWindow::OnKeyUp ) - EVT_CHAR ( wxGridCornerLabelWindow::OnChar ) + EVT_PAINT( wxGridCornerLabelWindow::OnPaint ) END_EVENT_TABLE() wxGridCornerLabelWindow::wxGridCornerLabelWindow( wxGrid *parent, wxWindowID id, const wxPoint &pos, const wxSize &size ) - : wxWindow( parent, id, pos, size, wxWANTS_CHARS|wxBORDER_NONE|wxFULL_REPAINT_ON_RESIZE ) + : wxGridSubwindow(parent, id, pos, size) { m_owner = parent; } @@ -3834,7 +3903,8 @@ void wxGridCornerLabelWindow::OnPaint( wxPaintEvent& WXUNUSED(event) ) 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 ); @@ -3843,7 +3913,7 @@ void wxGridCornerLabelWindow::OnPaint( wxPaintEvent& WXUNUSED(event) ) wxRendererNative::Get().DrawHeaderButton( this, dc, rect, 0 ); #else // !__WXGTK__ - dc.SetPen( wxPen(wxSystemSettings::GetColour(wxSYS_COLOUR_3DDKSHADOW), 1, wxSOLID) ); + dc.SetPen( wxPen(wxSystemSettings::GetColour(wxSYS_COLOUR_3DSHADOW), 1, wxPENSTYLE_SOLID) ); dc.DrawLine( client_width - 1, client_height - 1, client_width - 1, 0 ); dc.DrawLine( client_width - 1, client_height - 1, 0, client_height - 1 ); dc.DrawLine( 0, 0, client_width, 0 ); @@ -3865,38 +3935,17 @@ void wxGridCornerLabelWindow::OnMouseWheel( wxMouseEvent& event ) m_owner->GetEventHandler()->ProcessEvent(event); } -// This seems to be required for wxMotif otherwise the mouse -// cursor must be in the cell edit control to get key events -// -void wxGridCornerLabelWindow::OnKeyDown( wxKeyEvent& event ) -{ - if ( !m_owner->GetEventHandler()->ProcessEvent( event ) ) - event.Skip(); -} - -void wxGridCornerLabelWindow::OnKeyUp( wxKeyEvent& event ) -{ - if ( !m_owner->GetEventHandler()->ProcessEvent( event ) ) - event.Skip(); -} - -void wxGridCornerLabelWindow::OnChar( wxKeyEvent& event ) -{ - if ( !m_owner->GetEventHandler()->ProcessEvent( event ) ) - event.Skip(); -} - ////////////////////////////////////////////////////////////////////// IMPLEMENT_DYNAMIC_CLASS( wxGridWindow, wxWindow ) -BEGIN_EVENT_TABLE( wxGridWindow, wxWindow ) +BEGIN_EVENT_TABLE( wxGridWindow, wxGridSubwindow ) EVT_PAINT( wxGridWindow::OnPaint ) - EVT_MOUSEWHEEL( wxGridWindow::OnMouseWheel) + EVT_MOUSEWHEEL( wxGridWindow::OnMouseWheel ) EVT_MOUSE_EVENTS( wxGridWindow::OnMouseEvent ) EVT_KEY_DOWN( wxGridWindow::OnKeyDown ) EVT_KEY_UP( wxGridWindow::OnKeyUp ) - EVT_CHAR ( wxGridWindow::OnChar ) + EVT_CHAR( wxGridWindow::OnChar ) EVT_SET_FOCUS( wxGridWindow::OnFocus ) EVT_KILL_FOCUS( wxGridWindow::OnFocus ) EVT_ERASE_BACKGROUND( wxGridWindow::OnEraseBackground ) @@ -3908,10 +3957,9 @@ wxGridWindow::wxGridWindow( wxGrid *parent, wxWindowID id, const wxPoint &pos, const wxSize &size ) - : wxWindow( - parent, id, pos, size, - wxWANTS_CHARS | wxBORDER_NONE | wxCLIP_CHILDREN | wxFULL_REPAINT_ON_RESIZE, - wxT("grid window") ) + : wxGridSubwindow(parent, id, pos, size, + wxWANTS_CHARS | wxCLIP_CHILDREN, + wxT("grid window") ) { m_owner = parent; m_rowLabelWin = rowLblWin; @@ -3951,7 +3999,7 @@ void wxGridWindow::OnMouseEvent( wxMouseEvent& event ) void wxGridWindow::OnMouseWheel( wxMouseEvent& event ) { - m_owner->GetEventHandler()->ProcessEvent(event); + m_owner->GetEventHandler()->ProcessEvent( event ); } // This seems to be required for wxMotif/wxGTK otherwise the mouse @@ -3981,6 +4029,29 @@ void wxGridWindow::OnEraseBackground( wxEraseEvent& WXUNUSED(event) ) void wxGridWindow::OnFocus(wxFocusEvent& event) { + // and if we have any selection, it has to be repainted, because it + // uses different colour when the grid is not focused: + if ( m_owner->IsSelection() ) + { + Refresh(); + } + else + { + // NB: Note that this code is in "else" branch only because the other + // branch refreshes everything and so there's no point in calling + // Refresh() again, *not* because it should only be done if + // !IsSelection(). If the above code is ever optimized to refresh + // only selected area, this needs to be moved out of the "else" + // branch so that it's always executed. + + // current cell cursor {dis,re}appears on focus change: + const wxGridCellCoords cursorCoords(m_owner->GetGridCursorRow(), + m_owner->GetGridCursorCol()); + const wxRect cursor = + m_owner->BlockToDeviceRect(cursorCoords, cursorCoords); + Refresh(true, &cursor); + } + if ( !m_owner->GetEventHandler()->ProcessEvent( event ) ) event.Skip(); } @@ -3998,9 +4069,7 @@ static int CoordToRowOrCol(int coord, int defaultDist, int minDist, const wxArrayInt& BorderArray, int nMax, bool clipToMinMax); -#define internalXToCol(x) CoordToRowOrCol(x, m_defaultColWidth, \ - m_minAcceptableColWidth, \ - m_colRights, m_numCols, true) +#define internalXToCol(x) XToCol(x, true) #define internalYToRow(y) CoordToRowOrCol(y, m_defaultRowHeight, \ m_minAcceptableRowHeight, \ m_rowBottoms, m_numRows, true) @@ -4070,12 +4139,7 @@ END_EVENT_TABLE() wxGrid::wxGrid() { - // in order to make sure that a size event is not - // trigerred in a unfinished state - m_cornerLabelWin = NULL; - m_rowLabelWin = NULL; - m_colLabelWin = NULL; - m_gridWin = NULL; + InitVars(); } wxGrid::wxGrid( wxWindow *parent, @@ -4084,12 +4148,9 @@ wxGrid::wxGrid( wxWindow *parent, const wxSize& size, long style, const wxString& name ) - : wxScrolledWindow( parent, id, pos, size, (style | wxWANTS_CHARS), name ), - m_colMinWidths(GRID_HASH_SIZE), - m_rowMinHeights(GRID_HASH_SIZE) { - Create(); - SetBestFittingSize(size); + InitVars(); + Create(parent, id, pos, size, style, name); } bool wxGrid::Create(wxWindow *parent, wxWindowID id, @@ -4097,14 +4158,15 @@ bool wxGrid::Create(wxWindow *parent, wxWindowID id, long style, const wxString& name) { if (!wxScrolledWindow::Create(parent, id, pos, size, - style | wxWANTS_CHARS , name)) + style | wxWANTS_CHARS, name)) return false; m_colMinWidths = wxLongToLongHashMap(GRID_HASH_SIZE); m_rowMinHeights = wxLongToLongHashMap(GRID_HASH_SIZE); Create(); - SetBestFittingSize(size); + SetInitialSize(size); + CalcDimensions(); return true; } @@ -4124,8 +4186,12 @@ wxGrid::~wxGrid() 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; @@ -4139,16 +4205,10 @@ wxGrid::~wxGrid() // be removed as well as the #else cases below. #define _USE_VISATTR 0 -#if _USE_VISATTR -#include "wx/listbox.h" -#endif - void wxGrid::Create() { - m_created = false; // set to true by CreateGrid - - m_table = (wxGridTableBase *) NULL; - m_ownTable = false; + // create the type registry + m_typeRegistry = new wxGridTypeRegistry; m_cellEditCtrlEnabled = false; @@ -4183,16 +4243,7 @@ void wxGrid::Create() m_rowLabelWidth = WXGRID_DEFAULT_ROW_LABEL_WIDTH; m_colLabelHeight = WXGRID_DEFAULT_COL_LABEL_HEIGHT; - // create the type registry - m_typeRegistry = new wxGridTypeRegistry; - m_selection = NULL; - // subwindow components that make up the wxGrid - m_cornerLabelWin = new wxGridCornerLabelWindow( this, - wxID_ANY, - wxDefaultPosition, - wxDefaultSize ); - m_rowLabelWin = new wxGridRowLabelWindow( this, wxID_ANY, wxDefaultPosition, @@ -4203,6 +4254,11 @@ void wxGrid::Create() wxDefaultPosition, wxDefaultSize ); + m_cornerLabelWin = new wxGridCornerLabelWindow( this, + wxID_ANY, + wxDefaultPosition, + wxDefaultSize ); + m_gridWin = new wxGridWindow( this, m_rowLabelWin, m_colLabelWin, @@ -4278,24 +4334,33 @@ wxGrid::wxGridSelectionModes wxGrid::GetSelectionMode() const bool wxGrid::SetTable( wxGridTableBase *table, bool takeOwnership, wxGrid::wxGridSelectionModes selmode ) { + bool checkSelection = false; if ( m_created ) { // stop all processing m_created = false; - if (m_ownTable) + if (m_table) { - wxGridTableBase *t=m_table; - m_table=0; - delete t; + m_table->SetView(0); + if( m_ownTable ) + delete m_table; + m_table = NULL; } delete m_selection; + m_selection = NULL; - m_table = 0; - m_selection = 0; + m_ownTable = false; m_numRows = 0; m_numCols = 0; + checkSelection = true; + + // kill row and column size arrays + m_colWidths.Empty(); + m_colRights.Empty(); + m_rowHeights.Empty(); + m_rowBottoms.Empty(); } if (table) @@ -4307,7 +4372,28 @@ bool wxGrid::SetTable( wxGridTableBase *table, bool takeOwnership, m_table->SetView( this ); m_ownTable = takeOwnership; m_selection = new wxGridSelection( this, selmode ); - + if (checkSelection) + { + // If the newly set table is smaller than the + // original one current cell and selection regions + // might be invalid, + m_selectingKeyboard = wxGridNoCellCoords; + m_currentCellCoords = + wxGridCellCoords(wxMin(m_numRows, m_currentCellCoords.GetRow()), + wxMin(m_numCols, m_currentCellCoords.GetCol())); + if (m_selectingTopLeft.GetRow() >= m_numRows || + m_selectingTopLeft.GetCol() >= m_numCols) + { + m_selectingTopLeft = wxGridNoCellCoords; + m_selectingBottomRight = wxGridNoCellCoords; + } + else + m_selectingBottomRight = + wxGridCellCoords(wxMin(m_numRows, + m_selectingBottomRight.GetRow()), + wxMin(m_numCols, + m_selectingBottomRight.GetCol())); + } CalcDimensions(); m_created = true; @@ -4316,6 +4402,24 @@ bool wxGrid::SetTable( wxGridTableBase *table, bool takeOwnership, return m_created; } +void wxGrid::InitVars() +{ + m_created = false; + + m_cornerLabelWin = NULL; + m_rowLabelWin = NULL; + m_colLabelWin = NULL; + m_gridWin = NULL; + + m_table = NULL; + m_ownTable = false; + + m_selection = NULL; + m_defaultCellAttr = NULL; + m_typeRegistry = NULL; + m_winCapture = NULL; +} + void wxGrid::Init() { m_rowLabelWidth = WXGRID_DEFAULT_ROW_LABEL_WIDTH; @@ -4327,10 +4431,10 @@ void wxGrid::Init() } else { - m_labelBackgroundColour = wxColour( wxT("WHITE") ); + m_labelBackgroundColour = *wxWHITE; } - m_labelTextColour = wxColour( wxT("BLACK") ); + m_labelTextColour = *wxBLACK; // init attr cache m_attrCache.row = -1; @@ -4367,6 +4471,8 @@ void wxGrid::Init() m_cellHighlightPenWidth = 2; m_cellHighlightROPenWidth = 1; + m_canDragColMove = false; + m_cursorMode = WXGRID_CURSOR_SELECT_CELL; m_winCapture = (wxWindow *)NULL; m_canDragRowSize = true; @@ -4377,6 +4483,7 @@ void wxGrid::Init() m_dragRowOrCol = -1; m_isDragging = false; m_startDragPos = wxDefaultPosition; + m_nativeColumnLabels = false; m_waitForSlowClick = false; @@ -4385,8 +4492,8 @@ void wxGrid::Init() m_currentCellCoords = wxGridNoCellCoords; - m_selectingTopLeft = wxGridNoCellCoords; - m_selectingBottomRight = wxGridNoCellCoords; + ClearSelection(); + m_selectionBackground = wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHT); m_selectionForeground = wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT); @@ -4408,8 +4515,9 @@ void wxGrid::Init() // 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() @@ -4420,11 +4528,10 @@ void wxGrid::InitRowHeights() m_rowHeights.Alloc( m_numRows ); m_rowBottoms.Alloc( m_numRows ); - int rowBottom = 0; - m_rowHeights.Add( m_defaultRowHeight, m_numRows ); - for ( int i = 0; i < m_numRows; i++ ) + int rowBottom = 0; + for ( int i = 0; i < m_numRows; i++ ) { rowBottom += m_defaultRowHeight; m_rowBottoms.Add( rowBottom ); @@ -4438,13 +4545,13 @@ void wxGrid::InitColWidths() m_colWidths.Alloc( m_numCols ); m_colRights.Alloc( m_numCols ); - int colRight = 0; m_colWidths.Add( m_defaultColWidth, m_numCols ); - for ( int i = 0; i < m_numCols; i++ ) + int colRight = 0; + for ( int i = 0; i < m_numCols; i++ ) { - colRight += m_defaultColWidth; + colRight = ( GetColPos( i ) + 1 ) * m_defaultColWidth; m_colRights.Add( colRight ); } } @@ -4456,13 +4563,13 @@ int wxGrid::GetColWidth(int col) const int wxGrid::GetColLeft(int col) const { - return m_colRights.IsEmpty() ? col * m_defaultColWidth + return m_colRights.IsEmpty() ? GetColPos( col ) * m_defaultColWidth : m_colRights[col] - m_colWidths[col]; } int wxGrid::GetColRight(int col) const { - return m_colRights.IsEmpty() ? (col + 1) * m_defaultColWidth + return m_colRights.IsEmpty() ? (GetColPos( col ) + 1) * m_defaultColWidth : m_colRights[col]; } @@ -4485,39 +4592,34 @@ int wxGrid::GetRowBottom(int row) const void wxGrid::CalcDimensions() { - int cw, ch; - GetClientSize( &cw, &ch ); - - if ( m_rowLabelWin->IsShown() ) - cw -= m_rowLabelWidth; - if ( m_colLabelWin->IsShown() ) - ch -= m_colLabelHeight; + // 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; - // grid total size - int w = m_numCols > 0 ? GetColRight(m_numCols - 1) + m_extraWidth + 1 : 0; - int h = m_numRows > 0 ? GetRowBottom(m_numRows - 1) + m_extraHeight + 1 : 0; + w += m_extraWidth; + h += m_extraHeight; // take into account editor if shown if ( IsCellEditControlShown() ) { - int w2, h2; - int r = m_currentCellCoords.GetRow(); - int c = m_currentCellCoords.GetCol(); - int x = GetColLeft(c); - int y = GetRowTop(r); - - // how big is the editor - wxGridCellAttr* attr = GetCellAttr(r, c); - wxGridCellEditor* editor = attr->GetEditor(this, r, c); - editor->GetControl()->GetSize(&w2, &h2); - w2 += x; - h2 += y; - if ( w2 > w ) - w = w2; - if ( h2 > h ) - h = h2; - editor->DecRef(); - attr->DecRef(); + int w2, h2; + int r = m_currentCellCoords.GetRow(); + int c = m_currentCellCoords.GetCol(); + int x = GetColLeft(c); + int y = GetRowTop(r); + + // how big is the editor + wxGridCellAttr* attr = GetCellAttr(r, c); + wxGridCellEditor* editor = attr->GetEditor(this, r, c); + editor->GetControl()->GetSize(&w2, &h2); + w2 += x; + h2 += y; + if ( w2 > w ) + w = w2; + if ( h2 > h ) + h = h2; + editor->DecRef(); + attr->DecRef(); } // preserve (more or less) the previous position @@ -4532,7 +4634,8 @@ void wxGrid::CalcDimensions() // 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 @@ -4540,7 +4643,6 @@ void wxGrid::CalcDimensions() CalcWindowSizes(); } - void wxGrid::CalcWindowSizes() { // escape if the window is has not been fully created yet @@ -4551,22 +4653,57 @@ void wxGrid::CalcWindowSizes() 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); + } + } + + // the grid may be too small to have enough space for the labels yet, don't + // size the windows to negative sizes in this case + int gw = cw - m_rowLabelWidth; + int gh = ch - m_colLabelHeight; + if (gw < 0) + gw = 0; + if (gh < 0) + gh = 0; + if ( m_cornerLabelWin && m_cornerLabelWin->IsShown() ) m_cornerLabelWin->SetSize( 0, 0, m_rowLabelWidth, m_colLabelHeight ); - if ( m_colLabelWin && m_colLabelWin->IsShown() ) - m_colLabelWin->SetSize( m_rowLabelWidth, 0, cw - m_rowLabelWidth, m_colLabelHeight); + if ( m_colLabelWin && m_colLabelWin->IsShown() ) + m_colLabelWin->SetSize( m_rowLabelWidth, 0, gw, m_colLabelHeight ); if ( m_rowLabelWin && m_rowLabelWin->IsShown() ) - m_rowLabelWin->SetSize( 0, m_colLabelHeight, m_rowLabelWidth, ch - m_colLabelHeight); + m_rowLabelWin->SetSize( 0, m_colLabelHeight, m_rowLabelWidth, gh ); if ( m_gridWin && m_gridWin->IsShown() ) - m_gridWin->SetSize( m_rowLabelWidth, m_colLabelHeight, cw - m_rowLabelWidth, ch - m_colLabelHeight); + m_gridWin->SetSize( m_rowLabelWidth, m_colLabelHeight, gw, gh ); } - -// this is called when the grid table sends a message to say that it -// has been redimensioned +// this is called when the grid table sends a message +// to indicate that it has been redimensioned // bool wxGrid::Redimension( wxGridTableMessage& msg ) { @@ -4616,7 +4753,7 @@ bool wxGrid::Redimension( wxGridTableMessage& msg ) if ( pos > 0 ) bottom = m_rowBottoms[pos - 1]; - for ( i = pos; i < m_numRows; i++ ) + for ( i = pos; i < m_numRows; i++ ) { bottom += m_rowHeights[i]; m_rowBottoms[i] = bottom; @@ -4661,7 +4798,7 @@ bool wxGrid::Redimension( wxGridTableMessage& msg ) if ( oldNumRows > 0 ) bottom = m_rowBottoms[oldNumRows - 1]; - for ( i = oldNumRows; i < m_numRows; i++ ) + for ( i = oldNumRows; i < m_numRows; i++ ) { bottom += m_rowHeights[i]; m_rowBottoms[i] = bottom; @@ -4697,12 +4834,13 @@ bool wxGrid::Redimension( wxGridTableMessage& msg ) m_rowBottoms.RemoveAt( pos, numRows ); int h = 0; - for ( i = 0; i < m_numRows; i++ ) + for ( i = 0; i < m_numRows; i++ ) { h += m_rowHeights[i]; m_rowBottoms[i] = h; } } + if ( !m_numRows ) { m_currentCellCoords = wxGridNoCellCoords; @@ -4719,6 +4857,7 @@ bool wxGrid::Redimension( wxGridTableMessage& msg ) if (attrProvider) { attrProvider->UpdateAttrRows( pos, -((int)numRows) ); + // ifdef'd out following patch from Paul Gammans #if 0 // No need to touch column attributes, unless we @@ -4746,6 +4885,25 @@ bool wxGrid::Redimension( wxGridTableMessage& msg ) int numCols = msg.GetCommandInt2(); m_numCols += numCols; + if ( !m_colAt.IsEmpty() ) + { + //Shift the column IDs + int i; + for ( i = 0; i < m_numCols - numCols; i++ ) + { + if ( m_colAt[i] >= (int)pos ) + m_colAt[i] += numCols; + } + + m_colAt.Insert( pos, pos, numCols ); + + //Set the new columns' positions + for ( i = pos + 1; i < (int)pos + numCols; i++ ) + { + m_colAt[i] = i; + } + } + if ( !m_colWidths.IsEmpty() ) { m_colWidths.Insert( m_defaultColWidth, pos, numCols ); @@ -4753,10 +4911,13 @@ bool wxGrid::Redimension( wxGridTableMessage& msg ) int right = 0; if ( pos > 0 ) - right = m_colRights[pos - 1]; + right = m_colRights[GetColAt( pos - 1 )]; - for ( i = pos; i < m_numCols; i++ ) + int colPos; + for ( colPos = pos; colPos < m_numCols; colPos++ ) { + i = GetColAt( colPos ); + right += m_colWidths[i]; m_colRights[i] = right; } @@ -4780,7 +4941,6 @@ bool wxGrid::Redimension( wxGridTableMessage& msg ) CalcDimensions(); m_colLabelWin->Refresh(); } - } result = true; break; @@ -4790,6 +4950,19 @@ bool wxGrid::Redimension( wxGridTableMessage& msg ) int numCols = msg.GetCommandInt(); int oldNumCols = m_numCols; m_numCols += numCols; + + if ( !m_colAt.IsEmpty() ) + { + m_colAt.Add( 0, numCols ); + + //Set the new columns' positions + int i; + for ( i = oldNumCols; i < m_numCols; i++ ) + { + m_colAt[i] = i; + } + } + if ( !m_colWidths.IsEmpty() ) { m_colWidths.Add( m_defaultColWidth, numCols ); @@ -4797,10 +4970,13 @@ bool wxGrid::Redimension( wxGridTableMessage& msg ) int right = 0; if ( oldNumCols > 0 ) - right = m_colRights[oldNumCols - 1]; + right = m_colRights[GetColAt( oldNumCols - 1 )]; - for ( i = oldNumCols; i < m_numCols; i++ ) + int colPos; + for ( colPos = oldNumCols; colPos < m_numCols; colPos++ ) { + i = GetColAt( colPos ); + right += m_colWidths[i]; m_colRights[i] = right; } @@ -4828,14 +5004,32 @@ bool wxGrid::Redimension( wxGridTableMessage& msg ) int numCols = msg.GetCommandInt2(); m_numCols -= numCols; + if ( !m_colAt.IsEmpty() ) + { + int colID = GetColAt( pos ); + + m_colAt.RemoveAt( pos, numCols ); + + //Shift the column IDs + int colPos; + for ( colPos = 0; colPos < m_numCols; colPos++ ) + { + if ( m_colAt[colPos] > colID ) + m_colAt[colPos] -= numCols; + } + } + if ( !m_colWidths.IsEmpty() ) { m_colWidths.RemoveAt( pos, numCols ); m_colRights.RemoveAt( pos, numCols ); int w = 0; - for ( i = 0; i < m_numCols; i++ ) + int colPos; + for ( colPos = 0; colPos < m_numCols; colPos++ ) { + i = GetColAt( colPos ); + w += m_colWidths[i]; m_colRights[i] = w; } @@ -4886,7 +5080,7 @@ bool wxGrid::Redimension( wxGridTableMessage& msg ) return result; } -wxArrayInt wxGrid::CalcRowLabelsExposed( const wxRegion& reg ) +wxArrayInt wxGrid::CalcRowLabelsExposed( const wxRegion& reg ) const { wxRegionIterator iter( reg ); wxRect r; @@ -4906,7 +5100,8 @@ wxArrayInt wxGrid::CalcRowLabelsExposed( const wxRegion& reg ) #if defined(__WXMOTIF__) int cw, ch; m_gridWin->GetClientSize( &cw, &ch ); - if ( r.GetTop() > ch ) r.SetTop( 0 ); + if ( r.GetTop() > ch ) + r.SetTop( 0 ); r.SetBottom( wxMin( r.GetBottom(), ch ) ); #endif @@ -4919,7 +5114,7 @@ wxArrayInt wxGrid::CalcRowLabelsExposed( const wxRegion& reg ) // find the row labels within these bounds // int row; - for ( row = internalYToRow(top); row < m_numRows; row++ ) + for ( row = internalYToRow(top); row < m_numRows; row++ ) { if ( GetRowBottom(row) < top ) continue; @@ -4936,7 +5131,7 @@ wxArrayInt wxGrid::CalcRowLabelsExposed( const wxRegion& reg ) return rowlabels; } -wxArrayInt wxGrid::CalcColLabelsExposed( const wxRegion& reg ) +wxArrayInt wxGrid::CalcColLabelsExposed( const wxRegion& reg ) const { wxRegionIterator iter( reg ); wxRect r; @@ -4956,7 +5151,8 @@ wxArrayInt wxGrid::CalcColLabelsExposed( const wxRegion& reg ) #if defined(__WXMOTIF__) int cw, ch; m_gridWin->GetClientSize( &cw, &ch ); - if ( r.GetLeft() > cw ) r.SetLeft( 0 ); + if ( r.GetLeft() > cw ) + r.SetLeft( 0 ); r.SetRight( wxMin( r.GetRight(), cw ) ); #endif @@ -4969,8 +5165,11 @@ wxArrayInt wxGrid::CalcColLabelsExposed( const wxRegion& reg ) // find the cells within these bounds // int col; - for ( col = internalXToCol(left); col < m_numCols; col++ ) + int colPos; + for ( colPos = GetColPos( internalXToCol(left) ); colPos < m_numCols; colPos++ ) { + col = GetColAt( colPos ); + if ( GetColRight(col) < left ) continue; @@ -4986,7 +5185,7 @@ wxArrayInt wxGrid::CalcColLabelsExposed( const wxRegion& reg ) return colLabels; } -wxGridCellCoordsArray wxGrid::CalcCellsExposed( const wxRegion& reg ) +wxGridCellCoordsArray wxGrid::CalcCellsExposed( const wxRegion& reg ) const { wxRegionIterator iter( reg ); wxRect r; @@ -5020,7 +5219,7 @@ wxGridCellCoordsArray wxGrid::CalcCellsExposed( const wxRegion& reg ) // find the cells within these bounds // int row, col; - for ( row = internalYToRow(top); row < m_numRows; row++ ) + for ( row = internalYToRow(top); row < m_numRows; row++ ) { if ( GetRowBottom(row) <= top ) continue; @@ -5028,8 +5227,11 @@ wxGridCellCoordsArray wxGrid::CalcCellsExposed( const wxRegion& reg ) if ( GetRowTop(row) > bottom ) break; - for ( col = internalXToCol(left); col < m_numCols; col++ ) + int colPos; + for ( colPos = GetColPos( internalXToCol(left) ); colPos < m_numCols; colPos++ ) { + col = GetColAt( colPos ); + if ( GetColRight(col) <= left ) continue; @@ -5277,6 +5479,9 @@ void wxGrid::ProcessColLabelMouseEvent( wxMouseEvent& event ) { m_isDragging = true; m_colLabelWin->CaptureMouse(); + + if ( m_cursorMode == WXGRID_CURSOR_MOVE_COL ) + m_dragRowOrCol = XToCol( x ); } if ( event.LeftIsDown() ) @@ -5320,6 +5525,63 @@ void wxGrid::ProcessColLabelMouseEvent( wxMouseEvent& event ) } break; + case WXGRID_CURSOR_MOVE_COL: + { + if ( x < 0 ) + m_moveToCol = GetColAt( 0 ); + else + m_moveToCol = XToCol( x ); + + int markerX; + + if ( m_moveToCol < 0 ) + markerX = GetColRight( GetColAt( m_numCols - 1 ) ); + else + markerX = GetColLeft( m_moveToCol ); + + if ( markerX != m_dragLastPos ) + { + wxClientDC dc( m_colLabelWin ); + + int cw, ch; + m_colLabelWin->GetClientSize( &cw, &ch ); + + markerX++; + + //Clean up the last indicator + if ( m_dragLastPos >= 0 ) + { + wxPen pen( m_colLabelWin->GetBackgroundColour(), 2 ); + dc.SetPen(pen); + dc.DrawLine( m_dragLastPos + 1, 0, m_dragLastPos + 1, ch ); + dc.SetPen(wxNullPen); + + if ( XToCol( m_dragLastPos ) != -1 ) + DrawColLabel( dc, XToCol( m_dragLastPos ) ); + } + + //Moving to the same place? Don't draw a marker + if ( (m_moveToCol == m_dragRowOrCol) + || (GetColPos( m_moveToCol ) == GetColPos( m_dragRowOrCol ) + 1) + || (m_moveToCol < 0 && m_dragRowOrCol == GetColAt( m_numCols - 1 ))) + { + m_dragLastPos = -1; + return; + } + + //Draw the marker + wxPen pen( *wxBLUE, 2 ); + dc.SetPen(pen); + + dc.DrawLine( markerX, 0, markerX, ch ); + + dc.SetPen(wxNullPen); + + m_dragLastPos = markerX - 1; + } + } + break; + // default label to suppress warnings about "enumeration value // 'xxx' not handled in switch default: @@ -5360,31 +5622,46 @@ void wxGrid::ProcessColLabelMouseEvent( wxMouseEvent& event ) if ( col >= 0 && !SendEvent( wxEVT_GRID_LABEL_LEFT_CLICK, -1, col, event ) ) { - if ( !event.ShiftDown() && !event.CmdDown() ) - ClearSelection(); - if ( m_selection ) + if ( m_canDragColMove ) { - if ( event.ShiftDown() ) - { - m_selection->SelectBlock( 0, - m_currentCellCoords.GetCol(), - GetNumberRows() - 1, col, - event.ControlDown(), - event.ShiftDown(), - event.AltDown(), - event.MetaDown() ); - } - else + //Show button as pressed + wxClientDC dc( m_colLabelWin ); + int colLeft = GetColLeft( col ); + int colRight = GetColRight( col ) - 1; + dc.SetPen( wxPen( m_colLabelWin->GetBackgroundColour(), 1 ) ); + dc.DrawLine( colLeft, 1, colLeft, m_colLabelHeight-1 ); + dc.DrawLine( colLeft, 1, colRight, 1 ); + + ChangeCursorMode(WXGRID_CURSOR_MOVE_COL, m_colLabelWin); + } + else + { + if ( !event.ShiftDown() && !event.CmdDown() ) + ClearSelection(); + if ( m_selection ) { - m_selection->SelectCol( col, - event.ControlDown(), - event.ShiftDown(), - event.AltDown(), - event.MetaDown() ); + if ( event.ShiftDown() ) + { + m_selection->SelectBlock( 0, + m_currentCellCoords.GetCol(), + GetNumberRows() - 1, col, + event.ControlDown(), + event.ShiftDown(), + event.AltDown(), + event.MetaDown() ); + } + else + { + m_selection->SelectCol( col, + event.ControlDown(), + event.ShiftDown(), + event.AltDown(), + event.MetaDown() ); + } } - } - ChangeCursorMode(WXGRID_CURSOR_SELECT_COL, m_colLabelWin); + ChangeCursorMode(WXGRID_CURSOR_SELECT_COL, m_colLabelWin); + } } } else @@ -5424,14 +5701,29 @@ void wxGrid::ProcessColLabelMouseEvent( wxMouseEvent& event ) // else if ( event.LeftUp() ) { - if ( m_cursorMode == WXGRID_CURSOR_RESIZE_COL ) + switch ( m_cursorMode ) { - DoEndDragResizeCol(); + case WXGRID_CURSOR_RESIZE_COL: + DoEndDragResizeCol(); - // Note: we are ending the event *after* doing - // default processing in this case - // - SendEvent( wxEVT_GRID_COL_SIZE, -1, m_dragRowOrCol, event ); + // Note: we are ending the event *after* doing + // default processing in this case + // + SendEvent( wxEVT_GRID_COL_SIZE, -1, m_dragRowOrCol, event ); + break; + + case WXGRID_CURSOR_MOVE_COL: + DoEndDragMoveCol(); + + SendEvent( wxEVT_GRID_COL_MOVE, -1, m_dragRowOrCol, event ); + break; + + case WXGRID_CURSOR_SELECT_COL: + case WXGRID_CURSOR_SELECT_CELL: + case WXGRID_CURSOR_RESIZE_ROW: + case WXGRID_CURSOR_SELECT_ROW: + // nothing to do (?) + break; } ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL, m_colLabelWin); @@ -5515,6 +5807,21 @@ void wxGrid::ProcessCornerLabelMouseEvent( wxMouseEvent& event ) } } +void wxGrid::CancelMouseCapture() +{ + // cancel operation currently in progress, whatever it is + if ( m_winCapture ) + { + m_isDragging = false; + m_cursorMode = WXGRID_CURSOR_SELECT_CELL; + m_winCapture->SetCursor( *wxSTANDARD_CURSOR ); + m_winCapture = NULL; + + // remove traces of whatever we drew on screen + Refresh(); + } +} + void wxGrid::ChangeCursorMode(CursorMode mode, wxWindow *win, bool captureMouse) @@ -5526,7 +5833,8 @@ void wxGrid::ChangeCursorMode(CursorMode mode, _T("RESIZE_ROW"), _T("RESIZE_COL"), _T("SELECT_ROW"), - _T("SELECT_COL") + _T("SELECT_COL"), + _T("MOVE_COL"), }; wxLogTrace(_T("grid"), @@ -5567,6 +5875,10 @@ void wxGrid::ChangeCursorMode(CursorMode mode, win->SetCursor( m_colResizeCursor ); break; + case WXGRID_CURSOR_MOVE_COL: + win->SetCursor( wxCursor(wxCURSOR_HAND) ); + break; + default: win->SetCursor( *wxSTANDARD_CURSOR ); break; @@ -5629,20 +5941,13 @@ void wxGrid::ProcessGridCellMouseEvent( wxMouseEvent& event ) SaveEditControlValue(); } - // Have we captured the mouse yet? - if (! m_winCapture) - { - m_winCapture = m_gridWin; - m_winCapture->CaptureMouse(); - } - if ( coords != wxGridNoCellCoords ) { if ( event.CmdDown() ) { if ( m_selectingKeyboard == wxGridNoCellCoords) m_selectingKeyboard = coords; - HighlightBlock ( m_selectingKeyboard, coords ); + HighlightBlock( m_selectingKeyboard, coords ); } else if ( CanDragCell() ) { @@ -5655,6 +5960,7 @@ void wxGrid::ProcessGridCellMouseEvent( wxMouseEvent& event ) coords.GetRow(), coords.GetCol(), event ); + return; } } else @@ -5676,6 +5982,14 @@ void wxGrid::ProcessGridCellMouseEvent( wxMouseEvent& event ) // scrolling is way to fast, at least on MSW - also on GTK. } } + // Have we captured the mouse yet? + if (! m_winCapture) + { + m_winCapture = m_gridWin; + m_winCapture->CaptureMouse(); + } + + } else if ( m_cursorMode == WXGRID_CURSOR_RESIZE_ROW ) { @@ -5708,9 +6022,9 @@ void wxGrid::ProcessGridCellMouseEvent( wxMouseEvent& event ) dc.SetLogicalFunction(wxINVERT); if ( m_dragLastPos >= 0 ) { - dc.DrawLine( m_dragLastPos, top, m_dragLastPos, top+ch ); + dc.DrawLine( m_dragLastPos, top, m_dragLastPos, top + ch ); } - dc.DrawLine( x, top, x, top+ch ); + dc.DrawLine( x, top, x, top + ch ); m_dragLastPos = x; } @@ -5795,7 +6109,6 @@ void wxGrid::ProcessGridCellMouseEvent( wxMouseEvent& event ) } } - // ------------ Left double click // else if ( event.LeftDClick() && coords != wxGridNoCellCoords ) @@ -5816,7 +6129,6 @@ void wxGrid::ProcessGridCellMouseEvent( wxMouseEvent& event ) } } - // ------------ Left button released // else if ( event.LeftUp() ) @@ -5948,7 +6260,7 @@ void wxGrid::ProcessGridCellMouseEvent( wxMouseEvent& event ) if ( m_cursorMode == WXGRID_CURSOR_SELECT_CELL ) { if ( CanDragRowSize() && CanDragGridSize() ) - ChangeCursorMode(WXGRID_CURSOR_RESIZE_ROW); + ChangeCursorMode(WXGRID_CURSOR_RESIZE_ROW, NULL, false); } } else if ( dragCol >= 0 ) @@ -5958,7 +6270,7 @@ void wxGrid::ProcessGridCellMouseEvent( wxMouseEvent& event ) if ( m_cursorMode == WXGRID_CURSOR_SELECT_CELL ) { if ( CanDragColSize() && CanDragGridSize() ) - ChangeCursorMode(WXGRID_CURSOR_RESIZE_COL); + ChangeCursorMode(WXGRID_CURSOR_RESIZE_COL, NULL, false); } } else // Neither on a row or col edge @@ -5984,7 +6296,7 @@ void wxGrid::DoEndDragResizeRow() wxClientDC dc( m_gridWin ); PrepareDC( dc ); dc.SetLogicalFunction( wxINVERT ); - dc.DrawLine( left, m_dragLastPos, left+cw, m_dragLastPos ); + dc.DrawLine( left, m_dragLastPos, left + cw, m_dragLastPos ); HideCellEditControl(); SaveEditControlValue(); @@ -6008,7 +6320,7 @@ void wxGrid::DoEndDragResizeRow() { int i, cell_rows, cell_cols, subtract_rows = 0; int leftCol = XToCol(left); - int rightCol = internalXToCol(left+cw); + int rightCol = internalXToCol(left + cw); if (leftCol >= 0) { for (i=leftCol; i= 0) { for (i=topRow; iRefresh(); //Do this to "unpress" the column + return; + } + + int newPos; + if ( m_moveToCol == -1 ) + newPos = m_numCols - 1; + else + { + newPos = GetColPos( m_moveToCol ); + if ( newPos > GetColPos( m_dragRowOrCol ) ) + newPos--; + } + + SetColPos( m_dragRowOrCol, newPos ); +} + +void wxGrid::SetColPos( int colID, int newPos ) +{ + if ( m_colAt.IsEmpty() ) + { + m_colAt.Alloc( m_numCols ); + + int i; + for ( i = 0; i < m_numCols; i++ ) + { + m_colAt.Add( i ); + } + } + + int oldPos = GetColPos( colID ); + + //Reshuffle the m_colAt array + if ( newPos > oldPos ) + { + int i; + for ( i = oldPos; i < newPos; i++ ) + { + m_colAt[i] = m_colAt[i+1]; + } + } + else + { + int i; + for ( i = oldPos; i > newPos; i-- ) + { + m_colAt[i] = m_colAt[i-1]; + } + } + + m_colAt[newPos] = colID; + + //Recalculate the column rights + if ( !m_colWidths.IsEmpty() ) + { + int colRight = 0; + int colPos; + for ( colPos = 0; colPos < m_numCols; colPos++ ) + { + int colID = GetColAt( colPos ); + + colRight += m_colWidths[colID]; + m_colRights[colID] = colRight; + } + } + + m_colLabelWin->Refresh(); + m_gridWin->Refresh(); +} + + + +void wxGrid::EnableDragColMove( bool enable ) +{ + if ( m_canDragColMove == enable ) + return; + + m_canDragColMove = enable; + + if ( !m_canDragColMove ) + { + m_colAt.Clear(); + + //Recalculate the column rights + if ( !m_colWidths.IsEmpty() ) + { + int colRight = 0; + int colPos; + for ( colPos = 0; colPos < m_numCols; colPos++ ) + { + colRight += m_colWidths[colPos]; + m_colRights[colPos] = colRight; + } + } + + m_colLabelWin->Refresh(); + m_gridWin->Refresh(); + } +} + + // // ------ interaction with data model // @@ -6117,7 +6536,7 @@ bool wxGrid::ProcessTableMessage( wxGridTableMessage& msg ) } // The behaviour of this function depends on the grid table class -// Clear() function. For the default wxGridStringTable class the +// Clear() function. For the default wxGridStringTable class the // behavious is to replace all cell contents with wxEmptyString but // not to change the number of rows or cols. // @@ -6129,7 +6548,8 @@ void wxGrid::ClearGrid() DisableCellEditControl(); m_table->Clear(); - if ( !GetBatchCount() ) m_gridWin->Refresh(); + if (!GetBatchCount()) + m_gridWin->Refresh(); } } @@ -6154,6 +6574,7 @@ bool wxGrid::InsertRows( int pos, int numRows, bool WXUNUSED(updateLabels) ) // the table will have sent the results of the insert row // operation to this view object as a grid table message } + return false; } @@ -6171,9 +6592,11 @@ bool wxGrid::AppendRows( int numRows, bool WXUNUSED(updateLabels) ) { bool done = m_table && m_table->AppendRows( numRows ); return done; + // the table will have sent the results of the append row // operation to this view object as a grid table message } + return false; } @@ -6197,6 +6620,7 @@ bool wxGrid::DeleteRows( int pos, int numRows, bool WXUNUSED(updateLabels) ) // the table will have sent the results of the delete row // operation to this view object as a grid table message } + return false; } @@ -6317,6 +6741,32 @@ int wxGrid::SendEvent( const wxEventType type, claimed = GetEventHandler()->ProcessEvent(gridEvt); vetoed = !gridEvt.IsAllowed(); } + else if ( type == wxEVT_GRID_LABEL_LEFT_CLICK || + type == wxEVT_GRID_LABEL_LEFT_DCLICK || + type == wxEVT_GRID_LABEL_RIGHT_CLICK || + type == wxEVT_GRID_LABEL_RIGHT_DCLICK ) + { + wxPoint pos = mouseEv.GetPosition(); + + if ( mouseEv.GetEventObject() == GetGridRowLabelWindow() ) + pos.y += GetColLabelSize(); + if ( mouseEv.GetEventObject() == GetGridColLabelWindow() ) + pos.x += GetRowLabelSize(); + + wxGridEvent gridEvt( GetId(), + type, + this, + row, col, + pos.x, + pos.y, + false, + mouseEv.ControlDown(), + mouseEv.ShiftDown(), + mouseEv.AltDown(), + mouseEv.MetaDown() ); + claimed = GetEventHandler()->ProcessEvent(gridEvt); + vetoed = !gridEvt.IsAllowed(); + } else { wxGridEvent gridEvt( GetId(), @@ -6347,27 +6797,20 @@ int wxGrid::SendEvent( const wxEventType type, int wxGrid::SendEvent( const wxEventType type, int row, int col ) { - bool claimed; - bool vetoed; + bool claimed, vetoed; if ( type == wxEVT_GRID_ROW_SIZE || type == wxEVT_GRID_COL_SIZE ) { int rowOrCol = (row == -1 ? col : row); - wxGridSizeEvent gridEvt( GetId(), - type, - this, - rowOrCol ); + wxGridSizeEvent gridEvt( GetId(), type, this, rowOrCol ); claimed = GetEventHandler()->ProcessEvent(gridEvt); vetoed = !gridEvt.IsAllowed(); } else { - wxGridEvent gridEvt( GetId(), - type, - this, - row, col ); + wxGridEvent gridEvt( GetId(), type, this, row, col ); claimed = GetEventHandler()->ProcessEvent(gridEvt); vetoed = !gridEvt.IsAllowed(); @@ -6382,14 +6825,15 @@ int wxGrid::SendEvent( const wxEventType type, void wxGrid::OnPaint( wxPaintEvent& WXUNUSED(event) ) { - wxPaintDC dc(this); // needed to prevent zillions of paint events on MSW + // needed to prevent zillions of paint events on MSW + wxPaintDC dc(this); } 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()) + if ( m_created && !GetBatchCount() ) { // Refresh to get correct scrolled position: wxScrolledWindow::Refresh(eraseb, rect); @@ -6411,7 +6855,8 @@ void wxGrid::Refresh(bool eraseb, const wxRect* rect) width_label = rectWidth; height_label = m_colLabelHeight - rect_y; - if (height_label > rectHeight) height_label = rectHeight; + if (height_label > rectHeight) + height_label = rectHeight; if (rect_x > m_rowLabelWidth) { @@ -6473,14 +6918,13 @@ void wxGrid::Refresh(bool eraseb, const wxRect* rect) } } -void wxGrid::OnSize( wxSizeEvent& event ) +void wxGrid::OnSize(wxSizeEvent& WXUNUSED(event)) { - // position the child windows - CalcWindowSizes(); - - // don't call CalcDimensions() from here, the base class handles the size - // changes itself - event.Skip(); + if (m_targetWindow != this) // check whether initialisation has been done + { + // update our children window positions and scrollbars + CalcDimensions(); + } } void wxGrid::OnKeyDown( wxKeyEvent& event ) @@ -6495,15 +6939,21 @@ void wxGrid::OnKeyDown( wxKeyEvent& event ) m_inOnKeyDown = true; // propagate the event up and see if it gets processed - // wxWindow *parent = GetParent(); wxKeyEvent keyEvt( event ); keyEvt.SetEventObject( parent ); 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() ) { case WXK_UP: @@ -6600,8 +7050,8 @@ void wxGrid::OnKeyDown( wxKeyEvent& event ) case WXK_END: if ( event.ControlDown() ) { - MakeCellVisible( m_numRows-1, m_numCols - 1 ); - SetCurrentCell( m_numRows-1, m_numCols - 1 ); + MakeCellVisible( m_numRows - 1, m_numCols - 1 ); + SetCurrentCell( m_numRows - 1, m_numCols - 1 ); } else { @@ -6622,12 +7072,13 @@ void wxGrid::OnKeyDown( wxKeyEvent& event ) { if ( m_selection ) { - m_selection->ToggleCellSelection( m_currentCellCoords.GetRow(), - m_currentCellCoords.GetCol(), - event.ControlDown(), - event.ShiftDown(), - event.AltDown(), - event.MetaDown() ); + m_selection->ToggleCellSelection( + m_currentCellCoords.GetRow(), + m_currentCellCoords.GetCol(), + event.ControlDown(), + event.ShiftDown(), + event.AltDown(), + event.MetaDown() ); } break; } @@ -6658,14 +7109,15 @@ void wxGrid::OnKeyUp( wxKeyEvent& event ) { if ( m_selection ) { - m_selection->SelectBlock( m_selectingTopLeft.GetRow(), - m_selectingTopLeft.GetCol(), - m_selectingBottomRight.GetRow(), - m_selectingBottomRight.GetCol(), - event.ControlDown(), - true, - event.AltDown(), - event.MetaDown() ); + m_selection->SelectBlock( + m_selectingTopLeft.GetRow(), + m_selectingTopLeft.GetCol(), + m_selectingBottomRight.GetRow(), + m_selectingBottomRight.GetCol(), + event.ControlDown(), + true, + event.AltDown(), + event.MetaDown() ); } } @@ -6728,8 +7180,10 @@ void wxGrid::SetCurrentCell( const wxGridCellCoords& coords ) return; } +#if !defined(__WXMAC__) wxClientDC dc( m_gridWin ); PrepareDC( dc ); +#endif if ( m_currentCellCoords != wxGridNoCellCoords ) { @@ -6752,15 +7206,21 @@ void wxGrid::SetCurrentCell( const wxGridCellCoords& coords ) // Otherwise refresh redraws the highlight! m_currentCellCoords = coords; +#if defined(__WXMAC__) + m_gridWin->Refresh(true /*, & r */); +#else DrawGridCellArea( dc, cells ); DrawAllGridLines( dc, r ); +#endif } } m_currentCellCoords = coords; wxGridCellAttr *attr = GetCellAttr( coords ); +#if !defined(__WXMAC__) DrawCellHighlight( dc, attr ); +#endif attr->DecRef(); } @@ -6826,9 +7286,9 @@ void wxGrid::HighlightBlock( int topRow, int leftCol, int bottomRow, int rightCo int i; // Store intermediate values - wxCoord oldLeft = m_selectingTopLeft.GetCol(); - wxCoord oldTop = m_selectingTopLeft.GetRow(); - wxCoord oldRight = m_selectingBottomRight.GetCol(); + wxCoord oldLeft = m_selectingTopLeft.GetCol(); + wxCoord oldTop = m_selectingTopLeft.GetRow(); + wxCoord oldRight = m_selectingBottomRight.GetCol(); wxCoord oldBottom = m_selectingBottomRight.GetRow(); // Determine the outer/inner coordinates. @@ -6866,10 +7326,9 @@ void wxGrid::HighlightBlock( int topRow, int leftCol, int bottomRow, int rightCo // Refresh the newly selected or deselected // area to the left of the old or new selection. need_refresh[0] = true; - rect[0] = BlockToDeviceRect( wxGridCellCoords ( oldTop, - oldLeft ), - wxGridCellCoords ( oldBottom, - leftCol - 1 ) ); + rect[0] = BlockToDeviceRect( + wxGridCellCoords( oldTop, oldLeft ), + wxGridCellCoords( oldBottom, leftCol - 1 ) ); } if ( oldTop < topRow ) @@ -6888,8 +7347,8 @@ void wxGrid::HighlightBlock( int topRow, int leftCol, int bottomRow, int rightCo // area to the right of the old or new selection. need_refresh[2] = true; rect[2] = BlockToDeviceRect( - wxGridCellCoords ( oldTop, rightCol + 1 ), - wxGridCellCoords ( oldBottom, oldRight ) ); + wxGridCellCoords( oldTop, rightCol + 1 ), + wxGridCellCoords( oldBottom, oldRight ) ); } if ( oldBottom > bottomRow ) @@ -6898,8 +7357,8 @@ void wxGrid::HighlightBlock( int topRow, int leftCol, int bottomRow, int rightCo // area below the old or new selection. need_refresh[3] = true; rect[3] = BlockToDeviceRect( - wxGridCellCoords ( bottomRow + 1, leftCol ), - wxGridCellCoords ( oldBottom, rightCol ) ); + wxGridCellCoords( bottomRow + 1, leftCol ), + wxGridCellCoords( oldBottom, rightCol ) ); } // various Refresh() calls @@ -6944,9 +7403,9 @@ bool wxGrid::SetModelValues() if ( m_table ) { - for ( row = 0; row < m_numRows; row++ ) + for ( row = 0; row < m_numRows; row++ ) { - for ( col = 0; col < m_numCols; col++ ) + for ( col = 0; col < m_numCols; col++ ) { m_table->SetValue( row, col, GetCellValue(row, col) ); } @@ -6971,7 +7430,7 @@ void wxGrid::DrawGridCellArea( wxDC& dc, const wxGridCellCoordsArray& cells ) int row, col, cell_rows, cell_cols; wxGridCellCoordsArray redrawCells; - for ( i = numCells-1; i >= 0; i-- ) + for ( i = numCells - 1; i >= 0; i-- ) { row = cells[i].GetRow(); col = cells[i].GetCol(); @@ -6980,9 +7439,9 @@ void wxGrid::DrawGridCellArea( wxDC& dc, const wxGridCellCoordsArray& cells ) // If this cell is part of a multicell block, find owner for repaint if ( cell_rows <= 0 || cell_cols <= 0 ) { - wxGridCellCoords cell(row+cell_rows, col+cell_cols); + wxGridCellCoords cell( row + cell_rows, col + cell_cols ); bool marked = false; - for ( int j = 0; j < numCells; j++ ) + for ( int j = 0; j < numCells; j++ ) { if ( cell == cells[j] ) { @@ -7016,7 +7475,7 @@ void wxGrid::DrawGridCellArea( wxDC& dc, const wxGridCellCoordsArray& cells ) { for ( int l = 0; l < cell_rows; l++ ) { - // find a cell in this row to left alreay marked for repaint + // find a cell in this row to leave already marked for repaint int left = col; for (int k = 0; k < int(redrawCells.GetCount()); k++) if ((redrawCells[k].GetCol() < left) && @@ -7072,7 +7531,7 @@ void wxGrid::DrawGridCellArea( wxDC& dc, const wxGridCellCoordsArray& cells ) numCells = redrawCells.GetCount(); - for ( i = numCells - 1; i >= 0; i-- ) + for ( i = numCells - 1; i >= 0; i-- ) { DrawCell( dc, redrawCells[i] ); } @@ -7086,7 +7545,7 @@ void wxGrid::DrawGridSpace( wxDC& dc ) int right, bottom; CalcUnscrolledPosition( cw, ch, &right, &bottom ); - int rightCol = m_numCols > 0 ? GetColRight(m_numCols - 1) : 0; + int rightCol = m_numCols > 0 ? GetColRight(GetColAt( m_numCols - 1 )) : 0; int bottomRow = m_numRows > 0 ? GetRowBottom(m_numRows - 1) : 0; if ( right > rightCol || bottom > bottomRow ) @@ -7094,17 +7553,17 @@ void wxGrid::DrawGridSpace( wxDC& dc ) int left, top; CalcUnscrolledPosition( 0, 0, &left, &top ); - dc.SetBrush( wxBrush(GetDefaultCellBackgroundColour(), wxSOLID) ); + dc.SetBrush( wxBrush(GetDefaultCellBackgroundColour(), wxBRUSHSTYLE_SOLID) ); dc.SetPen( *wxTRANSPARENT_PEN ); if ( right > rightCol ) { - dc.DrawRectangle( rightCol, top, right - rightCol, ch); + dc.DrawRectangle( rightCol, top, right - rightCol, ch ); } if ( bottom > bottomRow ) { - dc.DrawRectangle( left, bottomRow, cw, bottom - bottomRow); + dc.DrawRectangle( left, bottomRow, cw, bottom - bottomRow ); } } } @@ -7133,11 +7592,11 @@ void wxGrid::DrawCell( wxDC& dc, const wxGridCellCoords& coords ) // Note: However, only if it is really _shown_, i.e. not hidden! if ( isCurrent && IsCellEditControlShown() ) { - // OSAF NB: this "#if..." is temporary and fixes a problem where the + // NB: this "#if..." is temporary and fixes a problem where the // 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(); @@ -7145,8 +7604,7 @@ void wxGrid::DrawCell( wxDC& dc, const wxGridCellCoords& coords ) } else { - // but all the rest is drawn by the cell renderer and hence may be - // customized + // but all the rest is drawn by the cell renderer and hence may be customized wxGridCellRenderer *renderer = attr->GetRenderer(this, row, col); renderer->Draw(*this, *attr, dc, rect, row, col, IsInSelection(coords)); renderer->DecRef(); @@ -7157,6 +7615,10 @@ void wxGrid::DrawCell( wxDC& dc, const wxGridCellCoords& coords ) void wxGrid::DrawCellHighlight( wxDC& dc, const wxGridCellAttr *attr ) { + // don't show highlight when the grid doesn't have focus + if ( !HasFocus() ) + return; + int row = m_currentCellCoords.GetRow(); int col = m_currentCellCoords.GetCol(); @@ -7173,10 +7635,10 @@ void wxGrid::DrawCellHighlight( wxDC& dc, const wxGridCellAttr *attr ) if (penWidth > 0) { - // The center of th drawn line is where the position/width/height of - // the rectangle is actually at, (on wxMSW atr least,) so we will - // reduce the size of the rectangle to compensate for the thickness of - // the line. If this is too strange on non wxMSW platforms then + // The center of the drawn line is where the position/width/height of + // the rectangle is actually at (on wxMSW at least), so the + // size of the rectangle is reduced to compensate for the thickness of + // the line. If this is too strange on non-wxMSW platforms then // please #ifdef this appropriately. rect.x += penWidth / 2; rect.y += penWidth / 2; @@ -7186,7 +7648,7 @@ void wxGrid::DrawCellHighlight( wxDC& dc, const wxGridCellAttr *attr ) // Now draw the rectangle // use the cellHighlightColour if the cell is inside a selection, this // will ensure the cell is always visible. - dc.SetPen(wxPen(IsInSelection(row,col) ? m_selectionForeground : m_cellHighlightColour, penWidth, wxSOLID)); + dc.SetPen(wxPen(IsInSelection(row,col) ? m_selectionForeground : m_cellHighlightColour, penWidth, wxPENSTYLE_SOLID)); dc.SetBrush(*wxTRANSPARENT_BRUSH); dc.DrawRectangle(rect); } @@ -7210,7 +7672,22 @@ void wxGrid::DrawCellHighlight( wxDC& dc, const wxGridCellAttr *attr ) dc.SetPen(*wxBLACK_PEN); dc.DrawLine(x1, y2, x2, y2); dc.DrawLine(x2, y1, x2, y2 + 1); -#endif // 0 +#endif +} + +wxPen wxGrid::GetDefaultGridLinePen() +{ + return wxPen(GetGridLineColour(), 1, wxPENSTYLE_SOLID); +} + +wxPen wxGrid::GetRowGridLinePen(int WXUNUSED(row)) +{ + return GetDefaultGridLinePen(); +} + +wxPen wxGrid::GetColGridLinePen(int WXUNUSED(col)) +{ + return GetDefaultGridLinePen(); } void wxGrid::DrawCellBorder( wxDC& dc, const wxGridCellCoords& coords ) @@ -7220,17 +7697,16 @@ void wxGrid::DrawCellBorder( wxDC& dc, const wxGridCellCoords& coords ) if ( GetColWidth(col) <= 0 || GetRowHeight(row) <= 0 ) return; - dc.SetPen( wxPen(GetGridLineColour(), 1, wxSOLID) ); wxRect rect = CellToRect( row, col ); // right hand border - // + dc.SetPen( GetColGridLinePen(col) ); dc.DrawLine( rect.x + rect.width, rect.y, rect.x + rect.width, rect.y + rect.height + 1 ); // bottom border - // + dc.SetPen( GetRowGridLinePen(row) ); dc.DrawLine( rect.x, rect.y + rect.height, rect.x + rect.width, rect.y + rect.height); } @@ -7310,26 +7786,27 @@ void wxGrid::DrawAllGridLines( wxDC& dc, const wxRegion & WXUNUSED(reg) ) // avoid drawing grid lines past the last row and col // - right = wxMin( right, GetColRight(m_numCols - 1) ); + right = wxMin( right, GetColRight(GetColAt( m_numCols - 1 )) ); bottom = wxMin( bottom, GetRowBottom(m_numRows - 1) ); // no gridlines inside multicells, clip them out - int leftCol = internalXToCol(left); - int topRow = internalYToRow(top); - int rightCol = internalXToCol(right); + int leftCol = GetColPos( internalXToCol(left) ); + int topRow = internalYToRow(top); + int rightCol = GetColPos( internalXToCol(right) ); int bottomRow = internalYToRow(bottom); -#ifndef __WXMAC__ - // CS: I don't know why suddenly unscrolled coordinates are used for clipping wxRegion clippedcells(0, 0, cw, ch); int i, j, cell_rows, cell_cols; wxRect rect; - for (j=topRow; j 1) || (cell_cols > 1)) { @@ -7339,39 +7816,15 @@ void wxGrid::DrawAllGridLines( wxDC& dc, const wxRegion & WXUNUSED(reg) ) } else if ((cell_rows < 0) || (cell_cols < 0)) { - rect = CellToRect(j+cell_rows, i+cell_cols); + rect = CellToRect(j + cell_rows, i + cell_cols); CalcScrolledPosition( rect.x, rect.y, &rect.x, &rect.y ); clippedcells.Subtract(rect); } } } -#else - wxRegion clippedcells( left , top, right - left, bottom - top); - int i, j, cell_rows, cell_cols; - wxRect rect; + dc.SetDeviceClippingRegion( clippedcells ); - for (j=topRow; j 1) || (cell_cols > 1)) - { - rect = CellToRect(j, i); - clippedcells.Subtract(rect); - } - else if ((cell_rows < 0) || (cell_cols < 0)) - { - rect = CellToRect(j + cell_rows, i + cell_cols); - clippedcells.Subtract(rect); - } - } - } -#endif - dc.SetClippingRegion( clippedcells ); - - dc.SetPen( wxPen(GetGridLineColour(), 1, wxSOLID) ); // horizontal grid lines // @@ -7387,15 +7840,24 @@ void wxGrid::DrawAllGridLines( wxDC& dc, const wxRegion & WXUNUSED(reg) ) if ( bot >= top ) { + dc.SetPen( GetRowGridLinePen(i) ); dc.DrawLine( left, bot, right, bot ); } } // vertical grid lines // - for ( i = internalXToCol(left); i < m_numCols; i++ ) + int colPos; + for ( colPos = leftCol; colPos < m_numCols; colPos++ ) { - int colRight = GetColRight(i) - 1; + i = GetColAt( colPos ); + + int colRight = GetColRight(i); +#ifdef __WXGTK__ + if (GetLayoutDirection() != wxLayout_RightToLeft) +#endif + colRight--; + if ( colRight > right ) { break; @@ -7403,13 +7865,15 @@ void wxGrid::DrawAllGridLines( wxDC& dc, const wxRegion & WXUNUSED(reg) ) if ( colRight >= left ) { + dc.SetPen( GetColGridLinePen(i) ); dc.DrawLine( colRight, top, colRight, bottom ); } } + dc.DestroyClippingRegion(); } -void wxGrid::DrawRowLabels( wxDC& dc ,const wxArrayInt& rows) +void wxGrid::DrawRowLabels( wxDC& dc, const wxArrayInt& rows) { if ( !m_numRows ) return; @@ -7430,35 +7894,19 @@ void wxGrid::DrawRowLabel( wxDC& dc, int row ) wxRect rect; -#ifdef __WXGTK20__ - rect.SetX( 1 ); - rect.SetY( GetRowTop(row) + 1 ); - rect.SetWidth( m_rowLabelWidth - 2 ); - rect.SetHeight( GetRowHeight(row) - 2 ); - - CalcScrolledPosition( 0, rect.y, NULL, &rect.y ); - - wxWindowDC *win_dc = (wxWindowDC*) &dc; - - wxRendererNative::Get().DrawHeaderButton( win_dc->m_owner, dc, rect, 0 ); -#else int rowTop = GetRowTop(row), rowBottom = GetRowBottom(row) - 1; - dc.SetPen( wxPen(wxSystemSettings::GetColour(wxSYS_COLOUR_3DDKSHADOW),1, wxSOLID) ); - dc.DrawLine( m_rowLabelWidth-1, rowTop, - m_rowLabelWidth-1, rowBottom ); - + dc.SetPen( wxPen(wxSystemSettings::GetColour(wxSYS_COLOUR_3DSHADOW), 1, wxPENSTYLE_SOLID) ); + dc.DrawLine( m_rowLabelWidth - 1, rowTop, m_rowLabelWidth - 1, rowBottom ); dc.DrawLine( 0, rowTop, 0, rowBottom ); - dc.DrawLine( 0, rowBottom, m_rowLabelWidth, rowBottom ); dc.SetPen( *wxWHITE_PEN ); dc.DrawLine( 1, rowTop, 1, rowBottom ); - dc.DrawLine( 1, rowTop, m_rowLabelWidth-1, rowTop ); -#endif + dc.DrawLine( 1, rowTop, m_rowLabelWidth - 1, rowTop ); - dc.SetBackgroundMode( wxTRANSPARENT ); + dc.SetBackgroundMode( wxBRUSHSTYLE_TRANSPARENT ); dc.SetTextForeground( GetLabelTextColour() ); dc.SetFont( GetLabelFont() ); @@ -7472,6 +7920,18 @@ void wxGrid::DrawRowLabel( wxDC& dc, int row ) DrawTextRectangle( dc, GetRowLabelValue( row ), rect, hAlign, vAlign ); } +void wxGrid::SetUseNativeColLabels( bool native ) +{ + m_nativeColumnLabels = native; + if (native) + { + int height = wxRendererNative::Get().GetHeaderButtonHeight( this ); + SetColLabelSize( height ); + } + + m_colLabelWin->Refresh(); +} + void wxGrid::DrawColLabels( wxDC& dc,const wxArrayInt& cols ) { if ( !m_numCols ) @@ -7480,7 +7940,7 @@ void wxGrid::DrawColLabels( wxDC& dc,const wxArrayInt& cols ) size_t i; size_t numLabels = cols.GetCount(); - for ( i = 0; i < numLabels; i++ ) + for ( i = 0; i < numLabels; i++ ) { DrawColLabel( dc, cols[i] ); } @@ -7495,32 +7955,32 @@ void wxGrid::DrawColLabel( wxDC& dc, int col ) wxRect rect; -#ifdef __WXGTK20__ - rect.SetX( colLeft + 1 ); - rect.SetY( 1 ); - rect.SetWidth( GetColWidth(col) - 2 ); - rect.SetHeight( m_colLabelHeight - 2 ); - - wxWindowDC *win_dc = (wxWindowDC*) &dc; - - wxRendererNative::Get().DrawHeaderButton( win_dc->m_owner, dc, rect, 0 ); -#else - int colRight = GetColRight(col) - 1; - - dc.SetPen( wxPen(wxSystemSettings::GetColour(wxSYS_COLOUR_3DDKSHADOW), 1, wxSOLID) ); - dc.DrawLine( colRight, 0, colRight, m_colLabelHeight - 1 ); + if (m_nativeColumnLabels) + { + rect.SetX( colLeft); + rect.SetY( 0 ); + rect.SetWidth( GetColWidth(col)); + rect.SetHeight( m_colLabelHeight ); - dc.DrawLine( colLeft, 0, colRight, 0 ); + wxWindowDC *win_dc = (wxWindowDC*) &dc; + wxRendererNative::Get().DrawHeaderButton( win_dc->GetWindow(), dc, rect, 0 ); + } + else + { + int colRight = GetColRight(col) - 1; - dc.DrawLine( colLeft, m_colLabelHeight - 1, + dc.SetPen( wxPen(wxSystemSettings::GetColour(wxSYS_COLOUR_3DSHADOW), 1, wxPENSTYLE_SOLID) ); + dc.DrawLine( colRight, 0, colRight, m_colLabelHeight - 1 ); + dc.DrawLine( colLeft, 0, colRight, 0 ); + dc.DrawLine( colLeft, m_colLabelHeight - 1, colRight + 1, m_colLabelHeight - 1 ); - dc.SetPen( *wxWHITE_PEN ); - dc.DrawLine( colLeft, 1, colLeft, m_colLabelHeight - 1 ); - dc.DrawLine( colLeft, 1, colRight, 1 ); -#endif + dc.SetPen( *wxWHITE_PEN ); + dc.DrawLine( colLeft, 1, colLeft, m_colLabelHeight - 1 ); + dc.DrawLine( colLeft, 1, colRight, 1 ); + } - dc.SetBackgroundMode( wxTRANSPARENT ); + dc.SetBackgroundMode( wxBRUSHSTYLE_TRANSPARENT ); dc.SetTextForeground( GetLabelTextColour() ); dc.SetFont( GetLabelFont() ); @@ -7547,7 +8007,7 @@ void wxGrid::DrawTextRectangle( wxDC& dc, StringToLines( value, lines ); // Forward to new API. - DrawTextRectangle( dc, + DrawTextRectangle( dc, lines, rect, horizAlign, @@ -7555,32 +8015,32 @@ void wxGrid::DrawTextRectangle( wxDC& dc, textOrientation ); } -void wxGrid::DrawTextRectangle( wxDC& dc, +// VZ: this should be replaced with wxDC::DrawLabel() to which we just have to +// add textOrientation support +void wxGrid::DrawTextRectangle(wxDC& dc, const wxArrayString& lines, const wxRect& rect, int horizAlign, int vertAlign, - int textOrientation ) + int textOrientation) { - long textWidth = 0, textHeight = 0; - long lineWidth = 0, lineHeight = 0; - int nLines; + if ( lines.empty() ) + return; - dc.SetClippingRegion( rect ); + wxDCClipper clip(dc, rect); - nLines = lines.GetCount(); - if ( nLines > 0 ) - { - int l; - float x = 0.0, y = 0.0; + long textWidth, + textHeight; - if ( textOrientation == wxHORIZONTAL ) - GetTextBoxSize(dc, lines, &textWidth, &textHeight); - else - GetTextBoxSize( dc, lines, &textHeight, &textWidth ); + if ( textOrientation == wxHORIZONTAL ) + GetTextBoxSize( dc, lines, &textWidth, &textHeight ); + else + GetTextBoxSize( dc, lines, &textHeight, &textWidth ); - switch ( vertAlign ) - { + int x = 0, + y = 0; + switch ( vertAlign ) + { case wxALIGN_BOTTOM: if ( textOrientation == wxHORIZONTAL ) y = rect.y + (rect.height - textHeight - 1); @@ -7590,9 +8050,9 @@ void wxGrid::DrawTextRectangle( wxDC& dc, case wxALIGN_CENTRE: if ( textOrientation == wxHORIZONTAL ) - y = rect.y + ((rect.height - textHeight)/2); + y = rect.y + ((rect.height - textHeight) / 2); else - x = rect.x + ((rect.width - textWidth)/2); + x = rect.x + ((rect.width - textWidth) / 2); break; case wxALIGN_TOP: @@ -7602,15 +8062,26 @@ void wxGrid::DrawTextRectangle( wxDC& dc, else x = rect.x + 1; break; - } + } - // Align each line of a multi-line label - for ( l = 0; l < nLines; l++ ) + // Align each line of a multi-line label + size_t nLines = lines.GetCount(); + for ( size_t l = 0; l < nLines; l++ ) + { + const wxString& line = lines[l]; + + if ( line.empty() ) { - dc.GetTextExtent(lines[l], &lineWidth, &lineHeight); + *(textOrientation == wxHORIZONTAL ? &y : &x) += dc.GetCharHeight(); + continue; + } - switch ( horizAlign ) - { + wxCoord lineWidth = 0, + lineHeight = 0; + dc.GetTextExtent(line, &lineWidth, &lineHeight); + + switch ( horizAlign ) + { case wxALIGN_RIGHT: if ( textOrientation == wxHORIZONTAL ) x = rect.x + (rect.width - lineWidth - 1); @@ -7632,28 +8103,26 @@ void wxGrid::DrawTextRectangle( wxDC& dc, else y = rect.y + rect.height - 1; break; - } + } - if ( textOrientation == wxHORIZONTAL ) - { - dc.DrawText( lines[l], (int)x, (int)y ); - y += lineHeight; - } - else - { - dc.DrawRotatedText( lines[l], (int)x, (int)y, 90.0 ); - x += lineHeight; - } + if ( textOrientation == wxHORIZONTAL ) + { + dc.DrawText( line, x, y ); + y += lineHeight; + } + else + { + dc.DrawRotatedText( line, x, y, 90.0 ); + x += lineHeight; } } - - dc.DestroyClippingRegion(); } // Split multi-line text up into an array of strings. // Any existing contents of the string array are preserved. // -void wxGrid::StringToLines( const wxString& value, wxArrayString& lines ) +// TODO: refactor wxTextFile::Read() and reuse the same code from here +void wxGrid::StringToLines( const wxString& value, wxArrayString& lines ) const { int startPos = 0; int pos; @@ -7673,27 +8142,28 @@ void wxGrid::StringToLines( const wxString& value, wxArrayString& lines ) } else { - lines.Add( value.Mid(startPos, pos) ); + lines.Add( tVal.Mid(startPos, pos) ); } + startPos += pos + 1; } - if ( startPos < (int)value.length() ) + if ( startPos < (int)tVal.length() ) { - lines.Add( value.Mid( startPos ) ); + lines.Add( tVal.Mid( startPos ) ); } } void wxGrid::GetTextBoxSize( const wxDC& dc, const wxArrayString& lines, - long *width, long *height ) + long *width, long *height ) const { - long w = 0; - long h = 0; - long lineW = 0, lineH = 0; + wxCoord w = 0; + wxCoord h = 0; + wxCoord lineW = 0, lineH = 0; size_t i; - for ( i = 0; i < lines.GetCount(); i++ ) + for ( i = 0; i < lines.GetCount(); i++ ) { dc.GetTextExtent( lines[i], &lineW, &lineH ); w = wxMax( w, lineW ); @@ -7773,8 +8243,7 @@ void wxGrid::EnableCellEditControl( bool enable ) return; // this should be checked by the caller! - wxASSERT_MSG( CanEnableCellControl(), - _T("can't enable editing for this cell!") ); + wxASSERT_MSG( CanEnableCellControl(), _T("can't enable editing for this cell!") ); // do it before ShowCellEditControl() m_cellEditCtrlEnabled = enable; @@ -7784,7 +8253,7 @@ void wxGrid::EnableCellEditControl( bool enable ) else { //FIXME:add veto support - SendEvent( wxEVT_GRID_EDITOR_HIDDEN); + SendEvent( wxEVT_GRID_EDITOR_HIDDEN ); HideCellEditControl(); SaveEditControlValue(); @@ -7809,7 +8278,6 @@ bool wxGrid::CanEnableCellControl() const { return m_editable && (m_currentCellCoords != wxGridNoCellCoords) && !IsCurrentCellReadOnly(); - } bool wxGrid::IsCellEditControlEnabled() const @@ -7871,24 +8339,21 @@ void wxGrid::ShowCellEditControl() m_currentCellCoords.SetCol( col ); } - // convert to scrolled coords - // - CalcScrolledPosition( rect.x, rect.y, &rect.x, &rect.y ); - - int nXMove = 0; - if (rect.x < 0) - nXMove = rect.x; - - // done in PaintBackground() -#if 0 // erase the highlight and the cell contents because the editor // might not cover the entire cell wxClientDC dc( m_gridWin ); PrepareDC( dc ); - dc.SetBrush(*wxLIGHT_GREY_BRUSH); //wxBrush(attr->GetBackgroundColour(), wxSOLID)); + wxGridCellAttr* attr = GetCellAttr(row, col); + dc.SetBrush(wxBrush(attr->GetBackgroundColour(), wxBRUSHSTYLE_SOLID)); dc.SetPen(*wxTRANSPARENT_PEN); dc.DrawRectangle(rect); -#endif // 0 + + // convert to scrolled coords + CalcScrolledPosition( rect.x, rect.y, &rect.x, &rect.y ); + + int nXMove = 0; + if (rect.x < 0) + nXMove = rect.x; // cell is shifted by one pixel // However, don't allow x or y to become negative @@ -7899,7 +8364,6 @@ void wxGrid::ShowCellEditControl() if (rect.y > 0) rect.y--; - wxGridCellAttr* attr = GetCellAttr(row, col); wxGridCellEditor* editor = attr->GetEditor(this, row, col); if ( !editor->IsCreated() ) { @@ -7955,24 +8419,12 @@ void wxGrid::ShowCellEditControl() editor->SetCellAttr( attr ); editor->SetSize( rect ); - editor->GetControl()->Move( - editor->GetControl()->GetPosition().x + nXMove, - editor->GetControl()->GetPosition().y ); + if (nXMove != 0) + editor->GetControl()->Move( + editor->GetControl()->GetPosition().x + nXMove, + editor->GetControl()->GetPosition().y ); editor->Show( true, attr ); - int colXPos = 0; - for (int i = 0; i < m_currentCellCoords.GetCol(); i++) - { - colXPos += GetColSize( i ); - } - - int xUnit = 1, yUnit = 1; - GetScrollPixelsPerUnit( &xUnit, &yUnit ); - if (m_currentCellCoords.GetCol() != 0) - Scroll( colXPos / xUnit - 1, GetScrollPos( wxVERTICAL ) ); - else - Scroll( colXPos / xUnit, GetScrollPos( wxVERTICAL ) ); - // recalc dimensions in case we need to // expand the scrolled window to account for editor CalcDimensions(); @@ -8051,12 +8503,12 @@ void wxGrid::SaveEditControlValue() // coordinates for mouse events etc. // -void wxGrid::XYToCell( int x, int y, wxGridCellCoords& coords ) +void wxGrid::XYToCell( int x, int y, wxGridCellCoords& coords ) const { int row = YToRow(y); int col = XToCol(x); - if ( row == -1 || col == -1 ) + if ( row == -1 || col == -1 ) { coords = wxGridNoCellCoords; } @@ -8133,27 +8585,89 @@ static int CoordToRowOrCol(int coord, int defaultDist, int minDist, return i_max; } -int wxGrid::YToRow( int y ) +int wxGrid::YToRow( int y ) const { return CoordToRowOrCol(y, m_defaultRowHeight, m_minAcceptableRowHeight, m_rowBottoms, m_numRows, false); } -int wxGrid::XToCol( int x ) +int wxGrid::XToCol( int x, bool clipToMinMax ) const { - return CoordToRowOrCol(x, m_defaultColWidth, - m_minAcceptableColWidth, m_colRights, m_numCols, false); + if (x < 0) + return clipToMinMax && (m_numCols > 0) ? GetColAt( 0 ) : -1; + + wxASSERT_MSG(m_defaultColWidth > 0, wxT("Default column width can not be zero")); + + int maxPos = x / m_defaultColWidth; + int minPos = 0; + + if (m_colRights.IsEmpty()) + { + if(maxPos < m_numCols) + return GetColAt( maxPos ); + return clipToMinMax ? GetColAt( m_numCols - 1 ) : -1; + } + + if ( maxPos >= m_numCols) + maxPos = m_numCols - 1; + else + { + if ( x >= m_colRights[GetColAt( maxPos )]) + { + minPos = maxPos; + if (m_minAcceptableColWidth) + maxPos = x / m_minAcceptableColWidth; + else + maxPos = m_numCols - 1; + } + if ( maxPos >= m_numCols) + maxPos = m_numCols - 1; + } + + //X is beyond the last column + if ( x >= m_colRights[GetColAt( maxPos )]) + return clipToMinMax ? GetColAt( maxPos ) : -1; + + //X is before the first column + if ( x < m_colRights[GetColAt( 0 )] ) + return GetColAt( 0 ); + + //Perform a binary search + while ( maxPos - minPos > 0 ) + { + wxCHECK_MSG(m_colRights[GetColAt( minPos )] <= x && x < m_colRights[GetColAt( maxPos )], + 0, _T("wxGrid: internal error in XToCol")); + + if (x >= m_colRights[GetColAt( maxPos - 1 )]) + return GetColAt( maxPos ); + else + maxPos--; + int median = minPos + (maxPos - minPos + 1) / 2; + if (x < m_colRights[GetColAt( median )]) + maxPos = median; + else + minPos = median; + } + 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 wxGrid::YToEdgeOfRow( int y ) const { 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. @@ -8168,15 +8682,16 @@ int wxGrid::YToEdgeOfRow( int y ) // 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 wxGrid::XToEdgeOfCol( int x ) const { 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 + // We know that we are in column i; test whether we are // close enough to right or left border, respectively. if ( abs(GetColRight(i) - x) < WXGRID_LABEL_EDGE_ZONE ) return i; @@ -8187,7 +8702,7 @@ int wxGrid::XToEdgeOfCol( int x ) return -1; } -wxRect wxGrid::CellToRect( int row, int col ) +wxRect wxGrid::CellToRect( int row, int col ) const { wxRect rect( -1, -1, -1, -1 ); @@ -8222,7 +8737,7 @@ wxRect wxGrid::CellToRect( int row, int col ) return rect; } -bool wxGrid::IsVisible( int row, int col, bool wholeCellVisible ) +bool wxGrid::IsVisible( int row, int col, bool wholeCellVisible ) const { // get the cell rectangle in logical coords // @@ -8241,7 +8756,6 @@ bool wxGrid::IsVisible( int row, int col, bool wholeCellVisible ) if ( wholeCellVisible ) { // is the cell wholly visible ? - // return ( left >= 0 && right <= cw && top >= 0 && bottom <= ch ); } @@ -8284,7 +8798,7 @@ void wxGrid::MakeCellVisible( int row, int col ) { int h = r.GetHeight(); ypos = r.GetTop(); - for ( i = row-1; i >= 0; i-- ) + for ( i = row - 1; i >= 0; i-- ) { int rowHeight = GetRowHeight(i); if ( h + rowHeight > ch ) @@ -8295,11 +8809,11 @@ void wxGrid::MakeCellVisible( int row, int col ) } // we divide it later by GRID_SCROLL_LINE, make sure that we don't - // have rounding errors (this is important, because if we do, we - // might not scroll at all and some cells won't be redrawn) + // have rounding errors (this is important, because if we do, + // we might not scroll at all and some cells won't be redrawn) // - // Sometimes GRID_SCROLL_LINE/2 is not enough, so just add a full - // scroll unit... + // Sometimes GRID_SCROLL_LINE / 2 is not enough, + // so just add a full scroll unit... ypos += m_scrollLineY; } @@ -8423,11 +8937,12 @@ bool wxGrid::MoveCursorLeft( bool expandSelection ) HighlightBlock( m_currentCellCoords, m_selectingKeyboard ); } } - else if ( m_currentCellCoords.GetCol() > 0 ) + else if ( GetColPos( m_currentCellCoords.GetCol() ) > 0 ) { int row = m_currentCellCoords.GetRow(); - int col = m_currentCellCoords.GetCol() - 1; + int col = GetColAt( GetColPos( m_currentCellCoords.GetCol() ) - 1 ); ClearSelection(); + MakeCellVisible( row, col ); SetCurrentCell( row, col ); } @@ -8457,11 +8972,12 @@ bool wxGrid::MoveCursorRight( bool expandSelection ) HighlightBlock( m_currentCellCoords, m_selectingKeyboard ); } } - else if ( m_currentCellCoords.GetCol() < m_numCols - 1 ) + else if ( GetColPos( m_currentCellCoords.GetCol() ) < m_numCols - 1 ) { int row = m_currentCellCoords.GetRow(); - int col = m_currentCellCoords.GetCol() + 1; + int col = GetColAt( GetColPos( m_currentCellCoords.GetCol() ) + 1 ); ClearSelection(); + MakeCellVisible( row, col ); SetCurrentCell( row, col ); } @@ -8490,7 +9006,7 @@ bool wxGrid::MovePageUp() if ( newRow == row ) { - //row > 0 , so newrow can never be less than 0 here. + // row > 0, so newRow can never be less than 0 here. newRow = row - 1; } @@ -8518,7 +9034,7 @@ bool wxGrid::MovePageDown() int newRow = internalYToRow( y + ch ); if ( newRow == row ) { - // row < m_numRows , so newrow can't overflow here. + // row < m_numRows, so newRow can't overflow here. newRow = row + 1; } @@ -8799,7 +9315,7 @@ bool wxGrid::MoveCursorRightBlock( bool expandSelection ) // ------ Label values and formatting // -void wxGrid::GetRowLabelAlignment( int *horiz, int *vert ) +void wxGrid::GetRowLabelAlignment( int *horiz, int *vert ) const { if ( horiz ) *horiz = m_rowLabelHorizAlign; @@ -8807,7 +9323,7 @@ void wxGrid::GetRowLabelAlignment( int *horiz, int *vert ) *vert = m_rowLabelVertAlign; } -void wxGrid::GetColLabelAlignment( int *horiz, int *vert ) +void wxGrid::GetColLabelAlignment( int *horiz, int *vert ) const { if ( horiz ) *horiz = m_colLabelHorizAlign; @@ -8815,12 +9331,12 @@ void wxGrid::GetColLabelAlignment( int *horiz, int *vert ) *vert = m_colLabelVertAlign; } -int wxGrid::GetColLabelTextOrientation() +int wxGrid::GetColLabelTextOrientation() const { return m_colLabelTextOrientation; } -wxString wxGrid::GetRowLabelValue( int row ) +wxString wxGrid::GetRowLabelValue( int row ) const { if ( m_table ) { @@ -8834,7 +9350,7 @@ wxString wxGrid::GetRowLabelValue( int row ) } } -wxString wxGrid::GetColLabelValue( int col ) +wxString wxGrid::GetColLabelValue( int col ) const { if ( m_table ) { @@ -8850,7 +9366,13 @@ wxString wxGrid::GetColLabelValue( int col ) void wxGrid::SetRowLabelSize( int width ) { - width = wxMax( width, 0 ); + wxASSERT( width >= 0 || width == wxGRID_AUTOSIZE ); + + if ( width == wxGRID_AUTOSIZE ) + { + width = CalcColOrRowLabelAreaMinSize(wxGRID_ROW); + } + if ( width != m_rowLabelWidth ) { if ( width == 0 ) @@ -8873,7 +9395,13 @@ void wxGrid::SetRowLabelSize( int width ) void wxGrid::SetColLabelSize( int height ) { - height = wxMax( height, 0 ); + wxASSERT( height >=0 || height == wxGRID_AUTOSIZE ); + + if ( height == wxGRID_AUTOSIZE ) + { + height = CalcColOrRowLabelAreaMinSize(wxGRID_COLUMN); + } + if ( height != m_colLabelHeight ) { if ( height == 0 ) @@ -8884,7 +9412,8 @@ void wxGrid::SetColLabelSize( int height ) else if ( m_colLabelHeight == 0 ) { m_colLabelWin->Show( true ); - if ( m_rowLabelWidth > 0 ) m_cornerLabelWin->Show( true ); + if ( m_rowLabelWidth > 0 ) + m_cornerLabelWin->Show( true ); } m_colLabelHeight = height; @@ -9010,14 +9539,10 @@ void wxGrid::SetColLabelAlignment( int horiz, int vert ) void wxGrid::SetColLabelTextOrientation( int textOrientation ) { if ( textOrientation == wxHORIZONTAL || textOrientation == wxVERTICAL ) - { m_colLabelTextOrientation = textOrientation; - } if ( !GetBatchCount() ) - { m_colLabelWin->Refresh(); - } } void wxGrid::SetRowLabelValue( int row, const wxString& s ) @@ -9094,7 +9619,7 @@ void wxGrid::SetCellHighlightPenWidth(int width) // make any visible change if the the thickness is getting smaller. int row = m_currentCellCoords.GetRow(); int col = m_currentCellCoords.GetCol(); - if ( GetColWidth(col) <= 0 || GetRowHeight(row) <= 0 ) + if ( row == -1 || col == -1 || GetColWidth(col) <= 0 || GetRowHeight(row) <= 0 ) return; wxRect rect = CellToRect(row, col); @@ -9112,7 +9637,8 @@ void wxGrid::SetCellHighlightROPenWidth(int width) // make any visible change if the the thickness is getting smaller. int row = m_currentCellCoords.GetRow(); int col = m_currentCellCoords.GetCol(); - if ( GetColWidth(col) <= 0 || GetRowHeight(row) <= 0 ) + if ( row == -1 || col == -1 || + GetColWidth(col) <= 0 || GetRowHeight(row) <= 0 ) return; wxRect rect = CellToRect(row, col); @@ -9142,24 +9668,24 @@ void wxGrid::EnableGridLines( bool enable ) } } -int wxGrid::GetDefaultRowSize() +int wxGrid::GetDefaultRowSize() const { return m_defaultRowHeight; } -int wxGrid::GetRowSize( int row ) +int wxGrid::GetRowSize( int row ) const { wxCHECK_MSG( row >= 0 && row < m_numRows, 0, _T("invalid row index") ); return GetRowHeight(row); } -int wxGrid::GetDefaultColSize() +int wxGrid::GetDefaultColSize() const { return m_defaultColWidth; } -int wxGrid::GetColSize( int col ) +int wxGrid::GetColSize( int col ) const { wxCHECK_MSG( col >= 0 && col < m_numCols, 0, _T("invalid column index") ); @@ -9223,30 +9749,30 @@ void wxGrid::SetDefaultEditor(wxGridCellEditor *editor) } // ---------------------------------------------------------------------------- -// access to the default attrbiutes +// access to the default attributes // ---------------------------------------------------------------------------- -wxColour wxGrid::GetDefaultCellBackgroundColour() +wxColour wxGrid::GetDefaultCellBackgroundColour() const { return m_defaultCellAttr->GetBackgroundColour(); } -wxColour wxGrid::GetDefaultCellTextColour() +wxColour wxGrid::GetDefaultCellTextColour() const { return m_defaultCellAttr->GetTextColour(); } -wxFont wxGrid::GetDefaultCellFont() +wxFont wxGrid::GetDefaultCellFont() const { return m_defaultCellAttr->GetFont(); } -void wxGrid::GetDefaultCellAlignment( int *horiz, int *vert ) +void wxGrid::GetDefaultCellAlignment( int *horiz, int *vert ) const { m_defaultCellAttr->GetAlignment(horiz, vert); } -bool wxGrid::GetDefaultCellOverflow() +bool wxGrid::GetDefaultCellOverflow() const { return m_defaultCellAttr->GetOverflow(); } @@ -9265,7 +9791,7 @@ wxGridCellEditor *wxGrid::GetDefaultEditor() const // access to cell attributes // ---------------------------------------------------------------------------- -wxColour wxGrid::GetCellBackgroundColour(int row, int col) +wxColour wxGrid::GetCellBackgroundColour(int row, int col) const { wxGridCellAttr *attr = GetCellAttr(row, col); wxColour colour = attr->GetBackgroundColour(); @@ -9274,7 +9800,7 @@ wxColour wxGrid::GetCellBackgroundColour(int row, int col) return colour; } -wxColour wxGrid::GetCellTextColour( int row, int col ) +wxColour wxGrid::GetCellTextColour( int row, int col ) const { wxGridCellAttr *attr = GetCellAttr(row, col); wxColour colour = attr->GetTextColour(); @@ -9283,7 +9809,7 @@ wxColour wxGrid::GetCellTextColour( int row, int col ) return colour; } -wxFont wxGrid::GetCellFont( int row, int col ) +wxFont wxGrid::GetCellFont( int row, int col ) const { wxGridCellAttr *attr = GetCellAttr(row, col); wxFont font = attr->GetFont(); @@ -9292,14 +9818,14 @@ wxFont wxGrid::GetCellFont( int row, int col ) return font; } -void wxGrid::GetCellAlignment( int row, int col, int *horiz, int *vert ) +void wxGrid::GetCellAlignment( int row, int col, int *horiz, int *vert ) const { wxGridCellAttr *attr = GetCellAttr(row, col); attr->GetAlignment(horiz, vert); attr->DecRef(); } -bool wxGrid::GetCellOverflow( int row, int col ) +bool wxGrid::GetCellOverflow( int row, int col ) const { wxGridCellAttr *attr = GetCellAttr(row, col); bool allow = attr->GetOverflow(); @@ -9308,14 +9834,14 @@ bool wxGrid::GetCellOverflow( int row, int col ) return allow; } -void wxGrid::GetCellSize( int row, int col, int *num_rows, int *num_cols ) +void wxGrid::GetCellSize( int row, int col, int *num_rows, int *num_cols ) const { wxGridCellAttr *attr = GetCellAttr(row, col); attr->GetSize( num_rows, num_cols ); attr->DecRef(); } -wxGridCellRenderer* wxGrid::GetCellRenderer(int row, int col) +wxGridCellRenderer* wxGrid::GetCellRenderer(int row, int col) const { wxGridCellAttr* attr = GetCellAttr(row, col); wxGridCellRenderer* renderer = attr->GetRenderer(this, row, col); @@ -9324,7 +9850,7 @@ wxGridCellRenderer* wxGrid::GetCellRenderer(int row, int col) return renderer; } -wxGridCellEditor* wxGrid::GetCellEditor(int row, int col) +wxGridCellEditor* wxGrid::GetCellEditor(int row, int col) const { wxGridCellAttr* attr = GetCellAttr(row, col); wxGridCellEditor* editor = attr->GetEditor(this, row, col); @@ -9346,7 +9872,7 @@ bool wxGrid::IsReadOnly(int row, int col) const // attribute support: cache, automatic provider creation, ... // ---------------------------------------------------------------------------- -bool wxGrid::CanHaveAttributes() +bool wxGrid::CanHaveAttributes() const { if ( !m_table ) { @@ -9412,7 +9938,7 @@ wxGridCellAttr *wxGrid::GetCellAttr(int row, int col) const { if ( !LookupAttr(row, col, &attr) ) { - attr = m_table ? m_table->GetAttr(row, col , wxGridCellAttr::Any) + attr = m_table ? m_table->GetAttr(row, col, wxGridCellAttr::Any) : (wxGridCellAttr *)NULL; CacheAttr(row, col, attr); } @@ -9683,27 +10209,24 @@ void wxGrid::RegisterDataType(const wxString& typeName, } -wxGridCellEditor* wxGrid::GetDefaultEditorForCell(int row, int col) const +wxGridCellEditor * wxGrid::GetDefaultEditorForCell(int row, int col) const { wxString typeName = m_table->GetTypeName(row, col); return GetDefaultEditorForType(typeName); } -wxGridCellRenderer* wxGrid::GetDefaultRendererForCell(int row, int col) const +wxGridCellRenderer * wxGrid::GetDefaultRendererForCell(int row, int col) const { wxString typeName = m_table->GetTypeName(row, col); return GetDefaultRendererForType(typeName); } -wxGridCellEditor* wxGrid::GetDefaultEditorForType(const wxString& typeName) const +wxGridCellEditor * wxGrid::GetDefaultEditorForType(const wxString& typeName) const { int index = m_typeRegistry->FindOrCloneDataType(typeName); if ( index == wxNOT_FOUND ) { - wxString errStr; - - errStr.Printf(wxT("Unknown data type name [%s]"), typeName.c_str()); - wxFAIL_MSG(errStr.c_str()); + wxFAIL_MSG(wxString::Format(wxT("Unknown data type name [%s]"), typeName.c_str())); return NULL; } @@ -9711,15 +10234,12 @@ wxGridCellEditor* wxGrid::GetDefaultEditorForType(const wxString& typeName) cons return m_typeRegistry->GetEditor(index); } -wxGridCellRenderer* wxGrid::GetDefaultRendererForType(const wxString& typeName) const +wxGridCellRenderer * wxGrid::GetDefaultRendererForType(const wxString& typeName) const { int index = m_typeRegistry->FindOrCloneDataType(typeName); if ( index == wxNOT_FOUND ) { - wxString errStr; - - errStr.Printf(wxT("Unknown data type name [%s]"), typeName.c_str()); - wxFAIL_MSG(errStr.c_str()); + wxFAIL_MSG(wxString::Format(wxT("Unknown data type name [%s]"), typeName.c_str())); return NULL; } @@ -9786,8 +10306,7 @@ void wxGrid::SetRowSize( int row, int height ) 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; } @@ -9798,7 +10317,8 @@ void wxGrid::SetRowSize( int row, int height ) void wxGrid::SetDefaultColSize( int width, bool resizeExistingCols ) { - m_defaultColWidth = wxMax( width, m_minAcceptableColWidth ); + // we dont allow zero default column width + m_defaultColWidth = wxMax( wxMax( width, m_minAcceptableColWidth ), 1 ); if ( resizeExistingCols ) { @@ -9820,7 +10340,7 @@ void wxGrid::SetColSize( int col, int width ) // should we check that it's bigger than GetColMinimalWidth(col) here? // (VZ) // No, because it is reasonable to assume the library user know's - // what he is doing. However whe should test against the weaker + // what he is doing. However we should test against the weaker // constraint of minimalAcceptableWidth, as this breaks rendering // // This test then fixes sf.net bug #645734 @@ -9834,26 +10354,25 @@ void wxGrid::SetColSize( int col, int width ) InitColWidths(); } - // if < 0 calc new width from label + // if < 0 then calculate new width from label if ( width < 0 ) { - long w, h; - wxArrayString lines; - wxClientDC dc(m_colLabelWin); - dc.SetFont(GetLabelFont()); - StringToLines(GetColLabelValue(col), lines); - GetTextBoxSize(dc, lines, &w, &h); - width = w + 6; + long w, h; + wxArrayString lines; + wxClientDC dc(m_colLabelWin); + dc.SetFont(GetLabelFont()); + StringToLines(GetColLabelValue(col), lines); + GetTextBoxSize(dc, lines, &w, &h); + width = w + 6; } int w = wxMax( 0, width ); int diff = w - m_colWidths[col]; m_colWidths[col] = w; - int i; - for ( i = col; i < m_numCols; i++ ) + for ( int colPos = GetColPos(col); colPos < m_numCols; colPos++ ) { - m_colRights[i] += diff; + m_colRights[GetColAt(colPos)] += diff; } if ( !GetBatchCount() ) @@ -9924,8 +10443,11 @@ int wxGrid::GetRowMinimalAcceptableHeight() const // auto sizing // ---------------------------------------------------------------------------- -void wxGrid::AutoSizeColOrRow( int colOrRow, bool setAsMin, bool column ) +void +wxGrid::AutoSizeColOrRow(int colOrRow, bool setAsMin, wxGridDirection direction) { + const bool column = direction == wxGRID_COLUMN; + wxClientDC dc(m_gridWin); // cancel editing of cell @@ -9956,9 +10478,7 @@ void wxGrid::AutoSizeColOrRow( int colOrRow, bool setAsMin, bool column ) wxSize size = renderer->GetBestSize(*this, *attr, dc, row, col); extent = column ? size.x : size.y; if ( extent > extentMax ) - { extentMax = extent; - } renderer->DecRef(); } @@ -9972,18 +10492,16 @@ void wxGrid::AutoSizeColOrRow( int colOrRow, bool setAsMin, bool column ) 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 ) - { extentMax = extent; - } if ( !extentMax ) { @@ -10002,6 +10520,12 @@ void wxGrid::AutoSizeColOrRow( int colOrRow, bool setAsMin, bool column ) if ( column ) { + // Ensure automatic width is not less than minimal width. See the + // comment in SetColSize() for explanation of why this isn't done + // in SetColSize(). + if ( !setAsMin ) + extentMax = wxMax(extentMax, GetColMinimalWidth(col)); + SetColSize( col, extentMax ); if ( !GetBatchCount() ) { @@ -10017,6 +10541,12 @@ void wxGrid::AutoSizeColOrRow( int colOrRow, bool setAsMin, bool column ) } else { + // Ensure automatic width is not less than minimal height. See the + // comment in SetColSize() for explanation of why this isn't done + // in SetRowSize(). + if ( !setAsMin ) + extentMax = wxMax(extentMax, GetRowMinimalHeight(row)); + SetRowSize(row, extentMax); if ( !GetBatchCount() ) { @@ -10040,26 +10570,75 @@ void wxGrid::AutoSizeColOrRow( int colOrRow, bool setAsMin, bool column ) } } +wxCoord wxGrid::CalcColOrRowLabelAreaMinSize(wxGridDirection direction) +{ + // calculate size for the rows or columns? + const bool calcRows = direction == wxGRID_ROW; + + wxClientDC dc(calcRows ? GetGridRowLabelWindow() + : GetGridColLabelWindow()); + dc.SetFont(GetLabelFont()); + + // which dimension should we take into account for calculations? + // + // for columns, the text can be only horizontal so it's easy but for rows + // we also have to take into account the text orientation + const bool + useWidth = calcRows || (GetColLabelTextOrientation() == wxVERTICAL); + + wxArrayString lines; + wxCoord extentMax = 0; + + const int numRowsOrCols = calcRows ? m_numRows : m_numCols; + for ( int rowOrCol = 0; rowOrCol < numRowsOrCols; rowOrCol++ ) + { + lines.Clear(); + + wxString label = calcRows ? GetRowLabelValue(rowOrCol) + : GetColLabelValue(rowOrCol); + StringToLines(label, lines); + + long w, h; + GetTextBoxSize(dc, lines, &w, &h); + + const wxCoord extent = useWidth ? w : h; + if ( extent > extentMax ) + extentMax = extent; + } + + if ( !extentMax ) + { + // empty column - give default extent (notice that if extentMax is less + // than default extent but != 0, it's OK) + extentMax = calcRows ? GetDefaultRowLabelSize() + : GetDefaultColLabelSize(); + } + + // leave some space around text (taken from AutoSizeColOrRow) + if ( calcRows ) + extentMax += 10; + else + extentMax += 6; + + return extentMax; +} + int wxGrid::SetOrCalcColumnSizes(bool calcOnly, bool setAsMin) { int width = m_rowLabelWidth; - if ( !calcOnly ) - BeginBatch(); + wxGridUpdateLocker locker; + if(!calcOnly) + locker.Create(this); for ( int col = 0; col < m_numCols; col++ ) { if ( !calcOnly ) - { AutoSizeColumn(col, setAsMin); - } width += GetColWidth(col); } - if ( !calcOnly ) - EndBatch(); - return width; } @@ -10067,8 +10646,9 @@ int wxGrid::SetOrCalcRowSizes(bool calcOnly, bool setAsMin) { int height = m_colLabelHeight; - if ( !calcOnly ) - BeginBatch(); + wxGridUpdateLocker locker; + if(!calcOnly) + locker.Create(this); for ( int row = 0; row < m_numRows; row++ ) { @@ -10078,31 +10658,24 @@ int wxGrid::SetOrCalcRowSizes(bool calcOnly, bool setAsMin) height += GetRowHeight(row); } - if ( !calcOnly ) - EndBatch(); - return height; } void wxGrid::AutoSize() { - BeginBatch(); + wxGridUpdateLocker locker(this); - 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 @@ -10127,7 +10700,7 @@ void wxGrid::AutoSize() } // 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 @@ -10151,9 +10724,11 @@ void wxGrid::AutoSize() } } - EndBatch(); - - SetClientSize(sizeFit); + // 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); } void wxGrid::AutoSizeRowLabelSize( int row ) @@ -10185,7 +10760,7 @@ void wxGrid::AutoSizeColLabelSize( int col ) long w, h; // Hide the edit control, so it - // won't interfer with drag-shrinking. + // won't interfere with drag-shrinking. if ( IsCellEditControlShown() ) { HideCellEditControl(); @@ -10207,46 +10782,22 @@ void wxGrid::AutoSizeColLabelSize( int col ) 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() @@ -10385,7 +10936,7 @@ void wxGrid::DeselectCell( int row, int col ) m_selection->ToggleCellSelection(row, col); } -bool wxGrid::IsSelection() +bool wxGrid::IsSelection() const { return ( m_selection && (m_selection->IsSelection() || ( m_selectingTopLeft != wxGridNoCellCoords && @@ -10458,8 +11009,9 @@ wxArrayInt wxGrid::GetSelectedCols() const void wxGrid::ClearSelection() { - m_selectingTopLeft = wxGridNoCellCoords; - m_selectingBottomRight = wxGridNoCellCoords; + m_selectingTopLeft = + m_selectingBottomRight = + m_selectingKeyboard = wxGridNoCellCoords; if ( m_selection ) m_selection->ClearSelection(); } @@ -10467,37 +11019,36 @@ void wxGrid::ClearSelection() // This function returns the rectangle that encloses the given block // in device coords clipped to the client size of the grid window. // -wxRect wxGrid::BlockToDeviceRect( const wxGridCellCoords &topLeft, - const wxGridCellCoords &bottomRight ) +wxRect wxGrid::BlockToDeviceRect( const wxGridCellCoords& topLeft, + const wxGridCellCoords& bottomRight ) const { - wxRect rect( wxGridNoCellRect ); - wxRect cellRect; - - cellRect = CellToRect( topLeft ); - if ( cellRect != wxGridNoCellRect ) + wxRect resultRect; + wxRect tempCellRect = CellToRect(topLeft); + if ( tempCellRect != wxGridNoCellRect ) { - rect = cellRect; + resultRect = tempCellRect; } else { - rect = wxRect(0, 0, 0, 0); + resultRect = wxRect(0, 0, 0, 0); } - cellRect = CellToRect( bottomRight ); - if ( cellRect != wxGridNoCellRect ) + tempCellRect = CellToRect(bottomRight); + if ( tempCellRect != wxGridNoCellRect ) { - rect += cellRect; + resultRect += tempCellRect; } else { + // If both inputs were "wxGridNoCellRect," then there's nothing to do. return wxGridNoCellRect; } - int i, j; - int left = rect.GetLeft(); - int top = rect.GetTop(); - int right = rect.GetRight(); - int bottom = rect.GetBottom(); + // Ensure that left/right and top/bottom pairs are in order. + int left = resultRect.GetLeft(); + int top = resultRect.GetTop(); + int right = resultRect.GetRight(); + int bottom = resultRect.GetBottom(); int leftCol = topLeft.GetCol(); int topRow = topLeft.GetRow(); @@ -10506,67 +11057,105 @@ wxRect wxGrid::BlockToDeviceRect( const wxGridCellCoords &topLeft, if (left > right) { - i = left; + int tmp = left; left = right; - right = i; - i = leftCol; + right = tmp; + + tmp = leftCol; leftCol = rightCol; - rightCol = i; + rightCol = tmp; } if (top > bottom) { - i = top; + int tmp = top; top = bottom; - bottom = i; - i = topRow; + bottom = tmp; + + tmp = topRow; topRow = bottomRow; - bottomRow = i; + bottomRow = tmp; } - for ( j = topRow; j <= bottomRow; j++ ) + // The following loop is ONLY necessary to detect and handle merged cells. + int cw, ch; + m_gridWin->GetClientSize( &cw, &ch ); + + // Get the origin coordinates: notice that they will be negative if the + // grid is scrolled downwards/to the right. + int gridOriginX = 0; + int gridOriginY = 0; + CalcScrolledPosition(gridOriginX, gridOriginY, &gridOriginX, &gridOriginY); + + int onScreenLeftmostCol = internalXToCol(-gridOriginX); + int onScreenUppermostRow = internalYToRow(-gridOriginY); + + int onScreenRightmostCol = internalXToCol(-gridOriginX + cw); + int onScreenBottommostRow = internalYToRow(-gridOriginY + ch); + + // Bound our loop so that we only examine the portion of the selected block + // that is shown on screen. Therefore, we compare the Top-Left block values + // to the Top-Left screen values, and the Bottom-Right block values to the + // Bottom-Right screen values, choosing appropriately. + const int visibleTopRow = wxMax(topRow, onScreenUppermostRow); + const int visibleBottomRow = wxMin(bottomRow, onScreenBottommostRow); + const int visibleLeftCol = wxMax(leftCol, onScreenLeftmostCol); + const int visibleRightCol = wxMin(rightCol, onScreenRightmostCol); + + for ( int j = visibleTopRow; j <= visibleBottomRow; j++ ) { - for ( i = leftCol; i <= rightCol; i++ ) + for ( int i = visibleLeftCol; i <= visibleRightCol; i++ ) { - if ((j == topRow) || (j == bottomRow) || (i == leftCol) || (i == rightCol)) + if ( (j == visibleTopRow) || (j == visibleBottomRow) || + (i == visibleLeftCol) || (i == visibleRightCol) ) { - cellRect = CellToRect( j, i ); + tempCellRect = CellToRect( j, i ); - if (cellRect.x < left) - left = cellRect.x; - if (cellRect.y < top) - top = cellRect.y; - if (cellRect.x + cellRect.width > right) - right = cellRect.x + cellRect.width; - if (cellRect.y + cellRect.height > bottom) - bottom = cellRect.y + cellRect.height; + if (tempCellRect.x < left) + left = tempCellRect.x; + if (tempCellRect.y < top) + top = tempCellRect.y; + if (tempCellRect.x + tempCellRect.width > right) + right = tempCellRect.x + tempCellRect.width; + if (tempCellRect.y + tempCellRect.height > bottom) + bottom = tempCellRect.y + tempCellRect.height; } else { - i = rightCol; // jump over inner cells. + i = visibleRightCol; // jump over inner cells. } } } - // convert to scrolled coords - // + // Convert to scrolled coords CalcScrolledPosition( left, top, &left, &top ); CalcScrolledPosition( right, bottom, &right, &bottom ); - int cw, ch; - m_gridWin->GetClientSize( &cw, &ch ); - if (right < 0 || bottom < 0 || left > cw || top > ch) return wxRect(0,0,0,0); - rect.SetLeft( wxMax(0, left) ); - rect.SetTop( wxMax(0, top) ); - rect.SetRight( wxMin(cw, right) ); - rect.SetBottom( wxMin(ch, bottom) ); + resultRect.SetLeft( wxMax(0, left) ); + resultRect.SetTop( wxMax(0, top) ); + resultRect.SetRight( wxMin(cw, right) ); + resultRect.SetBottom( wxMin(ch, bottom) ); - return rect; + return resultRect; } +// ---------------------------------------------------------------------------- +// drop target +// ---------------------------------------------------------------------------- + +#if wxUSE_DRAG_AND_DROP + +// this allow setting drop target directly on wxGrid +void wxGrid::SetDropTarget(wxDropTarget *dropTarget) +{ + GetGridWindow()->SetDropTarget(dropTarget); +} + +#endif // wxUSE_DRAG_AND_DROP + // ---------------------------------------------------------------------------- // grid event classes // ----------------------------------------------------------------------------