Add settings dialog, camera controls

This commit is contained in:
Gary Talent 2023-07-20 02:13:48 -05:00
parent a8327b2b67
commit 29cdc499e6
24 changed files with 793 additions and 82 deletions

3
.gitignore vendored
View File

@ -1,10 +1,13 @@
.cache
.clangd .clangd
.conanbuild .conanbuild
.current_build .current_build
__pycache__
CMakeLists.txt.user CMakeLists.txt.user
Session.vim Session.vim
build build
compile_commands.json compile_commands.json
cmake-build-debug
dist dist
graph_info.json graph_info.json
tags tags

8
.idea/.gitignore generated vendored
View File

@ -1,8 +0,0 @@
# Default ignored files
/shelf/
/workspace.xml
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml
# Editor-based HTTP Client requests
/httpRequests/

16
.idea/misc.xml generated
View File

@ -1,17 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project version="4"> <project version="4">
<component name="CompDBSettings"> <component name="CMakeWorkspace" PROJECT_DIR="$PROJECT_DIR$" />
<option name="linkedExternalProjectsSettings"> <component name="CompDBWorkspace">
<CompDBProjectSettings> <contentRoot DIR="$PROJECT_DIR$" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="modules">
<set>
<option value="$PROJECT_DIR$" />
</set>
</option>
</CompDBProjectSettings>
</option>
</component> </component>
<component name="CompDBWorkspace" PROJECT_DIR="$PROJECT_DIR$" />
<component name="ExternalStorageConfigurationManager" enabled="true" />
</project> </project>

2
.idea/vcs.xml generated
View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project version="4"> <project version="4">
<component name="VcsDirectoryMappings"> <component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" /> <mapping directory="" vcs="Git" />
</component> </component>
</project> </project>

View File

@ -2,7 +2,7 @@
source: source:
- . - .
copyright_notice: |- copyright_notice: |-
Copyright 2021 gary@drinkingtea.net Copyright 2021 - 2023 gary@drinkingtea.net
This Source Code Form is subject to the terms of the Mozilla Public This Source Code Form is subject to the terms of the Mozilla Public
License, v. 2.0. If a copy of the MPL was not distributed with this License, v. 2.0. If a copy of the MPL was not distributed with this

View File

@ -14,4 +14,4 @@ run: install
${ENV_RUN} ${PROJECT_EXECUTABLE} ${ENV_RUN} ${PROJECT_EXECUTABLE}
.PHONY: debug .PHONY: debug
debug: install debug: install
${ENV_RUN} gdb --args ${PROJECT_EXECUTABLE} ${DEBUGGER} lldb -- ${PROJECT_EXECUTABLE}

View File

@ -33,7 +33,7 @@ class RqstHandler(BaseHTTPRequestHandler):
def run(name): def run(name):
httpd = HTTPServer(('127.0.0.1', 9302), RqstHandler) httpd = HTTPServer(('0.0.0.0', 9302), RqstHandler)
httpd.serve_forever() httpd.serve_forever()

View File

@ -8,10 +8,13 @@ find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Network Widgets REQUIRED)
add_executable( add_executable(
SlideController MACOSX_BUNDLE WIN32 SlideController MACOSX_BUNDLE WIN32
cameraclient.cpp
main.cpp main.cpp
mainwindow.cpp mainwindow.cpp
obsclient.cpp obsclient.cpp
openlpclient.cpp openlpclient.cpp
settingsdata.cpp
settingsdialog.cpp
slideview.cpp slideview.cpp
) )

54
src/cameraclient.cpp Normal file
View File

@ -0,0 +1,54 @@
/*
* Copyright 2021 - 2023 gary@drinkingtea.net
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#include <QNetworkReply>
#include <QSettings>
#include "settingsdata.hpp"
#include "cameraclient.hpp"
CameraClient::CameraClient(QObject *parent): QObject(parent) {
setBaseUrl();
m_pollTimer.start(1000);
connect(&m_pollTimer, &QTimer::timeout, this, &CameraClient::poll);
connect(m_pollingNam, &QNetworkAccessManager::finished, this, &CameraClient::handlePollResponse);
}
void CameraClient::setPreset(int preset) {
if (preset > -1) {
get(QString("/cgi-bin/ptzctrl.cgi?ptzcmd&poscall&%1").arg(preset));
}
}
void CameraClient::setBaseUrl() {
const auto [host, port] = getCameraConnectionData();
m_baseUrl = QString("http://%1:%2").arg(host, QString::number(port));
}
void CameraClient::get(QString const&urlExt) {
QUrl url(QString(m_baseUrl) + urlExt);
QNetworkRequest rqst(url);
auto reply = m_nam->get(rqst);
connect(reply, &QIODevice::readyRead, reply, &QObject::deleteLater);
}
void CameraClient::poll() {
QUrl url(QString(m_baseUrl) + "/cgi-bin/param.cgi?get_device_conf");
QNetworkRequest rqst(url);
m_pollingNam->get(rqst);
}
void CameraClient::handlePollResponse(QNetworkReply *reply) {
reply->deleteLater();
if (reply->error()) {
qDebug() << "CameraClient error response:" << reply->errorString();
emit pollFailed();
return;
}
emit pollUpdate();
}

46
src/cameraclient.hpp Normal file
View File

@ -0,0 +1,46 @@
/*
* Copyright 2021 - 2023 gary@drinkingtea.net
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#pragma once
#include <QNetworkAccessManager>
#include <QObject>
#include <QTimer>
#include "consts.hpp"
class CameraClient: public QObject {
Q_OBJECT
private:
QString m_baseUrl;
QNetworkAccessManager *const m_nam = new QNetworkAccessManager(this);
QNetworkAccessManager *const m_pollingNam = new QNetworkAccessManager(this);
QTimer m_pollTimer;
public:
explicit CameraClient(QObject *parent = nullptr);
void setPreset(int preset);
public slots:
void setBaseUrl();
private:
void get(QString const&url);
void poll();
void handlePollResponse(QNetworkReply *reply);
signals:
void pollUpdate();
void pollFailed();
};

View File

@ -8,4 +8,3 @@
#pragma once #pragma once
constexpr auto SlideHost = "192.168.254.61";

View File

@ -7,10 +7,12 @@
*/ */
#include <QApplication> #include <QApplication>
#include <QSettings>
#include "mainwindow.hpp" #include "mainwindow.hpp"
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
QSettings::setDefaultFormat(QSettings::Format::IniFormat);
QApplication a(argc, argv); QApplication a(argc, argv);
QApplication::setApplicationName(QObject::tr("Slide Controller 9000")); QApplication::setApplicationName(QObject::tr("Slide Controller 9000"));
MainWindow w; MainWindow w;

