diff --git a/interface/wx/dataview.h b/interface/wx/dataview.h index 1a8ab039ae..85bc40acdb 100644 --- a/interface/wx/dataview.h +++ b/interface/wx/dataview.h @@ -1448,8 +1448,9 @@ public: /** Returns item rectangle. - If item is not currently visible because its parent is collapsed, - return an empty rectangle. + If item is not currently visible, either because its parent is + collapsed or it is outside of the visible part of the control due to + the current vertical scrollbar position, return an empty rectangle. Coordinates of the rectangle are specified in wxDataViewCtrl client area coordinates. diff --git a/src/generic/datavgen.cpp b/src/generic/datavgen.cpp index d82c2f051f..41c3b7fbed 100644 --- a/src/generic/datavgen.cpp +++ b/src/generic/datavgen.cpp @@ -3839,6 +3839,14 @@ wxRect wxDataViewMainWindow::GetItemRect( const wxDataViewItem & item, GetOwner()->CalcScrolledPosition( itemRect.x, itemRect.y, &itemRect.x, &itemRect.y ); + // Check if the rectangle is completely outside of the currently visible + // area and, if so, return an empty rectangle to indicate that the item is + // not visible. + if ( itemRect.GetBottom() < 0 || itemRect.GetTop() > GetClientSize().y ) + { + return wxRect(); + } + return itemRect; } @@ -5853,8 +5861,11 @@ wxRect wxDataViewCtrl::GetItemRect( const wxDataViewItem & item, // Convert position from the main window coordinates to the control coordinates. // (They can be different due to the presence of the header.). wxRect r = m_clientArea->GetItemRect(item, column); - const wxPoint ctrlPos = ScreenToClient(m_clientArea->ClientToScreen(r.GetPosition())); - r.SetPosition(ctrlPos); + if ( r.width || r.height ) + { + const wxPoint ctrlPos = ScreenToClient(m_clientArea->ClientToScreen(r.GetPosition())); + r.SetPosition(ctrlPos); + } return r; } diff --git a/tests/controls/dataviewctrltest.cpp b/tests/controls/dataviewctrltest.cpp index 720fdce938..f7fcaca67e 100644 --- a/tests/controls/dataviewctrltest.cpp +++ b/tests/controls/dataviewctrltest.cpp @@ -208,6 +208,9 @@ TEST_CASE_METHOD(SingleSelectDataViewCtrlTestCase, const wxRect rect1 = m_dvc->GetItemRect(m_child1); const wxRect rect2 = m_dvc->GetItemRect(m_child2); + CHECK( rect1 != wxRect() ); + CHECK( rect2 != wxRect() ); + CHECK( rect1.x == rect2.x ); CHECK( rect1.width == rect2.width ); CHECK( rect1.height == rect2.height ); @@ -215,6 +218,30 @@ TEST_CASE_METHOD(SingleSelectDataViewCtrlTestCase, const wxRect rectNotShown = m_dvc->GetItemRect(m_grandchild); CHECK( rectNotShown == wxRect() ); + + // Append enough items to make the window scrollable. + for ( int i = 3; i < 100; ++i ) + m_dvc->AppendItem(m_root, wxString::Format("child%d", i)); + + const wxDataViewItem last = m_dvc->AppendItem(m_root, "last"); + + // This should scroll the window to bring this item into view. + m_dvc->EnsureVisible(last); + + // Check that this was indeed the case. + const wxDataViewItem top = m_dvc->GetTopItem(); + CHECK( top != m_root ); + + // Verify that the coordinates are returned in physical coordinates of the + // window and not the logical coordinates affected by scrolling. + const wxRect rectScrolled = m_dvc->GetItemRect(top); + CHECK( rectScrolled.GetBottom() > 0 ); + CHECK( rectScrolled.GetTop() <= m_dvc->GetClientSize().y ); + + // Also check that the root item is not currently visible (because it's + // scrolled off). + const wxRect rectRoot = m_dvc->GetItemRect(m_root); + CHECK( rectRoot == wxRect() ); #endif }