From 6bbdf9a63da6898c59c38cfa3a7d333e8a6af0b5 Mon Sep 17 00:00:00 2001 From: falkTX Date: Wed, 2 Feb 2022 21:43:25 +0000 Subject: [PATCH] Move some common code to new header files --- plugins/Cardinal/src/Carla.cpp | 51 +--- plugins/Cardinal/src/HostAudio.cpp | 352 ++-------------------- plugins/Cardinal/src/HostCV.cpp | 46 +-- plugins/Cardinal/src/HostMIDI-CC.cpp | 1 + plugins/Cardinal/src/HostMIDI-Gate.cpp | 1 + plugins/Cardinal/src/HostMIDI-Map.cpp | 1 + plugins/Cardinal/src/HostMIDI.cpp | 78 ++--- plugins/Cardinal/src/HostTime.cpp | 2 +- plugins/Cardinal/src/ImGuiWidget.hpp | 2 +- plugins/Cardinal/src/ModuleWidgets.hpp | 90 ++++++ plugins/Cardinal/src/Widgets.hpp | 398 +++++++++++++++++++++++++ plugins/Cardinal/src/glBars.cpp | 1 + plugins/Cardinal/src/plugin.hpp | 89 ------ 13 files changed, 561 insertions(+), 551 deletions(-) create mode 100644 plugins/Cardinal/src/ModuleWidgets.hpp create mode 100644 plugins/Cardinal/src/Widgets.hpp diff --git a/plugins/Cardinal/src/Carla.cpp b/plugins/Cardinal/src/Carla.cpp index 5a48bb9..cd6a597 100644 --- a/plugins/Cardinal/src/Carla.cpp +++ b/plugins/Cardinal/src/Carla.cpp @@ -1,6 +1,6 @@ /* * DISTRHO Cardinal Plugin - * Copyright (C) 2021 Filipe Coelho + * Copyright (C) 2021-2022 Filipe Coelho * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -16,6 +16,7 @@ */ #include "plugincontext.hpp" +#include "ModuleWidgets.hpp" #include "CarlaNativePlugin.h" #include "CarlaBackendUtils.hpp" @@ -442,34 +443,23 @@ static intptr_t host_dispatcher(const NativeHostHandle handle, const NativeHostD // -------------------------------------------------------------------------------------------------------------------- #ifndef HEADLESS -struct CarlaModuleWidget : ModuleWidget, IdleCallback { - static constexpr const float startX_In = 14.0f; - static constexpr const float startX_Out = 96.0f; - static constexpr const float startY = 74.0f; - static constexpr const float padding = 29.0f; - static constexpr const float middleX = startX_In + (startX_Out - startX_In) * 0.5f + padding * 0.35f; - +struct CarlaModuleWidget : ModuleWidgetWith9HP, IdleCallback { CarlaModule* const module; bool idleCallbackActive = false; bool visible = false; CarlaModuleWidget(CarlaModule* const m) - : ModuleWidget(), - module(m) + : module(m) { setModule(module); setPanel(APP->window->loadSvg(asset::plugin(pluginInstance, "res/Carla.svg"))); - - addChild(createWidget(Vec(RACK_GRID_WIDTH, 0))); - addChild(createWidget(Vec(box.size.x - 2 * RACK_GRID_WIDTH, 0))); - addChild(createWidget(Vec(RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH))); - addChild(createWidget(Vec(box.size.x - 2 * RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH))); + setSideScrews(); for (uint i=0; i(Vec(startX_In, startY + padding * i), module, i)); + createAndAddInput(i); for (uint i=0; i(Vec(startX_Out, startY + padding * i), module, i)); + createAndAddOutput(i); } ~CarlaModuleWidget() override @@ -565,30 +555,11 @@ struct CarlaModuleWidget : ModuleWidget, IdleCallback { module->fCarlaPluginDescriptor->ui_idle(module->fCarlaPluginHandle); } - void drawTextLine(NVGcontext* const vg, const uint offset, const char* const text) - { - const float y = startY + offset * padding; - nvgBeginPath(vg); - nvgFillColor(vg, color::WHITE); - nvgText(vg, middleX, y + 16, text, nullptr); - } - void draw(const DrawArgs& args) override { - nvgBeginPath(args.vg); - nvgRect(args.vg, 0, 0, box.size.x, box.size.y); - nvgFillPaint(args.vg, nvgLinearGradient(args.vg, 0, 0, 0, box.size.y, - nvgRGB(0x18, 0x19, 0x19), nvgRGB(0x21, 0x22, 0x22))); - nvgFill(args.vg); - - nvgFontFaceId(args.vg, 0); - nvgFontSize(args.vg, 11); - nvgTextAlign(args.vg, NVG_ALIGN_CENTER); - - nvgBeginPath(args.vg); - nvgRoundedRect(args.vg, startX_Out - 2.5f, startY - 2.0f, padding, padding * CarlaModule::NUM_INPUTS, 4); - nvgFillColor(args.vg, nvgRGB(0xd0, 0xd0, 0xd0)); - nvgFill(args.vg); + drawBackground(args.vg); + drawOutputJacksArea(args.vg, CarlaModule::NUM_INPUTS); + setupTextLines(args.vg); drawTextLine(args.vg, 0, "Audio 1"); drawTextLine(args.vg, 1, "Audio 2"); @@ -601,7 +572,7 @@ struct CarlaModuleWidget : ModuleWidget, IdleCallback { drawTextLine(args.vg, 8, "CV 7"); drawTextLine(args.vg, 9, "CV 8"); - ModuleWidget::draw(args); + ModuleWidgetWith9HP::draw(args); } void showUI() diff --git a/plugins/Cardinal/src/HostAudio.cpp b/plugins/Cardinal/src/HostAudio.cpp index d7238a3..2a44213 100644 --- a/plugins/Cardinal/src/HostAudio.cpp +++ b/plugins/Cardinal/src/HostAudio.cpp @@ -16,192 +16,13 @@ */ #include "plugincontext.hpp" +#include "ModuleWidgets.hpp" +#include "Widgets.hpp" // ----------------------------------------------------------------------------------------------------------- USE_NAMESPACE_DISTRHO; -struct NanoKnob : Knob { - static const int ringSize = 4; - - std::string displayLabel = "Level"; - std::string displayString = "0 dB"; - float normalizedValue = 0.5f; - - NanoKnob() - { - box.size = Vec(100, 100); - } - - void drawLayer(const DrawArgs& args, int layer) override - { - if (layer != 1) - return Knob::drawLayer(args, layer); - - const float w = box.size.x; - const float h = box.size.y; - - const int knobSize = std::min(w, h - BND_WIDGET_HEIGHT * 2) - ringSize; - - const int knobStartX = w / 2 - knobSize / 2; - const int knobStartY = ringSize; - const int knobCenterX = knobStartX + knobSize / 2; - const int knobCenterY = knobStartY + knobSize / 2; - - const NVGcolor testing = nvgRGBf(0.76f, 0.11f, 0.22f); - - nvgLineCap(args.vg, NVG_ROUND); - - // outer ring value - nvgBeginPath(args.vg); - nvgArc(args.vg, - knobCenterX, - knobCenterY, - knobSize / 2 + ringSize / 2 + 1, - nvgDegToRad(135.0f), - nvgDegToRad(135.0f) + nvgDegToRad(270.0f * normalizedValue), - NVG_CW); - nvgStrokeWidth(args.vg, ringSize); - nvgStrokeColor(args.vg, testing); - nvgStroke(args.vg); - - // simulate color bleeding - nvgBeginPath(args.vg); - nvgArc(args.vg, - knobCenterX, - knobCenterY, - knobSize / 2 - 3, - nvgDegToRad(135.0f), - nvgDegToRad(135.0f) + nvgDegToRad(270.0f * normalizedValue), - NVG_CW); - nvgStrokeWidth(args.vg, 5); - nvgStrokeColor(args.vg, nvgRGBAf(testing.r, testing.g, testing.b, 0.1f)); - nvgStroke(args.vg); - - // line indicator - nvgStrokeWidth(args.vg, 2); - nvgSave(args.vg); - nvgTranslate(args.vg, knobCenterX, knobCenterY); - nvgRotate(args.vg, nvgDegToRad(45.0f) + normalizedValue * nvgDegToRad(270.0f)); - nvgBeginPath(args.vg); - nvgRoundedRect(args.vg, -2, knobSize / 2 - 9, 2, 6, 1); - nvgClosePath(args.vg); - nvgFillColor(args.vg, nvgRGBf(1.0f, 1.0f, 1.0f)); - nvgFill(args.vg); - nvgRestore(args.vg); - - // adjusted from VCVRack's LightWidget.cpp - if (const float halo = settings::haloBrightness) - { - float radius = knobSize * 0.5f; - float oradius = radius + std::min(radius * 4.f, 15.f); - - NVGcolor icol = color::mult(nvgRGBAf(testing.r, testing.g, testing.b, 0.2f), halo); - NVGcolor ocol = nvgRGBA(0, 0, 0, 0); - NVGpaint paint = nvgRadialGradient(args.vg, knobCenterX, knobCenterY, radius, oradius, icol, ocol); - - nvgBeginPath(args.vg); - nvgRect(args.vg, knobCenterX - oradius, knobCenterY - oradius, 2 * oradius, 2 * oradius); - nvgFillPaint(args.vg, paint); - nvgFill(args.vg); - } - - // bottom label (value) - bndIconLabelValue(args.vg, 0, knobSize + ringSize, w, BND_WIDGET_HEIGHT, -1, - testing, BND_CENTER, - BND_LABEL_FONT_SIZE, displayString.c_str(), nullptr); - - Knob::drawLayer(args, layer); - } - - void draw(const DrawArgs& args) override - { - if (engine::ParamQuantity* const pq = getParamQuantity()) - normalizedValue = pq->getScaledValue(); - - const float w = box.size.x; - const float h = box.size.y; - - const int knobSize = std::min(w, h - BND_WIDGET_HEIGHT * 2) - ringSize; - - const int knobStartX = w / 2 - knobSize / 2; - const int knobStartY = ringSize; - const int knobCenterX = knobStartX + knobSize / 2; - const int knobCenterY = knobStartY + knobSize / 2; - - // knob - NVGcolor shade_top; - NVGcolor shade_down; - BNDwidgetState state; - if (APP->event->getDraggedWidget() == this) - state = BND_ACTIVE; - else if (APP->event->getHoveredWidget() == this) - state = BND_HOVER; - else - state = BND_DEFAULT; - bndInnerColors(&shade_top, &shade_down, &bndGetTheme()->optionTheme, state, 0); - - // inner fill - nvgBeginPath(args.vg); - nvgCircle(args.vg, knobCenterX, knobCenterY, knobSize / 2); - nvgFillPaint(args.vg, nvgLinearGradient(args.vg, - knobStartX, - knobStartY, - knobStartX, - knobStartY + knobSize, - shade_top, - shade_down)); - nvgFill(args.vg); - - // inner fill border (inner) - nvgBeginPath(args.vg); - nvgArc(args.vg, knobCenterX, knobCenterY, knobSize / 2 - 1, nvgDegToRad(0.0f), nvgDegToRad(360.0f), NVG_CCW); - nvgClosePath(args.vg); - nvgStrokeWidth(args.vg, 1); - nvgStrokeColor(args.vg, nvgRGBAf(0.5f, 0.5f, 0.5f, 0.4f)); - nvgStroke(args.vg); - - // inner fill border (outer) - nvgBeginPath(args.vg); - nvgArc(args.vg, knobCenterX, knobCenterY, knobSize / 2, nvgDegToRad(0.0f), nvgDegToRad(360.0f), NVG_CCW); - nvgClosePath(args.vg); - nvgStrokeWidth(args.vg, 1); - nvgStrokeColor(args.vg, nvgRGBAf(0.0f, 0.0f, 0.0f, 0.4f)); - nvgStroke(args.vg); - - nvgLineCap(args.vg, NVG_ROUND); - - // outer ring background - nvgBeginPath(args.vg); - nvgArc(args.vg, - knobCenterX, - knobCenterY, - knobSize / 2 + ringSize / 2 + 1, - nvgDegToRad(135.0f), - nvgDegToRad(45.0f), - NVG_CW); - nvgStrokeWidth(args.vg, ringSize); - nvgStrokeColor(args.vg, nvgRGBf(0.5f, 0.5f, 0.5f)); - nvgStroke(args.vg); - - // bottom label (name) - bndIconLabelValue(args.vg, 0, knobStartY + knobSize + BND_WIDGET_HEIGHT * 0.75f, w, BND_WIDGET_HEIGHT, -1, - SCHEME_WHITE, BND_CENTER, - BND_LABEL_FONT_SIZE, displayLabel.c_str(), nullptr); - - Knob::draw(args); - } - - void onChange(const ChangeEvent&) override - { - engine::ParamQuantity* const pq = getParamQuantity(); - DISTRHO_SAFE_ASSERT_RETURN(pq != nullptr,); - - displayLabel = pq->getLabel(); - displayString = pq->getDisplayValueString() + pq->getUnit(); - } -}; - /* * Find the highest absolute and normalized value within a float array. */ @@ -365,132 +186,26 @@ struct HostAudio : Module { }; template -struct NanoMeter : Widget { +struct HostAudioNanoMeter : NanoMeter { HostAudio* const module; - float gainMeterL = 0.0f; - float gainMeterR = 0.0f; - NanoMeter(HostAudio* const m) - : module(m) - { - box.size = Vec(100, 100); - } + HostAudioNanoMeter(HostAudio* const m) + : module(m) {} - void drawLayer(const DrawArgs& args, int layer) override + void updateMeters() override { - if (layer != 1) + if (module == nullptr || module->resetMeters) return; - const float usableHeight = box.size.y - 10.0f; - - // draw background - nvgBeginPath(args.vg); - nvgRect(args.vg, - 0, - 0, - box.size.x, - usableHeight); - nvgFillColor(args.vg, nvgRGB(26, 26, 26)); - nvgFill(args.vg); - - nvgFillColor(args.vg, nvgRGBAf(0.76f, 0.11f, 0.22f, 0.5f)); - nvgStrokeColor(args.vg, nvgRGBf(0.76f, 0.11f, 0.22f)); - - if (module != nullptr) - { - // Only fetch new values once DSP side is updated - if (! module->resetMeters) - { - gainMeterL = module->gainMeterL; - gainMeterR = module->gainMeterR; - module->resetMeters = true; - } - - const float heightL = 1.0f + std::sqrt(gainMeterL) * (usableHeight - 1.0f); - nvgBeginPath(args.vg); - nvgRect(args.vg, 0.0f, usableHeight - heightL, box.size.x * 0.5f - 1.0f, heightL); - nvgFill(args.vg); - nvgStroke(args.vg); - - const float heightR = 1.0f + std::sqrt(gainMeterR) * (usableHeight - 1.0f); - nvgBeginPath(args.vg); - nvgRect(args.vg, box.size.x * 0.5f + 1.0f, usableHeight - heightR, box.size.x * 0.5f - 2.0f, heightR); - nvgFill(args.vg); - nvgStroke(args.vg); - } - - nvgLineCap(args.vg, NVG_ROUND); - - nvgBeginPath(args.vg); - nvgMoveTo(args.vg, 0.0f, usableHeight + 2.0f); - nvgLineTo(args.vg, box.size.x * 0.5f - 11.0f, usableHeight + 2.0f); - nvgStroke(args.vg); - - nvgBeginPath(args.vg); - nvgMoveTo(args.vg, 0.0f, usableHeight + 4.0f); - nvgLineTo(args.vg, box.size.x * 0.5f - 16.0f, usableHeight + 4.0f); - nvgStroke(args.vg); - - nvgBeginPath(args.vg); - nvgMoveTo(args.vg, 0.0f, usableHeight + 6.0f); - nvgLineTo(args.vg, box.size.x * 0.5f - 19.0f, usableHeight + 6.0f); - nvgStroke(args.vg); - - nvgBeginPath(args.vg); - nvgMoveTo(args.vg, 0.0f, usableHeight + 8.0f); - nvgLineTo(args.vg, box.size.x * 0.5f - 22.0f, usableHeight + 8.0f); - nvgStroke(args.vg); - - nvgBeginPath(args.vg); - nvgMoveTo(args.vg, 0.0f, usableHeight + 10.0f); - nvgLineTo(args.vg, box.size.x * 0.5f - 24.0f, usableHeight + 10.0f); - nvgStroke(args.vg); - - nvgBeginPath(args.vg); - nvgMoveTo(args.vg, 0.0f, usableHeight + 12.0f); - nvgLineTo(args.vg, box.size.x * 0.5f - 26.0f, usableHeight + 12.0f); - nvgStroke(args.vg); - - nvgBeginPath(args.vg); - nvgMoveTo(args.vg, box.size.x * 0.5f + 10.0f, usableHeight + 2.0f); - nvgLineTo(args.vg, box.size.x - 1.0f, usableHeight + 2.0f); - nvgStroke(args.vg); - - nvgBeginPath(args.vg); - nvgMoveTo(args.vg, box.size.x * 0.5f + 15.0f, usableHeight + 4.0f); - nvgLineTo(args.vg, box.size.x - 1.0f, usableHeight + 4.0f); - nvgStroke(args.vg); - - nvgBeginPath(args.vg); - nvgMoveTo(args.vg, box.size.x * 0.5f + 18.0f, usableHeight + 6.0f); - nvgLineTo(args.vg, box.size.x - 1.0f, usableHeight + 6.0f); - nvgStroke(args.vg); - - nvgBeginPath(args.vg); - nvgMoveTo(args.vg, box.size.x * 0.5f + 20.0f, usableHeight + 8.0f); - nvgLineTo(args.vg, box.size.x - 1.0f, usableHeight + 8.0f); - nvgStroke(args.vg); - - nvgBeginPath(args.vg); - nvgMoveTo(args.vg, box.size.x * 0.5f + 22.0f, usableHeight + 10.0f); - nvgLineTo(args.vg, box.size.x - 1.0f, usableHeight + 10.0f); - nvgStroke(args.vg); - - nvgBeginPath(args.vg); - nvgMoveTo(args.vg, box.size.x * 0.5f + 24.0f, usableHeight + 12.0f); - nvgLineTo(args.vg, box.size.x - 1.0f, usableHeight + 12.0f); - nvgStroke(args.vg); + // Only fetch new values once DSP side is updated + gainMeterL = module->gainMeterL; + gainMeterR = module->gainMeterR; + module->resetMeters = true; } }; template -struct HostAudioWidget : ModuleWidget { - static constexpr const float startX_In = 14.0f; - static constexpr const float startX_Out = 81.0f; - static constexpr const float startY = 74.0f; - static constexpr const float padding = 29.0f; - static constexpr const float middleX = startX_In + (startX_Out - startX_In) * 0.5f + padding * 0.35f; - +struct HostAudioWidget : ModuleWidgetWith8HP { HostAudio* const module; HostAudioWidget(HostAudio* const m) @@ -498,53 +213,30 @@ struct HostAudioWidget : ModuleWidget { { setModule(m); setPanel(APP->window->loadSvg(asset::plugin(pluginInstance, "res/HostAudio.svg"))); - - addChild(createWidget(Vec(RACK_GRID_WIDTH, 0))); - addChild(createWidget(Vec(box.size.x - 2 * RACK_GRID_WIDTH, 0))); - addChild(createWidget(Vec(RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH))); - addChild(createWidget(Vec(box.size.x - 2 * RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH))); + setSideScrews(); for (uint i=0; i(Vec(startX_In, startY + padding * i), m, i)); - - for (uint i=0; i(Vec(startX_Out, startY + padding * i), m, i)); + { + createAndAddInput(i); + createAndAddOutput(i); + } if (numIO == 2) { addParam(createParamCentered(Vec(middleX, 310.0f), m, 0)); - NanoMeter* const meter = new NanoMeter(m); + HostAudioNanoMeter* const meter = new HostAudioNanoMeter(m); meter->box.pos = Vec(middleX - padding + 2.75f, startY + padding * 2); meter->box.size = Vec(padding * 2.0f - 4.0f, 136.0f); addChild(meter); } } - void drawTextLine(NVGcontext* const vg, const uint posY, const char* const text) - { - const float y = startY + posY * padding; - nvgBeginPath(vg); - nvgFillColor(vg, color::WHITE); - nvgText(vg, middleX, y + 16, text, nullptr); - } - void draw(const DrawArgs& args) override { - nvgBeginPath(args.vg); - nvgRect(args.vg, 0, 0, box.size.x, box.size.y); - nvgFillPaint(args.vg, nvgLinearGradient(args.vg, 0, 0, 0, box.size.y, - nvgRGB(0x18, 0x19, 0x19), nvgRGB(0x21, 0x22, 0x22))); - nvgFill(args.vg); - - nvgFontFaceId(args.vg, 0); - nvgFontSize(args.vg, 11); - nvgTextAlign(args.vg, NVG_ALIGN_CENTER); - - nvgBeginPath(args.vg); - nvgRoundedRect(args.vg, startX_Out - 2.5f, startY - 2.0f, padding, padding * numIO, 4); - nvgFillColor(args.vg, nvgRGB(0xd0, 0xd0, 0xd0)); - nvgFill(args.vg); + drawBackground(args.vg); + drawOutputJacksArea(args.vg, numIO); + setupTextLines(args.vg); if (numIO == 2) { @@ -560,7 +252,7 @@ struct HostAudioWidget : ModuleWidget { } } - ModuleWidget::draw(args); + ModuleWidgetWith8HP::draw(args); } void appendContextMenu(Menu* const menu) override { diff --git a/plugins/Cardinal/src/HostCV.cpp b/plugins/Cardinal/src/HostCV.cpp index b8cbb70..050d0b7 100644 --- a/plugins/Cardinal/src/HostCV.cpp +++ b/plugins/Cardinal/src/HostCV.cpp @@ -16,6 +16,7 @@ */ #include "plugincontext.hpp" +#include "ModuleWidgets.hpp" #define CARDINAL_AUDIO_IO_OFFSET 8 @@ -98,54 +99,25 @@ struct HostCV : Module { } }; -struct HostCVWidget : ModuleWidget { - static constexpr const float startX_In = 14.0f; - static constexpr const float startX_Out = 81.0f; - static constexpr const float startY = 74.0f; - static constexpr const float padding = 29.0f; - static constexpr const float middleX = startX_In + (startX_Out - startX_In) * 0.5f + padding * 0.35f; - +struct HostCVWidget : ModuleWidgetWith8HP { HostCVWidget(HostCV* const module) { setModule(module); setPanel(APP->window->loadSvg(asset::plugin(pluginInstance, "res/HostCV.svg"))); - - addChild(createWidget(Vec(RACK_GRID_WIDTH, 0))); - addChild(createWidget(Vec(box.size.x - 2 * RACK_GRID_WIDTH, 0))); - addChild(createWidget(Vec(RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH))); - addChild(createWidget(Vec(box.size.x - 2 * RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH))); + setSideScrews(); for (uint i=0; i(Vec(startX_In, startY + padding * i), module, i)); + createAndAddInput(i); for (uint i=0; i(Vec(startX_Out, startY + padding * i), module, i)); - } - - void drawTextLine(NVGcontext* const vg, const uint offset, const char* const text) - { - const float y = startY + offset * padding; - nvgBeginPath(vg); - nvgFillColor(vg, color::WHITE); - nvgText(vg, middleX, y + 16, text, nullptr); + createAndAddOutput(i); } void draw(const DrawArgs& args) override { - nvgBeginPath(args.vg); - nvgRect(args.vg, 0, 0, box.size.x, box.size.y); - nvgFillPaint(args.vg, nvgLinearGradient(args.vg, 0, 0, 0, box.size.y, - nvgRGB(0x18, 0x19, 0x19), nvgRGB(0x21, 0x22, 0x22))); - nvgFill(args.vg); - - nvgFontFaceId(args.vg, 0); - nvgFontSize(args.vg, 11); - nvgTextAlign(args.vg, NVG_ALIGN_CENTER); - - nvgBeginPath(args.vg); - nvgRoundedRect(args.vg, startX_Out - 2.5f, startY - 2.0f, padding, padding * HostCV::NUM_INPUTS, 4); - nvgFillColor(args.vg, nvgRGB(0xd0, 0xd0, 0xd0)); - nvgFill(args.vg); + drawBackground(args.vg); + drawOutputJacksArea(args.vg, HostCV::NUM_INPUTS); + setupTextLines(args.vg); drawTextLine(args.vg, 0, "CV 1"); drawTextLine(args.vg, 1, "CV 2"); @@ -158,7 +130,7 @@ struct HostCVWidget : ModuleWidget { drawTextLine(args.vg, 8, "CV 9"); drawTextLine(args.vg, 9, "CV 10"); - ModuleWidget::draw(args); + ModuleWidgetWith8HP::draw(args); } void appendContextMenu(ui::Menu* const menu) override diff --git a/plugins/Cardinal/src/HostMIDI-CC.cpp b/plugins/Cardinal/src/HostMIDI-CC.cpp index cf60dcf..3f92cbe 100644 --- a/plugins/Cardinal/src/HostMIDI-CC.cpp +++ b/plugins/Cardinal/src/HostMIDI-CC.cpp @@ -26,6 +26,7 @@ */ #include "plugincontext.hpp" +#include "Widgets.hpp" #include diff --git a/plugins/Cardinal/src/HostMIDI-Gate.cpp b/plugins/Cardinal/src/HostMIDI-Gate.cpp index 97b0dad..9877af2 100644 --- a/plugins/Cardinal/src/HostMIDI-Gate.cpp +++ b/plugins/Cardinal/src/HostMIDI-Gate.cpp @@ -26,6 +26,7 @@ */ #include "plugincontext.hpp" +#include "Widgets.hpp" #include diff --git a/plugins/Cardinal/src/HostMIDI-Map.cpp b/plugins/Cardinal/src/HostMIDI-Map.cpp index 7f59b01..a02f715 100644 --- a/plugins/Cardinal/src/HostMIDI-Map.cpp +++ b/plugins/Cardinal/src/HostMIDI-Map.cpp @@ -26,6 +26,7 @@ */ #include "plugincontext.hpp" +#include "Widgets.hpp" #include diff --git a/plugins/Cardinal/src/HostMIDI.cpp b/plugins/Cardinal/src/HostMIDI.cpp index 458973a..9fb8441 100644 --- a/plugins/Cardinal/src/HostMIDI.cpp +++ b/plugins/Cardinal/src/HostMIDI.cpp @@ -26,6 +26,7 @@ */ #include "plugincontext.hpp" +#include "ModuleWidgets.hpp" #include @@ -661,13 +662,7 @@ struct HostMIDI : Module { // -------------------------------------------------------------------------------------------------------------------- -struct HostMIDIWidget : ModuleWidget { - static constexpr const float startX_In = 14.0f; - static constexpr const float startX_Out = 96.0f; - static constexpr const float startY = 74.0f; - static constexpr const float padding = 29.0f; - static constexpr const float middleX = startX_In + (startX_Out - startX_In) * 0.5f + padding * 0.35f; - +struct HostMIDIWidget : ModuleWidgetWith9HP { HostMIDI* const module; HostMIDIWidget(HostMIDI* const m) @@ -675,57 +670,34 @@ struct HostMIDIWidget : ModuleWidget { { setModule(m); setPanel(APP->window->loadSvg(asset::plugin(pluginInstance, "res/HostMIDI.svg"))); + setSideScrews(); - addChild(createWidget(Vec(RACK_GRID_WIDTH, 0))); - addChild(createWidget(Vec(box.size.x - 2 * RACK_GRID_WIDTH, 0))); - addChild(createWidget(Vec(RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH))); - addChild(createWidget(Vec(box.size.x - 2 * RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH))); + createAndAddInput(0, HostMIDI::PITCH_INPUT); + createAndAddInput(1, HostMIDI::GATE_INPUT); + createAndAddInput(2, HostMIDI::VELOCITY_INPUT); + createAndAddInput(3, HostMIDI::AFTERTOUCH_INPUT); + createAndAddInput(4, HostMIDI::PITCHBEND_INPUT); + createAndAddInput(5, HostMIDI::MODWHEEL_INPUT); + createAndAddInput(6, HostMIDI::START_INPUT); + createAndAddInput(7, HostMIDI::STOP_INPUT); + createAndAddInput(8, HostMIDI::CONTINUE_INPUT); - addInput(createInput(Vec(startX_In, startY + padding * 0), m, HostMIDI::PITCH_INPUT)); - addInput(createInput(Vec(startX_In, startY + padding * 1), m, HostMIDI::GATE_INPUT)); - addInput(createInput(Vec(startX_In, startY + padding * 2), m, HostMIDI::VELOCITY_INPUT)); - addInput(createInput(Vec(startX_In, startY + padding * 3), m, HostMIDI::AFTERTOUCH_INPUT)); - addInput(createInput(Vec(startX_In, startY + padding * 4), m, HostMIDI::PITCHBEND_INPUT)); - addInput(createInput(Vec(startX_In, startY + padding * 5), m, HostMIDI::MODWHEEL_INPUT)); - addInput(createInput(Vec(startX_In, startY + padding * 6), m, HostMIDI::START_INPUT)); - addInput(createInput(Vec(startX_In, startY + padding * 7), m, HostMIDI::STOP_INPUT)); - addInput(createInput(Vec(startX_In, startY + padding * 8), m, HostMIDI::CONTINUE_INPUT)); - - addOutput(createOutput(Vec(startX_Out, startY + padding * 0), m, HostMIDI::PITCH_OUTPUT)); - addOutput(createOutput(Vec(startX_Out, startY + padding * 1), m, HostMIDI::GATE_OUTPUT)); - addOutput(createOutput(Vec(startX_Out, startY + padding * 2), m, HostMIDI::VELOCITY_OUTPUT)); - addOutput(createOutput(Vec(startX_Out, startY + padding * 3), m, HostMIDI::AFTERTOUCH_OUTPUT)); - addOutput(createOutput(Vec(startX_Out, startY + padding * 4), m, HostMIDI::PITCHBEND_OUTPUT)); - addOutput(createOutput(Vec(startX_Out, startY + padding * 5), m, HostMIDI::MODWHEEL_OUTPUT)); - addOutput(createOutput(Vec(startX_Out, startY + padding * 6), m, HostMIDI::START_OUTPUT)); - addOutput(createOutput(Vec(startX_Out, startY + padding * 7), m, HostMIDI::STOP_OUTPUT)); - addOutput(createOutput(Vec(startX_Out, startY + padding * 8), m, HostMIDI::CONTINUE_OUTPUT)); - } - - void drawTextLine(NVGcontext* const vg, const uint posY, const char* const text) - { - const float y = startY + posY * padding; - nvgBeginPath(vg); - nvgFillColor(vg, color::WHITE); - nvgText(vg, middleX, y + 16, text, nullptr); + createAndAddOutput(0, HostMIDI::PITCH_OUTPUT); + createAndAddOutput(1, HostMIDI::GATE_OUTPUT); + createAndAddOutput(2, HostMIDI::VELOCITY_OUTPUT); + createAndAddOutput(3, HostMIDI::AFTERTOUCH_OUTPUT); + createAndAddOutput(4, HostMIDI::PITCHBEND_OUTPUT); + createAndAddOutput(5, HostMIDI::MODWHEEL_OUTPUT); + createAndAddOutput(6, HostMIDI::START_OUTPUT); + createAndAddOutput(7, HostMIDI::STOP_OUTPUT); + createAndAddOutput(8, HostMIDI::CONTINUE_OUTPUT); } void draw(const DrawArgs& args) override { - nvgBeginPath(args.vg); - nvgRect(args.vg, 0, 0, box.size.x, box.size.y); - nvgFillPaint(args.vg, nvgLinearGradient(args.vg, 0, 0, 0, box.size.y, - nvgRGB(0x18, 0x19, 0x19), nvgRGB(0x21, 0x22, 0x22))); - nvgFill(args.vg); - - nvgFontFaceId(args.vg, 0); - nvgFontSize(args.vg, 11); - nvgTextAlign(args.vg, NVG_ALIGN_CENTER); - - nvgBeginPath(args.vg); - nvgRoundedRect(args.vg, startX_Out - 2.5f, startY - 2.0f, padding, padding * 9, 4); - nvgFillColor(args.vg, nvgRGB(0xd0, 0xd0, 0xd0)); - nvgFill(args.vg); + drawBackground(args.vg); + drawOutputJacksArea(args.vg, 9); + setupTextLines(args.vg); drawTextLine(args.vg, 0, "V/Oct"); drawTextLine(args.vg, 1, "Gate"); @@ -737,7 +709,7 @@ struct HostMIDIWidget : ModuleWidget { drawTextLine(args.vg, 7, "Stop"); drawTextLine(args.vg, 8, "Cont"); - ModuleWidget::draw(args); + ModuleWidgetWith9HP::draw(args); } void appendContextMenu(Menu* const menu) override diff --git a/plugins/Cardinal/src/HostTime.cpp b/plugins/Cardinal/src/HostTime.cpp index 7a62ed2..3d84828 100644 --- a/plugins/Cardinal/src/HostTime.cpp +++ b/plugins/Cardinal/src/HostTime.cpp @@ -1,6 +1,6 @@ /* * DISTRHO Cardinal Plugin - * Copyright (C) 2021 Filipe Coelho + * Copyright (C) 2021-2022 Filipe Coelho * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as diff --git a/plugins/Cardinal/src/ImGuiWidget.hpp b/plugins/Cardinal/src/ImGuiWidget.hpp index 778069f..c3c61b4 100644 --- a/plugins/Cardinal/src/ImGuiWidget.hpp +++ b/plugins/Cardinal/src/ImGuiWidget.hpp @@ -17,7 +17,7 @@ #pragma once -#include "plugin.hpp" +#include "Widgets.hpp" #include "DearImGui/imgui.h" struct ImGuiWidget : OpenGlWidgetWithBrowserPreview { diff --git a/plugins/Cardinal/src/ModuleWidgets.hpp b/plugins/Cardinal/src/ModuleWidgets.hpp new file mode 100644 index 0000000..91d532d --- /dev/null +++ b/plugins/Cardinal/src/ModuleWidgets.hpp @@ -0,0 +1,90 @@ +/* + * DISTRHO Cardinal Plugin + * Copyright (C) 2021-2022 Filipe Coelho + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 3 of + * the License, or any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * For a full copy of the GNU General Public License see the LICENSE file. + */ + +#pragma once + +#include "rack.hpp" + +#ifdef NDEBUG +# undef DEBUG +#endif + +using namespace rack; + +template +struct ModuleWidgetWithSideScrews : ModuleWidget { + static constexpr const float startX_In = 14.0f; + static constexpr const float startY = 74.0f; + static constexpr const float padding = 29.0f; + static constexpr const float middleX = startX_In + (startX_Out - startX_In) * 0.5f + padding * 0.35f; + + void setSideScrews() { + addChild(createWidget(Vec(RACK_GRID_WIDTH, 0))); + addChild(createWidget(Vec(box.size.x - 2 * RACK_GRID_WIDTH, 0))); + addChild(createWidget(Vec(RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH))); + addChild(createWidget(Vec(box.size.x - 2 * RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH))); + } + + void setupTextLines(NVGcontext* const vg) { + nvgBeginPath(vg); + nvgRect(vg, startX_Out - 2.5f, startY - 2.0f, padding, padding); + nvgFontFaceId(vg, 0); + nvgFontSize(vg, 11); + nvgTextAlign(vg, NVG_ALIGN_CENTER); + } + + void createAndAddInput(const uint paramId) { + createAndAddInput(paramId, paramId); + } + + void createAndAddInput(const uint posY, const uint paramId) { + addInput(createInput(Vec(startX_In, startY + padding * posY), module, paramId)); + } + + void createAndAddOutput(const uint paramId) { + createAndAddOutput(paramId, paramId); + } + + void createAndAddOutput(const uint posY, const uint paramId) { + addOutput(createOutput(Vec(startX_Out, startY + padding * posY), module, paramId)); + } + + void drawBackground(NVGcontext* const vg) { + nvgBeginPath(vg); + nvgRect(vg, 0, 0, box.size.x, box.size.y); + nvgFillPaint(vg, nvgLinearGradient(vg, 0, 0, 0, box.size.y, + nvgRGB(0x18, 0x19, 0x19), nvgRGB(0x21, 0x22, 0x22))); + nvgFill(vg); + } + + void drawOutputJacksArea(NVGcontext* const vg, const int numOutputs) { + nvgBeginPath(vg); + nvgRoundedRect(vg, startX_Out - 2.5f, startY - 2.0f, padding, padding * numOutputs, 4); + nvgFillColor(vg, nvgRGB(0xd0, 0xd0, 0xd0)); + nvgFill(vg); + } + + void drawTextLine(NVGcontext* const vg, const uint posY, const char* const text) { + const float y = startY + posY * padding; + nvgBeginPath(vg); + nvgFillColor(vg, color::WHITE); + nvgText(vg, middleX, y + 16, text, nullptr); + } +}; + +typedef ModuleWidgetWithSideScrews<81> ModuleWidgetWith8HP; +typedef ModuleWidgetWithSideScrews<96> ModuleWidgetWith9HP; diff --git a/plugins/Cardinal/src/Widgets.hpp b/plugins/Cardinal/src/Widgets.hpp new file mode 100644 index 0000000..6906749 --- /dev/null +++ b/plugins/Cardinal/src/Widgets.hpp @@ -0,0 +1,398 @@ +/* + * DISTRHO Cardinal Plugin + * Copyright (C) 2021-2022 Filipe Coelho + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 3 of + * the License, or any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * For a full copy of the GNU General Public License see the LICENSE file. + */ + +#pragma once + +#include "rack.hpp" + +#ifdef NDEBUG +# undef DEBUG +#endif + +using namespace rack; + +struct CardinalLedDisplayChoice : LedDisplayChoice { + bool alignTextCenter = true; + + CardinalLedDisplayChoice(const char* const label = nullptr) + { + color = nvgRGBf(0.76f, 0.11f, 0.22f); + textOffset.y -= 4; + + if (label != nullptr) + text = label; + } + + void drawLayer(const DrawArgs& args, const int layer) override + { + if (layer == 1) + { + nvgFillColor(args.vg, color); + nvgTextLetterSpacing(args.vg, 0.0f); + + if (alignTextCenter) + { + nvgTextAlign(args.vg, NVG_ALIGN_CENTER); + nvgText(args.vg, box.size.x * 0.5f, textOffset.y, text.c_str(), nullptr); + } + else + { + nvgTextAlign(args.vg, NVG_ALIGN_LEFT); + nvgText(args.vg, textOffset.x, textOffset.y, text.c_str(), nullptr); + } + } + + Widget::drawLayer(args, layer); + } +}; + +struct NanoKnob : Knob { + static const int ringSize = 4; + + std::string displayLabel = "Level"; + std::string displayString = "0 dB"; + float normalizedValue = 0.5f; + + NanoKnob() + { + box.size = Vec(100, 100); + } + + void drawLayer(const DrawArgs& args, int layer) override + { + if (layer != 1) + return Knob::drawLayer(args, layer); + + const float w = box.size.x; + const float h = box.size.y; + + const int knobSize = std::min(w, h - BND_WIDGET_HEIGHT * 2) - ringSize; + + const int knobStartX = w / 2 - knobSize / 2; + const int knobStartY = ringSize; + const int knobCenterX = knobStartX + knobSize / 2; + const int knobCenterY = knobStartY + knobSize / 2; + + const NVGcolor testing = nvgRGBf(0.76f, 0.11f, 0.22f); + + nvgLineCap(args.vg, NVG_ROUND); + + // outer ring value + nvgBeginPath(args.vg); + nvgArc(args.vg, + knobCenterX, + knobCenterY, + knobSize / 2 + ringSize / 2 + 1, + nvgDegToRad(135.0f), + nvgDegToRad(135.0f) + nvgDegToRad(270.0f * normalizedValue), + NVG_CW); + nvgStrokeWidth(args.vg, ringSize); + nvgStrokeColor(args.vg, testing); + nvgStroke(args.vg); + + // simulate color bleeding + nvgBeginPath(args.vg); + nvgArc(args.vg, + knobCenterX, + knobCenterY, + knobSize / 2 - 3, + nvgDegToRad(135.0f), + nvgDegToRad(135.0f) + nvgDegToRad(270.0f * normalizedValue), + NVG_CW); + nvgStrokeWidth(args.vg, 5); + nvgStrokeColor(args.vg, nvgRGBAf(testing.r, testing.g, testing.b, 0.1f)); + nvgStroke(args.vg); + + // line indicator + nvgStrokeWidth(args.vg, 2); + nvgSave(args.vg); + nvgTranslate(args.vg, knobCenterX, knobCenterY); + nvgRotate(args.vg, nvgDegToRad(45.0f) + normalizedValue * nvgDegToRad(270.0f)); + nvgBeginPath(args.vg); + nvgRoundedRect(args.vg, -2, knobSize / 2 - 9, 2, 6, 1); + nvgClosePath(args.vg); + nvgFillColor(args.vg, nvgRGBf(1.0f, 1.0f, 1.0f)); + nvgFill(args.vg); + nvgRestore(args.vg); + + // adjusted from VCVRack's LightWidget.cpp + if (const float halo = settings::haloBrightness) + { + float radius = knobSize * 0.5f; + float oradius = radius + std::min(radius * 4.f, 15.f); + + NVGcolor icol = color::mult(nvgRGBAf(testing.r, testing.g, testing.b, 0.2f), halo); + NVGcolor ocol = nvgRGBA(0, 0, 0, 0); + NVGpaint paint = nvgRadialGradient(args.vg, knobCenterX, knobCenterY, radius, oradius, icol, ocol); + + nvgBeginPath(args.vg); + nvgRect(args.vg, knobCenterX - oradius, knobCenterY - oradius, 2 * oradius, 2 * oradius); + nvgFillPaint(args.vg, paint); + nvgFill(args.vg); + } + + // bottom label (value) + bndIconLabelValue(args.vg, 0, knobSize + ringSize, w, BND_WIDGET_HEIGHT, -1, + testing, BND_CENTER, + BND_LABEL_FONT_SIZE, displayString.c_str(), nullptr); + + Knob::drawLayer(args, layer); + } + + void draw(const DrawArgs& args) override + { + if (engine::ParamQuantity* const pq = getParamQuantity()) + normalizedValue = pq->getScaledValue(); + + const float w = box.size.x; + const float h = box.size.y; + + const int knobSize = std::min(w, h - BND_WIDGET_HEIGHT * 2) - ringSize; + + const int knobStartX = w / 2 - knobSize / 2; + const int knobStartY = ringSize; + const int knobCenterX = knobStartX + knobSize / 2; + const int knobCenterY = knobStartY + knobSize / 2; + + // knob + NVGcolor shade_top; + NVGcolor shade_down; + BNDwidgetState state; + if (APP->event->getDraggedWidget() == this) + state = BND_ACTIVE; + else if (APP->event->getHoveredWidget() == this) + state = BND_HOVER; + else + state = BND_DEFAULT; + bndInnerColors(&shade_top, &shade_down, &bndGetTheme()->optionTheme, state, 0); + + // inner fill + nvgBeginPath(args.vg); + nvgCircle(args.vg, knobCenterX, knobCenterY, knobSize / 2); + nvgFillPaint(args.vg, nvgLinearGradient(args.vg, + knobStartX, + knobStartY, + knobStartX, + knobStartY + knobSize, + shade_top, + shade_down)); + nvgFill(args.vg); + + // inner fill border (inner) + nvgBeginPath(args.vg); + nvgArc(args.vg, knobCenterX, knobCenterY, knobSize / 2 - 1, nvgDegToRad(0.0f), nvgDegToRad(360.0f), NVG_CCW); + nvgClosePath(args.vg); + nvgStrokeWidth(args.vg, 1); + nvgStrokeColor(args.vg, nvgRGBAf(0.5f, 0.5f, 0.5f, 0.4f)); + nvgStroke(args.vg); + + // inner fill border (outer) + nvgBeginPath(args.vg); + nvgArc(args.vg, knobCenterX, knobCenterY, knobSize / 2, nvgDegToRad(0.0f), nvgDegToRad(360.0f), NVG_CCW); + nvgClosePath(args.vg); + nvgStrokeWidth(args.vg, 1); + nvgStrokeColor(args.vg, nvgRGBAf(0.0f, 0.0f, 0.0f, 0.4f)); + nvgStroke(args.vg); + + nvgLineCap(args.vg, NVG_ROUND); + + // outer ring background + nvgBeginPath(args.vg); + nvgArc(args.vg, + knobCenterX, + knobCenterY, + knobSize / 2 + ringSize / 2 + 1, + nvgDegToRad(135.0f), + nvgDegToRad(45.0f), + NVG_CW); + nvgStrokeWidth(args.vg, ringSize); + nvgStrokeColor(args.vg, nvgRGBf(0.5f, 0.5f, 0.5f)); + nvgStroke(args.vg); + + // bottom label (name) + bndIconLabelValue(args.vg, 0, knobStartY + knobSize + BND_WIDGET_HEIGHT * 0.75f, w, BND_WIDGET_HEIGHT, -1, + SCHEME_WHITE, BND_CENTER, + BND_LABEL_FONT_SIZE, displayLabel.c_str(), nullptr); + + Knob::draw(args); + } + + void onChange(const ChangeEvent&) override + { + engine::ParamQuantity* const pq = getParamQuantity(); + DISTRHO_SAFE_ASSERT_RETURN(pq != nullptr,); + + displayLabel = pq->getLabel(); + displayString = pq->getDisplayValueString() + pq->getUnit(); + } +}; + +struct NanoMeter : Widget { + float gainMeterL = 0.0f; + float gainMeterR = 0.0f; + + virtual void updateMeters() = 0; + + void drawLayer(const DrawArgs& args, int layer) override + { + if (layer != 1) + return; + + const float usableHeight = box.size.y - 10.0f; + + // draw background + nvgBeginPath(args.vg); + nvgRect(args.vg, + 0, + 0, + box.size.x, + usableHeight); + nvgFillColor(args.vg, nvgRGB(26, 26, 26)); + nvgFill(args.vg); + + nvgFillColor(args.vg, nvgRGBAf(0.76f, 0.11f, 0.22f, 0.5f)); + nvgStrokeColor(args.vg, nvgRGBf(0.76f, 0.11f, 0.22f)); + + updateMeters(); + + const float heightL = 1.0f + std::sqrt(gainMeterL) * (usableHeight - 1.0f); + nvgBeginPath(args.vg); + nvgRect(args.vg, 0.0f, usableHeight - heightL, box.size.x * 0.5f - 1.0f, heightL); + nvgFill(args.vg); + nvgStroke(args.vg); + + const float heightR = 1.0f + std::sqrt(gainMeterR) * (usableHeight - 1.0f); + nvgBeginPath(args.vg); + nvgRect(args.vg, box.size.x * 0.5f + 1.0f, usableHeight - heightR, box.size.x * 0.5f - 2.0f, heightR); + nvgFill(args.vg); + nvgStroke(args.vg); + + nvgLineCap(args.vg, NVG_ROUND); + + nvgBeginPath(args.vg); + nvgMoveTo(args.vg, 0.0f, usableHeight + 2.0f); + nvgLineTo(args.vg, box.size.x * 0.5f - 11.0f, usableHeight + 2.0f); + nvgStroke(args.vg); + + nvgBeginPath(args.vg); + nvgMoveTo(args.vg, 0.0f, usableHeight + 4.0f); + nvgLineTo(args.vg, box.size.x * 0.5f - 16.0f, usableHeight + 4.0f); + nvgStroke(args.vg); + + nvgBeginPath(args.vg); + nvgMoveTo(args.vg, 0.0f, usableHeight + 6.0f); + nvgLineTo(args.vg, box.size.x * 0.5f - 19.0f, usableHeight + 6.0f); + nvgStroke(args.vg); + + nvgBeginPath(args.vg); + nvgMoveTo(args.vg, 0.0f, usableHeight + 8.0f); + nvgLineTo(args.vg, box.size.x * 0.5f - 22.0f, usableHeight + 8.0f); + nvgStroke(args.vg); + + nvgBeginPath(args.vg); + nvgMoveTo(args.vg, 0.0f, usableHeight + 10.0f); + nvgLineTo(args.vg, box.size.x * 0.5f - 24.0f, usableHeight + 10.0f); + nvgStroke(args.vg); + + nvgBeginPath(args.vg); + nvgMoveTo(args.vg, 0.0f, usableHeight + 12.0f); + nvgLineTo(args.vg, box.size.x * 0.5f - 26.0f, usableHeight + 12.0f); + nvgStroke(args.vg); + + nvgBeginPath(args.vg); + nvgMoveTo(args.vg, box.size.x * 0.5f + 10.0f, usableHeight + 2.0f); + nvgLineTo(args.vg, box.size.x - 1.0f, usableHeight + 2.0f); + nvgStroke(args.vg); + + nvgBeginPath(args.vg); + nvgMoveTo(args.vg, box.size.x * 0.5f + 15.0f, usableHeight + 4.0f); + nvgLineTo(args.vg, box.size.x - 1.0f, usableHeight + 4.0f); + nvgStroke(args.vg); + + nvgBeginPath(args.vg); + nvgMoveTo(args.vg, box.size.x * 0.5f + 18.0f, usableHeight + 6.0f); + nvgLineTo(args.vg, box.size.x - 1.0f, usableHeight + 6.0f); + nvgStroke(args.vg); + + nvgBeginPath(args.vg); + nvgMoveTo(args.vg, box.size.x * 0.5f + 20.0f, usableHeight + 8.0f); + nvgLineTo(args.vg, box.size.x - 1.0f, usableHeight + 8.0f); + nvgStroke(args.vg); + + nvgBeginPath(args.vg); + nvgMoveTo(args.vg, box.size.x * 0.5f + 22.0f, usableHeight + 10.0f); + nvgLineTo(args.vg, box.size.x - 1.0f, usableHeight + 10.0f); + nvgStroke(args.vg); + + nvgBeginPath(args.vg); + nvgMoveTo(args.vg, box.size.x * 0.5f + 24.0f, usableHeight + 12.0f); + nvgLineTo(args.vg, box.size.x - 1.0f, usableHeight + 12.0f); + nvgStroke(args.vg); + } +}; + +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; +}; diff --git a/plugins/Cardinal/src/glBars.cpp b/plugins/Cardinal/src/glBars.cpp index 2ebfc45..979f9f5 100644 --- a/plugins/Cardinal/src/glBars.cpp +++ b/plugins/Cardinal/src/glBars.cpp @@ -17,6 +17,7 @@ #ifndef HEADLESS # include "glBars.hpp" +# include "Widgets.hpp" #else # include "plugin.hpp" #endif diff --git a/plugins/Cardinal/src/plugin.hpp b/plugins/Cardinal/src/plugin.hpp index 6fac5ed..6aee084 100644 --- a/plugins/Cardinal/src/plugin.hpp +++ b/plugins/Cardinal/src/plugin.hpp @@ -25,95 +25,6 @@ using namespace rack; -#ifndef HEADLESS -struct CardinalLedDisplayChoice : LedDisplayChoice { - bool alignTextCenter = true; - - CardinalLedDisplayChoice(const char* const label = nullptr) - { - color = nvgRGBf(0.76f, 0.11f, 0.22f); - textOffset.y -= 4; - - if (label != nullptr) - text = label; - } - - void drawLayer(const DrawArgs& args, const int layer) override - { - if (layer == 1) - { - nvgFillColor(args.vg, color); - nvgTextLetterSpacing(args.vg, 0.0f); - - if (alignTextCenter) - { - nvgTextAlign(args.vg, NVG_ALIGN_CENTER); - nvgText(args.vg, box.size.x * 0.5f, textOffset.y, text.c_str(), nullptr); - } - else - { - nvgTextAlign(args.vg, NVG_ALIGN_LEFT); - nvgText(args.vg, textOffset.x, textOffset.y, text.c_str(), nullptr); - } - } - - Widget::drawLayer(args, layer); - } -}; - -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;