22#include <QAbstractScrollArea>
26#include <QStyleOptionSlider>
28#include "moc_qgsdecoratedscrollbar.cpp"
37 : QWidget( scrollBarController->scrollArea() )
38 , mHighlightController( scrollBarController )
40 setAttribute( Qt::WA_TransparentForMouseEvents );
41 scrollBar()->parentWidget()->installEventFilter(
this );
44 setVisible( scrollBar()->isVisible() );
47void QgsScrollBarHighlightOverlay::doResize()
49 resize( scrollBar()->size() );
52void QgsScrollBarHighlightOverlay::doMove()
54 move( parentWidget()->mapFromGlobal( scrollBar()->mapToGlobal( scrollBar()->pos() ) ) );
57void QgsScrollBarHighlightOverlay::scheduleUpdate()
59 if ( mIsCacheUpdateScheduled )
62 mIsCacheUpdateScheduled =
true;
64#ifndef __clang_analyzer__
65 QMetaObject::invokeMethod(
this, qOverload<>( &QWidget::update ), Qt::QueuedConnection );
69void QgsScrollBarHighlightOverlay::paintEvent( QPaintEvent *paintEvent )
71 QWidget::paintEvent( paintEvent );
75 if ( mHighlightCache.isEmpty() )
78 QPainter painter(
this );
79 painter.setRenderHint( QPainter::Antialiasing,
false );
81 const QRect &gRect = overlayRect();
82 const QRect &hRect = handleRect();
84 constexpr int marginX = 3;
85 constexpr int marginH = -2 * marginX + 1;
86 const QRect aboveHandleRect = QRect( gRect.x() + marginX, gRect.y(), gRect.width() + marginH, hRect.y() - gRect.y() );
87 const QRect handleRect = QRect( gRect.x() + marginX, hRect.y(), gRect.width() + marginH, hRect.height() );
88 const QRect belowHandleRect = QRect( gRect.x() + marginX, hRect.y() + hRect.height(), gRect.width() + marginH, gRect.height() - hRect.height() + gRect.y() - hRect.y() );
90 const int aboveValue = scrollBar()->value();
91 const int belowValue = scrollBar()->maximum() - scrollBar()->value();
92 const int sizeDocAbove = int( aboveValue * mHighlightController->lineHeight() );
93 const int sizeDocBelow = int( belowValue * mHighlightController->lineHeight() );
94 const int sizeDocVisible = int( mHighlightController->visibleRange() );
96 const int scrollBarBackgroundHeight = aboveHandleRect.height() + belowHandleRect.height();
97 const int sizeDocInvisible = sizeDocAbove + sizeDocBelow;
98 const double backgroundRatio = sizeDocInvisible ? ( ( double ) scrollBarBackgroundHeight / sizeDocInvisible ) : 0;
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 ? ( ( double ) handleRect.height() / sizeDocVisible ) : 0;
121 const double aboveVirtualHeight = sizeDocAbove * handleRatio;
124 const double accurateHandlePos = sizeDocAbove * backgroundRatio;
126 const double correction = aboveHandleRect.height() - accurateHandlePos;
128 const int offset =
static_cast<int>( std::round( aboveVirtualHeight + correction ) );
130 drawHighlights( &painter, sizeDocAbove, sizeDocVisible, handleRatio, offset, handleRect );
133void QgsScrollBarHighlightOverlay::drawHighlights( QPainter *painter,
int docStart,
int docSize,
double docSizeToHandleSizeRatio,
int handleOffset,
const QRect &viewport )
139 painter->setClipRect( viewport );
141 const double lineHeight = mHighlightController->lineHeight();
143 for (
const QMap<QRgb, QMap<int, int>> &colors : std::as_const( mHighlightCache ) )
145 const auto itColorEnd = colors.constEnd();
146 for (
auto itColor = colors.constBegin(); itColor != itColorEnd; ++itColor )
148 const QColor color = itColor.key();
149 const QMap<int, int> &positions = itColor.value();
150 const auto itPosEnd = positions.constEnd();
151 const auto firstPos = int( docStart / lineHeight );
152 auto itPos = positions.upperBound( firstPos );
153 if ( itPos != positions.constBegin() )
155 while ( itPos != itPosEnd )
157 const double posStart = itPos.key() * lineHeight;
158 const double posEnd = ( itPos.value() + 1 ) * lineHeight;
159 if ( posEnd < docStart )
164 if ( posStart > docStart + docSize )
167 const int height = std::max(
static_cast<int>( std::round( ( posEnd - posStart ) * docSizeToHandleSizeRatio ) ), 1 );
168 const int top =
static_cast<int>( std::round( posStart * docSizeToHandleSizeRatio ) - handleOffset + viewport.y() );
170 const QRect rect( viewport.left(), top, viewport.width(), height );
171 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() );
309 return mScrollArea->verticalScrollBar();
334 mOverlay =
new QgsScrollBarHighlightOverlay(
this );
335 mOverlay->scheduleUpdate();
341 return std::ceil( mLineHeight );
351 return mVisibleRange;
379 mHighlights[highlight.
category] << highlight;
380 mOverlay->scheduleUpdate();
388 mHighlights.remove( category );
389 mOverlay->scheduleUpdate();
398 mOverlay->scheduleUpdate();
Scoped object for saving and restoring a QPainter object's state.