mirror of
https://github.com/qgis/QGIS.git
synced 2025-10-08 00:05:09 -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/qgsdataitemguiproviderregistry.sip
|
||||||
%Include auto_generated/qgsdatasourceselectdialog.sip
|
%Include auto_generated/qgsdatasourceselectdialog.sip
|
||||||
%Include auto_generated/qgsdbrelationshipwidget.sip
|
%Include auto_generated/qgsdbrelationshipwidget.sip
|
||||||
|
%Include auto_generated/qgsdecoratedscrollbar.sip
|
||||||
%Include auto_generated/qgsnewdatabasetablenamewidget.sip
|
%Include auto_generated/qgsnewdatabasetablenamewidget.sip
|
||||||
%Include auto_generated/qgsdetaileditemdata.sip
|
%Include auto_generated/qgsdetaileditemdata.sip
|
||||||
%Include auto_generated/qgsdetaileditemdelegate.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/qgsdataitemguiproviderregistry.sip
|
||||||
%Include auto_generated/qgsdatasourceselectdialog.sip
|
%Include auto_generated/qgsdatasourceselectdialog.sip
|
||||||
%Include auto_generated/qgsdbrelationshipwidget.sip
|
%Include auto_generated/qgsdbrelationshipwidget.sip
|
||||||
|
%Include auto_generated/qgsdecoratedscrollbar.sip
|
||||||
%Include auto_generated/qgsnewdatabasetablenamewidget.sip
|
%Include auto_generated/qgsnewdatabasetablenamewidget.sip
|
||||||
%Include auto_generated/qgsdetaileditemdata.sip
|
%Include auto_generated/qgsdetaileditemdata.sip
|
||||||
%Include auto_generated/qgsdetaileditemdelegate.sip
|
%Include auto_generated/qgsdetaileditemdelegate.sip
|
||||||
|
@ -554,6 +554,7 @@ set(QGIS_GUI_SRCS
|
|||||||
qgsdatasourceselectdialog.cpp
|
qgsdatasourceselectdialog.cpp
|
||||||
qgsdbqueryhistoryprovider.cpp
|
qgsdbqueryhistoryprovider.cpp
|
||||||
qgsdbrelationshipwidget.cpp
|
qgsdbrelationshipwidget.cpp
|
||||||
|
qgsdecoratedscrollbar.cpp
|
||||||
qgsdetaileditemdata.cpp
|
qgsdetaileditemdata.cpp
|
||||||
qgsdetaileditemdelegate.cpp
|
qgsdetaileditemdelegate.cpp
|
||||||
qgsdetaileditemwidget.cpp
|
qgsdetaileditemwidget.cpp
|
||||||
@ -825,6 +826,7 @@ set(QGIS_GUI_HDRS
|
|||||||
qgsdatasourceselectdialog.h
|
qgsdatasourceselectdialog.h
|
||||||
qgsdbqueryhistoryprovider.h
|
qgsdbqueryhistoryprovider.h
|
||||||
qgsdbrelationshipwidget.h
|
qgsdbrelationshipwidget.h
|
||||||
|
qgsdecoratedscrollbar.h
|
||||||
qgsnewdatabasetablenamewidget.h
|
qgsnewdatabasetablenamewidget.h
|
||||||
qgsdetaileditemdata.h
|
qgsdetaileditemdata.h
|
||||||
qgsdetaileditemdelegate.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