#include "ui.h" #include #ifdef DEBUG #include #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(static_cast(size), static_cast(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(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(ev.size.getWidth()); int y = static_cast(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(x + add + 0.5), static_cast(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