diff --git a/include/app/RackScrollWidget.hpp b/include/app/RackScrollWidget.hpp index 2825852a..bb7569e2 100644 --- a/include/app/RackScrollWidget.hpp +++ b/include/app/RackScrollWidget.hpp @@ -29,6 +29,10 @@ struct RackScrollWidget : ui::ScrollWidget { */ void setZoom(float zoom); void setZoom(float zoom, math::Vec pivot); + /** Sets offset and zoom to fit module bounding box to view. */ + void zoomToModules(); + /** Sets offset and zoom to fit given bound (in module coordinates) to view. */ + void zoomToBound(math::Rect bound); void step() override; void draw(const DrawArgs& args) override; diff --git a/src/app/MenuBar.cpp b/src/app/MenuBar.cpp index 5f3b79f0..8e98bfcf 100644 --- a/src/app/MenuBar.cpp +++ b/src/app/MenuBar.cpp @@ -420,6 +420,14 @@ struct ViewButton : MenuButton { } })); + ZoomSlider* zoomSlider = new ZoomSlider; + zoomSlider->box.size.x = 250.0; + menu->addChild(zoomSlider); + + menu->addChild(createMenuItem("Zoom to fit modules", "F4", [=]() { + APP->scene->rackScroll->zoomToModules(); + })); + menu->addChild(new ui::MenuSeparator); menu->addChild(createMenuLabel("Appearance")); @@ -441,10 +449,6 @@ struct ViewButton : MenuButton { menu->addChild(createBoolPtrMenuItem("Show tooltips", "", &settings::tooltips)); // Various sliders - ZoomSlider* zoomSlider = new ZoomSlider; - zoomSlider->box.size.x = 250.0; - menu->addChild(zoomSlider); - CableOpacitySlider* cableOpacitySlider = new CableOpacitySlider; cableOpacitySlider->box.size.x = 250.0; menu->addChild(cableOpacitySlider); diff --git a/src/app/ModuleWidget.cpp b/src/app/ModuleWidget.cpp index 86e65c2c..1db34dd1 100644 --- a/src/app/ModuleWidget.cpp +++ b/src/app/ModuleWidget.cpp @@ -360,6 +360,10 @@ void ModuleWidget::onHoverKey(const HoverKeyEvent& e) { system::openBrowser(manualUrl); e.consume(this); } + if (e.key == GLFW_KEY_F4 && (e.mods & RACK_MOD_MASK) == RACK_MOD_CTRL) { + APP->scene->rackScroll->zoomToBound(getBox()); + e.consume(this); + } } if (e.isConsumed()) @@ -1111,6 +1115,13 @@ void ModuleWidget::createContextMenu() { weakThis->removeAction(); }, false, true)); + // Zoom to fit + menu->addChild(createMenuItem("Zoom to fit", RACK_MOD_CTRL_NAME "+F4", [=]() { + if (!weakThis) + return; + APP->scene->rackScroll->zoomToBound(weakThis->getBox()); + })); + appendContextMenu(menu); } diff --git a/src/app/RackScrollWidget.cpp b/src/app/RackScrollWidget.cpp index 940465cb..5ee1ed6a 100644 --- a/src/app/RackScrollWidget.cpp +++ b/src/app/RackScrollWidget.cpp @@ -71,6 +71,24 @@ void RackScrollWidget::setZoom(float zoom, math::Vec pivot) { } +void RackScrollWidget::zoomToModules() { + widget::Widget* moduleContainer = rackWidget->getModuleContainer(); + math::Rect bound = moduleContainer->getChildrenBoundingBox(); + zoomToBound(bound); +} + + +void RackScrollWidget::zoomToBound(math::Rect bound) { + if (!bound.pos.isFinite()) + return; + bound = bound.grow(math::Vec(24, 24)); + math::Vec size = getSize(); + float zoom = std::min(size.x / bound.size.x, size.y / bound.size.y); + offset = bound.getCenter() * zoom - size / 2; + zoomWidget->setZoom(zoom); +} + + void RackScrollWidget::step() { float zoom = getZoom(); diff --git a/src/app/Scene.cpp b/src/app/Scene.cpp index 2956f61d..7ba14ee2 100644 --- a/src/app/Scene.cpp +++ b/src/app/Scene.cpp @@ -232,6 +232,10 @@ void Scene::onHoverKey(const HoverKeyEvent& e) { settings::cpuMeter ^= true; e.consume(this); } + if (e.key == GLFW_KEY_F4 && (e.mods & RACK_MOD_MASK) == 0) { + APP->scene->rackScroll->zoomToModules(); + e.consume(this); + } if (e.key == GLFW_KEY_F11 && (e.mods & RACK_MOD_MASK) == 0) { APP->window->setFullScreen(!APP->window->isFullScreen()); // The MenuBar will be hidden when the mouse moves over the RackScrollWidget.