mirror of
https://github.com/qgis/QGIS.git
synced 2025-10-05 00:09:32 -04:00
Port decorated scrollbar widget class from QtCreator
Allows decorating scrollbars with colored highlight bars
This commit is contained in:
parent
09364b1945
commit
e59c0df8a8
9
python/PyQt6/gui/auto_additions/qgsdecoratedscrollbar.py
Normal file
9
python/PyQt6/gui/auto_additions/qgsdecoratedscrollbar.py
Normal file
@ -0,0 +1,9 @@
|
||||
# The following has been generated automatically from src/gui/qgsdecoratedscrollbar.h
|
||||
# monkey patching scoped based enum
|
||||
QgsScrollBarHighlight.Priority.Invalid.__doc__ = "Invalid"
|
||||
QgsScrollBarHighlight.Priority.LowPriority.__doc__ = "Low priority, rendered below all other highlights"
|
||||
QgsScrollBarHighlight.Priority.NormalPriority.__doc__ = "Normal priority"
|
||||
QgsScrollBarHighlight.Priority.HighPriority.__doc__ = "High priority"
|
||||
QgsScrollBarHighlight.Priority.HighestPriority.__doc__ = "Highest priority, rendered above all other highlights"
|
||||
QgsScrollBarHighlight.Priority.__doc__ = "Priority, which dictates how overlapping highlights are rendered\n\n" + '* ``Invalid``: ' + QgsScrollBarHighlight.Priority.Invalid.__doc__ + '\n' + '* ``LowPriority``: ' + QgsScrollBarHighlight.Priority.LowPriority.__doc__ + '\n' + '* ``NormalPriority``: ' + QgsScrollBarHighlight.Priority.NormalPriority.__doc__ + '\n' + '* ``HighPriority``: ' + QgsScrollBarHighlight.Priority.HighPriority.__doc__ + '\n' + '* ``HighestPriority``: ' + QgsScrollBarHighlight.Priority.HighestPriority.__doc__
|
||||
# --
|
153
python/PyQt6/gui/auto_generated/qgsdecoratedscrollbar.sip.in
Normal file
153
python/PyQt6/gui/auto_generated/qgsdecoratedscrollbar.sip.in
Normal file
@ -0,0 +1,153 @@
|
||||
/************************************************************************
|
||||
* This file has been generated automatically from *
|
||||
* *
|
||||
* src/gui/qgsdecoratedscrollbar.h *
|
||||
* *
|
||||
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
|
||||
************************************************************************/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class QgsScrollBarHighlight
|
||||
{
|
||||
%Docstring(signature="appended")
|
||||
Encapsulates the details of a highlight in a scrollbar, used alongside :py:class:`QgsScrollBarHighlightController`.
|
||||
|
||||
.. versionadded:: 3.38
|
||||
%End
|
||||
|
||||
%TypeHeaderCode
|
||||
#include "qgsdecoratedscrollbar.h"
|
||||
%End
|
||||
public:
|
||||
|
||||
enum class Priority /BaseType=IntEnum/
|
||||
{
|
||||
Invalid,
|
||||
LowPriority,
|
||||
NormalPriority,
|
||||
HighPriority,
|
||||
HighestPriority
|
||||
};
|
||||
|
||||
QgsScrollBarHighlight( int category, int position, const QColor &color, QgsScrollBarHighlight::Priority priority = QgsScrollBarHighlight::Priority::NormalPriority );
|
||||
%Docstring
|
||||
Constructor for QgsScrollBarHighlight.
|
||||
%End
|
||||
QgsScrollBarHighlight();
|
||||
|
||||
int category;
|
||||
|
||||
int position;
|
||||
|
||||
QColor color;
|
||||
|
||||
QgsScrollBarHighlight::Priority priority;
|
||||
};
|
||||
|
||||
class QgsScrollBarHighlightController
|
||||
{
|
||||
%Docstring(signature="appended")
|
||||
Adds highlights (colored markers) to a scrollbar.
|
||||
|
||||
.. versionadded:: 3.38
|
||||
%End
|
||||
|
||||
%TypeHeaderCode
|
||||
#include "qgsdecoratedscrollbar.h"
|
||||
%End
|
||||
public:
|
||||
|
||||
QgsScrollBarHighlightController();
|
||||
~QgsScrollBarHighlightController();
|
||||
|
||||
QScrollBar *scrollBar() const;
|
||||
%Docstring
|
||||
Returns the associated scroll bar.
|
||||
%End
|
||||
|
||||
QAbstractScrollArea *scrollArea() const;
|
||||
%Docstring
|
||||
Returns the associated scroll area.
|
||||
|
||||
.. seealso:: :py:func:`setScrollArea`
|
||||
%End
|
||||
|
||||
void setScrollArea( QAbstractScrollArea *scrollArea );
|
||||
%Docstring
|
||||
Sets the associated scroll bar.
|
||||
|
||||
.. seealso:: :py:func:`scrollArea`
|
||||
%End
|
||||
|
||||
double lineHeight() const;
|
||||
%Docstring
|
||||
Returns the line height for text associated with the scroll area.
|
||||
|
||||
.. seealso:: :py:func:`setLineHeight`
|
||||
%End
|
||||
|
||||
void setLineHeight( double height );
|
||||
%Docstring
|
||||
Sets the line ``height`` for text associated with the scroll area.
|
||||
|
||||
.. seealso:: :py:func:`lineHeight`
|
||||
%End
|
||||
|
||||
double visibleRange() const;
|
||||
%Docstring
|
||||
Returns the visible range of the scroll area (i.e. the viewport's height).
|
||||
|
||||
.. seealso:: :py:func:`setVisibleRange`
|
||||
%End
|
||||
|
||||
void setVisibleRange( double visibleRange );
|
||||
%Docstring
|
||||
Sets the visible range of the scroll area (i.e. the viewport's height).
|
||||
|
||||
.. seealso:: :py:func:`visibleRange`
|
||||
%End
|
||||
|
||||
double margin() const;
|
||||
%Docstring
|
||||
Returns the document margins for the associated viewport.
|
||||
|
||||
.. seealso:: :py:func:`setMargin`
|
||||
%End
|
||||
|
||||
void setMargin( double margin );
|
||||
%Docstring
|
||||
Sets the document ``margin`` for the associated viewport.
|
||||
|
||||
.. seealso:: :py:func:`margin`
|
||||
%End
|
||||
|
||||
|
||||
void addHighlight( const QgsScrollBarHighlight &highlight );
|
||||
%Docstring
|
||||
Adds a ``highlight`` to the scrollbar.
|
||||
%End
|
||||
|
||||
void removeHighlights( int category );
|
||||
%Docstring
|
||||
Removes all highlights with matching ``category`` from the scrollbar.
|
||||
%End
|
||||
|
||||
void removeAllHighlights();
|
||||
%Docstring
|
||||
Removes all highlights from the scroll bar.
|
||||
%End
|
||||
|
||||
};
|
||||
|
||||
|
||||
/************************************************************************
|
||||
* This file has been generated automatically from *
|
||||
* *
|
||||
* src/gui/qgsdecoratedscrollbar.h *
|
||||
* *
|
||||
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
|
||||
************************************************************************/
|
@ -46,6 +46,7 @@
|
||||
%Include auto_generated/qgsdataitemguiproviderregistry.sip
|
||||
%Include auto_generated/qgsdatasourceselectdialog.sip
|
||||
%Include auto_generated/qgsdbrelationshipwidget.sip
|
||||
%Include auto_generated/qgsdecoratedscrollbar.sip
|
||||
%Include auto_generated/qgsnewdatabasetablenamewidget.sip
|
||||
%Include auto_generated/qgsdetaileditemdata.sip
|
||||
%Include auto_generated/qgsdetaileditemdelegate.sip
|
||||
|
9
python/gui/auto_additions/qgsdecoratedscrollbar.py
Normal file
9
python/gui/auto_additions/qgsdecoratedscrollbar.py
Normal file
@ -0,0 +1,9 @@
|
||||
# The following has been generated automatically from src/gui/qgsdecoratedscrollbar.h
|
||||
# monkey patching scoped based enum
|
||||
QgsScrollBarHighlight.Priority.Invalid.__doc__ = "Invalid"
|
||||
QgsScrollBarHighlight.Priority.LowPriority.__doc__ = "Low priority, rendered below all other highlights"
|
||||
QgsScrollBarHighlight.Priority.NormalPriority.__doc__ = "Normal priority"
|
||||
QgsScrollBarHighlight.Priority.HighPriority.__doc__ = "High priority"
|
||||
QgsScrollBarHighlight.Priority.HighestPriority.__doc__ = "Highest priority, rendered above all other highlights"
|
||||
QgsScrollBarHighlight.Priority.__doc__ = "Priority, which dictates how overlapping highlights are rendered\n\n" + '* ``Invalid``: ' + QgsScrollBarHighlight.Priority.Invalid.__doc__ + '\n' + '* ``LowPriority``: ' + QgsScrollBarHighlight.Priority.LowPriority.__doc__ + '\n' + '* ``NormalPriority``: ' + QgsScrollBarHighlight.Priority.NormalPriority.__doc__ + '\n' + '* ``HighPriority``: ' + QgsScrollBarHighlight.Priority.HighPriority.__doc__ + '\n' + '* ``HighestPriority``: ' + QgsScrollBarHighlight.Priority.HighestPriority.__doc__
|
||||
# --
|
153
python/gui/auto_generated/qgsdecoratedscrollbar.sip.in
Normal file
153
python/gui/auto_generated/qgsdecoratedscrollbar.sip.in
Normal file
@ -0,0 +1,153 @@
|
||||
/************************************************************************
|
||||
* This file has been generated automatically from *
|
||||
* *
|
||||
* src/gui/qgsdecoratedscrollbar.h *
|
||||
* *
|
||||
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
|
||||
************************************************************************/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class QgsScrollBarHighlight
|
||||
{
|
||||
%Docstring(signature="appended")
|
||||
Encapsulates the details of a highlight in a scrollbar, used alongside :py:class:`QgsScrollBarHighlightController`.
|
||||
|
||||
.. versionadded:: 3.38
|
||||
%End
|
||||
|
||||
%TypeHeaderCode
|
||||
#include "qgsdecoratedscrollbar.h"
|
||||
%End
|
||||
public:
|
||||
|
||||
enum class Priority
|
||||
{
|
||||
Invalid,
|
||||
LowPriority,
|
||||
NormalPriority,
|
||||
HighPriority,
|
||||
HighestPriority
|
||||
};
|
||||
|
||||
QgsScrollBarHighlight( int category, int position, const QColor &color, QgsScrollBarHighlight::Priority priority = QgsScrollBarHighlight::Priority::NormalPriority );
|
||||
%Docstring
|
||||
Constructor for QgsScrollBarHighlight.
|
||||
%End
|
||||
QgsScrollBarHighlight();
|
||||
|
||||
int category;
|
||||
|
||||
int position;
|
||||
|
||||
QColor color;
|
||||
|
||||
QgsScrollBarHighlight::Priority priority;
|
||||
};
|
||||
|
||||
class QgsScrollBarHighlightController
|
||||
{
|
||||
%Docstring(signature="appended")
|
||||
Adds highlights (colored markers) to a scrollbar.
|
||||
|
||||
.. versionadded:: 3.38
|
||||
%End
|
||||
|
||||
%TypeHeaderCode
|
||||
#include "qgsdecoratedscrollbar.h"
|
||||
%End
|
||||
public:
|
||||
|
||||
QgsScrollBarHighlightController();
|
||||
~QgsScrollBarHighlightController();
|
||||
|
||||
QScrollBar *scrollBar() const;
|
||||
%Docstring
|
||||
Returns the associated scroll bar.
|
||||
%End
|
||||
|
||||
QAbstractScrollArea *scrollArea() const;
|
||||
%Docstring
|
||||
Returns the associated scroll area.
|
||||
|
||||
.. seealso:: :py:func:`setScrollArea`
|
||||
%End
|
||||
|
||||
void setScrollArea( QAbstractScrollArea *scrollArea );
|
||||
%Docstring
|
||||
Sets the associated scroll bar.
|
||||
|
||||
.. seealso:: :py:func:`scrollArea`
|
||||
%End
|
||||
|
||||
double lineHeight() const;
|
||||
%Docstring
|
||||
Returns the line height for text associated with the scroll area.
|
||||
|
||||
.. seealso:: :py:func:`setLineHeight`
|
||||
%End
|
||||
|
||||
void setLineHeight( double height );
|
||||
%Docstring
|
||||
Sets the line ``height`` for text associated with the scroll area.
|
||||
|
||||
.. seealso:: :py:func:`lineHeight`
|
||||
%End
|
||||
|
||||
double visibleRange() const;
|
||||
%Docstring
|
||||
Returns the visible range of the scroll area (i.e. the viewport's height).
|
||||
|
||||
.. seealso:: :py:func:`setVisibleRange`
|
||||
%End
|
||||
|
||||
void setVisibleRange( double visibleRange );
|
||||
%Docstring
|
||||
Sets the visible range of the scroll area (i.e. the viewport's height).
|
||||
|
||||
.. seealso:: :py:func:`visibleRange`
|
||||
%End
|
||||
|
||||
double margin() const;
|
||||
%Docstring
|
||||
Returns the document margins for the associated viewport.
|
||||
|
||||
.. seealso:: :py:func:`setMargin`
|
||||
%End
|
||||
|
||||
void setMargin( double margin );
|
||||
%Docstring
|
||||
Sets the document ``margin`` for the associated viewport.
|
||||
|
||||
.. seealso:: :py:func:`margin`
|
||||
%End
|
||||
|
||||
|
||||
void addHighlight( const QgsScrollBarHighlight &highlight );
|
||||
%Docstring
|
||||
Adds a ``highlight`` to the scrollbar.
|
||||
%End
|
||||
|
||||
void removeHighlights( int category );
|
||||
%Docstring
|
||||
Removes all highlights with matching ``category`` from the scrollbar.
|
||||
%End
|
||||
|
||||
void removeAllHighlights();
|
||||
%Docstring
|
||||
Removes all highlights from the scroll bar.
|
||||
%End
|
||||
|
||||
};
|
||||
|
||||
|
||||
/************************************************************************
|
||||
* This file has been generated automatically from *
|
||||
* *
|
||||
* src/gui/qgsdecoratedscrollbar.h *
|
||||
* *
|
||||
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
|
||||
************************************************************************/
|
@ -46,6 +46,7 @@
|
||||
%Include auto_generated/qgsdataitemguiproviderregistry.sip
|
||||
%Include auto_generated/qgsdatasourceselectdialog.sip
|
||||
%Include auto_generated/qgsdbrelationshipwidget.sip
|
||||
%Include auto_generated/qgsdecoratedscrollbar.sip
|
||||
%Include auto_generated/qgsnewdatabasetablenamewidget.sip
|
||||
%Include auto_generated/qgsdetaileditemdata.sip
|
||||
%Include auto_generated/qgsdetaileditemdelegate.sip
|
||||
|
@ -554,6 +554,7 @@ set(QGIS_GUI_SRCS
|
||||
qgsdatasourceselectdialog.cpp
|
||||
qgsdbqueryhistoryprovider.cpp
|
||||
qgsdbrelationshipwidget.cpp
|
||||
qgsdecoratedscrollbar.cpp
|
||||
qgsdetaileditemdata.cpp
|
||||
qgsdetaileditemdelegate.cpp
|
||||
qgsdetaileditemwidget.cpp
|
||||
@ -825,6 +826,7 @@ set(QGIS_GUI_HDRS
|
||||
qgsdatasourceselectdialog.h
|
||||
qgsdbqueryhistoryprovider.h
|
||||
qgsdbrelationshipwidget.h
|
||||
qgsdecoratedscrollbar.h
|
||||
qgsnewdatabasetablenamewidget.h
|
||||
qgsdetaileditemdata.h
|
||||
qgsdetaileditemdelegate.h
|
||||
|
424
src/gui/qgsdecoratedscrollbar.cpp
Normal file
424
src/gui/qgsdecoratedscrollbar.cpp
Normal file
@ -0,0 +1,424 @@
|
||||
/***************************************************************************
|
||||
qgsdecoratedscrollbar.cpp
|
||||
--------------------------------------
|
||||
Date : May 2024
|
||||
Copyright : (C) 2024 by Nyall Dawson
|
||||
Email : nyall dot dawson at gmail dot com
|
||||
***************************************************************************
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#include "qgsdecoratedscrollbar.h"
|
||||
#include <QAbstractScrollArea>
|
||||
#include <QScrollBar>
|
||||
#include <QPainter>
|
||||
#include <QEvent>
|
||||
#include <QStyleOptionSlider>
|
||||
#include <cmath>
|
||||
|
||||
///@cond PRIVATE
|
||||
|
||||
//
|
||||
// QgsScrollBarHighlightOverlay
|
||||
//
|
||||
|
||||
QgsScrollBarHighlightOverlay::QgsScrollBarHighlightOverlay( QgsScrollBarHighlightController *scrollBarController )
|
||||
: QWidget( scrollBarController->scrollArea() )
|
||||
, mHighlightController( scrollBarController )
|
||||
{
|
||||
setAttribute( Qt::WA_TransparentForMouseEvents );
|
||||
scrollBar()->parentWidget()->installEventFilter( this );
|
||||
doResize();
|
||||
doMove();
|
||||
setVisible( scrollBar()->isVisible() );
|
||||
}
|
||||
|
||||
void QgsScrollBarHighlightOverlay::doResize()
|
||||
{
|
||||
resize( scrollBar()->size() );
|
||||
}
|
||||
|
||||
void QgsScrollBarHighlightOverlay::doMove()
|
||||
{
|
||||
move( parentWidget()->mapFromGlobal( scrollBar()->mapToGlobal( scrollBar()->pos() ) ) );
|
||||
}
|
||||
|
||||
void QgsScrollBarHighlightOverlay::scheduleUpdate()
|
||||
{
|
||||
if ( mIsCacheUpdateScheduled )
|
||||
return;
|
||||
|
||||
mIsCacheUpdateScheduled = true;
|
||||
QMetaObject::invokeMethod( this, QOverload<>::of( &QWidget::update ), Qt::QueuedConnection );
|
||||
}
|
||||
|
||||
void QgsScrollBarHighlightOverlay::paintEvent( QPaintEvent *paintEvent )
|
||||
{
|
||||
QWidget::paintEvent( paintEvent );
|
||||
|
||||
updateCache();
|
||||
|
||||
if ( mHighlightCache.isEmpty() )
|
||||
return;
|
||||
|
||||
QPainter painter( this );
|
||||
painter.setRenderHint( QPainter::Antialiasing, false );
|
||||
|
||||
const QRect &gRect = overlayRect();
|
||||
const QRect &hRect = handleRect();
|
||||
|
||||
constexpr int marginX = 3;
|
||||
constexpr int marginH = -2 * marginX + 1;
|
||||
const QRect aboveHandleRect = QRect( gRect.x() + marginX,
|
||||
gRect.y(),
|
||||
gRect.width() + marginH,
|
||||
hRect.y() - gRect.y() );
|
||||
const QRect handleRect = QRect( gRect.x() + marginX,
|
||||
hRect.y(),
|
||||
gRect.width() + marginH,
|
||||
hRect.height() );
|
||||
const QRect belowHandleRect = QRect( gRect.x() + marginX,
|
||||
hRect.y() + hRect.height(),
|
||||
gRect.width() + marginH,
|
||||
gRect.height() - hRect.height() + gRect.y() - hRect.y() );
|
||||
|
||||
const int aboveValue = scrollBar()->value();
|
||||
const int belowValue = scrollBar()->maximum() - scrollBar()->value();
|
||||
const int sizeDocAbove = int( aboveValue * mHighlightController->lineHeight() );
|
||||
const int sizeDocBelow = int( belowValue * mHighlightController->lineHeight() );
|
||||
const int sizeDocVisible = int( mHighlightController->visibleRange() );
|
||||
|
||||
const int scrollBarBackgroundHeight = aboveHandleRect.height() + belowHandleRect.height();
|
||||
const int sizeDocInvisible = sizeDocAbove + sizeDocBelow;
|
||||
const double backgroundRatio = sizeDocInvisible
|
||||
? ( ( double )scrollBarBackgroundHeight / sizeDocInvisible ) : 0;
|
||||
|
||||
|
||||
if ( aboveValue )
|
||||
{
|
||||
drawHighlights( &painter,
|
||||
0,
|
||||
sizeDocAbove,
|
||||
backgroundRatio,
|
||||
0,
|
||||
aboveHandleRect );
|
||||
}
|
||||
|
||||
if ( belowValue )
|
||||
{
|
||||
// This is the hypothetical handle height if the handle would
|
||||
// be stretched using the background ratio.
|
||||
const double handleVirtualHeight = sizeDocVisible * backgroundRatio;
|
||||
// Skip the doc above and visible part.
|
||||
const int offset = qRound( aboveHandleRect.height() + handleVirtualHeight );
|
||||
|
||||
drawHighlights( &painter,
|
||||
sizeDocAbove + sizeDocVisible,
|
||||
sizeDocBelow,
|
||||
backgroundRatio,
|
||||
offset,
|
||||
belowHandleRect );
|
||||
}
|
||||
|
||||
const double handleRatio = sizeDocVisible
|
||||
? ( ( double )handleRect.height() / sizeDocVisible ) : 0;
|
||||
|
||||
// This is the hypothetical handle position if the background would
|
||||
// be stretched using the handle ratio.
|
||||
const double aboveVirtualHeight = sizeDocAbove * handleRatio;
|
||||
|
||||
// This is the accurate handle position (double)
|
||||
const double accurateHandlePos = sizeDocAbove * backgroundRatio;
|
||||
// The correction between handle position (int) and accurate position (double)
|
||||
const double correction = aboveHandleRect.height() - accurateHandlePos;
|
||||
// Skip the doc above and apply correction
|
||||
const int offset = qRound( aboveVirtualHeight + correction );
|
||||
|
||||
drawHighlights( &painter,
|
||||
sizeDocAbove,
|
||||
sizeDocVisible,
|
||||
handleRatio,
|
||||
offset,
|
||||
handleRect );
|
||||
}
|
||||
|
||||
void QgsScrollBarHighlightOverlay::drawHighlights( QPainter *painter,
|
||||
int docStart,
|
||||
int docSize,
|
||||
double docSizeToHandleSizeRatio,
|
||||
int handleOffset,
|
||||
const QRect &viewport )
|
||||
{
|
||||
if ( docSize <= 0 )
|
||||
return;
|
||||
|
||||
painter->save();
|
||||
painter->setClipRect( viewport );
|
||||
|
||||
const double lineHeight = mHighlightController->lineHeight();
|
||||
|
||||
for ( const QMap<QRgb, QMap<int, int>> &colors : std::as_const( mHighlightCache ) )
|
||||
{
|
||||
const auto itColorEnd = colors.constEnd();
|
||||
for ( auto itColor = colors.constBegin(); itColor != itColorEnd; ++itColor )
|
||||
{
|
||||
const QColor color = itColor.key();
|
||||
const QMap<int, int> &positions = itColor.value();
|
||||
const auto itPosEnd = positions.constEnd();
|
||||
const auto firstPos = int( docStart / lineHeight );
|
||||
auto itPos = positions.upperBound( firstPos );
|
||||
if ( itPos != positions.constBegin() )
|
||||
--itPos;
|
||||
while ( itPos != itPosEnd )
|
||||
{
|
||||
const double posStart = itPos.key() * lineHeight;
|
||||
const double posEnd = ( itPos.value() + 1 ) * lineHeight;
|
||||
if ( posEnd < docStart )
|
||||
{
|
||||
++itPos;
|
||||
continue;
|
||||
}
|
||||
if ( posStart > docStart + docSize )
|
||||
break;
|
||||
|
||||
const int height = qMax( qRound( ( posEnd - posStart ) * docSizeToHandleSizeRatio ), 1 );
|
||||
const int top = qRound( posStart * docSizeToHandleSizeRatio ) - handleOffset + viewport.y();
|
||||
|
||||
const QRect rect( viewport.left(), top, viewport.width(), height );
|
||||
painter->fillRect( rect, color );
|
||||
++itPos;
|
||||
}
|
||||
}
|
||||
}
|
||||
painter->restore();
|
||||
}
|
||||
|
||||
bool QgsScrollBarHighlightOverlay::eventFilter( QObject *object, QEvent *event )
|
||||
{
|
||||
switch ( event->type() )
|
||||
{
|
||||
case QEvent::Move:
|
||||
doMove();
|
||||
break;
|
||||
case QEvent::Resize:
|
||||
doResize();
|
||||
break;
|
||||
case QEvent::ZOrderChange:
|
||||
raise();
|
||||
break;
|
||||
case QEvent::Show:
|
||||
show();
|
||||
break;
|
||||
case QEvent::Hide:
|
||||
hide();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return QWidget::eventFilter( object, event );
|
||||
}
|
||||
|
||||
static void insertPosition( QMap<int, int> *map, int position )
|
||||
{
|
||||
auto itNext = map->upperBound( position );
|
||||
|
||||
bool gluedWithPrev = false;
|
||||
if ( itNext != map->begin() )
|
||||
{
|
||||
auto itPrev = std::prev( itNext );
|
||||
const int keyStart = itPrev.key();
|
||||
const int keyEnd = itPrev.value();
|
||||
if ( position >= keyStart && position <= keyEnd )
|
||||
return; // pos is already included
|
||||
|
||||
if ( keyEnd + 1 == position )
|
||||
{
|
||||
// glue with prev
|
||||
( *itPrev )++;
|
||||
gluedWithPrev = true;
|
||||
}
|
||||
}
|
||||
|
||||
if ( itNext != map->end() && itNext.key() == position + 1 )
|
||||
{
|
||||
const int keyEnd = itNext.value();
|
||||
itNext = map->erase( itNext );
|
||||
if ( gluedWithPrev )
|
||||
{
|
||||
// glue with prev and next
|
||||
auto itPrev = std::prev( itNext );
|
||||
*itPrev = keyEnd;
|
||||
}
|
||||
else
|
||||
{
|
||||
// glue with next
|
||||
itNext = map->insert( itNext, position, keyEnd );
|
||||
}
|
||||
return; // glued
|
||||
}
|
||||
|
||||
if ( gluedWithPrev )
|
||||
return; // glued
|
||||
|
||||
map->insert( position, position );
|
||||
}
|
||||
|
||||
void QgsScrollBarHighlightOverlay::updateCache()
|
||||
{
|
||||
if ( !mIsCacheUpdateScheduled )
|
||||
return;
|
||||
|
||||
mHighlightCache.clear();
|
||||
|
||||
const QHash<int, QVector<QgsScrollBarHighlight>> highlightsForId = mHighlightController->highlights();
|
||||
for ( const QVector<QgsScrollBarHighlight> &highlights : highlightsForId )
|
||||
{
|
||||
for ( const QgsScrollBarHighlight &highlight : highlights )
|
||||
{
|
||||
QMap<int, int> &highlightMap = mHighlightCache[highlight.priority][highlight.color.rgba()];
|
||||
insertPosition( &highlightMap, highlight.position );
|
||||
}
|
||||
}
|
||||
|
||||
mIsCacheUpdateScheduled = false;
|
||||
}
|
||||
|
||||
QRect QgsScrollBarHighlightOverlay::overlayRect() const
|
||||
{
|
||||
QStyleOptionSlider opt = qt_qscrollbarStyleOption( scrollBar() );
|
||||
return scrollBar()->style()->subControlRect( QStyle::CC_ScrollBar, &opt, QStyle::SC_ScrollBarGroove, scrollBar() );
|
||||
}
|
||||
|
||||
QRect QgsScrollBarHighlightOverlay::handleRect() const
|
||||
{
|
||||
QStyleOptionSlider opt = qt_qscrollbarStyleOption( scrollBar() );
|
||||
return scrollBar()->style()->subControlRect( QStyle::CC_ScrollBar, &opt, QStyle::SC_ScrollBarSlider, scrollBar() );
|
||||
}
|
||||
|
||||
///@endcond PRIVATE
|
||||
|
||||
//
|
||||
// QgsScrollBarHighlight
|
||||
//
|
||||
|
||||
QgsScrollBarHighlight::QgsScrollBarHighlight( int category, int position,
|
||||
const QColor &color, QgsScrollBarHighlight::Priority priority )
|
||||
: category( category )
|
||||
, position( position )
|
||||
, color( color )
|
||||
, priority( priority )
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// QgsScrollBarHighlightController
|
||||
//
|
||||
|
||||
QgsScrollBarHighlightController::QgsScrollBarHighlightController() = default;
|
||||
|
||||
QgsScrollBarHighlightController::~QgsScrollBarHighlightController()
|
||||
{
|
||||
if ( mOverlay )
|
||||
delete mOverlay;
|
||||
}
|
||||
|
||||
QScrollBar *QgsScrollBarHighlightController::scrollBar() const
|
||||
{
|
||||
if ( mScrollArea )
|
||||
return mScrollArea->verticalScrollBar();
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
QAbstractScrollArea *QgsScrollBarHighlightController::scrollArea() const
|
||||
{
|
||||
return mScrollArea;
|
||||
}
|
||||
|
||||
void QgsScrollBarHighlightController::setScrollArea( QAbstractScrollArea *scrollArea )
|
||||
{
|
||||
if ( mScrollArea == scrollArea )
|
||||
return;
|
||||
|
||||
if ( mOverlay )
|
||||
{
|
||||
delete mOverlay;
|
||||
mOverlay = nullptr;
|
||||
}
|
||||
|
||||
mScrollArea = scrollArea;
|
||||
|
||||
if ( mScrollArea )
|
||||
{
|
||||
mOverlay = new QgsScrollBarHighlightOverlay( this );
|
||||
mOverlay->scheduleUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
double QgsScrollBarHighlightController::lineHeight() const
|
||||
{
|
||||
return std::ceil( mLineHeight );
|
||||
}
|
||||
|
||||
void QgsScrollBarHighlightController::setLineHeight( double lineHeight )
|
||||
{
|
||||
mLineHeight = lineHeight;
|
||||
}
|
||||
|
||||
double QgsScrollBarHighlightController::visibleRange() const
|
||||
{
|
||||
return mVisibleRange;
|
||||
}
|
||||
|
||||
void QgsScrollBarHighlightController::setVisibleRange( double visibleRange )
|
||||
{
|
||||
mVisibleRange = visibleRange;
|
||||
}
|
||||
|
||||
double QgsScrollBarHighlightController::margin() const
|
||||
{
|
||||
return mMargin;
|
||||
}
|
||||
|
||||
void QgsScrollBarHighlightController::setMargin( double margin )
|
||||
{
|
||||
mMargin = margin;
|
||||
}
|
||||
|
||||
QHash<int, QVector<QgsScrollBarHighlight>> QgsScrollBarHighlightController::highlights() const
|
||||
{
|
||||
return mHighlights;
|
||||
}
|
||||
|
||||
void QgsScrollBarHighlightController::addHighlight( const QgsScrollBarHighlight &highlight )
|
||||
{
|
||||
if ( !mOverlay )
|
||||
return;
|
||||
|
||||
mHighlights[highlight.category] << highlight;
|
||||
mOverlay->scheduleUpdate();
|
||||
}
|
||||
|
||||
void QgsScrollBarHighlightController::removeHighlights( int category )
|
||||
{
|
||||
if ( !mOverlay )
|
||||
return;
|
||||
|
||||
mHighlights.remove( category );
|
||||
mOverlay->scheduleUpdate();
|
||||
}
|
||||
|
||||
void QgsScrollBarHighlightController::removeAllHighlights()
|
||||
{
|
||||
if ( !mOverlay )
|
||||
return;
|
||||
|
||||
mHighlights.clear();
|
||||
mOverlay->scheduleUpdate();
|
||||
}
|
215
src/gui/qgsdecoratedscrollbar.h
Normal file
215
src/gui/qgsdecoratedscrollbar.h
Normal file
@ -0,0 +1,215 @@
|
||||
/***************************************************************************
|
||||
qgsdecoratedscrollbar.h
|
||||
--------------------------------------
|
||||
Date : May 2024
|
||||
Copyright : (C) 2024 by Nyall Dawson
|
||||
Email : nyall dot dawson at gmail dot com
|
||||
***************************************************************************
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef QGSDECORATEDSCROLLBAR_H
|
||||
#define QGSDECORATEDSCROLLBAR_H
|
||||
|
||||
#include "qgis_gui.h"
|
||||
#include "qgis_sip.h"
|
||||
|
||||
#include <QColor>
|
||||
#include <QHash>
|
||||
#include <QPointer>
|
||||
#include <QWidget>
|
||||
#include <QMap>
|
||||
|
||||
class QScrollBar;
|
||||
class QAbstractScrollArea;
|
||||
class QgsScrollBarHighlightOverlay;
|
||||
|
||||
// ported from QtCreator's HighlightScrollBarController implementation
|
||||
|
||||
/**
|
||||
* \ingroup gui
|
||||
* \brief Encapsulates the details of a highlight in a scrollbar, used alongside QgsScrollBarHighlightController.
|
||||
* \since QGIS 3.38
|
||||
*/
|
||||
class GUI_EXPORT QgsScrollBarHighlight
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* Priority, which dictates how overlapping highlights are rendered
|
||||
*/
|
||||
enum class Priority : int
|
||||
{
|
||||
Invalid = -1, //!< Invalid
|
||||
LowPriority = 0, //!< Low priority, rendered below all other highlights
|
||||
NormalPriority = 1, //!< Normal priority
|
||||
HighPriority = 2, //!< High priority
|
||||
HighestPriority = 3 //!< Highest priority, rendered above all other highlights
|
||||
};
|
||||
|
||||
/**
|
||||
* Constructor for QgsScrollBarHighlight.
|
||||
*/
|
||||
QgsScrollBarHighlight( int category, int position, const QColor &color, QgsScrollBarHighlight::Priority priority = QgsScrollBarHighlight::Priority::NormalPriority );
|
||||
QgsScrollBarHighlight() = default;
|
||||
|
||||
//! Category ID
|
||||
int category = -1;
|
||||
|
||||
//! Position in scroll bar
|
||||
int position = -1;
|
||||
|
||||
//! Highlight color
|
||||
QColor color;
|
||||
|
||||
//! Priority, which dictates how overlapping highlights are rendered
|
||||
QgsScrollBarHighlight::Priority priority = QgsScrollBarHighlight::Priority::Invalid;
|
||||
};
|
||||
|
||||
/**
|
||||
* \ingroup gui
|
||||
* \brief Adds highlights (colored markers) to a scrollbar.
|
||||
* \since QGIS 3.38
|
||||
*/
|
||||
class GUI_EXPORT QgsScrollBarHighlightController
|
||||
{
|
||||
public:
|
||||
|
||||
QgsScrollBarHighlightController();
|
||||
~QgsScrollBarHighlightController();
|
||||
|
||||
/**
|
||||
* Returns the associated scroll bar.
|
||||
*/
|
||||
QScrollBar *scrollBar() const;
|
||||
|
||||
/**
|
||||
* Returns the associated scroll area.
|
||||
*
|
||||
* \see setScrollArea()
|
||||
*/
|
||||
QAbstractScrollArea *scrollArea() const;
|
||||
|
||||
/**
|
||||
* Sets the associated scroll bar.
|
||||
*
|
||||
* \see scrollArea()
|
||||
*/
|
||||
void setScrollArea( QAbstractScrollArea *scrollArea );
|
||||
|
||||
/**
|
||||
* Returns the line height for text associated with the scroll area.
|
||||
*
|
||||
* \see setLineHeight()
|
||||
*/
|
||||
double lineHeight() const;
|
||||
|
||||
/**
|
||||
* Sets the line \a height for text associated with the scroll area.
|
||||
*
|
||||
* \see lineHeight()
|
||||
*/
|
||||
void setLineHeight( double height );
|
||||
|
||||
/**
|
||||
* Returns the visible range of the scroll area (i.e. the viewport's height).
|
||||
*
|
||||
* \see setVisibleRange()
|
||||
*/
|
||||
double visibleRange() const;
|
||||
|
||||
/**
|
||||
* Sets the visible range of the scroll area (i.e. the viewport's height).
|
||||
*
|
||||
* \see visibleRange()
|
||||
*/
|
||||
void setVisibleRange( double visibleRange );
|
||||
|
||||
/**
|
||||
* Returns the document margins for the associated viewport.
|
||||
*
|
||||
* \see setMargin()
|
||||
*/
|
||||
double margin() const;
|
||||
|
||||
/**
|
||||
* Sets the document \a margin for the associated viewport.
|
||||
*
|
||||
* \see margin()
|
||||
*/
|
||||
void setMargin( double margin );
|
||||
|
||||
/**
|
||||
* Returns the hash of all highlights in the scrollbar, with highlight categories as hash keys.
|
||||
*
|
||||
* \note Not available in Python bindings
|
||||
*/
|
||||
QHash<int, QVector<QgsScrollBarHighlight>> highlights() const SIP_SKIP;
|
||||
|
||||
/**
|
||||
* Adds a \a highlight to the scrollbar.
|
||||
*/
|
||||
void addHighlight( const QgsScrollBarHighlight &highlight );
|
||||
|
||||
/**
|
||||
* Removes all highlights with matching \a category from the scrollbar.
|
||||
*/
|
||||
void removeHighlights( int category );
|
||||
|
||||
/**
|
||||
* Removes all highlights from the scroll bar.
|
||||
*/
|
||||
void removeAllHighlights();
|
||||
|
||||
private:
|
||||
|
||||
QHash<int, QVector<QgsScrollBarHighlight> > mHighlights;
|
||||
double mLineHeight = 0.0;
|
||||
double mVisibleRange = 0.0; // in pixels
|
||||
double mMargin = 0.0; // in pixels
|
||||
QAbstractScrollArea *mScrollArea = nullptr;
|
||||
QPointer<QgsScrollBarHighlightOverlay> mOverlay;
|
||||
};
|
||||
|
||||
///@cond PRIVATE
|
||||
#ifndef SIP_RUN
|
||||
class QgsScrollBarHighlightOverlay : public QWidget
|
||||
{
|
||||
public:
|
||||
QgsScrollBarHighlightOverlay( QgsScrollBarHighlightController *scrollBarController );
|
||||
|
||||
void doResize();
|
||||
void doMove();
|
||||
void scheduleUpdate();
|
||||
|
||||
protected:
|
||||
void paintEvent( QPaintEvent *paintEvent ) override;
|
||||
bool eventFilter( QObject *object, QEvent *event ) override;
|
||||
|
||||
private:
|
||||
void drawHighlights( QPainter *painter,
|
||||
int docStart,
|
||||
int docSize,
|
||||
double docSizeToHandleSizeRatio,
|
||||
int handleOffset,
|
||||
const QRect &viewport );
|
||||
void updateCache();
|
||||
QRect overlayRect() const;
|
||||
QRect handleRect() const;
|
||||
|
||||
// line start to line end
|
||||
QMap<QgsScrollBarHighlight::Priority, QMap<QRgb, QMap<int, int>>> mHighlightCache;
|
||||
|
||||
inline QScrollBar *scrollBar() const { return mHighlightController->scrollBar(); }
|
||||
QgsScrollBarHighlightController *mHighlightController = nullptr;
|
||||
bool mIsCacheUpdateScheduled = true;
|
||||
};
|
||||
#endif
|
||||
///@endcond PRIVATE
|
||||
|
||||
#endif // QGSDECORATEDSCROLLBAR_H
|
Loading…
x
Reference in New Issue
Block a user