-
Notifications
You must be signed in to change notification settings - Fork 1
/
zoomable_scroll_area.cpp
102 lines (90 loc) · 3.7 KB
/
zoomable_scroll_area.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
#include "navmesh_render_area.hpp"
#include "zoomable_scroll_area.hpp"
#include <QScrollBar>
void ZoomableScrollArea::mouseReleaseEvent(QMouseEvent *event) {
if (!(event->buttons() & Qt::LeftButton)) {
// Left button is no longer down
lastMouseLocalPos_.reset();
}
QScrollArea::mouseReleaseEvent(event);
}
void ZoomableScrollArea::mouseMoveEvent(QMouseEvent *event) {
if (event->buttons() & Qt::LeftButton) {
// Dragging while left clicking
if (dragModeEnabled_) {
// Moving the render area
const auto mouseLocalPos = event->localPos();
if (lastMouseLocalPos_) {
auto xDiff = mouseLocalPos.x() - lastMouseLocalPos_->x();
auto yDiff = mouseLocalPos.y() - lastMouseLocalPos_->y();
verticalScrollBar()->setValue(verticalScrollBar()->value() - yDiff);
horizontalScrollBar()->setValue(horizontalScrollBar()->value() - xDiff);
}
lastMouseLocalPos_ = mouseLocalPos;
event->accept();
return;
}
}
QScrollArea::mouseMoveEvent(event);
}
void ZoomableScrollArea::wheelEvent(QWheelEvent *event) {
/*
* TODO:
* This technically shouldn't be coupled to NavmeshRenderArea.
* Instead, treat the child widget as a generic widget and call resize.
* Within the NavmeshRenderArea, just render based on its overall size.
*/
bool handled = false;
NavmeshRenderAreaBase *renderArea = dynamic_cast<NavmeshRenderAreaBase*>(widget());
if (renderArea != nullptr) {
if (event->modifiers() & Qt::ControlModifier) {
// User is scrolling with the CTRL button held, zoom in/out while maintaining the position under the cursor
// Calculate position of cursor on the widget
auto mousePosWithinWidget = widget()->mapFromParent(event->position());
// Calculate size-independent position of cursor on the widget
double xPercent = mousePosWithinWidget.x() / static_cast<double>(widget()->width());
double yPercent = mousePosWithinWidget.y() / static_cast<double>(widget()->height());
// Zoom the widget
if (event->angleDelta().y() > 0) {
// TODO: Use angle delta?
renderArea->zoomIn(0.2);
} else {
renderArea->zoomOut(0.2);
}
// Scroll to maintain the cursor position
// Calculate the new position of the cursor on the widget
auto newMousePosWithinWidget = widget()->mapFromParent(event->position());
// Calculate the desired position of the cursor on the widget
double desiredXPos = xPercent * widget()->width();
double desiredYPos = yPercent * widget()->height();
// Calculate the offset between current and desired
auto xOffset = desiredXPos - newMousePosWithinWidget.x();
auto yOffset = desiredYPos - newMousePosWithinWidget.y();
auto size = widget()->size();
if (horizontalScrollBar()->maximum() > 0) {
// The scroll bar exists, scroll to maintain the previous cursor position relative to the child widget
const auto newVal = horizontalScrollBar()->value() + xOffset;
// TODO: Dont assume that 1 scroll tick == 1 pixel
horizontalScrollBar()->setValue(newVal);
}
if (verticalScrollBar()->maximum() > 0) {
// The scroll bar exists, scroll to maintain the previous cursor position relative to the child widget
const auto newVal = verticalScrollBar()->value() + yOffset;
// TODO: Dont assume that 1 scroll tick == 1 pixel
verticalScrollBar()->setValue(newVal);
}
handled = true;
}
}
if (handled) {
event->accept();
} else {
QScrollArea::wheelEvent(event);
}
}
QSize ZoomableScrollArea::sizeHint() const {
return {1200,1200};
}
void ZoomableScrollArea::setDragModeEnabled(bool enabled) {
dragModeEnabled_ = enabled;
}