View File

@ -6,17 +6,21 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. * file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/ */
#include <QApplication>
#include <QHBoxLayout> #include <QHBoxLayout>
#include <QMenuBar>
#include <QPushButton> #include <QPushButton>
#include <QStatusBar> #include <QStatusBar>
#include "settingsdialog.hpp"
#include "slideview.hpp" #include "slideview.hpp"
#include "mainwindow.hpp" #include "mainwindow.hpp"
MainWindow::MainWindow(QWidget *parent): QMainWindow(parent) { MainWindow::MainWindow(QWidget *parent): QMainWindow(parent) {
move(0, 0); move(0, 0);
setFixedSize(590, 555); setFixedSize(610, 555);
setWindowTitle(tr("Slide Controller 9000")); setWindowTitle(tr("Slide Controller 9000"));
setupMenu();
const auto mainWidget = new QWidget(this); const auto mainWidget = new QWidget(this);
const auto rootLyt = new QVBoxLayout; const auto rootLyt = new QVBoxLayout;
const auto controlsLayout = new QGridLayout; const auto controlsLayout = new QGridLayout;
@ -26,53 +30,159 @@ MainWindow::MainWindow(QWidget *parent): QMainWindow(parent) {
rootLyt->addWidget(m_slideView); rootLyt->addWidget(m_slideView);
rootLyt->addLayout(controlsLayout); rootLyt->addLayout(controlsLayout);
// setup slide controls // setup slide controls
const auto showHideLyt = new QHBoxLayout;
rootLyt->addLayout(showHideLyt);
const auto btnPrevSong = new QPushButton(tr("Previous Song (Left)"), this); const auto btnPrevSong = new QPushButton(tr("Previous Song (Left)"), this);
const auto btnPrevSlide = new QPushButton(tr("Previous Slide (Up)"), this); const auto btnPrevSlide = new QPushButton(tr("Previous Slide (Up)"), this);
const auto btnNextSlide = new QPushButton(tr("Next Slide (Down)"), this); const auto btnNextSlide = new QPushButton(tr("Next Slide (Down)"), this);
const auto btnNextSong = new QPushButton(tr("Next Song (Right)"), this); const auto btnNextSong = new QPushButton(tr("Next Song (Right)"), this);
const auto btnHideSlides = new QPushButton(tr("Hide (1)"), this);
const auto btnOpenLpShowSlides = new QPushButton(tr("Show in OpenLP Only (2)"), this);
const auto btnShowSlides = new QPushButton(tr("Show (3)"), mainWidget);
controlsLayout->addWidget(btnPrevSlide, 0, 1); controlsLayout->addWidget(btnPrevSlide, 0, 1);
controlsLayout->addWidget(btnNextSlide, 0, 2); controlsLayout->addWidget(btnNextSlide, 0, 2);
controlsLayout->addWidget(btnPrevSong, 0, 0); controlsLayout->addWidget(btnPrevSong, 0, 0);
controlsLayout->addWidget(btnNextSong, 0, 3); controlsLayout->addWidget(btnNextSong, 0, 3);
showHideLyt->addWidget(btnHideSlides); controlsLayout->setSpacing(2);
showHideLyt->addWidget(btnOpenLpShowSlides);
showHideLyt->addWidget(btnShowSlides);
btnNextSong->setShortcut(Qt::Key_Right); btnNextSong->setShortcut(Qt::Key_Right);
btnPrevSong->setShortcut(Qt::Key_Left); btnPrevSong->setShortcut(Qt::Key_Left);
btnNextSlide->setShortcut(Qt::Key_Down); btnNextSlide->setShortcut(Qt::Key_Down);
btnPrevSlide->setShortcut(Qt::Key_Up); btnPrevSlide->setShortcut(Qt::Key_Up);
btnHideSlides->setShortcut(Qt::Key_1); btnNextSong->setFixedWidth(135);
btnOpenLpShowSlides->setShortcut(Qt::Key_2); btnPrevSong->setFixedWidth(135);
btnHideSlides->setToolTip(tr("Also hides slides in OBS")); btnNextSlide->setFixedWidth(135);
btnShowSlides->setShortcut(Qt::Key_3); btnPrevSlide->setFixedWidth(135);
setupViewControls(rootLyt);
connect(btnNextSlide, &QPushButton::clicked, &m_openlpClient, &OpenLPClient::nextSlide); connect(btnNextSlide, &QPushButton::clicked, &m_openlpClient, &OpenLPClient::nextSlide);
connect(btnPrevSlide, &QPushButton::clicked, &m_openlpClient, &OpenLPClient::prevSlide); connect(btnPrevSlide, &QPushButton::clicked, &m_openlpClient, &OpenLPClient::prevSlide);
connect(btnNextSong, &QPushButton::clicked, &m_openlpClient, &OpenLPClient::nextSong); connect(btnNextSong, &QPushButton::clicked, &m_openlpClient, &OpenLPClient::nextSong);
connect(btnPrevSong, &QPushButton::clicked, &m_openlpClient, &OpenLPClient::prevSong); connect(btnPrevSong, &QPushButton::clicked, &m_openlpClient, &OpenLPClient::prevSong);
connect(btnHideSlides, &QPushButton::clicked, &m_openlpClient, &OpenLPClient::blankScreen);
connect(btnHideSlides, &QPushButton::clicked, &m_obsClient, &OBSClient::hideSlides);
connect(btnOpenLpShowSlides, &QPushButton::clicked, &m_openlpClient, &OpenLPClient::showSlides);
connect(btnShowSlides, &QPushButton::clicked, &m_obsClient, &OBSClient::showSlides);
connect(btnShowSlides, &QPushButton::clicked, &m_openlpClient, &OpenLPClient::showSlides);
connect(&m_openlpClient, &OpenLPClient::pollUpdate, m_slideView, &SlideView::pollUpdate); connect(&m_openlpClient, &OpenLPClient::pollUpdate, m_slideView, &SlideView::pollUpdate);
connect(&m_openlpClient, &OpenLPClient::songListUpdate, m_slideView, &SlideView::songListUpdate); connect(&m_openlpClient, &OpenLPClient::songListUpdate, m_slideView, &SlideView::songListUpdate);
connect(&m_openlpClient, &OpenLPClient::slideListUpdate, m_slideView, &SlideView::slideListUpdate); connect(&m_openlpClient, &OpenLPClient::slideListUpdate, m_slideView, &SlideView::slideListUpdate);
connect(&m_openlpClient, &OpenLPClient::pollFailed, m_slideView, &SlideView::reset); connect(&m_openlpClient, &OpenLPClient::pollFailed, m_slideView, &SlideView::reset);
connect(m_slideView, &SlideView::songChanged, &m_openlpClient, &OpenLPClient::changeSong); connect(m_slideView, &SlideView::songChanged, &m_openlpClient, &OpenLPClient::changeSong);
connect(m_slideView, &SlideView::slideChanged, &m_openlpClient, &OpenLPClient::changeSlide); connect(m_slideView, &SlideView::slideChanged, &m_openlpClient, &OpenLPClient::changeSlide);
// setup scene selector
connect(btnOpenLpShowSlides, &QPushButton::clicked, &m_obsClient, &OBSClient::hideSlides);
// setup status bar // setup status bar
setStatusBar(new QStatusBar(this)); setStatusBar(new QStatusBar(this));
connect(&m_cameraClient, &CameraClient::pollUpdate, this, &MainWindow::cameraConnectionInit);
connect(&m_openlpClient, &OpenLPClient::songChanged, this, &MainWindow::refreshStatusBar); connect(&m_openlpClient, &OpenLPClient::songChanged, this, &MainWindow::refreshStatusBar);
connect(&m_openlpClient, &OpenLPClient::pollUpdate, this, &MainWindow::openLpConnectionInit); connect(&m_openlpClient, &OpenLPClient::pollUpdate, this, &MainWindow::openLpConnectionInit);
connect(&m_obsClient, &OBSClient::pollUpdate, this, &MainWindow::obsConnectionInit); connect(&m_obsClient, &OBSClient::pollUpdate, this, &MainWindow::obsConnectionInit);
refreshStatusBar(); refreshStatusBar();
connect(statusBar(), &QStatusBar::messageChanged, this, [this](QStringView const&msg) {
if (msg.empty()) {
refreshStatusBar();
}
});
}
void MainWindow::setupMenu() {
// file menu
auto const fileMenu = menuBar()->addMenu(tr("&File"));
auto const settingsAct = new QAction(tr("&Settings"), this);
auto const quitAct = new QAction(tr("E&xit"), this);
settingsAct->setShortcuts(QKeySequence::Preferences);
connect(settingsAct, &QAction::triggered, this, &MainWindow::openSettings);
quitAct->setShortcuts(QKeySequence::Quit);
quitAct->setStatusTip(tr("Exit application"));
connect(quitAct, &QAction::triggered, &QApplication::quit);
fileMenu->addAction(settingsAct);
fileMenu->addAction(quitAct);
}
void MainWindow::setupDefaultViewControls(QHBoxLayout *viewCtlLyt) {
auto const mainWidget = viewCtlLyt->parentWidget();
auto const btnHideSlides = new QPushButton(tr("1. Hide"), mainWidget);
auto const btnOpenLpShowSlides = new QPushButton(tr("2. Show in OpenLP Only"), mainWidget);
auto const btnShowSlides = new QPushButton(tr("3. Show"), mainWidget);
viewCtlLyt->addWidget(btnHideSlides);
viewCtlLyt->addWidget(btnOpenLpShowSlides);
viewCtlLyt->addWidget(btnShowSlides);
btnHideSlides->setShortcut(Qt::Key_1);
btnOpenLpShowSlides->setShortcut(Qt::Key_2);
btnHideSlides->setToolTip(tr("Also hides slides in OBS"));
btnShowSlides->setShortcut(Qt::Key_3);
connect(btnHideSlides, &QPushButton::clicked, &m_openlpClient, &OpenLPClient::blankScreen);
connect(btnHideSlides, &QPushButton::clicked, &m_obsClient, &OBSClient::hideSlides);
connect(btnOpenLpShowSlides, &QPushButton::clicked, &m_openlpClient, &OpenLPClient::showSlides);
connect(btnOpenLpShowSlides, &QPushButton::clicked, &m_obsClient, &OBSClient::hideSlides);
connect(btnShowSlides, &QPushButton::clicked, &m_obsClient, &OBSClient::showSlides);
connect(btnShowSlides, &QPushButton::clicked, &m_openlpClient, &OpenLPClient::showSlides);
}
void MainWindow::setupCustomViewControls(QVector<View> const&views, QGridLayout *viewCtlLyt) {
constexpr auto columns = 3;
auto const parent = viewCtlLyt->parentWidget();
for (auto i = 0; auto const&view : views) {
auto const x = i % columns;
auto const y = i / columns;
auto const name = QString("%1. %2").arg(i + 1).arg(view.name);
auto const btn = new QPushButton(name, parent);
btn->setShortcut(Qt::Key_1 + i);
viewCtlLyt->addWidget(btn, y, x);
auto const slides = view.slides;
auto const obsSlides = view.obsSlides;
auto const cameraPreset = view.cameraPreset;
connect(btn, &QPushButton::clicked, this, [this, slides, obsSlides, cameraPreset] {
m_cameraClient.setPreset(cameraPreset);
m_openlpClient.setSlidesVisible(slides);
m_obsClient.setSlidesVisible(obsSlides);
});
++i;
}
}
void MainWindow::setupViewControls(QVBoxLayout *rootLyt) {
auto views = getViews();
if (!m_viewControlsParent) {
m_viewControlsParent = new QWidget(rootLyt->parentWidget());
m_viewControlsParentLyt = new QHBoxLayout(m_viewControlsParent);
m_viewControlsParentLyt->setContentsMargins(0, 0, 0, 0);
rootLyt->addWidget(m_viewControlsParent);
}
delete m_viewControls;
m_viewControls = new QWidget(m_viewControlsParent);
m_viewControlsParentLyt->addWidget(m_viewControls);
auto const viewCtlLyt = new QGridLayout(m_viewControls);
viewCtlLyt->setSpacing(5);
if (views.empty()) {
views.emplace_back(View{
.name = tr("Hide"),
.slides = false,
.obsSlides = false,
});
views.emplace_back(View{
.name = tr("Hide in OBS"),
.slides = false,
.obsSlides = false,
});
views.emplace_back(View{
.name = tr("Show"),
.slides = false,
.obsSlides = false,
});
}
setupCustomViewControls(views, viewCtlLyt);
}
void MainWindow::openSettings() {
SettingsDialog d(this);
auto const result = d.exec();
if (result == QDialog::Accepted) {
m_cameraClient.setBaseUrl();
m_obsClient.setBaseUrl();
m_openlpClient.setBaseUrl();
}
}
void MainWindow::cameraConnectionInit() {
disconnect(&m_cameraClient, &CameraClient::pollUpdate, this, &MainWindow::cameraConnectionInit);
connect(&m_cameraClient, &CameraClient::pollFailed, this, &MainWindow::cameraConnectionLost);
m_cameraConnected = true;
refreshStatusBar();
}
void MainWindow::cameraConnectionLost() {
disconnect(&m_cameraClient, &CameraClient::pollFailed, this, &MainWindow::cameraConnectionLost);
connect(&m_cameraClient, &CameraClient::pollUpdate, this, &MainWindow::cameraConnectionInit);
m_cameraConnected = false;
refreshStatusBar();
} }
void MainWindow::openLpConnectionInit() { void MainWindow::openLpConnectionInit() {
@ -104,9 +214,10 @@ void MainWindow::obsConnectionLost() {
} }
void MainWindow::refreshStatusBar() { void MainWindow::refreshStatusBar() {
const auto openLpStatus = m_openLpConnected ? tr("OpenLP: Connected") : tr("OpenLP: Not Connected"); auto const cameraStatus = m_cameraConnected ? tr("Camera: Connected") : tr("Camera: Not Connected");
const auto obsStatus = m_obsConnected ? tr("OBS: Connected") : tr("OBS: Not Connected"); auto const openLpStatus = m_openLpConnected ? tr("OpenLP: Connected") : tr("OpenLP: Not Connected");
const auto nextSong = m_openlpClient.getNextSong(); auto const obsStatus = m_obsConnected ? tr("OBS: Connected") : tr("OBS: Not Connected");
const auto nextSongTxt = m_openLpConnected ? " | Next Song: " + nextSong : ""; auto const nextSong = m_openlpClient.getNextSong();
statusBar()->showMessage(openLpStatus + " | " + obsStatus + nextSongTxt); auto const nextSongTxt = m_openLpConnected ? " | Next Song: " + nextSong : "";
statusBar()->showMessage(cameraStatus + " | " + openLpStatus + " | " + obsStatus + nextSongTxt);
} }

View File

@ -12,24 +12,45 @@
#include <QMainWindow> #include <QMainWindow>
#include "cameraclient.hpp"
#include "obsclient.hpp" #include "obsclient.hpp"
#include "openlpclient.hpp" #include "openlpclient.hpp"
#include "settingsdata.hpp"
class MainWindow: public QMainWindow { class MainWindow: public QMainWindow {
Q_OBJECT Q_OBJECT
private: private:
CameraClient m_cameraClient;
OBSClient m_obsClient; OBSClient m_obsClient;
OpenLPClient m_openlpClient; OpenLPClient m_openlpClient;
class SlideView *m_slideView = nullptr; class SlideView *m_slideView = nullptr;
bool m_cameraConnected = false;
bool m_openLpConnected = false; bool m_openLpConnected = false;
bool m_obsConnected = false; bool m_obsConnected = false;
class QHBoxLayout *m_viewControlsParentLyt = nullptr;
class QWidget *m_viewControlsParent = nullptr;
class QWidget *m_viewControls = nullptr;
public: public:
explicit MainWindow(QWidget *parent = nullptr); explicit MainWindow(QWidget *parent = nullptr);
~MainWindow() override = default; ~MainWindow() override = default;
private slots: private:
void setupMenu();
void setupDefaultViewControls(class QHBoxLayout *rootLyt);
void setupCustomViewControls(QVector<View> const&views, class QGridLayout *rootLyt);
void setupViewControls(class QVBoxLayout *rootLyt);
void openSettings();
void cameraConnectionInit();
void cameraConnectionLost();
void openLpConnectionInit(); void openLpConnectionInit();
void openLpConnectionLost(); void openLpConnectionLost();

View File

@ -8,17 +8,20 @@
#include <QNetworkReply> #include <QNetworkReply>
#include <QNetworkRequest> #include <QNetworkRequest>
#include <QSettings>
#include <QUrl> #include <QUrl>
#include "settingsdata.hpp"
#include "obsclient.hpp" #include "obsclient.hpp"
OBSClient::OBSClient(QObject *parent): QObject(parent) { OBSClient::OBSClient(QObject *parent): QObject(parent) {
setBaseUrl();
m_pollTimer.start(1000); m_pollTimer.start(1000);
connect(&m_pollTimer, &QTimer::timeout, this, &OBSClient::poll); connect(&m_pollTimer, &QTimer::timeout, this, &OBSClient::poll);
connect(m_pollingNam, &QNetworkAccessManager::finished, this, &OBSClient::handlePollResponse); connect(m_pollingNam, &QNetworkAccessManager::finished, this, &OBSClient::handlePollResponse);
} }
void OBSClient::setScene(QString scene) { void OBSClient::setScene(QString const&scene) {
get(QString("/Scene?name=%1").arg(scene)); get(QString("/Scene?name=%1").arg(scene));
} }
@ -30,7 +33,7 @@ void OBSClient::hideSlides() {
setScene("SpeakerScene"); setScene("SpeakerScene");
} }
void OBSClient::setSlidesVisible(int state) { void OBSClient::setSlidesVisible(bool state) {
if (state) { if (state) {
setScene("MusicScene"); setScene("MusicScene");
} else { } else {
@ -38,15 +41,20 @@ void OBSClient::setSlidesVisible(int state) {
} }
} }
void OBSClient::get(QString urlExt) { void OBSClient::setBaseUrl() {
QUrl url(QString(BaseUrl) + urlExt); const auto [host, port] = getOBSConnectionData();
m_baseUrl = QString("http://%1:%2").arg(host, QString::number(port));
}
void OBSClient::get(QString const&urlExt) {
QUrl url(QString(m_baseUrl) + urlExt);
QNetworkRequest rqst(url); QNetworkRequest rqst(url);
auto reply = m_nam->get(rqst); auto reply = m_nam->get(rqst);
connect(reply, &QIODevice::readyRead, reply, &QObject::deleteLater); connect(reply, &QIODevice::readyRead, reply, &QObject::deleteLater);
} }
void OBSClient::poll() { void OBSClient::poll() {
QUrl url(QString(BaseUrl) + "/ping"); QUrl url(QString(m_baseUrl) + "/ping");
QNetworkRequest rqst(url); QNetworkRequest rqst(url);
m_pollingNam->get(rqst); m_pollingNam->get(rqst);
} }

View File

@ -17,7 +17,7 @@
class OBSClient: public QObject { class OBSClient: public QObject {
Q_OBJECT Q_OBJECT
private: private:
const QString BaseUrl = QString("http://") + SlideHost + ":9302"; QString m_baseUrl;
QNetworkAccessManager *m_nam = new QNetworkAccessManager(this); QNetworkAccessManager *m_nam = new QNetworkAccessManager(this);
QNetworkAccessManager *m_pollingNam = new QNetworkAccessManager(this); QNetworkAccessManager *m_pollingNam = new QNetworkAccessManager(this);
QTimer m_pollTimer; QTimer m_pollTimer;
@ -26,16 +26,18 @@ class OBSClient: public QObject {
explicit OBSClient(QObject *parent = nullptr); explicit OBSClient(QObject *parent = nullptr);
public slots: public slots:
void setScene(QString scene); void setScene(QString const&scene);
void showSlides(); void showSlides();
void hideSlides(); void hideSlides();
void setSlidesVisible(int state); void setSlidesVisible(bool state);
void setBaseUrl();
private: private:
void get(QString url); void get(QString const&url);
void poll(); void poll();

View File

@ -11,10 +11,13 @@
#include <QJsonObject> #include <QJsonObject>
#include <QJsonValueRef> #include <QJsonValueRef>
#include <QNetworkReply> #include <QNetworkReply>
#include <QSettings>
#include "settingsdata.hpp"
#include "openlpclient.hpp" #include "openlpclient.hpp"
OpenLPClient::OpenLPClient(QObject *parent): QObject(parent) { OpenLPClient::OpenLPClient(QObject *parent): QObject(parent) {
setBaseUrl();
poll(); poll();
m_pollTimer.start(250); m_pollTimer.start(250);
connect(&m_pollTimer, &QTimer::timeout, this, &OpenLPClient::poll); connect(&m_pollTimer, &QTimer::timeout, this, &OpenLPClient::poll);
@ -57,6 +60,14 @@ void OpenLPClient::showSlides() {
get("/api/display/show"); get("/api/display/show");
} }
void OpenLPClient::setSlidesVisible(bool value) {
if (value) {
showSlides();
} else {
blankScreen();
}
}
void OpenLPClient::changeSong(int it) { void OpenLPClient::changeSong(int it) {
auto n = QString::number(it); auto n = QString::number(it);
auto url = "/api/service/set?data=%7B%22request%22%3A+%7B%22id%22%3A+" + n + "%7D%7D&_=1627181837297"; auto url = "/api/service/set?data=%7B%22request%22%3A+%7B%22id%22%3A+" + n + "%7D%7D&_=1627181837297";
@ -69,26 +80,31 @@ void OpenLPClient::changeSlide(int slide) {
get(url); get(url);
} }
void OpenLPClient::get(QString urlExt) { void OpenLPClient::setBaseUrl() {
QUrl url(QString(BaseUrl) + urlExt); const auto [host, port] = getOpenLPConnectionData();
m_baseUrl = QString("http://%1:%2").arg(host, QString::number(port));
}
void OpenLPClient::get(QString const&urlExt) {
QUrl url(m_baseUrl + urlExt);
QNetworkRequest rqst(url); QNetworkRequest rqst(url);
m_nam->get(rqst); m_nam->get(rqst);
} }
void OpenLPClient::requestSongList() { void OpenLPClient::requestSongList() {
QUrl url(QString(BaseUrl) + "/api/service/list?_=1626628079579"); QUrl url(m_baseUrl + "/api/service/list?_=1626628079579");
QNetworkRequest rqst(url); QNetworkRequest rqst(url);
m_songListNam->get(rqst); m_songListNam->get(rqst);
} }
void OpenLPClient::requestSlideList() { void OpenLPClient::requestSlideList() {
QUrl url(QString(BaseUrl) + "/api/controller/live/text?_=1626628079579"); QUrl url(m_baseUrl + "/api/controller/live/text?_=1626628079579");
QNetworkRequest rqst(url); QNetworkRequest rqst(url);
m_slideListNam->get(rqst); m_slideListNam->get(rqst);
} }
void OpenLPClient::poll() { void OpenLPClient::poll() {
QUrl url(QString(BaseUrl) + "/api/poll?_=1626628079579"); QUrl url(m_baseUrl + "/api/poll?_=1626628079579");
QNetworkRequest rqst(url); QNetworkRequest rqst(url);
m_pollingNam->get(rqst); m_pollingNam->get(rqst);
} }

View File

@ -19,11 +19,7 @@ class OpenLPClient: public QObject {
Q_OBJECT Q_OBJECT
private: private:
struct Song { QString m_baseUrl;
QString name;
QString id;
};
const QString BaseUrl = QString("http://") + SlideHost + ":4316";
QNetworkAccessManager *m_nam = new QNetworkAccessManager(this); QNetworkAccessManager *m_nam = new QNetworkAccessManager(this);
QNetworkAccessManager *m_pollingNam = new QNetworkAccessManager(this); QNetworkAccessManager *m_pollingNam = new QNetworkAccessManager(this);
QNetworkAccessManager *m_songListNam = new QNetworkAccessManager(this); QNetworkAccessManager *m_songListNam = new QNetworkAccessManager(this);
@ -53,12 +49,16 @@ class OpenLPClient: public QObject {
void showSlides(); void showSlides();
void setSlidesVisible(bool value);
void changeSong(int it); void changeSong(int it);
void changeSlide(int slide); void changeSlide(int slide);
void setBaseUrl();
private: private:
void get(QString url); void get(QString const&url);
void requestSongList(); void requestSongList();

142
src/settingsdata.cpp Normal file
View File

@ -0,0 +1,142 @@
/*
* Copyright 2021 - 2023 gary@drinkingtea.net
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#include <QSettings>
#include "settingsdata.hpp"
void setCameraConnectionData(QSettings &settings, ConnectionData const&cd) {
settings.beginGroup("CameraClient");
settings.setValue("Host", cd.host);
settings.setValue("Port", cd.port);
settings.endGroup();
}
void setOpenLPConnectionData(QSettings &settings, ConnectionData const&cd) {
settings.beginGroup("OpenLPClient");
settings.setValue("Host", cd.host);
settings.setValue("Port", cd.port);
settings.endGroup();
}
void setOBSConnectionData(QSettings &settings, ConnectionData const&cd) {
settings.beginGroup("OBSClient");
settings.setValue("Host", cd.host);
settings.setValue("Port", cd.port);
settings.endGroup();
}
ConnectionData getCameraConnectionData(QSettings &settings) {
ConnectionData out;
settings.beginGroup("CameraClient");
out.host = settings.value("Host", "192.168.100.88").toString();
out.port = static_cast<uint16_t>(settings.value("Port", 80).toInt());
settings.endGroup();
return out;
}
ConnectionData getOpenLPConnectionData(QSettings &settings) {
ConnectionData out;
settings.beginGroup("OpenLPClient");
out.host = settings.value("Host", "127.0.0.1").toString();
out.port = static_cast<uint16_t>(settings.value("Port", 4316).toInt());
settings.endGroup();
return out;
}
ConnectionData getOBSConnectionData(QSettings &settings) {
ConnectionData out;
settings.beginGroup("OBSClient");
out.host = settings.value("Host", "127.0.0.1").toString();
out.port = static_cast<uint16_t>(settings.value("Port", 9302).toInt());
settings.endGroup();
return out;
}
void setCameraConnectionData(ConnectionData const&cd) {
QSettings settings;
settings.beginGroup("CameraClient");
settings.setValue("Host", cd.host);
settings.setValue("Port", cd.port);
settings.endGroup();
}
void setOpenLPConnectionData(ConnectionData const&cd) {
QSettings settings;
settings.beginGroup("OpenLPClient");
settings.setValue("Host", cd.host);
settings.setValue("Port", cd.port);
settings.endGroup();
}
void setOBSConnectionData(ConnectionData const&cd) {
QSettings settings;
settings.beginGroup("OBSClient");
settings.setValue("Host", cd.host);
settings.setValue("Port", cd.port);
settings.endGroup();
}
ConnectionData getCameraConnectionData() {
QSettings s;
return getCameraConnectionData(s);
}
ConnectionData getOpenLPConnectionData() {
QSettings s;
return getOpenLPConnectionData(s);
}
ConnectionData getOBSConnectionData() {
QSettings s;
return getOBSConnectionData(s);
}
void setViews(QSettings &settings, QVector<View> const&views) {
settings.beginGroup("Views");
settings.beginWriteArray("Views");
for (auto i = 0; auto const&view : views) {
settings.setArrayIndex(i);
settings.setValue("Name", view.name);
settings.setValue("Slides", view.slides);
settings.setValue("ObsSlides", view.obsSlides);
settings.setValue("Preset", view.cameraPreset);
++i;
}
settings.endArray();
settings.endGroup();
}
void setViews(QVector<View> const&views) {
QSettings s;
return setViews(s, views);
}
QVector<View> getViews(QSettings &settings) {
QVector<View> out;
settings.beginGroup("Views");
const auto size = settings.beginReadArray("Views");
for (auto i = 0; i < size; ++i) {
settings.setArrayIndex(i);
out.emplace_back(View{
.name = settings.value("Name").toString(),
.slides = settings.value("Slides").toBool(),
.obsSlides = settings.value("ObsSlides").toBool(),
.cameraPreset = settings.value("Preset").toInt(),
});
}
settings.endArray();
settings.endGroup();
return out;
}
QVector<View> getViews() {
QSettings s;
return getViews(s);
}

59
src/settingsdata.hpp Normal file
View File

@ -0,0 +1,59 @@
/*
* Copyright 2021 - 2023 gary@drinkingtea.net
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#pragma once
#include <QString>
#include <QVector>
struct ConnectionData {
QString host;
uint16_t port = 0;
};
void setCameraConnectionData(class QSettings &settings, ConnectionData const&cd);
void setOpenLPConnectionData(class QSettings &settings, ConnectionData const&cd);
void setOBSConnectionData(class QSettings &settings, ConnectionData const&cd);
[[nodiscard]]
ConnectionData getCameraConnectionData(class QSettings &settings);
[[nodiscard]]
ConnectionData getOpenLPConnectionData(class QSettings &settings);
[[nodiscard]]
ConnectionData getOBSConnectionData(class QSettings &settings);
[[nodiscard]]
ConnectionData getCameraConnectionData();
[[nodiscard]]
ConnectionData getOpenLPConnectionData();
[[nodiscard]]
ConnectionData getOBSConnectionData();
struct View {
QString name;
bool slides = false;
bool obsSlides = false;
int cameraPreset = -1;
};
void setViews(class QSettings &settings, QVector<View> const&views);
void setViews(QVector<View> const&views);
[[nodiscard]]
QVector<View> getViews(class QSettings &settings);
[[nodiscard]]
QVector<View> getViews();

224
src/settingsdialog.cpp Normal file
View File

@ -0,0 +1,224 @@
/*
* Copyright 2021 - 2023 gary@drinkingtea.net
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#include <QCheckBox>
#include <QFormLayout>
#include <QHeaderView>
#include <QIntValidator>
#include <QLabel>
#include <QLineEdit>
#include <QPushButton>
#include <QSettings>
#include <QSpacerItem>
#include <QTabWidget>
#include <QTableWidget>
#include <QVBoxLayout>
#include "settingsdialog.hpp"
constexpr auto MaxPresets = 9;
constexpr auto MaxViews = 9;
enum ViewColumn {
Name = 0,
Slides,
ObsSlides,
CameraPreset,
Count
};
SettingsDialog::SettingsDialog(QWidget *parent): QDialog(parent) {
const auto lyt = new QVBoxLayout(this);
const auto tabs = new QTabWidget(this);
lyt->addWidget(tabs);
tabs->addTab(setupViewConfig(tabs), tr("&Views"));
tabs->addTab(setupNetworkInputs(tabs), tr("&Network"));
lyt->addWidget(setupButtons(this));
setFixedSize(440, 440);
}
QWidget *SettingsDialog::setupNetworkInputs(QWidget *parent) {
const auto root = new QWidget(parent);
const auto lyt = new QFormLayout(root);
const auto portValidator = new QIntValidator(1, 65536, this);
QSettings settings;
// camera settings
{
const auto c = getCameraConnectionData(settings);
m_cameraIpLe = new QLineEdit(root);
m_cameraPortLe = new QLineEdit(root);
m_cameraIpLe->setText(c.host);
m_cameraPortLe->setText(QString::number(c.port));
m_cameraPortLe->setValidator(portValidator);
lyt->addRow(tr("C&amera IP Address:"), m_cameraIpLe);
lyt->addRow(tr("Ca&mera Port:"), m_cameraPortLe);
}
// OpenLP settings
{
const auto c = getOpenLPConnectionData(settings);
m_openLpIpLe = new QLineEdit(root);
m_openLpPortLe = new QLineEdit(root);
m_openLpIpLe->setText(c.host);
m_openLpPortLe->setText(QString::number(c.port));
m_openLpPortLe->setValidator(portValidator);
lyt->addRow(tr("Op&enLP IP Address:"), m_openLpIpLe);
lyt->addRow(tr("Open&LP Port:"), m_openLpPortLe);
}
// OBS settings
{
const auto c = getOBSConnectionData(settings);
m_obsIpLe = new QLineEdit(root);
m_obsPortLe = new QLineEdit(root);
m_obsIpLe->setText(c.host);
m_obsPortLe->setText(QString::number(c.port));
m_obsPortLe->setValidator(portValidator);
lyt->addRow(tr("O&BS IP Address:"), m_obsIpLe);
lyt->addRow(tr("OB&S Port:"), m_obsPortLe);
}
return root;
}
QWidget *SettingsDialog::setupViewConfig(QWidget *parent) {
auto const root = new QWidget(parent);
auto const lyt = new QVBoxLayout(root);
// table
m_viewTable = new QTableWidget(parent);
{
lyt->addWidget(m_viewTable);
QStringList columns;
columns.resize(ViewColumn::Count);
columns[ViewColumn::Name] = tr("Name");
columns[ViewColumn::Slides] = tr("Slides");
columns[ViewColumn::ObsSlides] = tr("OBS Slides");
columns[ViewColumn::CameraPreset] = tr("Camera Preset");
m_viewTable->setColumnCount(static_cast<int>(columns.size()));
m_viewTable->setHorizontalHeaderLabels(columns);
m_viewTable->setSelectionMode(QAbstractItemView::SelectionMode::SingleSelection);
m_viewTable->setSelectionBehavior(QAbstractItemView::SelectionBehavior::SelectRows);
auto const hdr = m_viewTable->horizontalHeader();
m_viewTable->setColumnWidth(1, 70);
m_viewTable->setColumnWidth(2, 70);
m_viewTable->setColumnWidth(3, 70);
hdr->setStretchLastSection(true);
}
// add/removes buttons
{
auto const btnsRoot = new QWidget(root);
auto const btnsLyt = new QHBoxLayout(btnsRoot);
auto const addBtn = new QPushButton("+", btnsRoot);
auto const rmBtn = new QPushButton("-", btnsRoot);
addBtn->setFixedWidth(20);
rmBtn->setFixedWidth(20);
rmBtn->setDisabled(true);
lyt->addWidget(btnsRoot);
btnsLyt->addWidget(addBtn);
btnsLyt->addWidget(rmBtn);
btnsLyt->addSpacerItem(new QSpacerItem(1000, 0, QSizePolicy::Expanding, QSizePolicy::Ignored));
connect(addBtn, &QPushButton::clicked, this, [this, addBtn] {
auto const row = m_viewTable->rowCount();
m_viewTable->setRowCount(row + 1);
setupViewRow(row);
addBtn->setEnabled(m_viewTable->rowCount() < MaxViews);
});
connect(rmBtn, &QPushButton::clicked, this, [this, addBtn] {
auto const row = m_viewTable->currentRow();
m_viewTable->removeRow(row);
addBtn->setEnabled(m_viewTable->rowCount() < MaxViews);
});
connect(m_viewTable, &QTableWidget::currentCellChanged, rmBtn, [this, addBtn, rmBtn] (int row) {
rmBtn->setEnabled(row > -1 && row < m_viewTable->rowCount());
addBtn->setEnabled(m_viewTable->rowCount() < MaxViews);
});
const auto views = getViews();
m_viewTable->setRowCount(static_cast<int>(views.size()));
for (auto row = 0; auto const&view : views) {
setupViewRow(row, view);
++row;
}
}
return root;
}
QWidget *SettingsDialog::setupButtons(QWidget *parent) {
const auto root = new QWidget(parent);
const auto lyt = new QHBoxLayout(root);
m_errLbl = new QLabel(root);
const auto okBtn = new QPushButton(tr("&OK"), root);
const auto cancelBtn = new QPushButton(tr("&Cancel"), root);
lyt->addWidget(m_errLbl);
lyt->addSpacerItem(new QSpacerItem(1000, 0, QSizePolicy::Expanding, QSizePolicy::Ignored));
lyt->addWidget(okBtn);
lyt->addWidget(cancelBtn);
connect(okBtn, &QPushButton::clicked, this, &SettingsDialog::handleOK);
connect(cancelBtn, &QPushButton::clicked, this, &SettingsDialog::reject);
return root;
}
void SettingsDialog::handleOK() {
QSettings settings;
QVector<View> views;
auto const viewsErr = collectViews(views);
if (viewsErr) {
return;
}
setViews(settings, views);
setCameraConnectionData(settings, {
.host = m_cameraIpLe->text(),
.port = m_cameraPortLe->text().toUShort(),
});
setOpenLPConnectionData(settings, {
.host = m_openLpIpLe->text(),
.port = m_openLpPortLe->text().toUShort(),
});
setOBSConnectionData(settings, {
.host = m_obsIpLe->text(),
.port = m_obsPortLe->text().toUShort(),
});
accept();
}
void SettingsDialog::setupViewRow(int row, View const&view) {
// name
const auto nameItem = new QTableWidgetItem(view.name);
m_viewTable->setItem(row, ViewColumn::Name, nameItem);
// slides
const auto slidesCb = new QCheckBox(m_viewTable);
slidesCb->setChecked(view.slides);
m_viewTable->setCellWidget(row, ViewColumn::Slides, slidesCb);
// obs slides
const auto obsSlidesCb = new QCheckBox(m_viewTable);
obsSlidesCb->setChecked(view.obsSlides);
m_viewTable->setCellWidget(row, ViewColumn::ObsSlides, obsSlidesCb);
// camera preset
const auto presetItem = new QTableWidgetItem(QString::number(view.cameraPreset));
m_viewTable->setItem(row, ViewColumn::CameraPreset, presetItem);
}
int SettingsDialog::collectViews(QVector<View> &views) const {
for (auto row = 0; row < m_viewTable->rowCount(); ++row) {
auto const viewNo = row + 1;
bool ok = false;
auto const name = m_viewTable->item(row, ViewColumn::Name)->text();
if (name.trimmed() == "") {
m_errLbl->setText(tr("View %1 has no name.").arg(viewNo));
return 1;
}
const auto cameraPreset = m_viewTable->item(row, ViewColumn::CameraPreset)->text().toInt(&ok);
if (!ok || cameraPreset < 1 || cameraPreset > MaxPresets) {
m_errLbl->setText(tr("View %1 has invalid preset (1-%2)").arg(viewNo).arg(MaxPresets));
return 2;
}
views.emplace_back(View{
.name = name,
.slides = dynamic_cast<QCheckBox*>(m_viewTable->cellWidget(row, ViewColumn::Slides))->isChecked(),
.obsSlides = dynamic_cast<QCheckBox*>(m_viewTable->cellWidget(row, ViewColumn::ObsSlides))->isChecked(),
.cameraPreset = cameraPreset,
});
}
return 0;
}

40
src/settingsdialog.hpp Normal file
View File

@ -0,0 +1,40 @@
/*
* Copyright 2021 - 2023 gary@drinkingtea.net
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#pragma once
#include <QDialog>
#include "settingsdata.hpp"
class SettingsDialog: public QDialog {
Q_OBJECT
private:
class QLabel *m_errLbl = nullptr;
class QLineEdit *m_cameraIpLe = nullptr;
class QLineEdit *m_cameraPortLe = nullptr;
class QLineEdit *m_openLpIpLe = nullptr;
class QLineEdit *m_openLpPortLe = nullptr;
class QLineEdit *m_obsIpLe = nullptr;
class QLineEdit *m_obsPortLe = nullptr;
class QTableWidget *m_viewTable = nullptr;
public:
explicit SettingsDialog(QWidget *parent);
private:
QWidget *setupNetworkInputs(QWidget *parent);
QWidget *setupViewConfig(QWidget *parent);
QWidget *setupButtons(QWidget *parent);
void handleOK();
void setupViewRow(int row, View const&view = {});
/**
* Gets views from table.
* @return error code
*/
[[nodiscard("Must check error code")]]
int collectViews(QVector<View> &views) const;
};

View File

@ -6,7 +6,6 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. * file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/ */
#include <QComboBox>
#include <QDebug> #include <QDebug>
#include <QHBoxLayout> #include <QHBoxLayout>
#include <QHeaderView> #include <QHeaderView>
@ -43,9 +42,9 @@ QString SlideView::getNextSong() const {
return ""; return "";
} }
void SlideView::pollUpdate(QString songName, int slide) { void SlideView::pollUpdate(QString const&songName, int slide) {
auto songItems = m_songSelector->findItems(songName, Qt::MatchFixedString); auto songItems = m_songSelector->findItems(songName, Qt::MatchFixedString);
if (songItems.size() < 1) { if (songItems.empty()) {
return; return;
} }
auto songItem = songItems.first(); auto songItem = songItems.first();
@ -66,11 +65,11 @@ void SlideView::changeSong(int song) {
} }
} }
void SlideView::slideListUpdate(QStringList tagList, QStringList slideList) { void SlideView::slideListUpdate(QStringList const&tagList, QStringList const&slideList) {
m_currentSlide = 0; m_currentSlide = 0;
m_slideTable->setRowCount(slideList.size()); m_slideTable->setRowCount(static_cast<int>(slideList.size()));
for (int i = 0; i < slideList.size(); ++i) { for (int i = 0; i < slideList.size(); ++i) {
auto txt = slideList[i]; const auto& txt = slideList[i];
auto item = new QTableWidgetItem(txt); auto item = new QTableWidgetItem(txt);
item->setFlags(item->flags() & ~Qt::ItemIsEditable); item->setFlags(item->flags() & ~Qt::ItemIsEditable);
m_slideTable->setItem(i, 0, item); m_slideTable->setItem(i, 0, item);
@ -86,7 +85,7 @@ void SlideView::reset() {
m_currentSlide = -1; m_currentSlide = -1;
} }
void SlideView::songListUpdate(QStringList songList) { void SlideView::songListUpdate(QStringList const&songList) {
// Is this replacing an existing song list or is it the initial song list? // Is this replacing an existing song list or is it the initial song list?
// We want to reset the song to 0 upon replacement, // We want to reset the song to 0 upon replacement,
// but leave it alone upon initialization. // but leave it alone upon initialization.

View File

@ -24,11 +24,11 @@ class SlideView: public QWidget {
QString getNextSong() const; QString getNextSong() const;
public slots: public slots:
void pollUpdate(QString songId, int slideNum); void pollUpdate(const QString& songId, int slideNum);
void songListUpdate(QStringList songList); void songListUpdate(QStringList const&songList);
void slideListUpdate(QStringList tagList, QStringList songList); void slideListUpdate(QStringList const&tagList, QStringList const&songList);
void reset(); void reset();