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
97 ? ( ( double ) scrollBarBackgroundHeight / sizeDocInvisible )
103 drawHighlights( &painter, 0, sizeDocAbove, backgroundRatio, 0, aboveHandleRect );
110 const double handleVirtualHeight = sizeDocVisible * backgroundRatio;
112 const int offset =
static_cast<int>( std::round( aboveHandleRect.height() + handleVirtualHeight ) );
114 drawHighlights( &painter, sizeDocAbove + sizeDocVisible, sizeDocBelow, backgroundRatio, offset, belowHandleRect );
117 const double handleRatio = sizeDocVisible
118 ? ( ( double ) handleRect.height() / sizeDocVisible )
123 const double aboveVirtualHeight = sizeDocAbove * handleRatio;
126 const double accurateHandlePos = sizeDocAbove * backgroundRatio;
128 const double correction = aboveHandleRect.height() - accurateHandlePos;
130 const int offset =
static_cast<int>( std::round( aboveVirtualHeight + correction ) );
132 drawHighlights( &painter, sizeDocAbove, sizeDocVisible, handleRatio, offset, handleRect );
135void QgsScrollBarHighlightOverlay::drawHighlights( QPainter *painter,
int docStart,
int docSize,
double docSizeToHandleSizeRatio,
int handleOffset,
const QRect &viewport )
141 painter->setClipRect( viewport );
143 const double lineHeight = mHighlightController->lineHeight();
145 for (
const QMap<QRgb, QMap<int, int>> &colors : std::as_const( mHighlightCache ) )
147 const auto itColorEnd = colors.constEnd();
148 for (
auto itColor = colors.constBegin(); itColor != itColorEnd; ++itColor )
150 const QColor color = itColor.key();
151 const QMap<int, int> &positions = itColor.value();
152 const auto itPosEnd = positions.constEnd();
153 const auto firstPos = int( docStart / lineHeight );
154 auto itPos = positions.upperBound( firstPos );
155 if ( itPos != positions.constBegin() )
157 while ( itPos != itPosEnd )
159 const double posStart = itPos.key() * lineHeight;
160 const double posEnd = ( itPos.value() + 1 ) * lineHeight;
161 if ( posEnd < docStart )
166 if ( posStart > docStart + docSize )
169 const int height = std::max(
static_cast<int>( std::round( ( posEnd - posStart ) * docSizeToHandleSizeRatio ) ), 1 );
170 const int top =
static_cast<int>( std::round( posStart * docSizeToHandleSizeRatio ) - handleOffset + viewport.y() );
172 const QRect rect( viewport.left(), top, viewport.width(), height );
173 painter->fillRect( rect, color );
181bool QgsScrollBarHighlightOverlay::eventFilter( QObject *
object, QEvent *event )
183 switch ( event->type() )
191 case QEvent::ZOrderChange:
203 return QWidget::eventFilter(
object, event );
206static void insertPosition( QMap<int, int> *map,
int position )
208 auto itNext = map->upperBound( position );
210 bool gluedWithPrev =
false;
211 if ( itNext != map->begin() )
213 auto itPrev = std::prev( itNext );
214 const int keyStart = itPrev.key();
215 const int keyEnd = itPrev.value();
216 if ( position >= keyStart && position <= keyEnd )
219 if ( keyEnd + 1 == position )
223 gluedWithPrev =
true;
227 if ( itNext != map->end() && itNext.key() == position + 1 )
229 const int keyEnd = itNext.value();
230 itNext = map->erase( itNext );
234 auto itPrev = std::prev( itNext );
240 itNext = map->insert( itNext, position, keyEnd );
248 map->insert( position, position );
251void QgsScrollBarHighlightOverlay::updateCache()
253 if ( !mIsCacheUpdateScheduled )
256 mHighlightCache.clear();
258 const QHash<int, QVector<QgsScrollBarHighlight>> highlightsForId = mHighlightController->highlights();
259 for (
const QVector<QgsScrollBarHighlight> &highlights : highlightsForId )
263 QMap<int, int> &highlightMap = mHighlightCache[highlight.priority][highlight.color.rgba()];
264 insertPosition( &highlightMap, highlight.position );
268 mIsCacheUpdateScheduled =
false;
271QRect QgsScrollBarHighlightOverlay::overlayRect()
const
273 QStyleOptionSlider opt = qt_qscrollbarStyleOption( scrollBar() );
274 return scrollBar()->style()->subControlRect( QStyle::CC_ScrollBar, &opt, QStyle::SC_ScrollBarGroove, scrollBar() );
277QRect QgsScrollBarHighlightOverlay::handleRect()
const
279 QStyleOptionSlider opt = qt_qscrollbarStyleOption( scrollBar() );
280 return scrollBar()->style()->subControlRect( QStyle::CC_ScrollBar, &opt, QStyle::SC_ScrollBarSlider, scrollBar() );
313 return mScrollArea->verticalScrollBar();
338 mOverlay =
new QgsScrollBarHighlightOverlay(
this );
339 mOverlay->scheduleUpdate();
345 return std::ceil( mLineHeight );
355 return mVisibleRange;
383 mHighlights[highlight.
category] << highlight;
384 mOverlay->scheduleUpdate();
392 mHighlights.remove( category );
393 mOverlay->scheduleUpdate();
402 mOverlay->scheduleUpdate();