#include "mainwindow.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include const QString DARK_STYLESHEET = R"( QWidget { background-color: transparent; color: #DAE0ED; font-family: Arial; } QLabel { background-color: transparent; } QLabel#Title { font-size: 15pt; font-weight: bold; color: #FFFFFF; } QLabel#SectionHeader { font-size: 11pt; font-weight: bold; color: #92E8FF; margin-top: 10px; margin-bottom: 3px; } QLabel#ControlLabel { font-size: 9pt; color: #CBD2E6; } QComboBox { background-color: rgba(10, 10, 20, 0.25); border: 1px solid #3A4760; border-radius: 4px; padding: 4px; color: #DAE0ED; } QComboBox:hover { background-color: rgba(15, 15, 25, 0.35); border: 1px solid #6482B4; } QComboBox::drop-down { border: none; } QComboBox QAbstractItemView { background-color: rgba(15, 15, 25, 0.9); border: 1px solid #3A4760; selection-background-color: #6A3AB1; color: #DAE0ED; } QPushButton { background-color: rgba(10, 10, 20, 0.25); border: 1px solid #3A4760; border-radius: 4px; padding: 5px; color: #92E8FF; } QPushButton:hover { background-color: rgba(15, 15, 25, 0.35); border: 1px solid #6482B4; } QPushButton:pressed { background-color: rgba(20, 20, 30, 0.45); border: 1px solid #A020F0; } )"; MainWindow::MainWindow(QWidget *parent) : QWidget(parent) , m_alsa() , m_aboutDialog(nullptr) { if (!m_alsa.isCardFound()) { QMessageBox::critical(this, "Error", "TASCAM US-144/US-144MKII Not Found.\nPlease ensure the device is connected and the 'us144mkii' driver is loaded."); QTimer::singleShot(0, this, &QWidget::close); return; } initUi(); loadDynamicSettings(); } void MainWindow::initUi() { setWindowTitle("TASCAM US-144MKII Control Panel"); setWindowIcon(QIcon(":/tascam-control-panel.png")); setFixedSize(550, 450); setStyleSheet(DARK_STYLESHEET); m_background.load(":/bg.png"); if (m_background.isNull()) { qWarning() << "Failed to load background image from resources!"; } auto *topLevelLayout = new QHBoxLayout(this); topLevelLayout->setContentsMargins(20, 20, 20, 20); topLevelLayout->setSpacing(25); auto *leftPanel = new QVBoxLayout(); auto *middlePanel = new QVBoxLayout(); auto *logoLabel = new QLabel(); logoLabel->setPixmap(QPixmap(":/logo.png").scaledToWidth(250, Qt::SmoothTransformation)); auto *titleLabel = new QLabel("US-144 MKII Control Panel"); titleLabel->setObjectName("Title"); auto *infoGrid = new QGridLayout(); infoGrid->setSpacing(5); const QMap infoData = { {"Device:", "device"}, {"Sample Width:", "sample_width"}, {"Sample Rate:", "sample_rate"} }; int row = 0; for (auto it = infoData.constBegin(); it != infoData.constEnd(); ++it) { auto *label = new QLabel(it.key()); label->setFont(QFont("Arial", 9, QFont::Bold)); auto *valueLabel = new QLabel("N/A"); valueLabel->setFont(QFont("Arial", 9)); infoGrid->addWidget(label, row, 0); infoGrid->addWidget(valueLabel, row, 1); m_infoLabels[it.value()] = valueLabel; row++; } auto *deviceImageLabel = new QLabel(); deviceImageLabel->setPixmap(QPixmap(":/device.png").scaled(250, 250, Qt::KeepAspectRatio, Qt::SmoothTransformation)); deviceImageLabel->setAlignment(Qt::AlignCenter); leftPanel->addWidget(logoLabel); leftPanel->addWidget(titleLabel); leftPanel->addLayout(infoGrid); leftPanel->addStretch(); leftPanel->addWidget(deviceImageLabel); middlePanel->setSpacing(0); auto addSection = [&](const QString& title, QWidget* widget) { auto* header = new QLabel(title); header->setObjectName("SectionHeader"); middlePanel->addWidget(header); middlePanel->addWidget(widget); }; auto capture12Pair = createControlWidget("ch1 and ch2", {"analog inputs", "digital inputs"}); m_capture12Combo = capture12Pair.second; m_capture12Combo->setToolTip("Select the source for capture channels 1 and 2."); auto capture34Pair = createControlWidget("ch3 and ch4", {"analog inputs", "digital inputs"}); m_capture34Combo = capture34Pair.second; m_capture34Combo->setToolTip("Select the source for capture channels 3 and 4."); addSection("INPUTS", capture12Pair.first); middlePanel->addWidget(capture34Pair.first); auto lineOutPair = createControlWidget("ch1 and ch2", {"ch1 and ch2", "ch3 and ch4"}); m_lineOutCombo = lineOutPair.second; m_lineOutCombo->setToolTip("Select the source for the line outputs."); addSection("LINE OUTPUTS", lineOutPair.first); auto digitalOutPair = createControlWidget("ch3 and ch4", {"ch1 and ch2", "ch3 and ch4"}); m_digitalOutCombo = digitalOutPair.second; m_digitalOutCombo->setToolTip("Select the source for the digital outputs."); addSection("DIGITAL OUTPUTS", digitalOutPair.first); middlePanel->addStretch(); auto *buttonLayout = new QHBoxLayout(); auto *aboutButton = new QPushButton("About"); aboutButton->setFixedSize(100, 30); connect(aboutButton, &QPushButton::clicked, this, &MainWindow::showAboutDialog); buttonLayout->addWidget(aboutButton); middlePanel->addLayout(buttonLayout); topLevelLayout->addLayout(leftPanel, 1); topLevelLayout->addLayout(middlePanel, 1); connect(m_lineOutCombo, &QComboBox::currentIndexChanged, this, [this](int index){ onControlChanged("Line Playback Source", index, m_lineOutCombo); }); connect(m_digitalOutCombo, &QComboBox::currentIndexChanged, this, [this](int index){ onControlChanged("Digital Playback Source", index, m_digitalOutCombo); }); connect(m_capture12Combo, &QComboBox::currentIndexChanged, this, [this](int index){ onControlChanged("Ch1/2 Capture Source", index, m_capture12Combo); }); connect(m_capture34Combo, &QComboBox::currentIndexChanged, this, [this](int index){ onControlChanged("Ch3/4 Capture Source", index, m_capture34Combo); }); } void MainWindow::loadDynamicSettings() { m_infoLabels["device"]->setText("US-144 MKII"); m_infoLabels["sample_width"]->setText("24 bits"); long rate_val = m_alsa.getControlValue("Sample Rate"); m_infoLabels["sample_rate"]->setText(rate_val > 0 ? QString("%1 kHz").arg(rate_val / 1000.0, 0, 'f', 1) : "N/A (inactive)"); updateCombo(m_lineOutCombo, "Line Playback Source"); updateCombo(m_digitalOutCombo, "Digital Playback Source"); updateCombo(m_capture12Combo, "Ch1/2 Capture Source"); updateCombo(m_capture34Combo, "Ch3/4 Capture Source"); } void MainWindow::updateCombo(QComboBox* combo, const std::string& controlName) { long value = m_alsa.getControlValue(controlName); combo->blockSignals(true); combo->setCurrentIndex(static_cast(value)); combo->blockSignals(false); } void MainWindow::onControlChanged(const std::string& controlName, int index, QComboBox* combo) { m_alsa.setControlValue(controlName, index); if (combo) { QString originalStyle = combo->styleSheet(); combo->setStyleSheet(originalStyle + " QComboBox { border: 1px solid #A020F0; }"); QTimer::singleShot(200, [combo, originalStyle]() { combo->setStyleSheet(originalStyle); }); } } std::pair MainWindow::createControlWidget(const QString& labelText, const QStringList& items) { auto *container = new QWidget(); auto *layout = new QVBoxLayout(container); layout->setContentsMargins(0, 8, 0, 8); layout->setSpacing(2); auto *label = new QLabel(labelText); label->setObjectName("ControlLabel"); auto *combo = new QComboBox(); combo->addItems(items); layout->addWidget(label); layout->addWidget(combo); return {container, combo}; } void MainWindow::showAboutDialog() { if (m_aboutDialog && m_aboutDialog->isVisible()) { m_aboutDialog->raise(); m_aboutDialog->activateWindow(); return; } if (!m_aboutDialog) { m_aboutDialog = new QDialog(this); m_aboutDialog->setWindowTitle("About TASCAM US-144MKII Control Panel"); m_aboutDialog->setWindowIcon(QIcon(":/tascam-control-panel.png")); m_aboutDialog->setFixedSize(400, 250); auto *layout = new QVBoxLayout(m_aboutDialog); auto *textLabel = new QLabel(m_aboutDialog); textLabel->setTextFormat(Qt::RichText); textLabel->setOpenExternalLinks(true); textLabel->setText(QString("TASCAM US-144MKII Control Panel
" "Copyright @serifpersia 2025

" "This application provides a graphical interface to control the TASCAM US-144MKII audio interface on Linux. " "It utilizes the 'us144mkii' ALSA driver.

" "For more information, bug reports, and contributions, please visit the GitHub repository:
" "https://github.com/serifpersia/us144mkii")); textLabel->setWordWrap(true); layout->addWidget(textLabel); } m_aboutDialog->show(); } void MainWindow::paintEvent(QPaintEvent *event) { QPainter painter(this); if (!m_background.isNull()) { painter.drawPixmap(this->rect(), m_background); } QWidget::paintEvent(event); }