diff --git a/plugins/Cardinal/src/HostMIDI-CC.cpp b/plugins/Cardinal/src/HostMIDI-CC.cpp index 560245e..87daf14 100644 --- a/plugins/Cardinal/src/HostMIDI-CC.cpp +++ b/plugins/Cardinal/src/HostMIDI-CC.cpp @@ -497,15 +497,7 @@ struct HostMIDICC : Module { // -------------------------------------------------------------------------------------------------------------------- -struct CardinalMIDILearnPJ301MPort : PJ301MPort { - void onDragStart(const DragStartEvent& e) override { - PJ301MPort::onDragStart(e); - } - void onDragEnd(const DragEndEvent& e) override { - PJ301MPort::onDragEnd(e); - } -}; - +#ifndef HEADLESS /** * Based on VCVRack's CcChoice as defined in src/core/plugin.hpp * Copyright (C) 2016-2021 VCV. @@ -523,7 +515,14 @@ struct CardinalCcChoice : CardinalLedDisplayChoice { CardinalCcChoice(HostMIDICC* const m, const int i) : CardinalLedDisplayChoice(), module(m), - id(i) {} + id(i) + { + // Module browser setup + if (m == nullptr) + { + text = string::f("%d", i+1); + } + } void step() override { @@ -691,14 +690,14 @@ struct HostMIDICCWidget : ModuleWidget { { const float x = startX_In + int(i / 6) * padding; const float y = startY + int(i % 6) * padding; - addInput(createInput(Vec(x, y), module, i)); + addInput(createInput(Vec(x, y), module, i)); } for (int i=0; i<18; ++i) { const float x = startX_Out + int(i / 6) * padding; const float y = startY + int(i % 6) * padding; - addOutput(createOutput(Vec(x, y), module, i)); + addOutput(createOutput(Vec(x, y), module, i)); } CCGridDisplay* const display = createWidget(Vec(startX_In - 3.0f, 70.0f)); @@ -775,6 +774,9 @@ struct HostMIDICCWidget : ModuleWidget { menu->addChild(outputChannelItem); } }; +#else +typedef ModuleWidget HostMIDICCWidget; +#endif // -------------------------------------------------------------------------------------------------------------------- diff --git a/plugins/Cardinal/src/HostMIDI-Gate.cpp b/plugins/Cardinal/src/HostMIDI-Gate.cpp index 990d28b..ec574b6 100644 --- a/plugins/Cardinal/src/HostMIDI-Gate.cpp +++ b/plugins/Cardinal/src/HostMIDI-Gate.cpp @@ -404,15 +404,7 @@ struct HostMIDIGate : Module { // -------------------------------------------------------------------------------------------------------------------- -struct CardinalMIDILearnPJ301MPort : PJ301MPort { - void onDragStart(const DragStartEvent& e) override { - PJ301MPort::onDragStart(e); - } - void onDragEnd(const DragEndEvent& e) override { - PJ301MPort::onDragEnd(e); - } -}; - +#ifndef HEADLESS /** * Based on VCVRack's NoteChoice as defined in src/core/plugin.hpp * Copyright (C) 2016-2021 VCV. @@ -605,14 +597,14 @@ struct HostMIDIGateWidget : ModuleWidget { { const float x = startX_In + int(i / 6) * padding; const float y = startY + int(i % 6) * padding; - addInput(createInput(Vec(x, y), module, i)); + addInput(createInput(Vec(x, y), module, i)); } for (int i=0; i<18; ++i) { const float x = startX_Out + int(i / 6) * padding; const float y = startY + int(i % 6) * padding; - addOutput(createOutput(Vec(x, y), module, i)); + addOutput(createOutput(Vec(x, y), module, i)); } NoteGridDisplay* const display = createWidget(Vec(startX_In - 3.0f, 70.0f)); @@ -696,6 +688,9 @@ struct HostMIDIGateWidget : ModuleWidget { )); } }; +#else +typedef ModuleWidget HostMIDIGateWidget; +#endif // -------------------------------------------------------------------------------------------------------------------- diff --git a/plugins/Cardinal/src/HostMIDI-Map.cpp b/plugins/Cardinal/src/HostMIDI-Map.cpp index ef9606b..92e70ee 100644 --- a/plugins/Cardinal/src/HostMIDI-Map.cpp +++ b/plugins/Cardinal/src/HostMIDI-Map.cpp @@ -90,10 +90,10 @@ struct HostMIDIMap : Module { config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); for (int id = 0; id < MAX_MIDI_CONTROL; ++id) -// { -// paramHandles[id].color = nvgRGB(0xff, 0xff, 0x40); + { + paramHandles[id].color = nvgRGBf(0.76f, 0.11f, 0.22f); pcontext->engine->addParamHandle(¶mHandles[id]); -// } + } for (int i = 0; i < MAX_MIDI_CONTROL; i++) valueFilters[i].setTau(1 / 30.f); @@ -460,18 +460,27 @@ struct HostMIDIMap : Module { // -------------------------------------------------------------------------------------------------------------------- -struct MIDIMapChoice : CardinalLedDisplayChoice { +#ifndef HEADLESS +struct CardinalMIDIMapChoice : CardinalLedDisplayChoice { HostMIDIMap* const module; const int id; int disableLearnFrames = -1; ParamWidget* lastTouchedParam = nullptr; - MIDIMapChoice(HostMIDIMap* const m, const int i) + CardinalMIDIMapChoice(HostMIDIMap* const m, const int i) : CardinalLedDisplayChoice(), module(m), id(i) { alignTextCenter = false; + + // Module browser setup + if (m == nullptr) + { + bgColor = nvgRGB(0, 0, 0); + color.a = 0.75f; + text = "Click here to map"; + } } void draw(const DrawArgs& args) override @@ -489,7 +498,7 @@ struct MIDIMapChoice : CardinalLedDisplayChoice { void step() override { - if (!module) + if (module == nullptr) return; // Set bgColor and selected state @@ -609,7 +618,7 @@ struct MIDIMapChoice : CardinalLedDisplayChoice { struct HostMIDIMapDisplay : Widget { HostMIDIMap* module; ScrollWidget* scroll; - MIDIMapChoice* choices[MAX_MIDI_CONTROL]; + CardinalMIDIMapChoice* choices[MAX_MIDI_CONTROL]; LedDisplaySeparator* separators[MAX_MIDI_CONTROL]; void drawLayer(const DrawArgs& args, int layer) override @@ -634,13 +643,15 @@ struct HostMIDIMapDisplay : Widget { { LedDisplaySeparator* separator = createWidget(Vec(0.0f, posY)); separator->box.size = Vec(box.size.x, 1.0f); + separator->visible = false; scroll->container->addChild(separator); separators[id] = separator; } - MIDIMapChoice* const choice = new MIDIMapChoice(module, id); + CardinalMIDIMapChoice* const choice = new CardinalMIDIMapChoice(module, id); choice->box.pos = Vec(0.0f, posY); choice->box.size = Vec(box.size.x, 20.0f); + choice->visible = id == 0; scroll->container->addChild(choice); choices[id] = choice; @@ -722,6 +733,9 @@ struct HostMIDIMapWidget : ModuleWidget { menu->addChild(inputChannelItem); } }; +#else +typedef ModuleWidget HostMIDIMapWidget; +#endif // -------------------------------------------------------------------------------------------------------------------- diff --git a/plugins/Cardinal/src/Ildaeil.cpp b/plugins/Cardinal/src/Ildaeil.cpp index d5a62b5..8330406 100644 --- a/plugins/Cardinal/src/Ildaeil.cpp +++ b/plugins/Cardinal/src/Ildaeil.cpp @@ -745,25 +745,33 @@ struct IldaeilWidget : ImGuiWidget, IdleCallback, Thread { : ImGuiWidget(), module(m) { - if (module->fCarlaHostHandle == nullptr) - { - fDrawingState = kDrawingErrorInit; - fIdleState = kIdleNothing; - fPopupError = "Ildaeil backend failed to init properly, cannot continue."; - return; - } - std::strcpy(fPluginSearchString, "Search..."); - if (checkIfPluginIsLoaded()) - fIdleState = kIdleInitPluginAlreadyLoaded; + if (m != nullptr) + { + if (m->fCarlaHostHandle == nullptr) + { + fDrawingState = kDrawingErrorInit; + fIdleState = kIdleNothing; + fPopupError = "Ildaeil backend failed to init properly, cannot continue."; + return; + } + + if (checkIfPluginIsLoaded()) + fIdleState = kIdleInitPluginAlreadyLoaded; - module->fUI = this; + m->fUI = this; + } + else + { + fDrawingState = kDrawingPluginList; + fIdleState = kIdleNothing; + } } ~IldaeilWidget() override { - if (module->fCarlaHostHandle != nullptr) + if (module != nullptr && module->fCarlaHostHandle != nullptr) { if (idleCallbackActive) { @@ -1009,6 +1017,9 @@ struct IldaeilWidget : ImGuiWidget, IdleCallback, Thread { void widgetCreated() { + if (module == nullptr) + return; + if (const CarlaHostHandle handle = module->fCarlaHostHandle) { const CardinalPluginContext* const pcontext = module->pcontext; @@ -1031,6 +1042,9 @@ struct IldaeilWidget : ImGuiWidget, IdleCallback, Thread { void widgetDestroyed() { + if (module == nullptr) + return; + if (const CarlaHostHandle handle = module->fCarlaHostHandle) { const CardinalPluginContext* const pcontext = module->pcontext; @@ -1532,7 +1546,7 @@ struct IldaeilWidget : ImGuiWidget, IdleCallback, Thread { if (ImGui::Button("Load Plugin")) fIdleState = kIdleLoadSelectedPlugin; - if (fPluginType != PLUGIN_INTERNAL && module->canUseBridges) + if (fPluginType != PLUGIN_INTERNAL && (module == nullptr || module->canUseBridges)) { ImGui::SameLine(); ImGui::Checkbox("Run in bridge mode", &fPluginWillRunInBridgeMode); @@ -1657,7 +1671,7 @@ struct IldaeilModuleWidget : ModuleWidget { setModule(module); setPanel(APP->window->loadSvg(asset::plugin(pluginInstance, "res/Ildaeil.svg"))); - if (module != nullptr && module->pcontext != nullptr) + if (module == nullptr || module->pcontext != nullptr) { ildaeilWidget = new IldaeilWidget(module); ildaeilWidget->box.pos = Vec(2 * RACK_GRID_WIDTH, 0); diff --git a/plugins/Cardinal/src/ImGuiWidget.cpp b/plugins/Cardinal/src/ImGuiWidget.cpp index 204f026..dbe2a2f 100644 --- a/plugins/Cardinal/src/ImGuiWidget.cpp +++ b/plugins/Cardinal/src/ImGuiWidget.cpp @@ -1,6 +1,6 @@ /* * Dear ImGui for DPF, converted to VCV - * Copyright (C) 2021 Filipe Coelho + * Copyright (C) 2021-2022 Filipe Coelho * Copyright (C) 2021 Jean Pierre Cimalando * * Permission to use, copy, modify, and/or distribute this software for any purpose with @@ -145,7 +145,7 @@ float ImGuiWidget::getScaleFactor() const noexcept void ImGuiWidget::onContextCreate(const ContextCreateEvent& e) { - OpenGlWidget::onContextCreate(e); + OpenGlWidgetWithBrowserPreview::onContextCreate(e); DISTRHO_SAFE_ASSERT_RETURN(!imData->created,); ImGui::SetCurrentContext(imData->context); @@ -162,7 +162,7 @@ void ImGuiWidget::onContextDestroy(const ContextDestroyEvent& e) imData->created = false; } - OpenGlWidget::onContextDestroy(e); + OpenGlWidgetWithBrowserPreview::onContextDestroy(e); } void ImGuiWidget::setAsCurrentContext() @@ -308,11 +308,37 @@ void ImGuiWidget::onSelectText(const SelectTextEvent& e) void ImGuiWidget::drawFramebuffer() { + const float scaleFactor = APP->window->pixelRatio; + + drawFramebufferCommon(getFramebufferSize(), scaleFactor); +} + +void ImGuiWidget::drawFramebufferForBrowserPreview() +{ + if (imData->created) + { + ImGui::SetCurrentContext(imData->context); + ImGui_ImplOpenGL2_Shutdown(); + ImGui::DestroyContext(imData->context); + + imData->created = false; + imData->fontGenerated = false; + imData->originalScaleFactor = 0.0f; + imData->scaleFactor = 0.0f; + } + + imData->context = ImGui::CreateContext(); ImGui::SetCurrentContext(imData->context); - ImGuiIO& io(ImGui::GetIO()); + ImGui_ImplOpenGL2_Init(); + imData->created = true; - const math::Vec fbSize = getFramebufferSize(); - const float scaleFactor = APP->window->pixelRatio; + drawFramebufferCommon(box.size.mult(oversample), oversample); +} + +void ImGuiWidget::drawFramebufferCommon(const Vec& fbSize, const float scaleFactor) +{ + ImGui::SetCurrentContext(imData->context); + ImGuiIO& io(ImGui::GetIO()); if (d_isNotEqual(imData->scaleFactor, scaleFactor)) { diff --git a/plugins/Cardinal/src/ImGuiWidget.hpp b/plugins/Cardinal/src/ImGuiWidget.hpp index e1169d4..bcb0ba7 100644 --- a/plugins/Cardinal/src/ImGuiWidget.hpp +++ b/plugins/Cardinal/src/ImGuiWidget.hpp @@ -1,6 +1,6 @@ /* * Dear ImGui for DPF, converted to VCV - * Copyright (C) 2021 Filipe Coelho + * Copyright (C) 2021-2022 Filipe Coelho * Copyright (C) 2021 Jean Pierre Cimalando * * Permission to use, copy, modify, and/or distribute this software for any purpose with @@ -20,7 +20,7 @@ #include "plugin.hpp" #include "DearImGui/imgui.h" -struct ImGuiWidget : OpenGlWidget { +struct ImGuiWidget : OpenGlWidgetWithBrowserPreview { struct PrivateData; PrivateData* const imData; @@ -50,4 +50,6 @@ protected: private: void drawFramebuffer() override; + void drawFramebufferForBrowserPreview() override; + void drawFramebufferCommon(const Vec& fbSize, float scaleFactor); }; diff --git a/plugins/Cardinal/src/TextEditor.cpp b/plugins/Cardinal/src/TextEditor.cpp index bb9cd1b..518d0dd 100644 --- a/plugins/Cardinal/src/TextEditor.cpp +++ b/plugins/Cardinal/src/TextEditor.cpp @@ -326,21 +326,24 @@ struct TextEditorModuleWidget : ModuleWidget { addChild(rightHandle = new ModuleResizeHandle(module, this, true)); addChild(new ModuleResizeHandle(module, this, false)); + box.size = Vec(RACK_GRID_WIDTH * (module != nullptr ? module->width : DEFAULT_WIDTH), RACK_GRID_HEIGHT); + + textEditorModule = module; + textEditorWidget = new ImGuiTextEditor(); + textEditorWidget->box.pos = Vec(RACK_GRID_WIDTH, 0); + textEditorWidget->box.size = Vec(box.size.x - 2 * RACK_GRID_WIDTH, box.size.y); + addChild(textEditorWidget); + if (module != nullptr) { - box.size = Vec(RACK_GRID_WIDTH * module->width, RACK_GRID_HEIGHT); - textEditorModule = module; - textEditorWidget = new ImGuiTextEditor(); - textEditorWidget->setFileWithKnownText(module->file, module->text); textEditorWidget->setLanguageDefinition(module->lang); - textEditorWidget->box.pos = Vec(RACK_GRID_WIDTH, 0); - textEditorWidget->box.size = Vec((module->width - 2) * RACK_GRID_WIDTH, box.size.y); - addChild(textEditorWidget); + textEditorWidget->setFileWithKnownText(module->file, module->text); module->widgetPtr = textEditorWidget; } else { - box.size = Vec(RACK_GRID_WIDTH * DEFAULT_WIDTH, RACK_GRID_HEIGHT); + textEditorWidget->setLanguageDefinition(DEFAULT_LANG); + textEditorWidget->setText(DEFAULT_TEXT); } } diff --git a/plugins/Cardinal/src/glBars.cpp b/plugins/Cardinal/src/glBars.cpp index e105b2b..d150160 100644 --- a/plugins/Cardinal/src/glBars.cpp +++ b/plugins/Cardinal/src/glBars.cpp @@ -61,13 +61,13 @@ struct glBarsModule : Module { }; #ifndef HEADLESS -struct glBarsRendererWidget : OpenGlWidget { +struct glBarsRendererWidget : OpenGlWidgetWithBrowserPreview { glBarsModule* const glBars; glBarsRendererWidget(glBarsModule* const module) : glBars(module) { - if (APP->window->pixelRatio < 2.0f) + if (glBars != nullptr && APP->window->pixelRatio < 2.0f) oversample = 2.0f; } @@ -75,22 +75,34 @@ struct glBarsRendererWidget : OpenGlWidget { { } - void drawLayer(const DrawArgs& args, int layer) override + void drawLayer(const DrawArgs& args, const int layer) override { if (layer != 1) return; - OpenGlWidget::draw(args); + OpenGlWidgetWithBrowserPreview::draw(args); } - void drawFramebuffer() override { - math::Vec fbSize = getFramebufferSize(); + void drawFramebuffer() override + { + DISTRHO_SAFE_ASSERT_RETURN(glBars != nullptr,); + + drawFramebuffer(glBars->state, getFramebufferSize()); + } + void drawFramebufferForBrowserPreview() override + { + glBarsState state; + drawFramebuffer(state, box.size); + } + + void drawFramebuffer(glBarsState& state, const Vec& fbSize) + { glDisable(GL_BLEND); glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); - glViewport(0.0, -100, fbSize.x * oversample, fbSize.y * oversample); + glViewport(0.0, -50 * oversample, fbSize.x * oversample, fbSize.y * oversample); glFrustum(-1, 1, -1, 1, 1.5, 10); glMatrixMode(GL_MODELVIEW); glPushMatrix(); @@ -99,7 +111,7 @@ struct glBarsRendererWidget : OpenGlWidget { glClearColor(0.0f, 0.0f, 0.0f, 0.0f); glClear(GL_COLOR_BUFFER_BIT); - glBars->state.Render(); + state.Render(); glPopMatrix(); glMatrixMode(GL_PROJECTION); @@ -107,18 +119,17 @@ struct glBarsRendererWidget : OpenGlWidget { glEnable(GL_BLEND); } - void step() override { + void step() override + { OpenGlWidget::step(); - oversample = APP->window->pixelRatio < 2.0f ? 2.0f : 1.0f; + if (glBars != nullptr) + oversample = APP->window->pixelRatio < 2.0f ? 2.0f : 1.0f; } }; struct glBarsWidget : ModuleWidget { - glBarsRendererWidget* const glBarsRenderer; - glBarsWidget(glBarsModule* const module) - : glBarsRenderer(new glBarsRendererWidget(module)) { setModule(module); setPanel(APP->window->loadSvg(asset::plugin(pluginInstance, "res/glBars.svg"))); @@ -131,6 +142,7 @@ struct glBarsWidget : ModuleWidget { addInput(createInput(Vec(135.0f, 20.0f), module, glBarsModule::IN1_INPUT)); const float size = mm2px(127.0f); + glBarsRendererWidget* const glBarsRenderer = new glBarsRendererWidget(module); glBarsRenderer->box.pos = Vec((box.size.x - size) * 0.5f, (box.size.y - size) * 0.5f); glBarsRenderer->box.size = Vec(size, size); addChild(glBarsRenderer); diff --git a/plugins/Cardinal/src/plugin.hpp b/plugins/Cardinal/src/plugin.hpp index 5ddfde7..6fac5ed 100644 --- a/plugins/Cardinal/src/plugin.hpp +++ b/plugins/Cardinal/src/plugin.hpp @@ -25,6 +25,7 @@ using namespace rack; +#ifndef HEADLESS struct CardinalLedDisplayChoice : LedDisplayChoice { bool alignTextCenter = true; @@ -60,6 +61,59 @@ struct CardinalLedDisplayChoice : LedDisplayChoice { } }; +struct OpenGlWidgetWithBrowserPreview : OpenGlWidget { + NVGLUframebuffer* fb = nullptr; + + void draw(const DrawArgs& args) override + { + if (args.fb == nullptr) + return OpenGlWidget::draw(args); + + // set oversample to current scale + float trans[6]; + nvgCurrentTransform(args.vg, trans); + oversample = std::max(1.0f, trans[0]); + + // recreate framebuffer + deleteFramebuffer(); + fb = nvgluCreateFramebuffer(args.vg, box.size.x * oversample, box.size.y * oversample, 0); + DISTRHO_SAFE_ASSERT_RETURN(fb != nullptr,); + + // draw our special framebuffer + nvgluBindFramebuffer(fb); + drawFramebufferForBrowserPreview(); + + // reset to regular framebuffer + nvgluBindFramebuffer(args.fb); + + // render image generated by our framebuffer + nvgBeginPath(args.vg); + nvgRect(args.vg, 0.0f, 0.0f, box.size.x, box.size.y); + NVGpaint paint = nvgImagePattern(args.vg, + 0.0f, 0.0f, box.size.x, box.size.y, + 0.0f, fb->image, 1.0f); + nvgFillPaint(args.vg, paint); + nvgFill(args.vg); + } + + void onContextDestroy(const ContextDestroyEvent& e) override + { + deleteFramebuffer(); + OpenGlWidget::onContextDestroy(e); + } + + void deleteFramebuffer() + { + if (fb == nullptr) + return; + nvgluDeleteFramebuffer(fb); + fb = nullptr; + } + + virtual void drawFramebufferForBrowserPreview() = 0; +}; +#endif + extern Plugin* pluginInstance; extern Model* modelAudioFile;