From fad50e74b7737708233cf6fcc2f374d69c79b923 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sun, 4 Nov 2018 18:25:16 +0100 Subject: [PATCH] Fix wxDataViewCtrl::GetItemRect() in wxGTK and enable its test A couple of fixes compared to the previous commit: - Use the correct gtk_tree_view_get_cell_area() rather than gtk_tree_view_get_background_area() which doesn't work correctly for the items which are not shown because their parent is collapsed. - Translate logical coordinates to physical ones using gtk_tree_view_convert_bin_window_to_widget_coords(). With these fixes, the unit tests for this function pass and can now be enabled under wxGTK as well. See https://github.com/wxWidgets/wxWidgets/pull/990 --- src/gtk/dataview.cpp | 37 ++++++++++++++++++++++++++++- tests/controls/dataviewctrltest.cpp | 19 +++++++++++---- 2 files changed, 51 insertions(+), 5 deletions(-) diff --git a/src/gtk/dataview.cpp b/src/gtk/dataview.cpp index c5662aa26e..d2c1abf352 100644 --- a/src/gtk/dataview.cpp +++ b/src/gtk/dataview.cpp @@ -5304,7 +5304,15 @@ wxDataViewCtrl::GetItemRect(const wxDataViewItem& item, wxGtkTreePath path(m_internal->get_path( &iter )); GdkRectangle item_rect; - gtk_tree_view_get_background_area(GTK_TREE_VIEW(m_treeview), path, gcolumn, &item_rect); + gtk_tree_view_get_cell_area(GTK_TREE_VIEW(m_treeview), path, gcolumn, &item_rect); + + // GTK returns rectangles with the position and height, but not width, for + // some reason, set to 0 if the item is not currently shown, so an explicit + // check is needed as this rectangle is not quite the empty rectangle we're + // supposed to return in this case. + if ( item_rect.height == 0 ) + return wxRect(); + // If column is NULL we compute the combined width of all the columns if ( !column ) { @@ -5318,6 +5326,33 @@ wxDataViewCtrl::GetItemRect(const wxDataViewItem& item, } item_rect.width = width; } + + // We need to convert logical coordinates to physical ones, i.e. the + // rectangle of the topmost item should start at ~0, even if it's a 100th + // item shown on top only because the window is scrolled. +#if GTK_CHECK_VERSION(2, 12, 0) + if ( wx_is_at_least_gtk2(12) ) + { + gtk_tree_view_convert_bin_window_to_widget_coords + ( + GTK_TREE_VIEW(m_treeview), + item_rect.x, item_rect.y, + &item_rect.x, &item_rect.y + ); + + if ( item_rect.y > GetClientSize().y || + item_rect.y + item_rect.height < 0 ) + { + // If it turns out that the item is not visible at all, indicate it + // by returning an empty rectangle for it. + return wxRect(); + } + } + //else: There doesn't seem to be anything reasonable to do here, so we'll + // just return wrong values with the very old GTK+ versions if the + // window is scrolled. +#endif // GTK+ 2.12+ + return wxRectFromGDKRect(&item_rect); } diff --git a/tests/controls/dataviewctrltest.cpp b/tests/controls/dataviewctrltest.cpp index f7fcaca67e..0f99eecfbe 100644 --- a/tests/controls/dataviewctrltest.cpp +++ b/tests/controls/dataviewctrltest.cpp @@ -22,6 +22,7 @@ #include "wx/dataview.h" #include "testableframe.h" +#include "asserthelper.h" // ---------------------------------------------------------------------------- // test class @@ -203,8 +204,10 @@ TEST_CASE_METHOD(SingleSelectDataViewCtrlTestCase, "[wxDataViewCtrl][item]") { #ifdef __WXGTK__ - WARN("Disabled under GTK because GetItemRect() is not implemented"); -#else + // We need to let the native control have some events to lay itself out. + wxYield(); +#endif // __WXGTK__ + const wxRect rect1 = m_dvc->GetItemRect(m_child1); const wxRect rect2 = m_dvc->GetItemRect(m_child2); @@ -214,7 +217,11 @@ TEST_CASE_METHOD(SingleSelectDataViewCtrlTestCase, CHECK( rect1.x == rect2.x ); CHECK( rect1.width == rect2.width ); CHECK( rect1.height == rect2.height ); - CHECK( rect1.y < rect2.y ); + + { + INFO("First child: " << rect1 << ", second one: " << rect2); + CHECK( rect1.y < rect2.y ); + } const wxRect rectNotShown = m_dvc->GetItemRect(m_grandchild); CHECK( rectNotShown == wxRect() ); @@ -228,6 +235,11 @@ TEST_CASE_METHOD(SingleSelectDataViewCtrlTestCase, // This should scroll the window to bring this item into view. m_dvc->EnsureVisible(last); +#ifdef __WXGTK__ + // And again to let it scroll the correct items into view. + wxYield(); +#endif + // Check that this was indeed the case. const wxDataViewItem top = m_dvc->GetTopItem(); CHECK( top != m_root ); @@ -242,7 +254,6 @@ TEST_CASE_METHOD(SingleSelectDataViewCtrlTestCase, // scrolled off). const wxRect rectRoot = m_dvc->GetItemRect(m_root); CHECK( rectRoot == wxRect() ); -#endif } #endif //wxUSE_DATAVIEWCTRL