From 9ae9473acdb7cb3310c3028765cc4b30fedfce27 Mon Sep 17 00:00:00 2001 From: "Danilo M." Date: Thu, 1 Oct 2026 10:49:18 +0200 Subject: feat: scroll the thread list smoothly The list scrolled per ITEM, Qt's default, so a wheel notch jumped several whole cards at once and a touchpad's small deltas were quantised into card-sized jumps. The eye lost track of how far the list had moved. The view now scrolls per pixel, so a touchpad moves it continuously, and ThreadListView::wheelEvent turns each wheel notch into a 160ms eased glide of exactly one card. Notches arriving mid-glide add to its target rather than restarting from where it has got to. Pixel deltas and modified wheels pass through to Qt unchanged. The cost of per-pixel scrolling is that a card can rest half above the top edge. Co-Authored-By: Claude Opus 5.5 --- src/threadlistview.cpp | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) (limited to 'src/threadlistview.cpp') diff --git a/src/threadlistview.cpp b/src/threadlistview.cpp index 019d7c9..b5176bf 100644 --- a/src/threadlistview.cpp +++ b/src/threadlistview.cpp @@ -22,6 +22,9 @@ #include "threadlistmodel.h" #include +#include +#include +#include void ThreadListView::mousePressEvent(QMouseEvent *event) { @@ -53,3 +56,33 @@ void ThreadListView::mousePressEvent(QMouseEvent *event) QTreeView::mousePressEvent(event); } + +void ThreadListView::wheelEvent(QWheelEvent *event) +{ + const int notches = event->angleDelta().y() / QWheelEvent::DefaultDeltasPerStep; + if (!event->pixelDelta().isNull() || event->modifiers() != Qt::NoModifier + || notches == 0) { + // ponytail: a high-resolution wheel sending less than one notch per + // event falls through to the plain per-pixel scroll, unanimated. + QTreeView::wheelEvent(event); + return; + } + + QScrollBar *bar = verticalScrollBar(); + if (!m_glide) { + m_glide = new QPropertyAnimation(bar, "value", this); + m_glide->setDuration(160); + m_glide->setEasingCurve(QEasingCurve::OutCubic); + } + + const bool gliding = m_glide->state() == QAbstractAnimation::Running; + const int from = gliding ? m_glide->endValue().toInt() : bar->value(); + const int to = qBound(bar->minimum(), from - notches * bar->singleStep(), + bar->maximum()); + + m_glide->stop(); + m_glide->setStartValue(bar->value()); + m_glide->setEndValue(to); + m_glide->start(); + event->accept(); +} -- cgit v1.2.3