257 lines
5.6 KiB
C++
257 lines
5.6 KiB
C++
#include "ui.h"
|
|
#include <format>
|
|
#ifdef DEBUG
|
|
#include <optional>
|
|
#endif
|
|
|
|
START_NAMESPACE_DISTRHO
|
|
|
|
ButtonMappingWidget::ButtonMappingWidget(
|
|
Widget *parent,
|
|
float initialSize,
|
|
float initialX,
|
|
float initialY,
|
|
Parameters associatedParameter,
|
|
ButtonEventHandler::Callback *const callback) : x(initialX),
|
|
y(initialY),
|
|
size(initialSize),
|
|
param(associatedParameter),
|
|
isClicked(false),
|
|
isPenPressed(false),
|
|
mask(0),
|
|
NanoSubWidget(parent),
|
|
ButtonEventHandler(this)
|
|
{
|
|
setSize(Size<uint>(static_cast<uint>(size), static_cast<uint>(size)));
|
|
setAbsolutePos((int)x, (int)y);
|
|
ButtonEventHandler::setCallback(callback);
|
|
}
|
|
|
|
void ButtonMappingWidget::onNanoDisplay()
|
|
{
|
|
beginPath();
|
|
strokeColor(200, 200, 200);
|
|
fillColor(0.5f, 0.5f, 0.5f, 0.5f * (isClicked + isPenPressed));
|
|
roundedRect(0.f, 0.f, size, size, 0.25f * size);
|
|
stroke();
|
|
fill();
|
|
closePath();
|
|
}
|
|
|
|
bool ButtonMappingWidget::onMouse(const MouseEvent &ev)
|
|
{
|
|
isClicked = ev.press && contains(ev.pos);
|
|
return ButtonEventHandler::mouseEvent(ev);
|
|
}
|
|
|
|
static constexpr uint kInitialWidth = 800;
|
|
static constexpr uint kInitialHeight = 600;
|
|
|
|
TabUI::TabUI()
|
|
: UI(kInitialWidth, kInitialHeight),
|
|
tab(getWindow().getNativeWindowHandle()),
|
|
AButtonWidget(this, 75.f, kInitialWidth - 100, kInitialHeight - 100, kParameterButtonA, this),
|
|
BButtonWidget(this, 75.f, kInitialWidth - 100, kInitialHeight - 200, kParameterButtonB, this)
|
|
{
|
|
|
|
#ifdef DGL_NO_SHARED_RESOURCES
|
|
createFontFromFile("sans", "/usr/share/fonts/truetype/ttf-dejavu/DejaVuSans.ttf");
|
|
#else
|
|
loadSharedResources();
|
|
#endif
|
|
|
|
if (!tab.initialized)
|
|
return;
|
|
float tabletAspectRatio = tab.ext.x ? tab.ext.y / tab.ext.x : 1.f;
|
|
setGeometryConstraints(400, static_cast<uint>(300 * tabletAspectRatio), true, false);
|
|
}
|
|
|
|
void TabUI::getTabletData()
|
|
{
|
|
if (!tab.initialized || !tab.GetPacket(pkt))
|
|
return;
|
|
if (pkt == lastPkt)
|
|
return;
|
|
if (pkt.x != lastPkt.x)
|
|
setParameterValue(ktpax, pkt.x);
|
|
if (pkt.y != lastPkt.y)
|
|
setParameterValue(ktpay, pkt.y);
|
|
if (pkt.z != lastPkt.z)
|
|
setParameterValue(ktpaz, pkt.z);
|
|
if (pkt.p != lastPkt.p)
|
|
setParameterValue(ktpap, pkt.p);
|
|
if (pkt.buttons != lastPkt.buttons)
|
|
setButtonsValue(pkt.buttons);
|
|
lastPkt = pkt;
|
|
}
|
|
|
|
void TabUI::setButtonsValue(unsigned long buttonMask)
|
|
{
|
|
if (AButtonWidget.matchesMask(buttonMask))
|
|
setParameterValue(kParameterButtonA, 1.f);
|
|
else
|
|
setParameterValue(kParameterButtonA, 0.f);
|
|
|
|
if (BButtonWidget.matchesMask(buttonMask))
|
|
setParameterValue(kParameterButtonB, 1.f);
|
|
else
|
|
setParameterValue(kParameterButtonB, 0.f);
|
|
}
|
|
|
|
void TabUI::buttonClicked(SubWidget *const widget, int)
|
|
{
|
|
if (widget == &AButtonWidget)
|
|
AButtonWidget.setMask(pkt.buttons);
|
|
if (widget == &BButtonWidget)
|
|
BButtonWidget.setMask(pkt.buttons);
|
|
}
|
|
|
|
void TabUI::parameterChanged(uint32_t index, float value)
|
|
{
|
|
|
|
if (index != kParameterTime && index < kParameterCount)
|
|
{
|
|
switch (index)
|
|
{
|
|
case (kFundamentalFrequency):
|
|
hz = value;
|
|
case (ktpax):
|
|
pkt.x = value;
|
|
case (ktpay):
|
|
pkt.y = value;
|
|
case (ktpaz):
|
|
pkt.z = value;
|
|
case (ktpap):
|
|
pkt.p = value;
|
|
}
|
|
return;
|
|
}
|
|
|
|
}
|
|
|
|
void TabUI::uiIdle()
|
|
{
|
|
getTabletData();
|
|
repaint();
|
|
}
|
|
|
|
bool TabUI::onMouse(const MouseEvent &ev)
|
|
{
|
|
getTabletData();
|
|
repaint();
|
|
return false; // Allow event to propagate.
|
|
}
|
|
|
|
void TabUI::onResize(const ResizeEvent &ev)
|
|
{
|
|
int x = static_cast<int>(ev.size.getWidth());
|
|
int y = static_cast<int>(ev.size.getHeight());
|
|
AButtonWidget.setAbsolutePos(x - 100, y - 100);
|
|
BButtonWidget.setAbsolutePos(x - 100, y - 200);
|
|
return UI::onResize(ev);
|
|
}
|
|
|
|
bool TabUI::onScroll(const ScrollEvent &ev)
|
|
{
|
|
double add;
|
|
const uint x = getWidth();
|
|
const uint y = getHeight();
|
|
|
|
add = (ev.delta.getY() > 0) ? 20 : -20;
|
|
|
|
float tabletAspectRatio;
|
|
if (tab.initialized)
|
|
tabletAspectRatio = tab.ext.y / tab.ext.x;
|
|
else
|
|
tabletAspectRatio = 1.f;
|
|
setSize(static_cast<uint>(x + add + 0.5), static_cast<uint>(tabletAspectRatio * (x + add + 0.5)));
|
|
return true;
|
|
}
|
|
|
|
void TabUI::onNanoDisplay()
|
|
{
|
|
fontSize(15.0f);
|
|
textLineHeight(1.f);
|
|
|
|
// Numerical feedback.
|
|
beginPath();
|
|
fillColor(200, 200, 200);
|
|
textBox(0.f, 15.f, 250.f,
|
|
std::format("Frequency: {:.3f}\nNearest: {}\n",
|
|
hz, scale.getNearestNoteNumber(hz))
|
|
.c_str(),
|
|
nullptr);
|
|
closePath();
|
|
|
|
// Report tablet errors.
|
|
#ifdef DEBUG
|
|
if (!tab.initialized)
|
|
{
|
|
const std::string err = std::vformat("Tablet not supported:\n{}",
|
|
std::make_format_args(tab.errormsg));
|
|
beginPath();
|
|
fillColor(200, 200, 200);
|
|
textBox(0.f, 15.f, 250.f, err.c_str(), nullptr);
|
|
closePath();
|
|
return;
|
|
}
|
|
|
|
// Numerical feedback.
|
|
beginPath();
|
|
fillColor(200, 200, 200);
|
|
textBox(0.f, 15.f, 250.f,
|
|
std::format("x: {:.3f}\ny: {:.3f}\nz: {:.3f}\np: {:.3f}\nb: {}",
|
|
pkt.x, pkt.y, pkt.z, pkt.p, pkt.buttons)
|
|
.c_str(),
|
|
nullptr);
|
|
closePath();
|
|
#endif
|
|
|
|
// Pen position and pressure.
|
|
drawCircle(pkt.x, pkt.y, pkt.z, pkt.p);
|
|
}
|
|
|
|
void TabUI::drawCircle(float x, float y, float z, float p)
|
|
{
|
|
|
|
static constexpr float circleRadius = 25.f;
|
|
x *= getWidth();
|
|
y = (1.f - y) * getHeight();
|
|
z = 1.f - z;
|
|
|
|
beginPath();
|
|
strokeColor(1.f, 1.f, 1.f, 0.5f);
|
|
moveTo(x - z * circleRadius, y);
|
|
lineTo(x + z * circleRadius, y);
|
|
stroke();
|
|
closePath();
|
|
|
|
beginPath();
|
|
strokeColor(1.f, 1.f, 1.f, 0.5f);
|
|
moveTo(x, y - z * circleRadius);
|
|
lineTo(x, y + z * circleRadius);
|
|
stroke();
|
|
closePath();
|
|
|
|
beginPath();
|
|
fillColor(1.f, 1.f, 1.f, p);
|
|
strokeColor(255, 255, 255, 255);
|
|
circle(x, y, circleRadius);
|
|
fill();
|
|
stroke();
|
|
closePath();
|
|
|
|
beginPath();
|
|
strokeColor(1.f, 1.f, 1.f, z);
|
|
circle(x, y, z * circleRadius);
|
|
stroke();
|
|
closePath();
|
|
}
|
|
|
|
UI *createUI()
|
|
{
|
|
return new TabUI();
|
|
}
|
|
|
|
END_NAMESPACE_DISTRHO
|