@@ -12,6 +12,7 @@ struct Settings { | |||||
math::Vec windowSize; | math::Vec windowSize; | ||||
math::Vec windowPos; | math::Vec windowPos; | ||||
float zoom = 1.0; | float zoom = 1.0; | ||||
bool invertZoom = false; | |||||
float cableOpacity = 0.5; | float cableOpacity = 0.5; | ||||
float cableTension = 0.5; | float cableTension = 0.5; | ||||
bool allowCursorLock = true; | bool allowCursorLock = true; | ||||
@@ -93,6 +93,8 @@ void RackScrollWidget::onHoverScroll(const widget::HoverScrollEvent &e) { | |||||
if ((APP->window->getMods() & WINDOW_MOD_MASK) == WINDOW_MOD_CTRL) { | if ((APP->window->getMods() & WINDOW_MOD_MASK) == WINDOW_MOD_CTRL) { | ||||
// Increase zoom | // Increase zoom | ||||
float zoomDelta = e.scrollDelta.y / 50 / 4; | float zoomDelta = e.scrollDelta.y / 50 / 4; | ||||
if (settings.invertZoom) | |||||
zoomDelta *= -1; | |||||
settings.zoom *= std::pow(2, zoomDelta); | settings.zoom *= std::pow(2, zoomDelta); | ||||
settings.zoom = math::clamp(settings.zoom, 0.25f, 2.f); | settings.zoom = math::clamp(settings.zoom, 0.25f, 2.f); | ||||
zoomPos = e.pos; | zoomPos = e.pos; | ||||
@@ -25,6 +25,8 @@ json_t *Settings::toJson() { | |||||
json_object_set_new(rootJ, "zoom", json_real(zoom)); | json_object_set_new(rootJ, "zoom", json_real(zoom)); | ||||
json_object_set_new(rootJ, "invertZoom", json_boolean(invertZoom)); | |||||
json_object_set_new(rootJ, "cableOpacity", json_real(cableOpacity)); | json_object_set_new(rootJ, "cableOpacity", json_real(cableOpacity)); | ||||
json_object_set_new(rootJ, "cableTension", json_real(cableTension)); | json_object_set_new(rootJ, "cableTension", json_real(cableTension)); | ||||
@@ -81,6 +83,10 @@ void Settings::fromJson(json_t *rootJ) { | |||||
if (zoomJ) | if (zoomJ) | ||||
zoom = json_number_value(zoomJ); | zoom = json_number_value(zoomJ); | ||||
json_t *invertZoomJ = json_object_get(rootJ, "invertZoom"); | |||||
if (invertZoomJ) | |||||
invertZoom = json_boolean_value(invertZoomJ); | |||||
json_t *cableOpacityJ = json_object_get(rootJ, "cableOpacity"); | json_t *cableOpacityJ = json_object_get(rootJ, "cableOpacity"); | ||||
if (cableOpacityJ) | if (cableOpacityJ) | ||||
cableOpacity = json_number_value(cableOpacityJ); | cableOpacity = json_number_value(cableOpacityJ); | ||||
@@ -35,6 +35,9 @@ void FramebufferWidget::step() { | |||||
NVGcontext *vg = APP->window->vg; | NVGcontext *vg = APP->window->vg; | ||||
fbScale = scale; | fbScale = scale; | ||||
// Set scale to zero so we must wait for the next draw() call before drawing the framebuffer again. | |||||
// Otherwise, if the zoom level is changed while the FramebufferWidget is off-screen, the next draw() call will be skipped, the `dirty` flag will be true, and the framebuffer will be redrawn, but at the wrong scale, since it was not set in draw(). | |||||
scale = math::Vec(); | |||||
// Get subpixel offset in range [0, 1) | // Get subpixel offset in range [0, 1) | ||||
math::Vec offsetI = offset.floor(); | math::Vec offsetI = offset.floor(); | ||||
fbOffset = offset.minus(offsetI); | fbOffset = offset.minus(offsetI); | ||||