Files
ts-qt/modern-qt/layout/mixer.hh
2025-10-20 00:32:01 +08:00

113 lines
2.8 KiB
C++

#pragma once
#include <qpainter.h>
#include <qpainterpath.h>
#include "modern-qt/utility/animation/animatable.hh"
#include "modern-qt/utility/animation/state/pid.hh"
#include "modern-qt/utility/animation/transition.hh"
#include "modern-qt/utility/wrapper/widget.hh"
namespace creeper::mixer::internal {
class MixerMask : public QWidget {
public:
explicit MixerMask(auto* widget) noexcept
: QWidget { widget }
, animatable { *this } {
QWidget::setAttribute(Qt::WA_TransparentForMouseEvents);
mask_frame.fill(Qt::transparent);
{
auto state = std::make_shared<PidState<double>>();
state->config.kp = 05.0;
state->config.ki = 00.0;
state->config.kd = 00.0;
state->config.epsilon = 1e-3;
mask_radius = make_transition(animatable, std::move(state));
}
}
auto initiate_animation(QPoint const& point) noexcept {
mask_frame.fill(Qt::transparent);
auto* widget = parentWidget();
if (widget == nullptr) return;
mask_radius->snap_to(0.);
mask_radius->transition_to(1.);
mask_point = point;
mask_frame = widget->grab();
update_animation = true;
QWidget::setFixedSize(widget->size());
}
auto initiate_animation(int x, int y) noexcept {
// Forward Point
initiate_animation(QPoint { x, y });
}
protected:
auto paintEvent(QPaintEvent* e) -> void override {
if (!update_animation) return;
auto const w = QWidget::width();
auto const h = QWidget::height();
auto const x = std::sqrt(w * w + h * h);
auto painter = QPainter { this };
auto const radius = double { *mask_radius * x };
auto const round = [&] {
auto path = QPainterPath {};
path.addRect(QWidget::rect());
auto inner = QPainterPath();
inner.addEllipse(mask_point, radius, radius);
return path.subtracted(inner);
}();
painter.setClipPath(round);
painter.setClipping(true);
painter.drawPixmap(QWidget::rect(), mask_frame);
if (std::abs(*mask_radius - 1.) < 1e-2) {
update_animation = false;
}
}
private:
QPixmap mask_frame;
QPointF mask_point;
bool update_animation = false;
Animatable animatable;
std::unique_ptr<TransitionValue<PidState<double>>> mask_radius;
};
}
namespace creeper::mixer::pro {
struct SetMixerMask : widget::pro::Token {
internal::MixerMask*& mask;
explicit SetMixerMask(auto*& mask)
: mask { mask } { }
auto apply(auto& self) noexcept {
//
mask = new internal::MixerMask { &self };
}
};
}
namespace creeper {
using MixerMask = mixer::internal::MixerMask;
}