20#include <QAbstractScrollArea>
24#include <QStyleOptionSlider>
26#include "moc_qgsdecoratedscrollbar.cpp"
35 : QWidget( scrollBarController->scrollArea() )
36 , mHighlightController( scrollBarController )
38 setAttribute( Qt::WA_TransparentForMouseEvents );
39 scrollBar()->parentWidget()->installEventFilter(
this );
42 setVisible( scrollBar()->isVisible() );
45void QgsScrollBarHighlightOverlay::doResize()
47 resize( scrollBar()->size() );
50void QgsScrollBarHighlightOverlay::doMove()
52 move( parentWidget()->mapFromGlobal( scrollBar()->mapToGlobal( scrollBar()->pos() ) ) );
55void QgsScrollBarHighlightOverlay::scheduleUpdate()
57 if ( mIsCacheUpdateScheduled )
60 mIsCacheUpdateScheduled =
true;
62#ifndef __clang_analyzer__
63 QMetaObject::invokeMethod(
this, qOverload<>( &QWidget::update ), Qt::QueuedConnection );
67void QgsScrollBarHighlightOverlay::paintEvent( QPaintEvent *paintEvent )
69 QWidget::paintEvent( paintEvent );
73 if ( mHighlightCache.isEmpty() )
76 QPainter painter(
this );
77 painter.setRenderHint( QPainter::Antialiasing,
false );
79 const QRect &gRect = overlayRect();
80 const QRect &hRect = handleRect();
82 constexpr int marginX = 3;
83 constexpr int marginH = -2 * marginX + 1;
84 const QRect aboveHandleRect = QRect( gRect.x() + marginX, gRect.y(), gRect.width() + marginH, hRect.y() - gRect.y() );
85 const QRect handleRect = QRect( gRect.x() + marginX, hRect.y(), gRect.width() + marginH, hRect.height() );
86 const QRect belowHandleRect = QRect( gRect.x() + marginX, hRect.y() + hRect.height(), gRect.width() + marginH, gRect.height() - hRect.height() + gRect.y() - hRect.y() );
88 const int aboveValue = scrollBar()->value();
89 const int belowValue = scrollBar()->maximum() - scrollBar()->value();
90 const int sizeDocAbove = int( aboveValue * mHighlightController->lineHeight() );
91 const int sizeDocBelow = int( belowValue * mHighlightController->lineHeight() );
92 const int sizeDocVisible = int( mHighlightController->visibleRange() );
94 const int scrollBarBackgroundHeight = aboveHandleRect.height() + belowHandleRect.height();
95 const int sizeDocInvisible = sizeDocAbove + sizeDocBelow;
96 const double backgroundRatio = sizeDocInvisible ? ( ( double ) scrollBarBackgroundHeight / sizeDocInvisible ) : 0;
101 drawHighlights( &painter, 0, sizeDocAbove, backgroundRatio, 0, aboveHandleRect );
108 const double handleVirtualHeight = sizeDocVisible * backgroundRatio;
110 const int offset =
static_cast<int>( std::round( aboveHandleRect.height() + handleVirtualHeight ) );
112 drawHighlights( &painter, sizeDocAbove + sizeDocVisible, sizeDocBelow, backgroundRatio, offset, belowHandleRect );
115 const double handleRatio = sizeDocVisible ? ( ( double ) handleRect.height() / sizeDocVisible ) : 0;
119 const double aboveVirtualHeight = sizeDocAbove * handleRatio;
122 const double accurateHandlePos = sizeDocAbove * backgroundRatio;
124 const double correction = aboveHandleRect.height() - accurateHandlePos;
126 const int offset =
static_cast<int>( std::round( aboveVirtualHeight + correction ) );
128 drawHighlights( &painter, sizeDocAbove, sizeDocVisible, handleRatio, offset, handleRect );
131void QgsScrollBarHighlightOverlay::drawHighlights( QPainter *painter,
int docStart,
int docSize,
double docSizeToHandleSizeRatio,
int handleOffset,
const QRect &viewport )
137 painter->setClipRect( viewport );
139 const double lineHeight = mHighlightController->lineHeight();
141 for (
const QMap<QRgb, QMap<int, int>> &colors : std::as_const( mHighlightCache ) )
143 const auto itColorEnd = colors.constEnd();
144 for (
auto itColor = colors.constBegin(); itColor != itColorEnd; ++itColor )
146 const QColor color = itColor.key();
147 const QMap<int, int> &positions = itColor.value();
148 const auto itPosEnd = positions.constEnd();
149 const auto firstPos = int( docStart / lineHeight );
150 auto itPos = positions.upperBound( firstPos );
151 if ( itPos != positions.constBegin() )
153 while ( itPos != itPosEnd )
155 const double posStart = itPos.key() * lineHeight;
156 const double posEnd = ( itPos.value() + 1 ) * lineHeight;
157 if ( posEnd < docStart )
162 if ( posStart > docStart + docSize )
165 const int height = std::max(
static_cast<int>( std::round( ( posEnd - posStart ) * docSizeToHandleSizeRatio ) ), 1 );
166 const int top =
static_cast<int>( std::round( posStart * docSizeToHandleSizeRatio ) - handleOffset + viewport.y() );
168 const QRect rect( viewport.left(), top, viewport.width(), height );
169 painter->fillRect( rect, color );
177bool QgsScrollBarHighlightOverlay::eventFilter( QObject *
object, QEvent *event )
179 switch ( event->type() )
187 case QEvent::ZOrderChange:
199 return QWidget::eventFilter(
object, event );
202static void insertPosition( QMap<int, int> *map,
int position )
204 auto itNext = map->upperBound( position );
206 bool gluedWithPrev =
false;
207 if ( itNext != map->begin() )
209 auto itPrev = std::prev( itNext );
210 const int keyStart = itPrev.key();
211 const int keyEnd = itPrev.value();
212 if ( position >= keyStart && position <= keyEnd )
215 if ( keyEnd + 1 == position )
219 gluedWithPrev =
true;
223 if ( itNext != map->end() && itNext.key() == position + 1 )
225 const int keyEnd = itNext.value();
226 itNext = map->erase( itNext );
230 auto itPrev = std::prev( itNext );
236 itNext = map->insert( itNext, position, keyEnd );
244 map->insert( position, position );
247void QgsScrollBarHighlightOverlay::updateCache()
249 if ( !mIsCacheUpdateScheduled )
252 mHighlightCache.clear();
254 const QHash<int, QVector<QgsScrollBarHighlight>> highlightsForId = mHighlightController->highlights();
255 for (
const QVector<QgsScrollBarHighlight> &highlights : highlightsForId )
259 QMap<int, int> &highlightMap = mHighlightCache[highlight.priority][highlight.color.rgba()];
260 insertPosition( &highlightMap, highlight.position );
264 mIsCacheUpdateScheduled =
false;
267QRect QgsScrollBarHighlightOverlay::overlayRect()
const
269 QStyleOptionSlider opt = qt_qscrollbarStyleOption( scrollBar() );
270 return scrollBar()->style()->subControlRect( QStyle::CC_ScrollBar, &opt, QStyle::SC_ScrollBarGroove, scrollBar() );
273QRect QgsScrollBarHighlightOverlay::handleRect()
const
275 QStyleOptionSlider opt = qt_qscrollbarStyleOption( scrollBar() );
276 return scrollBar()->style()->subControlRect( QStyle::CC_ScrollBar, &opt, QStyle::SC_ScrollBarSlider, scrollBar() );
308 return mScrollArea->verticalScrollBar();
333 mOverlay =
new QgsScrollBarHighlightOverlay(
this );
334 mOverlay->scheduleUpdate();
340 return std::ceil( mLineHeight );
350 return mVisibleRange;
378 mHighlights[highlight.
category] << highlight;
379 mOverlay->scheduleUpdate();
387 mHighlights.remove( category );
388 mOverlay->scheduleUpdate();
397 mOverlay->scheduleUpdate();