17#include "moc_qgsdecoratedscrollbar.cpp"
18#include <QAbstractScrollArea>
22#include <QStyleOptionSlider>
32 : QWidget( scrollBarController->scrollArea() )
33 , mHighlightController( scrollBarController )
35 setAttribute( Qt::WA_TransparentForMouseEvents );
36 scrollBar()->parentWidget()->installEventFilter(
this );
39 setVisible( scrollBar()->isVisible() );
42void QgsScrollBarHighlightOverlay::doResize()
44 resize( scrollBar()->size() );
47void QgsScrollBarHighlightOverlay::doMove()
49 move( parentWidget()->mapFromGlobal( scrollBar()->mapToGlobal( scrollBar()->pos() ) ) );
52void QgsScrollBarHighlightOverlay::scheduleUpdate()
54 if ( mIsCacheUpdateScheduled )
57 mIsCacheUpdateScheduled =
true;
59#ifndef __clang_analyzer__
60 QMetaObject::invokeMethod(
this, qOverload<>( &QWidget::update ), Qt::QueuedConnection );
64void QgsScrollBarHighlightOverlay::paintEvent( QPaintEvent *paintEvent )
66 QWidget::paintEvent( paintEvent );
70 if ( mHighlightCache.isEmpty() )
73 QPainter painter(
this );
74 painter.setRenderHint( QPainter::Antialiasing,
false );
76 const QRect &gRect = overlayRect();
77 const QRect &hRect = handleRect();
79 constexpr int marginX = 3;
80 constexpr int marginH = -2 * marginX + 1;
81 const QRect aboveHandleRect = QRect( gRect.x() + marginX,
83 gRect.width() + marginH,
84 hRect.y() - gRect.y() );
85 const QRect handleRect = QRect( gRect.x() + marginX,
87 gRect.width() + marginH,
89 const QRect belowHandleRect = QRect( gRect.x() + marginX,
90 hRect.y() + hRect.height(),
91 gRect.width() + marginH,
92 gRect.height() - hRect.height() + gRect.y() - hRect.y() );
94 const int aboveValue = scrollBar()->value();
95 const int belowValue = scrollBar()->maximum() - scrollBar()->value();
96 const int sizeDocAbove = int( aboveValue * mHighlightController->lineHeight() );
97 const int sizeDocBelow = int( belowValue * mHighlightController->lineHeight() );
98 const int sizeDocVisible = int( mHighlightController->visibleRange() );
100 const int scrollBarBackgroundHeight = aboveHandleRect.height() + belowHandleRect.height();
101 const int sizeDocInvisible = sizeDocAbove + sizeDocBelow;
102 const double backgroundRatio = sizeDocInvisible
103 ? ( ( double )scrollBarBackgroundHeight / sizeDocInvisible ) : 0;
108 drawHighlights( &painter,
120 const double handleVirtualHeight = sizeDocVisible * backgroundRatio;
122 const int offset =
static_cast< int >( std::round( aboveHandleRect.height() + handleVirtualHeight ) );
124 drawHighlights( &painter,
125 sizeDocAbove + sizeDocVisible,
132 const double handleRatio = sizeDocVisible
133 ? ( ( double )handleRect.height() / sizeDocVisible ) : 0;
137 const double aboveVirtualHeight = sizeDocAbove * handleRatio;
140 const double accurateHandlePos = sizeDocAbove * backgroundRatio;
142 const double correction = aboveHandleRect.height() - accurateHandlePos;
144 const int offset =
static_cast< int >( std::round( aboveVirtualHeight + correction ) );
146 drawHighlights( &painter,
154void QgsScrollBarHighlightOverlay::drawHighlights( QPainter *painter,
157 double docSizeToHandleSizeRatio,
159 const QRect &viewport )
165 painter->setClipRect( viewport );
167 const double lineHeight = mHighlightController->lineHeight();
169 for (
const QMap<QRgb, QMap<int, int>> &colors : std::as_const( mHighlightCache ) )
171 const auto itColorEnd = colors.constEnd();
172 for (
auto itColor = colors.constBegin(); itColor != itColorEnd; ++itColor )
174 const QColor color = itColor.key();
175 const QMap<int, int> &positions = itColor.value();
176 const auto itPosEnd = positions.constEnd();
177 const auto firstPos = int( docStart / lineHeight );
178 auto itPos = positions.upperBound( firstPos );
179 if ( itPos != positions.constBegin() )
181 while ( itPos != itPosEnd )
183 const double posStart = itPos.key() * lineHeight;
184 const double posEnd = ( itPos.value() + 1 ) * lineHeight;
185 if ( posEnd < docStart )
190 if ( posStart > docStart + docSize )
193 const int height = std::max(
static_cast< int >( std::round( ( posEnd - posStart ) * docSizeToHandleSizeRatio ) ), 1 );
194 const int top =
static_cast< int >( std::round( posStart * docSizeToHandleSizeRatio ) - handleOffset + viewport.y() );
196 const QRect rect( viewport.left(), top, viewport.width(), height );
197 painter->fillRect( rect, color );
205bool QgsScrollBarHighlightOverlay::eventFilter( QObject *
object, QEvent *event )
207 switch ( event->type() )
215 case QEvent::ZOrderChange:
227 return QWidget::eventFilter(
object, event );
230static void insertPosition( QMap<int, int> *map,
int position )
232 auto itNext = map->upperBound( position );
234 bool gluedWithPrev =
false;
235 if ( itNext != map->begin() )
237 auto itPrev = std::prev( itNext );
238 const int keyStart = itPrev.key();
239 const int keyEnd = itPrev.value();
240 if ( position >= keyStart && position <= keyEnd )
243 if ( keyEnd + 1 == position )
247 gluedWithPrev =
true;
251 if ( itNext != map->end() && itNext.key() == position + 1 )
253 const int keyEnd = itNext.value();
254 itNext = map->erase( itNext );
258 auto itPrev = std::prev( itNext );
264 itNext = map->insert( itNext, position, keyEnd );
272 map->insert( position, position );
275void QgsScrollBarHighlightOverlay::updateCache()
277 if ( !mIsCacheUpdateScheduled )
280 mHighlightCache.clear();
282 const QHash<int, QVector<QgsScrollBarHighlight>> highlightsForId = mHighlightController->highlights();
283 for (
const QVector<QgsScrollBarHighlight> &highlights : highlightsForId )
287 QMap<int, int> &highlightMap = mHighlightCache[highlight.priority][highlight.color.rgba()];
288 insertPosition( &highlightMap, highlight.position );
292 mIsCacheUpdateScheduled =
false;
295QRect QgsScrollBarHighlightOverlay::overlayRect()
const
297 QStyleOptionSlider opt = qt_qscrollbarStyleOption( scrollBar() );
298 return scrollBar()->style()->subControlRect( QStyle::CC_ScrollBar, &opt, QStyle::SC_ScrollBarGroove, scrollBar() );
301QRect QgsScrollBarHighlightOverlay::handleRect()
const
303 QStyleOptionSlider opt = qt_qscrollbarStyleOption( scrollBar() );
304 return scrollBar()->style()->subControlRect( QStyle::CC_ScrollBar, &opt, QStyle::SC_ScrollBarSlider, scrollBar() );
315 : category( category )
316 , position( position )
318 , priority( priority )
338 return mScrollArea->verticalScrollBar();
363 mOverlay =
new QgsScrollBarHighlightOverlay(
this );
364 mOverlay->scheduleUpdate();
370 return std::ceil( mLineHeight );
380 return mVisibleRange;
408 mHighlights[highlight.
category] << highlight;
409 mOverlay->scheduleUpdate();
417 mHighlights.remove( category );
418 mOverlay->scheduleUpdate();
427 mOverlay->scheduleUpdate();