From ada6599d9feba05187fdc39c187a46ce3b296fbb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jens=20G=C3=B6pfert?= Date: Tue, 10 Jan 2023 15:36:02 +0100 Subject: [PATCH] Improve ScrollTo() when using wxDV_VARIABLE_LINE_HEIGHT Calculate the last visible item based on item position instead of the first visible row when using variable line heights. Also extend the sample for testing EnsureVisible with item and column. See #23102, #23128. (cherry picked from commit 842ca1e8b8d754ed9782aa652d7cd00109848942) --- docs/changes.txt | 1 + samples/dataview/dataview.cpp | 18 +++++++ src/generic/datavgen.cpp | 95 +++++++++++++++++++++++------------ 3 files changed, 83 insertions(+), 31 deletions(-) diff --git a/docs/changes.txt b/docs/changes.txt index 1ca467f0b9..28a64dbd63 100644 --- a/docs/changes.txt +++ b/docs/changes.txt @@ -375,6 +375,7 @@ wxMSW: - Fix link error with wxSimplebook in DLL builds (Mark Roszko, #22805). - Avoid errors when including wx/msw/msvcrt.h before other wx headers (#23194). - Fix drawing owner-drawn menu items with bitmaps (Jacob Gillespie, #23230). +- Improve ScrollTo() with wxDV_VARIABLE_LINE_HEIGHT (Jens Göpfert, #23102). wxOSX: diff --git a/samples/dataview/dataview.cpp b/samples/dataview/dataview.cpp index 4b2f1d933e..0b76a5c1d3 100644 --- a/samples/dataview/dataview.cpp +++ b/samples/dataview/dataview.cpp @@ -103,6 +103,7 @@ private: void OnShowCurrent(wxCommandEvent& event); void OnSetNinthCurrent(wxCommandEvent& event); void OnChangeNinthTitle(wxCommandEvent& event); + void OnEnsureNinthAndSecondColumn(wxCommandEvent& event); void OnPrependList(wxCommandEvent& event); void OnDeleteList(wxCommandEvent& event); @@ -450,6 +451,7 @@ enum ID_SHOW_CURRENT, ID_SET_NINTH_CURRENT, ID_CHANGE_NINTH_TITLE, + ID_ENSURE_NINTH_SECOND_COLUMN, ID_PREPEND_LIST = 200, ID_DELETE_LIST = 201, @@ -503,6 +505,7 @@ wxBEGIN_EVENT_TABLE(MyFrame, wxFrame) EVT_BUTTON( ID_SHOW_CURRENT, MyFrame::OnShowCurrent ) EVT_BUTTON( ID_SET_NINTH_CURRENT, MyFrame::OnSetNinthCurrent ) EVT_BUTTON( ID_CHANGE_NINTH_TITLE, MyFrame::OnChangeNinthTitle ) + EVT_BUTTON( ID_ENSURE_NINTH_SECOND_COLUMN, MyFrame::OnEnsureNinthAndSecondColumn ) EVT_BUTTON( ID_PREPEND_LIST, MyFrame::OnPrependList ) EVT_BUTTON( ID_DELETE_LIST, MyFrame::OnDeleteList ) @@ -737,8 +740,15 @@ MyFrame::MyFrame(wxFrame *frame, const wxString &title, int x, int y, int w, int BuildDataViewCtrl(fifthPanel, Page_VarHeight); + wxBoxSizer* button_sizer5 = new wxBoxSizer(wxHORIZONTAL); + button_sizer5->Add( + new wxButton(fifthPanel, ID_ENSURE_NINTH_SECOND_COLUMN, + "Make ninth symphony and second column visible"), + wxSizerFlags().DoubleBorder()); + wxSizer *fifthPanelSz = new wxBoxSizer(wxVERTICAL); fifthPanelSz->Add(m_ctrl[Page_VarHeight], 1, wxGROW | wxALL, 5); + fifthPanelSz->Add(button_sizer5); fifthPanel->SetSizerAndFit(fifthPanelSz); // page showing the indexed list model @@ -1562,6 +1572,14 @@ void MyFrame::OnChangeNinthTitle(wxCommandEvent& WXUNUSED(event)) m_music_model->ItemChanged(item); } +void MyFrame::OnEnsureNinthAndSecondColumn(wxCommandEvent& WXUNUSED(event)) +{ + wxDataViewItem item(m_long_music_model->GetNinthItem()); + m_ctrl[Page_VarHeight]->Select(item); + wxDataViewColumn *col = m_ctrl[Page_VarHeight]->GetColumn(1); + m_ctrl[Page_VarHeight]->EnsureVisible(item, col); +} + void MyFrame::OnValueChanged( wxDataViewEvent &event ) { wxString title = m_music_model->GetTitle( event.GetItem() ); diff --git a/src/generic/datavgen.cpp b/src/generic/datavgen.cpp index ce902605eb..c5bba24f6b 100644 --- a/src/generic/datavgen.cpp +++ b/src/generic/datavgen.cpp @@ -822,6 +822,11 @@ public: int GetCountPerPage() const; int GetEndOfLastCol() const; + + // Returns the position where the given column starts. + // The column must be valid. + int GetColumnStart(int column) const; + unsigned int GetFirstVisibleRow() const; wxDataViewItem GetTopItem() const; @@ -3471,33 +3476,7 @@ void wxDataViewMainWindow::ScrollTo( int rows, int column ) int sy = y ? GetLineStart( rows )/y : -1; int sx = -1; if( column != -1 && x ) - { - wxRect rect = GetClientRect(); - int colnum = 0; - int x_start, w = 0; - int xx, yy, xe; - m_owner->CalcUnscrolledPosition( rect.x, rect.y, &xx, &yy ); - for (x_start = 0; colnum < column; colnum++) - { - wxDataViewColumn *col = GetOwner()->GetColumnAt(colnum); - if (col->IsHidden()) - continue; // skip it! - - w = col->GetWidth(); - x_start += w; - } - - int x_end = x_start + w; - xe = xx + rect.width; - if( x_end > xe ) - { - sx = ( xx + x_end - xe )/x; - } - if( x_start < xx ) - { - sx = x_start/x; - } - } + sx = GetColumnStart(column) / x; m_owner->Scroll( sx, sy ); } @@ -3543,6 +3522,39 @@ int wxDataViewMainWindow::GetEndOfLastCol() const return width; } +int wxDataViewMainWindow::GetColumnStart(int column) const +{ + wxASSERT(column >= 0); + int sx = -1; + + wxRect rect = GetClientRect(); + int colnum = 0; + int x_start, w = 0; + int xx, yy, xe; + m_owner->CalcUnscrolledPosition(rect.x, rect.y, &xx, &yy); + for (x_start = 0; colnum < column; colnum++) + { + wxDataViewColumn* col = GetOwner()->GetColumnAt(colnum); + if (col->IsHidden()) + continue; // skip it! + + w = col->GetWidth(); + x_start += w; + } + + int x_end = x_start + w; + xe = xx + rect.width; + if (x_end > xe) + { + sx = (xx + x_end - xe); + } + if (x_start < xx) + { + sx = x_start; + } + return sx; +} + unsigned int wxDataViewMainWindow::GetFirstVisibleRow() const { int x = 0; @@ -6444,12 +6456,33 @@ void wxDataViewCtrl::EnsureVisibleRowCol( int row, int column ) int first = m_clientArea->GetFirstVisibleRow(); int last = m_clientArea->GetLastFullyVisibleRow(); - if( row < first ) + if( row <= first ) + { m_clientArea->ScrollTo( row, column ); + } else if( row > last ) - m_clientArea->ScrollTo( row - last + first, column ); - else - m_clientArea->ScrollTo( first, column ); + { + if ( !HasFlag(wxDV_VARIABLE_LINE_HEIGHT) ) + { + // Simple case as we can directly find the item to scroll to. + m_clientArea->ScrollTo(row - last + first, column); + } + else + { + // calculate scroll position based on last visible item + const int itemStart = m_clientArea->GetLineStart(row); + const int itemHeight = m_clientArea->GetLineHeight(row); + const int clientHeight = m_clientArea->GetSize().y; + int scrollX, scrollY; + GetScrollPixelsPerUnit(&scrollX, &scrollY); + int scrollPosY = + (itemStart + itemHeight - clientHeight + scrollY - 1) / scrollY; + int scrollPosX = -1; + if (column != -1 && scrollX) + scrollPosX = m_clientArea->GetColumnStart(column) / scrollX; + Scroll(scrollPosX, scrollPosY); + } + } } void wxDataViewCtrl::EnsureVisible( const wxDataViewItem & item, const wxDataViewColumn * column )