diff --git a/include/app.hpp b/include/app.hpp index 1e63ac83..21a3bdc0 100644 --- a/include/app.hpp +++ b/include/app.hpp @@ -164,7 +164,7 @@ struct CircularShadow : TransparentWidget { void draw(NVGcontext *vg) override; }; -struct Light : TransparentWidget { +struct LightWidget : TransparentWidget { NVGcolor bgColor = nvgRGBf(0, 0, 0); NVGcolor color = nvgRGBf(1, 1, 1); void draw(NVGcontext *vg) override; @@ -327,6 +327,10 @@ struct PluginManagerWidget : Widget { void step() override; }; +struct RackScrollWidget : ScrollWidget { + void step() override; +}; + struct RackScene : Scene { ScrollWidget *scrollWidget; ZoomWidget *zoomWidget; diff --git a/include/components.hpp b/include/components.hpp index a9b02a22..38012576 100644 --- a/include/components.hpp +++ b/include/components.hpp @@ -432,10 +432,10 @@ struct CL1362Port : SVGPort { }; //////////////////// -// LEDs +// Lights //////////////////// -struct ValueLight : Light { +struct ValueLight : LightWidget { float *value = NULL; virtual void setValue(float v) {} void step() override { diff --git a/include/engine.hpp b/include/engine.hpp index b2f897b3..ce7d43d0 100644 --- a/include/engine.hpp +++ b/include/engine.hpp @@ -29,21 +29,28 @@ struct Output { bool active = false; }; +struct Light { + float value = 0.0; + void setSmooth(float v); +}; + struct Module { std::vector params; std::vector inputs; std::vector outputs; + std::vector lights; /** For CPU usage meter */ float cpuTime = 0.0; /** Deprecated, use constructor below this one */ Module() {} /** Constructs Module with a fixed number of params, inputs, and outputs */ - Module(int numParams, int numInputs, int numOutputs) { + Module(int numParams, int numInputs, int numOutputs, int numLights = 0) { params.resize(numParams); inputs.resize(numInputs); outputs.resize(numOutputs); + lights.resize(numLights); } virtual ~Module() {} diff --git a/include/widgets.hpp b/include/widgets.hpp index af9b1346..693bccc1 100644 --- a/include/widgets.hpp +++ b/include/widgets.hpp @@ -382,7 +382,6 @@ struct ScrollWidget : OpaqueWidget { ScrollWidget(); void step() override; - Widget *onMouseMove(Vec pos, Vec mouseRel) override; bool onScrollOpaque(Vec scrollRel) override; }; diff --git a/src/app/Light.cpp b/src/app/LightWidget.cpp similarity index 95% rename from src/app/Light.cpp rename to src/app/LightWidget.cpp index aca594f9..1a27bb95 100644 --- a/src/app/Light.cpp +++ b/src/app/LightWidget.cpp @@ -4,7 +4,7 @@ namespace rack { -void Light::draw(NVGcontext *vg) { +void LightWidget::draw(NVGcontext *vg) { float radius = box.size.x / 2.0; float oradius = radius + 20.0; diff --git a/src/app/RackScene.cpp b/src/app/RackScene.cpp index 98b8e52d..e13e3cea 100644 --- a/src/app/RackScene.cpp +++ b/src/app/RackScene.cpp @@ -28,7 +28,7 @@ static void checkVersion() { RackScene::RackScene() { - scrollWidget = new ScrollWidget(); + scrollWidget = new RackScrollWidget(); { zoomWidget = new ZoomWidget(); zoomWidget->zoom = 1.0; diff --git a/src/app/RackScrollWidget.cpp b/src/app/RackScrollWidget.cpp new file mode 100644 index 00000000..b4bafafd --- /dev/null +++ b/src/app/RackScrollWidget.cpp @@ -0,0 +1,26 @@ +#include "app.hpp" + + +namespace rack { + + +void RackScrollWidget::step() { + Vec pos = gMousePos.minus(getAbsolutePos()); + // Scroll rack if dragging cable near the edge of the screen + if (gRackWidget->wireContainer->activeWire) { + float margin = 20.0; + float speed = 15.0; + if (pos.x <= margin) + offset.x -= speed; + if (pos.x >= box.size.x - margin) + offset.x += speed; + if (pos.y <= margin) + offset.y -= speed; + if (pos.y >= box.size.y - margin) + offset.y += speed; + } + ScrollWidget::step(); +} + + +} // namespace rack diff --git a/src/app/RackWidget.cpp b/src/app/RackWidget.cpp index a318ffc3..e27624cf 100644 --- a/src/app/RackWidget.cpp +++ b/src/app/RackWidget.cpp @@ -396,6 +396,9 @@ struct AddManufacturerMenuItem : MenuItem { } } + if (models.empty()) + return NULL; + // Model items Menu *menu = new Menu(); for (Model *model : models) { @@ -455,9 +458,14 @@ void RackWidget::onMouseDownOpaque(int button) { Vec modulePos = gMousePos.minus(getAbsolutePos()); Menu *menu = gScene->createMenu(); - MenuLabel *menuLabel = new MenuLabel(); - menuLabel->text = "Add module"; - menu->pushChild(menuLabel); + menu->pushChild(construct(&MenuLabel::text, "Add module")); + + // TODO make functional + TextField *searchField = construct(); + menu->pushChild(searchField); + // Focus search field + gFocusedWidget = searchField; + // Collect manufacturer names std::set manufacturerNames; for (Plugin *plugin : gPlugins) { diff --git a/src/engine.cpp b/src/engine.cpp index 4d79e4f6..f34ca99e 100644 --- a/src/engine.cpp +++ b/src/engine.cpp @@ -14,7 +14,7 @@ namespace rack { -float sampleRate; +float sampleRate = 0.0; bool gPaused = false; @@ -33,11 +33,17 @@ static int smoothParamId; static float smoothValue; +void Light::setSmooth(float v) { + value += (v - value) / sampleRate * 60.0; +} + + void Wire::step() { float value = outputModule->outputs[outputId].value; inputModule->inputs[inputId].value = value; } + void engineInit() { engineSetSampleRate(44100.0); } diff --git a/src/widgets/Menu.cpp b/src/widgets/Menu.cpp index d895f7ab..4099b1a4 100644 --- a/src/widgets/Menu.cpp +++ b/src/widgets/Menu.cpp @@ -42,6 +42,8 @@ void Menu::draw(NVGcontext *vg) { // Resize the width to the widest child for (Widget *child : children) { MenuEntry *menuEntry = dynamic_cast(child); + if (!menuEntry) + continue; float width = menuEntry->computeMinWidth(vg); if (width > box.size.x) { box.size.x = width; diff --git a/src/widgets/ScrollWidget.cpp b/src/widgets/ScrollWidget.cpp index f8608a5d..42fa4bff 100644 --- a/src/widgets/ScrollWidget.cpp +++ b/src/widgets/ScrollWidget.cpp @@ -32,26 +32,30 @@ void ScrollWidget::step() { // Update the container's positions from the offset container->box.pos = offset.neg().round(); - Widget::step(); -} - -Widget *ScrollWidget::onMouseMove(Vec pos, Vec mouseRel) { + // Scroll with arrow keys if (!gFocusedWidget) { - const float arrowSpeed = 50.0; + float arrowSpeed = 30.0; + if (guiIsShiftPressed() && guiIsModPressed()) + arrowSpeed /= 16.0; + else if (guiIsShiftPressed()) + arrowSpeed *= 4.0; + else if (guiIsModPressed()) + arrowSpeed /= 4.0; + if (glfwGetKey(gWindow, GLFW_KEY_LEFT) == GLFW_PRESS) { - offset = offset.minus(Vec(1, 0).mult(arrowSpeed)); + offset.x -= arrowSpeed; } if (glfwGetKey(gWindow, GLFW_KEY_RIGHT) == GLFW_PRESS) { - offset = offset.minus(Vec(-1, 0).mult(arrowSpeed)); + offset.x += arrowSpeed; } if (glfwGetKey(gWindow, GLFW_KEY_UP) == GLFW_PRESS) { - offset = offset.minus(Vec(0, 1).mult(arrowSpeed)); + offset.y -= arrowSpeed; } if (glfwGetKey(gWindow, GLFW_KEY_DOWN) == GLFW_PRESS) { - offset = offset.minus(Vec(0, -1).mult(arrowSpeed)); + offset.y += arrowSpeed; } } - return OpaqueWidget::onMouseMove(pos, mouseRel); + Widget::step(); } bool ScrollWidget::onScrollOpaque(Vec scrollRel) { diff --git a/src/widgets/TextField.cpp b/src/widgets/TextField.cpp index 16b051f4..c98b2054 100644 --- a/src/widgets/TextField.cpp +++ b/src/widgets/TextField.cpp @@ -18,9 +18,6 @@ void TextField::draw(NVGcontext *vg) { state = BND_DEFAULT; bndTextField(vg, 0.0, 0.0, box.size.x, box.size.y, BND_CORNER_NONE, state, -1, text.c_str(), begin, end); - if (text.empty() && state != BND_ACTIVE) { - bndIconLabelCaret(vg, 0.0, 0.0, box.size.x, box.size.y, -1, bndGetTheme()->textFieldTheme.itemColor, 13, placeholder.c_str(), bndGetTheme()->textFieldTheme.itemColor, 0, -1); - } } Widget *TextField::onMouseDown(Vec pos, int button) {