aluf/src/PlayerControls.cpp

385 lines
13 KiB
C++

// src/PlayerControls.cpp
#include "PlayerControls.h"
#include <QGridLayout>
#include <QHBoxLayout>
#include <QVBoxLayout>
#include <cmath>
PlaybackWidget::PlaybackWidget(QWidget *parent) : QWidget(parent) {
setStyleSheet(
"background-color: rgba(0, 0, 0, 150); border-top: 1px solid #444;");
QVBoxLayout *mainLayout = new QVBoxLayout(this);
mainLayout->setContentsMargins(10, 5, 10, 10);
m_seekSlider = new QSlider(Qt::Horizontal, this);
m_seekSlider->setRange(0, 1000);
m_seekSlider->setFixedHeight(30);
m_seekSlider->setStyleSheet(
"QSlider::handle:horizontal { background: white; width: 20px; margin: "
"-8px 0; border-radius: 10px; }"
"QSlider::groove:horizontal { background: #444; height: 4px; }"
"QSlider::sub-page:horizontal { background: #00d4ff; }");
connect(m_seekSlider, &QSlider::sliderPressed, this,
&PlaybackWidget::onSeekPressed);
connect(m_seekSlider, &QSlider::sliderReleased, this,
&PlaybackWidget::onSeekReleased);
mainLayout->addWidget(m_seekSlider);
QHBoxLayout *rowLayout = new QHBoxLayout();
QString btnStyle =
"QPushButton { background: transparent; color: white; font-size: 24px; "
"border: 1px solid #444; border-radius: 8px; padding: 10px 20px; } "
"QPushButton:pressed { background: #333; }";
QPushButton *btnPrev = new QPushButton("<<", this);
btnPrev->setStyleSheet(btnStyle);
connect(btnPrev, &QPushButton::clicked, this, &PlaybackWidget::prevClicked);
m_btnPlay = new QPushButton(">", this);
m_btnPlay->setStyleSheet(btnStyle);
connect(m_btnPlay, &QPushButton::clicked, this,
&PlaybackWidget::onPlayToggle);
QPushButton *btnNext = new QPushButton(">>", this);
btnNext->setStyleSheet(btnStyle);
connect(btnNext, &QPushButton::clicked, this, &PlaybackWidget::nextClicked);
QPushButton *btnSettings = new QPushButton("", this);
btnSettings->setStyleSheet(
"QPushButton { background: transparent; color: #aaa; font-size: 24px; "
"border: none; padding: 10px; } QPushButton:pressed { color: white; }");
connect(btnSettings, &QPushButton::clicked, this,
&PlaybackWidget::settingsClicked);
QPushButton *btnHome = new QPushButton("", this); // House icon or similar
btnHome->setStyleSheet(
"QPushButton { background: transparent; color: #aaa; font-size: 24px; "
"border: none; padding: 10px; } QPushButton:pressed { color: white; }");
connect(btnHome, &QPushButton::clicked, this, &PlaybackWidget::homeClicked);
rowLayout->addWidget(btnHome);
rowLayout
->addStretch(); // Add stretch so home is left-aligned, controls center
rowLayout->addWidget(btnPrev);
rowLayout->addSpacing(10);
rowLayout->addWidget(m_btnPlay);
rowLayout->addSpacing(10);
rowLayout->addWidget(btnNext);
rowLayout->addStretch();
rowLayout->addWidget(btnSettings);
mainLayout->addLayout(rowLayout);
}
void PlaybackWidget::setPlaying(bool playing) {
m_isPlaying = playing;
m_btnPlay->setText(playing ? "||" : ">");
}
void PlaybackWidget::updateSeek(float pos) {
if (!m_seeking)
m_seekSlider->setValue(static_cast<int>(pos * 1000));
}
void PlaybackWidget::onSeekPressed() { m_seeking = true; }
void PlaybackWidget::onSeekReleased() {
m_seeking = false;
emit seekChanged(m_seekSlider->value() / 1000.0f);
}
void PlaybackWidget::onPlayToggle() {
if (m_isPlaying)
emit pauseClicked();
else
emit playClicked();
}
SettingsWidget::SettingsWidget(QWidget *parent) : QWidget(parent) {
setStyleSheet("background-color: rgba(30, 30, 30, 230); border-radius: 12px; "
"border: 1px solid #666;");
QVBoxLayout *layout = new QVBoxLayout(this);
layout->setContentsMargins(15, 15, 15, 15);
layout->setSpacing(10);
QHBoxLayout *header = new QHBoxLayout();
QLabel *title = new QLabel("Settings", this);
title->setStyleSheet("color: white; font-size: 18px; font-weight: bold; "
"border: none; background: transparent;");
QPushButton *btnClose = new QPushButton("", this);
btnClose->setFixedSize(30, 30);
btnClose->setStyleSheet("QPushButton { background: #444; color: white; "
"border-radius: 15px; border: none; font-weight: "
"bold; } QPushButton:pressed { background: #666; }");
connect(btnClose, &QPushButton::clicked, this, &SettingsWidget::closeClicked);
header->addWidget(title);
header->addStretch();
header->addWidget(btnClose);
layout->addLayout(header);
QGridLayout *grid = new QGridLayout();
auto createCheck = [&](const QString &text, bool checked, int r, int c) {
QCheckBox *cb = new QCheckBox(text, this);
cb->setChecked(checked);
cb->setStyleSheet("QCheckBox { color: white; font-size: 14px; padding: "
"5px; border: none; background: transparent; } "
"QCheckBox::indicator { width: 20px; height: 20px; }");
connect(cb, &QCheckBox::toggled, this, &SettingsWidget::emitParams);
grid->addWidget(cb, r, c);
return cb;
};
// Updated Defaults based on user request
m_checkGlass = createCheck("Glass", true, 0, 0);
m_checkFocus = createCheck("Focus", true, 0, 1);
m_checkAlbumColors = createCheck("Album Colors", false, 1, 0);
m_checkMirrored = createCheck("Mirrored", true, 1, 1);
m_checkInverted = createCheck("Invert", false, 2, 0);
layout->addLayout(grid);
// Helper for sliders
auto addSlider = [&](const QString &label, int min, int max, int val,
QSlider *&slider, QLabel *&lbl) {
QHBoxLayout *h = new QHBoxLayout();
lbl = new QLabel(label, this);
lbl->setStyleSheet("color: white; font-weight: bold; border: none; "
"background: transparent; min-width: 80px;");
slider = new QSlider(Qt::Horizontal, this);
slider->setRange(min, max);
slider->setValue(val);
slider->setStyleSheet(
"QSlider::handle:horizontal { background: #aaa; width: 24px; margin: "
"-10px 0; border-radius: 12px; } QSlider::groove:horizontal { "
"background: #444; height: 4px; }");
h->addWidget(lbl);
h->addWidget(slider);
layout->addLayout(h);
};
// Updated Slider Defaults
addSlider("Bins: 21", 10, 64, 21, m_sliderBins, m_lblBins);
connect(m_sliderBins, &QSlider::valueChanged, this,
&SettingsWidget::onBinsChanged);
addSlider("FPS: 60", 15, 120, 60, m_sliderFps, m_lblFps);
connect(m_sliderFps, &QSlider::valueChanged, this, [this](int val) {
m_lblFps->setText(QString("FPS: %1").arg(val));
emit fpsChanged(val);
});
addSlider("Bright: 66%", 10, 200, 66, m_sliderBrightness, m_lblBrightness);
connect(m_sliderBrightness, &QSlider::valueChanged, this,
&SettingsWidget::onBrightnessChanged);
addSlider("Granularity", 0, 100, 95, m_sliderGranularity, m_lblGranularity);
connect(m_sliderGranularity, &QSlider::valueChanged, this,
&SettingsWidget::onSmoothingChanged);
addSlider("Detail", 0, 100, 5, m_sliderDetail, m_lblDetail);
connect(m_sliderDetail, &QSlider::valueChanged, this,
&SettingsWidget::onSmoothingChanged);
addSlider("Strength", 0, 100, 95, m_sliderStrength, m_lblStrength);
connect(m_sliderStrength, &QSlider::valueChanged, this,
&SettingsWidget::onSmoothingChanged);
// BPM Scale Selector
QHBoxLayout *bpmLayout = new QHBoxLayout();
QLabel *lblBpm = new QLabel("BPM Scale:", this);
lblBpm->setStyleSheet("color: white; font-weight: bold; border: none; "
"background: transparent; min-width: 80px;");
m_comboBpmScale = new QComboBox(this);
m_comboBpmScale->addItems({"1/1", "1/2", "1/4 (Default)", "1/8", "1/16"});
m_comboBpmScale->setCurrentIndex(4); // Default to 1/16
m_comboBpmScale->setStyleSheet(
"QComboBox { background: #444; color: white; border: 1px solid #666; "
"border-radius: 4px; padding: 4px; } QComboBox::drop-down { border: "
"none; }");
connect(m_comboBpmScale, QOverload<int>::of(&QComboBox::currentIndexChanged),
this, &SettingsWidget::onBpmScaleChanged);
bpmLayout->addWidget(lblBpm);
bpmLayout->addWidget(m_comboBpmScale);
layout->addLayout(bpmLayout);
QHBoxLayout *padsLayout = new QHBoxLayout();
m_padDsp = new XYPad("DSP", this);
m_padDsp->setFormatter([](float x, float y) {
int power = 6 + (int)(x * 7.0f + 0.5f);
int fft = std::pow(2, power);
int hop = 64 + y * (8192 - 64);
return QString("FFT: %1\nHop: %2").arg(fft).arg(hop);
});
// Default to FFT 8192 (x=1.0), Hop 64 (y=0.0)
m_padDsp->setValues(1.0f, 0.0f);
connect(m_padDsp, &XYPad::valuesChanged, this,
&SettingsWidget::onDspPadChanged);
padsLayout->addWidget(m_padDsp);
m_padColor = new XYPad("Color", this);
m_padColor->setFormatter([](float x, float y) {
float hue = x * 2.0f;
float cont = 0.1f + y * 2.9f;
return QString("Hue: %1\nCont: %2")
.arg(hue, 0, 'f', 2)
.arg(cont, 0, 'f', 2);
});
// Default to Hue 0.35 (x=0.175), Cont 0.10 (y=0.0)
m_padColor->setValues(0.175f, 0.0f);
connect(m_padColor, &XYPad::valuesChanged, this,
&SettingsWidget::onColorPadChanged);
padsLayout->addWidget(m_padColor);
layout->addLayout(padsLayout);
}
void SettingsWidget::setParams(bool glass, bool focus, bool albumColors,
bool mirrored, bool inverted, int bins, int fps,
float brightness, int granularity, int detail,
float strength, int bpmScaleIndex) {
bool oldState = blockSignals(true);
m_checkGlass->setChecked(glass);
m_checkFocus->setChecked(focus);
m_checkAlbumColors->setChecked(albumColors);
m_checkMirrored->setChecked(mirrored);
m_checkInverted->setChecked(inverted);
m_sliderBins->setValue(bins);
m_lblBins->setText(QString("Bins: %1").arg(bins));
m_sliderFps->setValue(fps);
m_lblFps->setText(QString("FPS: %1").arg(fps));
m_brightness = brightness;
m_sliderBrightness->setValue(static_cast<int>(brightness * 100.0f));
m_lblBrightness->setText(
QString("Bright: %1%").arg(static_cast<int>(brightness * 100.0f)));
m_granularity = granularity;
m_sliderGranularity->setValue(granularity);
m_detail = detail;
m_sliderDetail->setValue(detail);
m_strength = strength;
m_sliderStrength->setValue(static_cast<int>(strength * 100.0f));
if (bpmScaleIndex >= 0 && bpmScaleIndex < m_comboBpmScale->count()) {
m_comboBpmScale->setCurrentIndex(bpmScaleIndex);
}
blockSignals(oldState);
emitParams();
emit binsChanged(bins);
}
void SettingsWidget::emitParams() {
emit paramsChanged(m_checkGlass->isChecked(), m_checkFocus->isChecked(),
m_checkAlbumColors->isChecked(),
m_checkMirrored->isChecked(),
m_checkInverted->isChecked(), m_hue, m_contrast,
m_brightness, m_granularity, m_detail, m_strength);
}
float SettingsWidget::getBpmScale() const {
switch (m_comboBpmScale->currentIndex()) {
case 0:
return 0.25f; // 1/1
case 1:
return 0.5f; // 1/2
case 2:
return 1.0f; // 1/4 (Default)
case 3:
return 2.0f; // 1/8
case 4:
return 4.0f; // 1/16
default:
return 1.0f;
}
}
int SettingsWidget::getBpmScaleIndex() const {
return m_comboBpmScale->currentIndex();
}
void SettingsWidget::onBpmScaleChanged(int index) {
emit bpmScaleChanged(getBpmScale());
}
void SettingsWidget::onDspPadChanged(float x, float y) {
int power = 6 + (int)(x * 7.0f + 0.5f);
m_fft = std::pow(2, power);
m_hop = 64 + y * (8192 - 64);
emit dspParamsChanged(m_fft, m_hop);
}
void SettingsWidget::onColorPadChanged(float x, float y) {
m_hue = x * 2.0f;
m_contrast = 0.1f + y * 2.9f;
emitParams();
}
void SettingsWidget::onBinsChanged(int val) {
m_bins = val;
m_lblBins->setText(QString("Bins: %1").arg(val));
emit binsChanged(val);
}
void SettingsWidget::onBrightnessChanged(int val) {
m_brightness = val / 100.0f;
m_lblBrightness->setText(QString("Bright: %1%").arg(val));
emitParams();
}
void SettingsWidget::onSmoothingChanged(int val) {
m_granularity = m_sliderGranularity->value();
m_detail = m_sliderDetail->value();
m_strength = m_sliderStrength->value() / 100.0f;
emitParams();
}
PlayerPage::PlayerPage(QWidget *parent) : QWidget(parent) {
m_visualizer = new VisualizerWidget(this);
m_playback = new PlaybackWidget(this);
m_settings = new SettingsWidget();
m_overlay = new OverlayWidget(m_settings, this);
connect(m_playback, &PlaybackWidget::settingsClicked, this,
&PlayerPage::toggleOverlay);
connect(m_playback, &PlaybackWidget::homeClicked, this,
&PlayerPage::homeClicked);
connect(m_settings, &SettingsWidget::closeClicked, this,
&PlayerPage::closeOverlay);
connect(m_visualizer, &VisualizerWidget::tapDetected, this,
&PlayerPage::toggleFullScreen);
}
void PlayerPage::setFullScreen(bool fs) { m_playback->setVisible(!fs); }
void PlayerPage::toggleOverlay() {
if (m_overlay->isVisible())
m_overlay->hide();
else {
m_overlay->raise();
m_overlay->show();
}
}
void PlayerPage::closeOverlay() { m_overlay->hide(); }
void PlayerPage::resizeEvent(QResizeEvent *event) {
int w = event->size().width();
int h = event->size().height();
m_visualizer->setGeometry(0, 0, w, h);
int pbHeight = 120;
m_playback->setGeometry(0, h - pbHeight, w, pbHeight);
m_overlay->setGeometry(0, 0, w, h);
}