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, gRect.y(), gRect.width() + marginH, hRect.y() - gRect.y() );
82 const QRect handleRect = QRect( gRect.x() + marginX, hRect.y(), gRect.width() + marginH, hRect.height() );
83 const QRect belowHandleRect = QRect( gRect.x() + marginX, hRect.y() + hRect.height(), gRect.width() + marginH, gRect.height() - hRect.height() + gRect.y() - hRect.y() );
85 const int aboveValue = scrollBar()->value();
86 const int belowValue = scrollBar()->maximum() - scrollBar()->value();
87 const int sizeDocAbove = int( aboveValue * mHighlightController->lineHeight() );
88 const int sizeDocBelow = int( belowValue * mHighlightController->lineHeight() );
89 const int sizeDocVisible = int( mHighlightController->visibleRange() );
91 const int scrollBarBackgroundHeight = aboveHandleRect.height() + belowHandleRect.height();
92 const int sizeDocInvisible = sizeDocAbove + sizeDocBelow;
93 const double backgroundRatio = sizeDocInvisible
94 ? ( ( double ) scrollBarBackgroundHeight / sizeDocInvisible )
100 drawHighlights( &painter, 0, sizeDocAbove, backgroundRatio, 0, aboveHandleRect );
107 const double handleVirtualHeight = sizeDocVisible * backgroundRatio;
109 const int offset =
static_cast<int>( std::round( aboveHandleRect.height() + handleVirtualHeight ) );
111 drawHighlights( &painter, sizeDocAbove + sizeDocVisible, sizeDocBelow, backgroundRatio, offset, belowHandleRect );
114 const double handleRatio = sizeDocVisible
115 ? ( ( double ) handleRect.height() / sizeDocVisible )
120 const double aboveVirtualHeight = sizeDocAbove * handleRatio;
123 const double accurateHandlePos = sizeDocAbove * backgroundRatio;
125 const double correction = aboveHandleRect.height() - accurateHandlePos;
127 const int offset =
static_cast<int>( std::round( aboveVirtualHeight + correction ) );
129 drawHighlights( &painter, sizeDocAbove, sizeDocVisible, handleRatio, offset, handleRect );
132void QgsScrollBarHighlightOverlay::drawHighlights( QPainter *painter,
int docStart,
int docSize,
double docSizeToHandleSizeRatio,
int handleOffset,
const QRect &viewport )
138 painter->setClipRect( viewport );
140 const double lineHeight = mHighlightController->lineHeight();
142 for (
const QMap<QRgb, QMap<int, int>> &colors : std::as_const( mHighlightCache ) )
144 const auto itColorEnd = colors.constEnd();
145 for (
auto itColor = colors.constBegin(); itColor != itColorEnd; ++itColor )
147 const QColor color = itColor.key();
148 const QMap<int, int> &positions = itColor.value();
149 const auto itPosEnd = positions.constEnd();
150 const auto firstPos = int( docStart / lineHeight );
151 auto itPos = positions.upperBound( firstPos );
152 if ( itPos != positions.constBegin() )
154 while ( itPos != itPosEnd )
156 const double posStart = itPos.key() * lineHeight;
157 const double posEnd = ( itPos.value() + 1 ) * lineHeight;
158 if ( posEnd < docStart )
163 if ( posStart > docStart + docSize )
166 const int height = std::max(
static_cast<int>( std::round( ( posEnd - posStart ) * docSizeToHandleSizeRatio ) ), 1 );
167 const int top =
static_cast<int>( std::round( posStart * docSizeToHandleSizeRatio ) - handleOffset + viewport.y() );
169 const QRect rect( viewport.left(), top, viewport.width(), height );
170 painter->fillRect( rect, color );
178bool QgsScrollBarHighlightOverlay::eventFilter( QObject *
object, QEvent *event )
180 switch ( event->type() )
188 case QEvent::ZOrderChange:
200 return QWidget::eventFilter(
object, event );
203static void insertPosition( QMap<int, int> *map,
int position )
205 auto itNext = map->upperBound( position );
207 bool gluedWithPrev =
false;
208 if ( itNext != map->begin() )
210 auto itPrev = std::prev( itNext );
211 const int keyStart = itPrev.key();
212 const int keyEnd = itPrev.value();
213 if ( position >= keyStart && position <= keyEnd )
216 if ( keyEnd + 1 == position )
220 gluedWithPrev =
true;
224 if ( itNext != map->end() && itNext.key() == position + 1 )
226 const int keyEnd = itNext.value();
227 itNext = map->erase( itNext );
231 auto itPrev = std::prev( itNext );
237 itNext = map->insert( itNext, position, keyEnd );
245 map->insert( position, position );
248void QgsScrollBarHighlightOverlay::updateCache()
250 if ( !mIsCacheUpdateScheduled )
253 mHighlightCache.clear();
255 const QHash<int, QVector<QgsScrollBarHighlight>> highlightsForId = mHighlightController->highlights();
256 for (
const QVector<QgsScrollBarHighlight> &highlights : highlightsForId )
260 QMap<int, int> &highlightMap = mHighlightCache[highlight.priority][highlight.color.rgba()];
261 insertPosition( &highlightMap, highlight.position );
265 mIsCacheUpdateScheduled =
false;
268QRect QgsScrollBarHighlightOverlay::overlayRect()
const
270 QStyleOptionSlider opt = qt_qscrollbarStyleOption( scrollBar() );
271 return scrollBar()->style()->subControlRect( QStyle::CC_ScrollBar, &opt, QStyle::SC_ScrollBarGroove, scrollBar() );
274QRect QgsScrollBarHighlightOverlay::handleRect()
const
276 QStyleOptionSlider opt = qt_qscrollbarStyleOption( scrollBar() );
277 return scrollBar()->style()->subControlRect( QStyle::CC_ScrollBar, &opt, QStyle::SC_ScrollBarSlider, scrollBar() );
287 : category( category )
288 , position( position )
290 , priority( priority )
310 return mScrollArea->verticalScrollBar();
335 mOverlay =
new QgsScrollBarHighlightOverlay(
this );
336 mOverlay->scheduleUpdate();
342 return std::ceil( mLineHeight );
352 return mVisibleRange;
380 mHighlights[highlight.
category] << highlight;
381 mOverlay->scheduleUpdate();
389 mHighlights.remove( category );
390 mOverlay->scheduleUpdate();
399 mOverlay->scheduleUpdate();