Krita Source Code Documentation
Loading...
Searching...
No Matches
kis_zoom_scrollbar.cpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2020 Eoin O 'Neill <eoinoneill1991@gmail.com>
3 * SPDX-FileCopyrightText: 2020 Emmet O 'Neill <emmetoneill.pdx@gmail.com>
4 *
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 */
8
9#include "kis_config.h"
10#include "kis_global.h"
11#include "kis_debug.h"
12#include "kis_tool_utils.h"
13#include <QMouseEvent>
14#include <QTabletEvent>
15
17 : QScrollBar(parent)
18 , lastKnownPosition(0,0)
19 , accelerationAccumulator(0,0)
20 , scrollSubPixelAccumulator(0.0f)
21 , zoomThreshold(0.75f)
22 , wheelOverscrollSensitivity(1.0f)
23 , catchTeleportCorrection(false)
24{
25 KisConfig config(true);
27}
28
29KisZoomableScrollBar::KisZoomableScrollBar(Qt::Orientation orientation, QWidget *parent)
30 : KisZoomableScrollBar(parent)
31{
32 setOrientation(orientation);
33}
34
38
40{
41 float barPositionNormalized = (float)(value() - minimum()) / (float)(maximum() + pageStep() - minimum());
42 QPoint barPosition = orientation() == Qt::Horizontal ?
43 QPoint(barPositionNormalized * width() * devicePixelRatio(), 0) :
44 QPoint(0, barPositionNormalized * height() * devicePixelRatio());
45
46 return mapToGlobal(QPoint(0,0)) + barPosition;
47}
48
49bool KisZoomableScrollBar::catchTeleports(QMouseEvent *event) {
52 event->accept();
53 return true;
54 }
55
56 return false;
57}
58
59void KisZoomableScrollBar::handleWrap( const QPoint &accel, const QPoint &mouseCoord)
60{
61 QRect windowRect = window()->geometry();
62 windowRect = kisGrowRect(windowRect, -2);
63 const int windowWidth = windowRect.width();
64 const int windowHeight = windowRect.height();
65 const int windowX = windowRect.x();
66 const int windowY = windowRect.y();
67 const bool xWrap = true;
68 const bool yWrap = true;
69
70 if (!windowRect.contains(mouseCoord)) {
71 int x = mouseCoord.x();
72 int y = mouseCoord.y();
73
74 if (x < windowX && xWrap ) {
75 x += (windowWidth - 2);
76 } else if (x > (windowX + windowWidth) && xWrap ) {
77 x -= (windowWidth - 2);
78 }
79
80 if (y < windowY && yWrap) {
81 y += (windowHeight - 2);
82 } else if (y > (windowY + windowHeight) && yWrap) {
83 y -= (windowHeight - 2);
84 }
85
86 KisToolUtils::setCursorPos(QPoint(x, y));
87 lastKnownPosition = QPoint(x, y) - accel;
88
89 //Important -- teleportation needs to caught to prevent high-acceleration
90 //values from QCursor::setPos being read in this event.
92 }
93}
94
95void KisZoomableScrollBar::handleScroll(const QPoint &accel)
96{
97 const qreal sliderMovementPix = (orientation() == Qt::Horizontal) ? accel.x() * devicePixelRatio() : accel.y() * devicePixelRatio();
98 const qreal zoomMovementPix = (orientation() == Qt::Horizontal) ? -accel.y() : -accel.x();
99 const qreal documentLength = maximum() - minimum() + pageStep();
100 const qreal widgetLength = (orientation() == Qt::Horizontal) ? width() * devicePixelRatio() : height() * devicePixelRatio();
101 const qreal widgetThickness = (orientation() == Qt::Horizontal) ? height() * devicePixelRatio() : width() * devicePixelRatio();
102
103 const QVector2D perpendicularDirection = (orientation() == Qt::Horizontal) ? QVector2D(0, 1) : QVector2D(1, 0);
104 const float perpendicularity = QVector2D::dotProduct(perpendicularDirection.normalized(), accelerationAccumulator.normalized());
105
106 if (zoomEnabled && qAbs(perpendicularity) > zoomThreshold && zoomMovementPix != 0) {
107 zoom(qreal(zoomMovementPix) / qreal(widgetThickness * 2));
108 } else if (sliderMovementPix != 0) {
109 const int currentPosition = sliderPosition();
110 scrollSubPixelAccumulator += (documentLength) * (sliderMovementPix / widgetLength);
111
112 setSliderPosition(currentPosition + scrollSubPixelAccumulator);
113 if (currentPosition + scrollSubPixelAccumulator > maximum() ||
114 currentPosition + scrollSubPixelAccumulator < minimum()) {
116 }
117
120 }
121}
122
123void KisZoomableScrollBar::tabletEvent(QTabletEvent *event) {
124 if ( event->type() == QTabletEvent::TabletMove && isSliderDown() ) {
125 QPoint globalMouseCoord = mapToGlobal(event->pos());
126 QPoint accel = globalMouseCoord - lastKnownPosition;
127 accelerationAccumulator += QVector2D(accel);
128
129 if( accelerationAccumulator.length() > 5) {
131 }
132
133 handleScroll(accel);
134 lastKnownPosition = globalMouseCoord;
135 event->accept();
136 } else {
137 if (event->type() == QTabletEvent::TabletPress) {
138 QPoint globalMouseCoord = mapToGlobal(event->pos());
139 lastKnownPosition = globalMouseCoord;
140 setSliderDown(true);
141 event->accept();
142 } else if(event->type() == QTabletEvent::TabletRelease) {
143 setSliderDown(false);
144 event->accept();
145 } else {
146 QScrollBar::tabletEvent(event);
147 }
148 }
149}
150
152{
153 QScrollBar::mousePressEvent(event);
154
155 lastKnownPosition = mapToGlobal(event->pos());
156 accelerationAccumulator = QVector2D(0,0);
157 QPoint worldPosition = mapToGlobal(event->pos());
158 QPoint barPosition = this->barPosition();
160 setCursor(Qt::BlankCursor);
161}
162
163
165{
166 QPoint globalMouseCoord = mapToGlobal(event->pos());
167
168 QPoint accel = globalMouseCoord - lastKnownPosition;
169 accelerationAccumulator += QVector2D(accel);
170
171 if (catchTeleports(event)) {
172 return;
173 }
174
175 if (accelerationAccumulator.length() > 5) {
177 }
178
179 handleScroll(accel);
180 lastKnownPosition = globalMouseCoord;
181 handleWrap(accel, mapToGlobal(event->pos()));
182 event->accept();
183}
184
186{
187 //If there's nowhere for our slider to go, we should
188 //still Q_EMIT the slider release value.
189 if (maximum() == minimum()) {
190 Q_EMIT sliderReleased();
191 }
192 const QPoint maximumCoordinates = mapToGlobal(QPoint(width() * devicePixelRatio(), height() * devicePixelRatio()));
193 const QPoint minimumCoordinates = mapToGlobal(QPoint(0,0));
194 const QPoint desiredCoordinates = barPosition() + initialPositionRelativeToBar;
195 QPoint cursorPosition = QPoint(
196 qMax(minimumCoordinates.x(), qMin(maximumCoordinates.x(), desiredCoordinates.x())),
197 qMax(minimumCoordinates.y(), qMin(maximumCoordinates.y(), desiredCoordinates.y()))
198 );
199 KisToolUtils::setCursorPos(cursorPosition);
200 setCursor(Qt::ArrowCursor);
201 QScrollBar::mouseReleaseEvent(event);
202}
203
204void KisZoomableScrollBar::wheelEvent(QWheelEvent *event) {
205 const int delta = (event->angleDelta().y() / 8) * singleStep() * -1;
206 const int currentPosition = sliderPosition();
207
208 if (currentPosition + delta > maximum() || currentPosition + delta < minimum()){
210 }
211
212 QScrollBar::wheelEvent(event);
213}
214
219
221{
222 wheelOverscrollSensitivity = sensitivity;
223}
float value(const T *src, size_t ch)
bool scrollbarZoomEnabled(bool defaultValue=false) const
virtual void mouseReleaseEvent(QMouseEvent *event) override
bool catchTeleports(QMouseEvent *event)
void setWheelOverscrollSensitivity(float sensitivity)
void setZoomDeadzone(float value)
KisZoomableScrollBar(QWidget *parent=0)
virtual void mouseMoveEvent(QMouseEvent *event) override
virtual void mousePressEvent(QMouseEvent *event) override
void handleWrap(const QPoint &accel, const QPoint &globalMouseCoord)
void overscroll(qreal delta)
void zoom(qreal delta)
void handleScroll(const QPoint &accel)
virtual void wheelEvent(QWheelEvent *event) override
void tabletEvent(QTabletEvent *event) override
T kisGrowRect(const T &rect, U offset)
Definition kis_global.h:186
void KRITAUI_EXPORT setCursorPos(const QPoint &point)