Move some common code to new header files
This commit is contained in:
parent
5c3367299e
commit
6bbdf9a63d
13 changed files with 561 additions and 551 deletions
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* DISTRHO Cardinal Plugin
|
* DISTRHO Cardinal Plugin
|
||||||
* Copyright (C) 2021 Filipe Coelho <falktx@falktx.com>
|
* Copyright (C) 2021-2022 Filipe Coelho <falktx@falktx.com>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or
|
* This program is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU General Public License as
|
* modify it under the terms of the GNU General Public License as
|
||||||
|
@ -16,6 +16,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "plugincontext.hpp"
|
#include "plugincontext.hpp"
|
||||||
|
#include "ModuleWidgets.hpp"
|
||||||
|
|
||||||
#include "CarlaNativePlugin.h"
|
#include "CarlaNativePlugin.h"
|
||||||
#include "CarlaBackendUtils.hpp"
|
#include "CarlaBackendUtils.hpp"
|
||||||
|
@ -442,34 +443,23 @@ static intptr_t host_dispatcher(const NativeHostHandle handle, const NativeHostD
|
||||||
// --------------------------------------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
#ifndef HEADLESS
|
#ifndef HEADLESS
|
||||||
struct CarlaModuleWidget : ModuleWidget, IdleCallback {
|
struct CarlaModuleWidget : ModuleWidgetWith9HP, 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;
|
|
||||||
|
|
||||||
CarlaModule* const module;
|
CarlaModule* const module;
|
||||||
bool idleCallbackActive = false;
|
bool idleCallbackActive = false;
|
||||||
bool visible = false;
|
bool visible = false;
|
||||||
|
|
||||||
CarlaModuleWidget(CarlaModule* const m)
|
CarlaModuleWidget(CarlaModule* const m)
|
||||||
: ModuleWidget(),
|
: module(m)
|
||||||
module(m)
|
|
||||||
{
|
{
|
||||||
setModule(module);
|
setModule(module);
|
||||||
setPanel(APP->window->loadSvg(asset::plugin(pluginInstance, "res/Carla.svg")));
|
setPanel(APP->window->loadSvg(asset::plugin(pluginInstance, "res/Carla.svg")));
|
||||||
|
setSideScrews();
|
||||||
addChild(createWidget<ScrewBlack>(Vec(RACK_GRID_WIDTH, 0)));
|
|
||||||
addChild(createWidget<ScrewBlack>(Vec(box.size.x - 2 * RACK_GRID_WIDTH, 0)));
|
|
||||||
addChild(createWidget<ScrewBlack>(Vec(RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH)));
|
|
||||||
addChild(createWidget<ScrewBlack>(Vec(box.size.x - 2 * RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH)));
|
|
||||||
|
|
||||||
for (uint i=0; i<CarlaModule::NUM_INPUTS; ++i)
|
for (uint i=0; i<CarlaModule::NUM_INPUTS; ++i)
|
||||||
addInput(createInput<PJ301MPort>(Vec(startX_In, startY + padding * i), module, i));
|
createAndAddInput(i);
|
||||||
|
|
||||||
for (uint i=0; i<CarlaModule::NUM_OUTPUTS; ++i)
|
for (uint i=0; i<CarlaModule::NUM_OUTPUTS; ++i)
|
||||||
addOutput(createOutput<PJ301MPort>(Vec(startX_Out, startY + padding * i), module, i));
|
createAndAddOutput(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
~CarlaModuleWidget() override
|
~CarlaModuleWidget() override
|
||||||
|
@ -565,30 +555,11 @@ struct CarlaModuleWidget : ModuleWidget, IdleCallback {
|
||||||
module->fCarlaPluginDescriptor->ui_idle(module->fCarlaPluginHandle);
|
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
|
void draw(const DrawArgs& args) override
|
||||||
{
|
{
|
||||||
nvgBeginPath(args.vg);
|
drawBackground(args.vg);
|
||||||
nvgRect(args.vg, 0, 0, box.size.x, box.size.y);
|
drawOutputJacksArea(args.vg, CarlaModule::NUM_INPUTS);
|
||||||
nvgFillPaint(args.vg, nvgLinearGradient(args.vg, 0, 0, 0, box.size.y,
|
setupTextLines(args.vg);
|
||||||
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);
|
|
||||||
|
|
||||||
drawTextLine(args.vg, 0, "Audio 1");
|
drawTextLine(args.vg, 0, "Audio 1");
|
||||||
drawTextLine(args.vg, 1, "Audio 2");
|
drawTextLine(args.vg, 1, "Audio 2");
|
||||||
|
@ -601,7 +572,7 @@ struct CarlaModuleWidget : ModuleWidget, IdleCallback {
|
||||||
drawTextLine(args.vg, 8, "CV 7");
|
drawTextLine(args.vg, 8, "CV 7");
|
||||||
drawTextLine(args.vg, 9, "CV 8");
|
drawTextLine(args.vg, 9, "CV 8");
|
||||||
|
|
||||||
ModuleWidget::draw(args);
|
ModuleWidgetWith9HP::draw(args);
|
||||||
}
|
}
|
||||||
|
|
||||||
void showUI()
|
void showUI()
|
||||||
|
|
|
@ -16,192 +16,13 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "plugincontext.hpp"
|
#include "plugincontext.hpp"
|
||||||
|
#include "ModuleWidgets.hpp"
|
||||||
|
#include "Widgets.hpp"
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
USE_NAMESPACE_DISTRHO;
|
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.
|
* Find the highest absolute and normalized value within a float array.
|
||||||
*/
|
*/
|
||||||
|
@ -365,132 +186,26 @@ struct HostAudio : Module {
|
||||||
};
|
};
|
||||||
|
|
||||||
template<int numIO>
|
template<int numIO>
|
||||||
struct NanoMeter : Widget {
|
struct HostAudioNanoMeter : NanoMeter {
|
||||||
HostAudio<numIO>* const module;
|
HostAudio<numIO>* const module;
|
||||||
float gainMeterL = 0.0f;
|
|
||||||
float gainMeterR = 0.0f;
|
|
||||||
|
|
||||||
NanoMeter(HostAudio<numIO>* const m)
|
HostAudioNanoMeter(HostAudio<numIO>* const m)
|
||||||
: module(m)
|
: module(m) {}
|
||||||
{
|
|
||||||
box.size = Vec(100, 100);
|
|
||||||
}
|
|
||||||
|
|
||||||
void drawLayer(const DrawArgs& args, int layer) override
|
void updateMeters() override
|
||||||
{
|
{
|
||||||
if (layer != 1)
|
if (module == nullptr || module->resetMeters)
|
||||||
return;
|
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
|
// Only fetch new values once DSP side is updated
|
||||||
if (! module->resetMeters)
|
|
||||||
{
|
|
||||||
gainMeterL = module->gainMeterL;
|
gainMeterL = module->gainMeterL;
|
||||||
gainMeterR = module->gainMeterR;
|
gainMeterR = module->gainMeterR;
|
||||||
module->resetMeters = true;
|
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);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
template<int numIO>
|
template<int numIO>
|
||||||
struct HostAudioWidget : ModuleWidget {
|
struct HostAudioWidget : ModuleWidgetWith8HP {
|
||||||
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;
|
|
||||||
|
|
||||||
HostAudio<numIO>* const module;
|
HostAudio<numIO>* const module;
|
||||||
|
|
||||||
HostAudioWidget(HostAudio<numIO>* const m)
|
HostAudioWidget(HostAudio<numIO>* const m)
|
||||||
|
@ -498,53 +213,30 @@ struct HostAudioWidget : ModuleWidget {
|
||||||
{
|
{
|
||||||
setModule(m);
|
setModule(m);
|
||||||
setPanel(APP->window->loadSvg(asset::plugin(pluginInstance, "res/HostAudio.svg")));
|
setPanel(APP->window->loadSvg(asset::plugin(pluginInstance, "res/HostAudio.svg")));
|
||||||
|
setSideScrews();
|
||||||
addChild(createWidget<ScrewBlack>(Vec(RACK_GRID_WIDTH, 0)));
|
|
||||||
addChild(createWidget<ScrewBlack>(Vec(box.size.x - 2 * RACK_GRID_WIDTH, 0)));
|
|
||||||
addChild(createWidget<ScrewBlack>(Vec(RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH)));
|
|
||||||
addChild(createWidget<ScrewBlack>(Vec(box.size.x - 2 * RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH)));
|
|
||||||
|
|
||||||
for (uint i=0; i<numIO; ++i)
|
for (uint i=0; i<numIO; ++i)
|
||||||
addInput(createInput<PJ301MPort>(Vec(startX_In, startY + padding * i), m, i));
|
{
|
||||||
|
createAndAddInput(i);
|
||||||
for (uint i=0; i<numIO; ++i)
|
createAndAddOutput(i);
|
||||||
addOutput(createOutput<PJ301MPort>(Vec(startX_Out, startY + padding * i), m, i));
|
}
|
||||||
|
|
||||||
if (numIO == 2)
|
if (numIO == 2)
|
||||||
{
|
{
|
||||||
addParam(createParamCentered<NanoKnob>(Vec(middleX, 310.0f), m, 0));
|
addParam(createParamCentered<NanoKnob>(Vec(middleX, 310.0f), m, 0));
|
||||||
|
|
||||||
NanoMeter<numIO>* const meter = new NanoMeter<numIO>(m);
|
HostAudioNanoMeter<numIO>* const meter = new HostAudioNanoMeter<numIO>(m);
|
||||||
meter->box.pos = Vec(middleX - padding + 2.75f, startY + padding * 2);
|
meter->box.pos = Vec(middleX - padding + 2.75f, startY + padding * 2);
|
||||||
meter->box.size = Vec(padding * 2.0f - 4.0f, 136.0f);
|
meter->box.size = Vec(padding * 2.0f - 4.0f, 136.0f);
|
||||||
addChild(meter);
|
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
|
void draw(const DrawArgs& args) override
|
||||||
{
|
{
|
||||||
nvgBeginPath(args.vg);
|
drawBackground(args.vg);
|
||||||
nvgRect(args.vg, 0, 0, box.size.x, box.size.y);
|
drawOutputJacksArea(args.vg, numIO);
|
||||||
nvgFillPaint(args.vg, nvgLinearGradient(args.vg, 0, 0, 0, box.size.y,
|
setupTextLines(args.vg);
|
||||||
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);
|
|
||||||
|
|
||||||
if (numIO == 2)
|
if (numIO == 2)
|
||||||
{
|
{
|
||||||
|
@ -560,7 +252,7 @@ struct HostAudioWidget : ModuleWidget {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ModuleWidget::draw(args);
|
ModuleWidgetWith8HP::draw(args);
|
||||||
}
|
}
|
||||||
|
|
||||||
void appendContextMenu(Menu* const menu) override {
|
void appendContextMenu(Menu* const menu) override {
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "plugincontext.hpp"
|
#include "plugincontext.hpp"
|
||||||
|
#include "ModuleWidgets.hpp"
|
||||||
|
|
||||||
#define CARDINAL_AUDIO_IO_OFFSET 8
|
#define CARDINAL_AUDIO_IO_OFFSET 8
|
||||||
|
|
||||||
|
@ -98,54 +99,25 @@ struct HostCV : Module {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct HostCVWidget : ModuleWidget {
|
struct HostCVWidget : ModuleWidgetWith8HP {
|
||||||
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;
|
|
||||||
|
|
||||||
HostCVWidget(HostCV* const module)
|
HostCVWidget(HostCV* const module)
|
||||||
{
|
{
|
||||||
setModule(module);
|
setModule(module);
|
||||||
setPanel(APP->window->loadSvg(asset::plugin(pluginInstance, "res/HostCV.svg")));
|
setPanel(APP->window->loadSvg(asset::plugin(pluginInstance, "res/HostCV.svg")));
|
||||||
|
setSideScrews();
|
||||||
addChild(createWidget<ScrewBlack>(Vec(RACK_GRID_WIDTH, 0)));
|
|
||||||
addChild(createWidget<ScrewBlack>(Vec(box.size.x - 2 * RACK_GRID_WIDTH, 0)));
|
|
||||||
addChild(createWidget<ScrewBlack>(Vec(RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH)));
|
|
||||||
addChild(createWidget<ScrewBlack>(Vec(box.size.x - 2 * RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH)));
|
|
||||||
|
|
||||||
for (uint i=0; i<HostCV::NUM_INPUTS; ++i)
|
for (uint i=0; i<HostCV::NUM_INPUTS; ++i)
|
||||||
addInput(createInput<PJ301MPort>(Vec(startX_In, startY + padding * i), module, i));
|
createAndAddInput(i);
|
||||||
|
|
||||||
for (uint i=0; i<HostCV::NUM_OUTPUTS; ++i)
|
for (uint i=0; i<HostCV::NUM_OUTPUTS; ++i)
|
||||||
addOutput(createOutput<PJ301MPort>(Vec(startX_Out, startY + padding * i), module, i));
|
createAndAddOutput(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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void draw(const DrawArgs& args) override
|
void draw(const DrawArgs& args) override
|
||||||
{
|
{
|
||||||
nvgBeginPath(args.vg);
|
drawBackground(args.vg);
|
||||||
nvgRect(args.vg, 0, 0, box.size.x, box.size.y);
|
drawOutputJacksArea(args.vg, HostCV::NUM_INPUTS);
|
||||||
nvgFillPaint(args.vg, nvgLinearGradient(args.vg, 0, 0, 0, box.size.y,
|
setupTextLines(args.vg);
|
||||||
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);
|
|
||||||
|
|
||||||
drawTextLine(args.vg, 0, "CV 1");
|
drawTextLine(args.vg, 0, "CV 1");
|
||||||
drawTextLine(args.vg, 1, "CV 2");
|
drawTextLine(args.vg, 1, "CV 2");
|
||||||
|
@ -158,7 +130,7 @@ struct HostCVWidget : ModuleWidget {
|
||||||
drawTextLine(args.vg, 8, "CV 9");
|
drawTextLine(args.vg, 8, "CV 9");
|
||||||
drawTextLine(args.vg, 9, "CV 10");
|
drawTextLine(args.vg, 9, "CV 10");
|
||||||
|
|
||||||
ModuleWidget::draw(args);
|
ModuleWidgetWith8HP::draw(args);
|
||||||
}
|
}
|
||||||
|
|
||||||
void appendContextMenu(ui::Menu* const menu) override
|
void appendContextMenu(ui::Menu* const menu) override
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "plugincontext.hpp"
|
#include "plugincontext.hpp"
|
||||||
|
#include "Widgets.hpp"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "plugincontext.hpp"
|
#include "plugincontext.hpp"
|
||||||
|
#include "Widgets.hpp"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "plugincontext.hpp"
|
#include "plugincontext.hpp"
|
||||||
|
#include "Widgets.hpp"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "plugincontext.hpp"
|
#include "plugincontext.hpp"
|
||||||
|
#include "ModuleWidgets.hpp"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
|
@ -661,13 +662,7 @@ struct HostMIDI : Module {
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
struct HostMIDIWidget : ModuleWidget {
|
struct HostMIDIWidget : ModuleWidgetWith9HP {
|
||||||
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;
|
|
||||||
|
|
||||||
HostMIDI* const module;
|
HostMIDI* const module;
|
||||||
|
|
||||||
HostMIDIWidget(HostMIDI* const m)
|
HostMIDIWidget(HostMIDI* const m)
|
||||||
|
@ -675,57 +670,34 @@ struct HostMIDIWidget : ModuleWidget {
|
||||||
{
|
{
|
||||||
setModule(m);
|
setModule(m);
|
||||||
setPanel(APP->window->loadSvg(asset::plugin(pluginInstance, "res/HostMIDI.svg")));
|
setPanel(APP->window->loadSvg(asset::plugin(pluginInstance, "res/HostMIDI.svg")));
|
||||||
|
setSideScrews();
|
||||||
|
|
||||||
addChild(createWidget<ScrewBlack>(Vec(RACK_GRID_WIDTH, 0)));
|
createAndAddInput(0, HostMIDI::PITCH_INPUT);
|
||||||
addChild(createWidget<ScrewBlack>(Vec(box.size.x - 2 * RACK_GRID_WIDTH, 0)));
|
createAndAddInput(1, HostMIDI::GATE_INPUT);
|
||||||
addChild(createWidget<ScrewBlack>(Vec(RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH)));
|
createAndAddInput(2, HostMIDI::VELOCITY_INPUT);
|
||||||
addChild(createWidget<ScrewBlack>(Vec(box.size.x - 2 * RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH)));
|
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<PJ301MPort>(Vec(startX_In, startY + padding * 0), m, HostMIDI::PITCH_INPUT));
|
createAndAddOutput(0, HostMIDI::PITCH_OUTPUT);
|
||||||
addInput(createInput<PJ301MPort>(Vec(startX_In, startY + padding * 1), m, HostMIDI::GATE_INPUT));
|
createAndAddOutput(1, HostMIDI::GATE_OUTPUT);
|
||||||
addInput(createInput<PJ301MPort>(Vec(startX_In, startY + padding * 2), m, HostMIDI::VELOCITY_INPUT));
|
createAndAddOutput(2, HostMIDI::VELOCITY_OUTPUT);
|
||||||
addInput(createInput<PJ301MPort>(Vec(startX_In, startY + padding * 3), m, HostMIDI::AFTERTOUCH_INPUT));
|
createAndAddOutput(3, HostMIDI::AFTERTOUCH_OUTPUT);
|
||||||
addInput(createInput<PJ301MPort>(Vec(startX_In, startY + padding * 4), m, HostMIDI::PITCHBEND_INPUT));
|
createAndAddOutput(4, HostMIDI::PITCHBEND_OUTPUT);
|
||||||
addInput(createInput<PJ301MPort>(Vec(startX_In, startY + padding * 5), m, HostMIDI::MODWHEEL_INPUT));
|
createAndAddOutput(5, HostMIDI::MODWHEEL_OUTPUT);
|
||||||
addInput(createInput<PJ301MPort>(Vec(startX_In, startY + padding * 6), m, HostMIDI::START_INPUT));
|
createAndAddOutput(6, HostMIDI::START_OUTPUT);
|
||||||
addInput(createInput<PJ301MPort>(Vec(startX_In, startY + padding * 7), m, HostMIDI::STOP_INPUT));
|
createAndAddOutput(7, HostMIDI::STOP_OUTPUT);
|
||||||
addInput(createInput<PJ301MPort>(Vec(startX_In, startY + padding * 8), m, HostMIDI::CONTINUE_INPUT));
|
createAndAddOutput(8, HostMIDI::CONTINUE_OUTPUT);
|
||||||
|
|
||||||
addOutput(createOutput<PJ301MPort>(Vec(startX_Out, startY + padding * 0), m, HostMIDI::PITCH_OUTPUT));
|
|
||||||
addOutput(createOutput<PJ301MPort>(Vec(startX_Out, startY + padding * 1), m, HostMIDI::GATE_OUTPUT));
|
|
||||||
addOutput(createOutput<PJ301MPort>(Vec(startX_Out, startY + padding * 2), m, HostMIDI::VELOCITY_OUTPUT));
|
|
||||||
addOutput(createOutput<PJ301MPort>(Vec(startX_Out, startY + padding * 3), m, HostMIDI::AFTERTOUCH_OUTPUT));
|
|
||||||
addOutput(createOutput<PJ301MPort>(Vec(startX_Out, startY + padding * 4), m, HostMIDI::PITCHBEND_OUTPUT));
|
|
||||||
addOutput(createOutput<PJ301MPort>(Vec(startX_Out, startY + padding * 5), m, HostMIDI::MODWHEEL_OUTPUT));
|
|
||||||
addOutput(createOutput<PJ301MPort>(Vec(startX_Out, startY + padding * 6), m, HostMIDI::START_OUTPUT));
|
|
||||||
addOutput(createOutput<PJ301MPort>(Vec(startX_Out, startY + padding * 7), m, HostMIDI::STOP_OUTPUT));
|
|
||||||
addOutput(createOutput<PJ301MPort>(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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void draw(const DrawArgs& args) override
|
void draw(const DrawArgs& args) override
|
||||||
{
|
{
|
||||||
nvgBeginPath(args.vg);
|
drawBackground(args.vg);
|
||||||
nvgRect(args.vg, 0, 0, box.size.x, box.size.y);
|
drawOutputJacksArea(args.vg, 9);
|
||||||
nvgFillPaint(args.vg, nvgLinearGradient(args.vg, 0, 0, 0, box.size.y,
|
setupTextLines(args.vg);
|
||||||
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);
|
|
||||||
|
|
||||||
drawTextLine(args.vg, 0, "V/Oct");
|
drawTextLine(args.vg, 0, "V/Oct");
|
||||||
drawTextLine(args.vg, 1, "Gate");
|
drawTextLine(args.vg, 1, "Gate");
|
||||||
|
@ -737,7 +709,7 @@ struct HostMIDIWidget : ModuleWidget {
|
||||||
drawTextLine(args.vg, 7, "Stop");
|
drawTextLine(args.vg, 7, "Stop");
|
||||||
drawTextLine(args.vg, 8, "Cont");
|
drawTextLine(args.vg, 8, "Cont");
|
||||||
|
|
||||||
ModuleWidget::draw(args);
|
ModuleWidgetWith9HP::draw(args);
|
||||||
}
|
}
|
||||||
|
|
||||||
void appendContextMenu(Menu* const menu) override
|
void appendContextMenu(Menu* const menu) override
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* DISTRHO Cardinal Plugin
|
* DISTRHO Cardinal Plugin
|
||||||
* Copyright (C) 2021 Filipe Coelho <falktx@falktx.com>
|
* Copyright (C) 2021-2022 Filipe Coelho <falktx@falktx.com>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or
|
* This program is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU General Public License as
|
* modify it under the terms of the GNU General Public License as
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "plugin.hpp"
|
#include "Widgets.hpp"
|
||||||
#include "DearImGui/imgui.h"
|
#include "DearImGui/imgui.h"
|
||||||
|
|
||||||
struct ImGuiWidget : OpenGlWidgetWithBrowserPreview {
|
struct ImGuiWidget : OpenGlWidgetWithBrowserPreview {
|
||||||
|
|
90
plugins/Cardinal/src/ModuleWidgets.hpp
Normal file
90
plugins/Cardinal/src/ModuleWidgets.hpp
Normal file
|
@ -0,0 +1,90 @@
|
||||||
|
/*
|
||||||
|
* DISTRHO Cardinal Plugin
|
||||||
|
* Copyright (C) 2021-2022 Filipe Coelho <falktx@falktx.com>
|
||||||
|
*
|
||||||
|
* 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<int startX_Out>
|
||||||
|
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<ScrewBlack>(Vec(RACK_GRID_WIDTH, 0)));
|
||||||
|
addChild(createWidget<ScrewBlack>(Vec(box.size.x - 2 * RACK_GRID_WIDTH, 0)));
|
||||||
|
addChild(createWidget<ScrewBlack>(Vec(RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH)));
|
||||||
|
addChild(createWidget<ScrewBlack>(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<PJ301MPort>(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<PJ301MPort>(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;
|
398
plugins/Cardinal/src/Widgets.hpp
Normal file
398
plugins/Cardinal/src/Widgets.hpp
Normal file
|
@ -0,0 +1,398 @@
|
||||||
|
/*
|
||||||
|
* DISTRHO Cardinal Plugin
|
||||||
|
* Copyright (C) 2021-2022 Filipe Coelho <falktx@falktx.com>
|
||||||
|
*
|
||||||
|
* 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;
|
||||||
|
};
|
|
@ -17,6 +17,7 @@
|
||||||
|
|
||||||
#ifndef HEADLESS
|
#ifndef HEADLESS
|
||||||
# include "glBars.hpp"
|
# include "glBars.hpp"
|
||||||
|
# include "Widgets.hpp"
|
||||||
#else
|
#else
|
||||||
# include "plugin.hpp"
|
# include "plugin.hpp"
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -25,95 +25,6 @@
|
||||||
|
|
||||||
using namespace rack;
|
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 Plugin* pluginInstance;
|
||||||
|
|
||||||
extern Model* modelAudioFile;
|
extern Model* modelAudioFile;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue