17#include <QAbstractScrollArea>
21#include <QStyleOptionSlider>
31 : QWidget( scrollBarController->scrollArea() )
32 , mHighlightController( scrollBarController )
34 setAttribute( Qt::WA_TransparentForMouseEvents );
35 scrollBar()->parentWidget()->installEventFilter(
this );
38 setVisible( scrollBar()->isVisible() );
41void QgsScrollBarHighlightOverlay::doResize()
43 resize( scrollBar()->size() );
46void QgsScrollBarHighlightOverlay::doMove()
48 move( parentWidget()->mapFromGlobal( scrollBar()->mapToGlobal( scrollBar()->pos() ) ) );
51void QgsScrollBarHighlightOverlay::scheduleUpdate()
53 if ( mIsCacheUpdateScheduled )
56 mIsCacheUpdateScheduled =
true;
58#ifndef __clang_analyzer__
59 QMetaObject::invokeMethod(
this, qOverload<>( &QWidget::update ), Qt::QueuedConnection );
63void QgsScrollBarHighlightOverlay::paintEvent( QPaintEvent *paintEvent )
65 QWidget::paintEvent( paintEvent );
69 if ( mHighlightCache.isEmpty() )
72 QPainter painter(
this );
73 painter.setRenderHint( QPainter::Antialiasing,
false );
75 const QRect &gRect = overlayRect();
76 const QRect &hRect = handleRect();
78 constexpr int marginX = 3;
79 constexpr int marginH = -2 * marginX + 1;
80 const QRect aboveHandleRect = QRect( gRect.x() + marginX,
82 gRect.width() + marginH,
83 hRect.y() - gRect.y() );
84 const QRect handleRect = QRect( gRect.x() + marginX,
86 gRect.width() + marginH,
88 const QRect belowHandleRect = QRect( gRect.x() + marginX,
89 hRect.y() + hRect.height(),
90 gRect.width() + marginH,
91 gRect.height() - hRect.height() + gRect.y() - hRect.y() );
93 const int aboveValue = scrollBar()->value();
94 const int belowValue = scrollBar()->maximum() - scrollBar()->value();
95 const int sizeDocAbove = int( aboveValue * mHighlightController->lineHeight() );
96 const int sizeDocBelow = int( belowValue * mHighlightController->lineHeight() );
97 const int sizeDocVisible = int( mHighlightController->visibleRange() );
99 const int scrollBarBackgroundHeight = aboveHandleRect.height() + belowHandleRect.height();
100 const int sizeDocInvisible = sizeDocAbove + sizeDocBelow;
101 const double backgroundRatio = sizeDocInvisible
102 ? ( ( double )scrollBarBackgroundHeight / sizeDocInvisible ) : 0;
107 drawHighlights( &painter,
119 const double handleVirtualHeight = sizeDocVisible * backgroundRatio;
121 const int offset =
static_cast< int >( std::round( aboveHandleRect.height() + handleVirtualHeight ) );
123 drawHighlights( &painter,
124 sizeDocAbove + sizeDocVisible,
131 const double handleRatio = sizeDocVisible
132 ? ( ( double )handleRect.height() / sizeDocVisible ) : 0;
136 const double aboveVirtualHeight = sizeDocAbove * handleRatio;
139 const double accurateHandlePos = sizeDocAbove * backgroundRatio;
141 const double correction = aboveHandleRect.height() - accurateHandlePos;
143 const int offset =
static_cast< int >( std::round( aboveVirtualHeight + correction ) );
145 drawHighlights( &painter,
153void QgsScrollBarHighlightOverlay::drawHighlights( QPainter *painter,
156 double docSizeToHandleSizeRatio,
158 const QRect &viewport )
164 painter->setClipRect( viewport );
166 const double lineHeight = mHighlightController->lineHeight();
168 for (
const QMap<QRgb, QMap<int, int>> &colors : std::as_const( mHighlightCache ) )
170 const auto itColorEnd = colors.constEnd();
171 for (
auto itColor = colors.constBegin(); itColor != itColorEnd; ++itColor )
173 const QColor color = itColor.key();
174 const QMap<int, int> &positions = itColor.value();
175 const auto itPosEnd = positions.constEnd();
176 const auto firstPos = int( docStart / lineHeight );
177 auto itPos = positions.upperBound( firstPos );
178 if ( itPos != positions.constBegin() )
180 while ( itPos != itPosEnd )
182 const double posStart = itPos.key() * lineHeight;
183 const double posEnd = ( itPos.value() + 1 ) * lineHeight;
184 if ( posEnd < docStart )
189 if ( posStart > docStart + docSize )
192 const int height = std::max(
static_cast< int >( std::round( ( posEnd - posStart ) * docSizeToHandleSizeRatio ) ), 1 );
193 const int top =
static_cast< int >( std::round( posStart * docSizeToHandleSizeRatio ) - handleOffset + viewport.y() );
195 const QRect rect( viewport.left(), top, viewport.width(), height );
196 painter->fillRect( rect, color );
204bool QgsScrollBarHighlightOverlay::eventFilter( QObject *
object, QEvent *event )
206 switch ( event->type() )
214 case QEvent::ZOrderChange:
226 return QWidget::eventFilter(
object, event );
229static void insertPosition( QMap<int, int> *map,
int position )
231 auto itNext = map->upperBound( position );
233 bool gluedWithPrev =
false;
234 if ( itNext != map->begin() )
236 auto itPrev = std::prev( itNext );
237 const int keyStart = itPrev.key();
238 const int keyEnd = itPrev.value();
239 if ( position >= keyStart && position <= keyEnd )
242 if ( keyEnd + 1 == position )
246 gluedWithPrev =
true;
250 if ( itNext != map->end() && itNext.key() == position + 1 )
252 const int keyEnd = itNext.value();
253 itNext = map->erase( itNext );
257 auto itPrev = std::prev( itNext );
263 itNext = map->insert( itNext, position, keyEnd );
271 map->insert( position, position );
274void QgsScrollBarHighlightOverlay::updateCache()
276 if ( !mIsCacheUpdateScheduled )
279 mHighlightCache.clear();
281 const QHash<int, QVector<QgsScrollBarHighlight>> highlightsForId = mHighlightController->highlights();
282 for (
const QVector<QgsScrollBarHighlight> &highlights : highlightsForId )
286 QMap<int, int> &highlightMap = mHighlightCache[highlight.priority][highlight.color.rgba()];
287 insertPosition( &highlightMap, highlight.position );
291 mIsCacheUpdateScheduled =
false;
294QRect QgsScrollBarHighlightOverlay::overlayRect()
const
296 QStyleOptionSlider opt = qt_qscrollbarStyleOption( scrollBar() );
297 return scrollBar()->style()->subControlRect( QStyle::CC_ScrollBar, &opt, QStyle::SC_ScrollBarGroove, scrollBar() );
300QRect QgsScrollBarHighlightOverlay::handleRect()
const
302 QStyleOptionSlider opt = qt_qscrollbarStyleOption( scrollBar() );
303 return scrollBar()->style()->subControlRect( QStyle::CC_ScrollBar, &opt, QStyle::SC_ScrollBarSlider, scrollBar() );
314 : category( category )
315 , position( position )
317 , priority( priority )
337 return mScrollArea->verticalScrollBar();
362 mOverlay =
new QgsScrollBarHighlightOverlay(
this );
363 mOverlay->scheduleUpdate();
369 return std::ceil( mLineHeight );
379 return mVisibleRange;
407 mHighlights[highlight.
category] << highlight;
408 mOverlay->scheduleUpdate();
416 mHighlights.remove( category );
417 mOverlay->scheduleUpdate();
426 mOverlay->scheduleUpdate();