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
|
||||
* 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
|
||||
* 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<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)));
|
||||
setSideScrews();
|
||||
|
||||
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)
|
||||
addOutput(createOutput<PJ301MPort>(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()
|
||||
|
|
|
@ -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<int numIO>
|
||||
struct NanoMeter : Widget {
|
||||
struct HostAudioNanoMeter : NanoMeter {
|
||||
HostAudio<numIO>* const module;
|
||||
float gainMeterL = 0.0f;
|
||||
float gainMeterR = 0.0f;
|
||||
|
||||
NanoMeter(HostAudio<numIO>* const m)
|
||||
: module(m)
|
||||
{
|
||||
box.size = Vec(100, 100);
|
||||
}
|
||||
HostAudioNanoMeter(HostAudio<numIO>* 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<int numIO>
|
||||
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<numIO>* const module;
|
||||
|
||||
HostAudioWidget(HostAudio<numIO>* const m)
|
||||
|
@ -498,53 +213,30 @@ struct HostAudioWidget : ModuleWidget {
|
|||
{
|
||||
setModule(m);
|
||||
setPanel(APP->window->loadSvg(asset::plugin(pluginInstance, "res/HostAudio.svg")));
|
||||
|
||||
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)));
|
||||
setSideScrews();
|
||||
|
||||
for (uint i=0; i<numIO; ++i)
|
||||
addInput(createInput<PJ301MPort>(Vec(startX_In, startY + padding * i), m, i));
|
||||
|
||||
for (uint i=0; i<numIO; ++i)
|
||||
addOutput(createOutput<PJ301MPort>(Vec(startX_Out, startY + padding * i), m, i));
|
||||
{
|
||||
createAndAddInput(i);
|
||||
createAndAddOutput(i);
|
||||
}
|
||||
|
||||
if (numIO == 2)
|
||||
{
|
||||
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.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 {
|
||||
|
|
|
@ -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<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)));
|
||||
setSideScrews();
|
||||
|
||||
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)
|
||||
addOutput(createOutput<PJ301MPort>(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
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
*/
|
||||
|
||||
#include "plugincontext.hpp"
|
||||
#include "Widgets.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
*/
|
||||
|
||||
#include "plugincontext.hpp"
|
||||
#include "Widgets.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
*/
|
||||
|
||||
#include "plugincontext.hpp"
|
||||
#include "Widgets.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
*/
|
||||
|
||||
#include "plugincontext.hpp"
|
||||
#include "ModuleWidgets.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
|
@ -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<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)));
|
||||
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<PJ301MPort>(Vec(startX_In, startY + padding * 0), m, HostMIDI::PITCH_INPUT));
|
||||
addInput(createInput<PJ301MPort>(Vec(startX_In, startY + padding * 1), m, HostMIDI::GATE_INPUT));
|
||||
addInput(createInput<PJ301MPort>(Vec(startX_In, startY + padding * 2), m, HostMIDI::VELOCITY_INPUT));
|
||||
addInput(createInput<PJ301MPort>(Vec(startX_In, startY + padding * 3), m, HostMIDI::AFTERTOUCH_INPUT));
|
||||
addInput(createInput<PJ301MPort>(Vec(startX_In, startY + padding * 4), m, HostMIDI::PITCHBEND_INPUT));
|
||||
addInput(createInput<PJ301MPort>(Vec(startX_In, startY + padding * 5), m, HostMIDI::MODWHEEL_INPUT));
|
||||
addInput(createInput<PJ301MPort>(Vec(startX_In, startY + padding * 6), m, HostMIDI::START_INPUT));
|
||||
addInput(createInput<PJ301MPort>(Vec(startX_In, startY + padding * 7), m, HostMIDI::STOP_INPUT));
|
||||
addInput(createInput<PJ301MPort>(Vec(startX_In, startY + padding * 8), m, HostMIDI::CONTINUE_INPUT));
|
||||
|
||||
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);
|
||||
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
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
* 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
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "plugin.hpp"
|
||||
#include "Widgets.hpp"
|
||||
#include "DearImGui/imgui.h"
|
||||
|
||||
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
|
||||
# include "glBars.hpp"
|
||||
# include "Widgets.hpp"
|
||||
#else
|
||||
# include "plugin.hpp"
|
||||
#endif
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue