@@ -29,6 +29,10 @@ struct RackScrollWidget : ui::ScrollWidget { | |||||
*/ | */ | ||||
void setZoom(float zoom); | void setZoom(float zoom); | ||||
void setZoom(float zoom, math::Vec pivot); | 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 step() override; | ||||
void draw(const DrawArgs& args) override; | void draw(const DrawArgs& args) override; | ||||
@@ -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(new ui::MenuSeparator); | ||||
menu->addChild(createMenuLabel("Appearance")); | menu->addChild(createMenuLabel("Appearance")); | ||||
@@ -441,10 +449,6 @@ struct ViewButton : MenuButton { | |||||
menu->addChild(createBoolPtrMenuItem("Show tooltips", "", &settings::tooltips)); | menu->addChild(createBoolPtrMenuItem("Show tooltips", "", &settings::tooltips)); | ||||
// Various sliders | // Various sliders | ||||
ZoomSlider* zoomSlider = new ZoomSlider; | |||||
zoomSlider->box.size.x = 250.0; | |||||
menu->addChild(zoomSlider); | |||||
CableOpacitySlider* cableOpacitySlider = new CableOpacitySlider; | CableOpacitySlider* cableOpacitySlider = new CableOpacitySlider; | ||||
cableOpacitySlider->box.size.x = 250.0; | cableOpacitySlider->box.size.x = 250.0; | ||||
menu->addChild(cableOpacitySlider); | menu->addChild(cableOpacitySlider); | ||||
@@ -360,6 +360,10 @@ void ModuleWidget::onHoverKey(const HoverKeyEvent& e) { | |||||
system::openBrowser(manualUrl); | system::openBrowser(manualUrl); | ||||
e.consume(this); | 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()) | if (e.isConsumed()) | ||||
@@ -1111,6 +1115,13 @@ void ModuleWidget::createContextMenu() { | |||||
weakThis->removeAction(); | weakThis->removeAction(); | ||||
}, false, true)); | }, 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); | appendContextMenu(menu); | ||||
} | } | ||||
@@ -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() { | void RackScrollWidget::step() { | ||||
float zoom = getZoom(); | float zoom = getZoom(); | ||||
@@ -232,6 +232,10 @@ void Scene::onHoverKey(const HoverKeyEvent& e) { | |||||
settings::cpuMeter ^= true; | settings::cpuMeter ^= true; | ||||
e.consume(this); | 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) { | if (e.key == GLFW_KEY_F11 && (e.mods & RACK_MOD_MASK) == 0) { | ||||
APP->window->setFullScreen(!APP->window->isFullScreen()); | APP->window->setFullScreen(!APP->window->isFullScreen()); | ||||
// The MenuBar will be hidden when the mouse moves over the RackScrollWidget. | // The MenuBar will be hidden when the mouse moves over the RackScrollWidget. | ||||