summaryrefslogtreecommitdiff
path: root/src/app/RackScrollWidget.cpp
blob: fa9949a8ebea4119caf9bff43a8cd7a9270f37e1 (plain)
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
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
#include "app/RackScrollWidget.hpp"
#include "app/Scene.hpp"
#include "window.hpp"
#include "app.hpp"
#include "settings.hpp"


namespace rack {
namespace app {


RackScrollWidget::RackScrollWidget() {
	zoomWidget = new widget::ZoomWidget;
	container->addChild(zoomWidget);

	rackWidget = new RackWidget;
	rackWidget->box.size = RACK_OFFSET.mult(2);
	zoomWidget->addChild(rackWidget);

	reset();
}

void RackScrollWidget::step() {
	// Clamp zoom
	settings::zoom = math::clamp(settings::zoom, 0.25f, 2.f);
	// Round zoom to nearest percent
	float zoom = std::round(settings::zoom / 0.01) * 0.01;
	if (zoom != zoomWidget->zoom) {
		// Set offset based on zoomPos
		offset = offset.plus(zoomPos).div(zoomWidget->zoom).mult(zoom).minus(zoomPos);
		// Set zoom
		zoomWidget->setZoom(zoom);
	}

	zoomPos = box.size.div(2);

	// Set zoomWidget box to module bounding box
	math::Rect moduleBox = rackWidget->moduleContainer->getChildrenBoundingBox();
	if (!moduleBox.size.isFinite())
		moduleBox = math::Rect(RACK_OFFSET, math::Vec(0, 0));
	zoomWidget->box.pos = moduleBox.pos.mult(zoomWidget->zoom);
	zoomWidget->box.size = moduleBox.size.mult(zoomWidget->zoom);
	// Expand to viewport
	math::Rect viewportBox = box;
	viewportBox.pos = viewportBox.pos.plus(offset);
	zoomWidget->box = zoomWidget->box.expand(viewportBox);
	// Grow a few pixels
	zoomWidget->box = zoomWidget->box.grow(math::Vec(100, 100));
	// Reposition rackWidget
	rackWidget->box.pos = zoomWidget->box.pos.div(zoomWidget->zoom).neg();

	// Scroll rack if dragging cable near the edge of the screen
	math::Vec pos = APP->window->mousePos;
	math::Rect viewport = getViewport(box.zeroPos());
	if (rackWidget->incompleteCable) {
		float margin = 20.0;
		float speed = 15.0;
		if (pos.x <= viewport.pos.x + margin)
			offset.x -= speed;
		if (pos.x >= viewport.pos.x + viewport.size.x - margin)
			offset.x += speed;
		if (pos.y <= viewport.pos.y + margin)
			offset.y -= speed;
		if (pos.y >= viewport.pos.y + viewport.size.y - margin)
			offset.y += speed;
	}

	ScrollWidget::step();
}


void RackScrollWidget::draw(const DrawArgs &args) {
	// DEBUG("%f %f %f %f", RECT_ARGS(args.clipBox));
	ScrollWidget::draw(args);
}

void RackScrollWidget::onHover(const event::Hover &e) {
	if (!APP->event->selectedWidget) {
		// Scroll with arrow keys
		float arrowSpeed = 30.0;
		if ((APP->window->getMods() & WINDOW_MOD_MASK) == (WINDOW_MOD_CTRL |GLFW_MOD_SHIFT))
			arrowSpeed /= 16.0;
		else if ((APP->window->getMods() & WINDOW_MOD_MASK) == WINDOW_MOD_CTRL)
			arrowSpeed *= 4.0;
		else if ((APP->window->getMods() & WINDOW_MOD_MASK) == GLFW_MOD_SHIFT)
			arrowSpeed /= 4.0;

		if (glfwGetKey(APP->window->win, GLFW_KEY_LEFT) == GLFW_PRESS)
			offset.x -= arrowSpeed;
		if (glfwGetKey(APP->window->win, GLFW_KEY_RIGHT) == GLFW_PRESS)
			offset.x += arrowSpeed;
		if (glfwGetKey(APP->window->win, GLFW_KEY_UP) == GLFW_PRESS)
			offset.y -= arrowSpeed;
		if (glfwGetKey(APP->window->win, GLFW_KEY_DOWN) == GLFW_PRESS)
			offset.y += arrowSpeed;
	}

	ScrollWidget::onHover(e);
}

void RackScrollWidget::onHoverScroll(const event::HoverScroll &e) {
	if ((APP->window->getMods() & WINDOW_MOD_MASK) == WINDOW_MOD_CTRL) {
		// Increase zoom
		float zoomDelta = e.scrollDelta.y / 50 / 4;
		if (settings::invertZoom)
			zoomDelta *= -1;
		settings::zoom *= std::pow(2, zoomDelta);
		zoomPos = e.pos;
		e.consume(this);
		return;
	}

	ScrollWidget::onHoverScroll(e);
}

void RackScrollWidget::reset() {
	offset = RACK_OFFSET.mult(zoomWidget->zoom);
	offset = offset.minus(math::Vec(30, 30));
}


} // namespace app
} // namespace rack