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.

Closes #23102.

Closes #23128.
This commit is contained in:
Jens Göpfert 2023-01-10 15:36:02 +01:00 committed by Vadim Zeitlin
parent 38bc9c2a8d
commit 842ca1e8b8
2 changed files with 82 additions and 31 deletions

View file

@ -104,6 +104,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);
@ -452,6 +453,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,
@ -506,6 +508,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 )
@ -741,8 +744,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
@ -1588,6 +1598,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() );

View file

@ -825,6 +825,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;
@ -3475,33 +3480,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 );
}
@ -3547,6 +3526,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;
@ -6448,12 +6460,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 )
{
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
m_clientArea->ScrollTo( first, column );
{
// 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 )