136 lines
4.7 KiB
C++
136 lines
4.7 KiB
C++
#pragma once
|
|
|
|
#include "ui/gadgets/gadget.h"
|
|
#include "nodelib/param.h"
|
|
|
|
#include <memory>
|
|
#include <functional>
|
|
#include <atomic>
|
|
|
|
#include "util/strings.h"
|
|
|
|
namespace Xybrid::NodeLib { class ADSR; }
|
|
namespace Xybrid::UI {
|
|
class LayoutGadget;
|
|
class KnobGadget : public Gadget {
|
|
Q_OBJECT
|
|
|
|
bool highlighted = false;
|
|
double lastVal = 0.0;
|
|
bool dirty = true;
|
|
|
|
QGraphicsSimpleTextItem* label;
|
|
QGraphicsSimpleTextItem* valLabel;
|
|
|
|
double get();
|
|
public:
|
|
enum Step : int {
|
|
NoStep = 1,
|
|
SmallStep = 3,
|
|
MedStep = 7,
|
|
BigStep = 15,
|
|
};
|
|
|
|
std::function<double()> fGet = [] { return 0.0; };
|
|
std::function<void(double)> fSet = [](double) { };
|
|
std::function<QString(double)> fText = [](double d) { return QString::number(d); };
|
|
|
|
double min = 0.0;
|
|
double max = 1.0;
|
|
double step = 0.01;
|
|
double subStep = -1;
|
|
int stepPx = SmallStep;
|
|
double defaultVal = 0.0;
|
|
|
|
qreal size = 32;
|
|
|
|
KnobGadget(QGraphicsItem* parent = nullptr);
|
|
~KnobGadget() override = default;
|
|
|
|
QRectF boundingRect() const override;
|
|
QRectF layoutBoundingRect() const override;
|
|
QPainterPath shape() const override;
|
|
void paint(QPainter*, const QStyleOptionGraphicsItem*, QWidget*) override;
|
|
|
|
void hoverEnterEvent(QGraphicsSceneHoverEvent*) override;
|
|
void mousePressEvent(QGraphicsSceneMouseEvent*) override;
|
|
void mouseReleaseEvent(QGraphicsSceneMouseEvent*) override;
|
|
void mouseMoveEvent(QGraphicsSceneMouseEvent*) override;
|
|
void wheelEvent(QGraphicsSceneWheelEvent*) override;
|
|
void contextMenuEvent(QGraphicsSceneContextMenuEvent*) override;
|
|
|
|
inline KnobGadget* setLabel(const QString& s) { label->setText(s); dirty = true; update(); return this; }
|
|
inline KnobGadget* setTextFunc(const std::function<QString(double)>& f) { fText = f; dirty = true; update(); return this; }
|
|
inline KnobGadget* setSize(decltype(size) s) { this->size = s; return this; }
|
|
inline KnobGadget* setRange(double min, double max, double step = -1, int px = -1, double sub = -1) {
|
|
this->min = min;
|
|
this->max = max;
|
|
if (step > 0) this->step = step;
|
|
if (px > 0) stepPx = px;
|
|
if (sub > 0) subStep = sub;
|
|
update();
|
|
return this;
|
|
}
|
|
inline KnobGadget* setDefault(double d) { this->defaultVal = d; return this; }
|
|
|
|
// and binding templates
|
|
template<typename T> KnobGadget* bind(T& ref) {
|
|
auto p = &ref; // pointerize
|
|
fGet = [p] { return static_cast<double>(*p); };
|
|
fSet = [p](double d) { *p = static_cast<T>(d); };
|
|
update();
|
|
return this;
|
|
}
|
|
template<typename T> KnobGadget* bind(std::atomic<T>& atm) {
|
|
auto p = &atm;
|
|
fGet = [p] { return p->load(); };
|
|
fSet = [p](double d) { p->store(static_cast<T>(d)); };
|
|
update();
|
|
return this;
|
|
}
|
|
KnobGadget* bind(NodeLib::Param& par) {
|
|
auto p = ∥
|
|
fGet = [p] { return p->value; };
|
|
fSet = [p](double d) {
|
|
p->value = d;
|
|
p->vt = std::numeric_limits<double>::quiet_NaN();
|
|
};
|
|
|
|
// binding to one of these populates metadata
|
|
min = p->min;
|
|
max = p->max;
|
|
defaultVal = p->def;
|
|
label->setText(p->name);
|
|
|
|
dirty = true;
|
|
update();
|
|
return this;
|
|
}
|
|
|
|
static QString textPercent(double);
|
|
static QString textOffset(double);
|
|
static QString textFrequency(double);
|
|
|
|
static QString textGain(double);
|
|
static QString textBalance(double);
|
|
|
|
static void autoCreate(LayoutGadget*, NodeLib::ADSR&);
|
|
|
|
// macro to vastly reduce boilerplate
|
|
#define preset(NAME) \
|
|
template<typename T> static inline KnobGadget* auto##NAME (QGraphicsItem* p, T& v) { return auto##NAME (p)->bind(v); } \
|
|
static inline KnobGadget* auto##NAME (QGraphicsItem* p)
|
|
|
|
// common presets
|
|
preset(Percent) { return (new KnobGadget(p))->setRange(0.0, 1.0, .01)->setTextFunc(KnobGadget::textPercent); }
|
|
|
|
preset(Gain) { return (new KnobGadget(p))->setRange(-60, 12, .1)->setLabel(qs("Gain"))->setTextFunc(KnobGadget::textGain); }
|
|
preset(Balance) { return (new KnobGadget(p))->setRange(-1.0, 1.0, .01)->setLabel(qs("Balance"))->setTextFunc(KnobGadget::textBalance); }
|
|
preset(Cutoff) { return (new KnobGadget(p))->setRange(0, 16000, 10, NoStep, 1)->setLabel(qs("Cutoff"))->setTextFunc(KnobGadget::textFrequency); }
|
|
|
|
};
|
|
}
|
|
|
|
// keep this local
|
|
#undef preset
|