diff --git a/assets.qrc b/assets.qrc index 8b63932..daa91ee 100644 --- a/assets.qrc +++ b/assets.qrc @@ -1,5 +1,6 @@ - assets/notificationAreaIcon.png + assets/notificationAreaIcon.png + assets/style.qss diff --git a/assets/style.qss b/assets/style.qss new file mode 100644 index 0000000..4f6466c --- /dev/null +++ b/assets/style.qss @@ -0,0 +1,6 @@ +QMainWindow { background: rgba(100,100,100,100); } + + + + +QCheckBox:hover, QCheckBox:checked { color: white } \ No newline at end of file diff --git a/bueno.bat b/bueno.bat index 2c8ac1c..edb534d 100644 --- a/bueno.bat +++ b/bueno.bat @@ -1,3 +1,4 @@ +taskkill /F /IM "qtest.exe" qmake -o build\Makefile .\qtest.pro copy /Y /B .\assets\SoundVolumeView.exe .\build\debug copy /Y /B .\assets\SoundVolumeView.exe .\build\release diff --git a/src/back/backlasses.cpp b/src/back/backlasses.cpp index a25d4c4..a53c052 100644 --- a/src/back/backlasses.cpp +++ b/src/back/backlasses.cpp @@ -689,6 +689,32 @@ Overseer::Overseer() { //: epsc(deviceEnumerator, playbackDevices){ if(FAILED(deviceEnumerator->RegisterEndpointNotificationCallback(((IMMNotificationClient*)&epsc)))) { log_debugcpp("when no enchufas......"); } } +void Overseer::openControlPanel() { + STARTUPINFOEXW startupConfig; + PROCESS_INFORMATION processInfo; + SecureZeroMemory(&startupConfig, sizeof(STARTUPINFOEXW)); + SecureZeroMemory(&startupConfig.StartupInfo, sizeof(STARTUPINFOW)); + startupConfig.StartupInfo.cb = sizeof(STARTUPINFOEXW); + SecureZeroMemory(&processInfo, sizeof(PROCESS_INFORMATION)); + + std::wstring command = L"rundll32 shell32, Control_RunDLL mmsys.cpl"; + if(CreateProcessW( + NULL, + (wchar_t*)command.c_str(), + NULL, + NULL, + false, + CREATE_UNICODE_ENVIRONMENT, + NULL, + NULL, + (LPSTARTUPINFOW)&startupConfig, + &processInfo + ) == true) { + CloseHandle(processInfo.hProcess); + CloseHandle(processInfo.hThread); + } +} + NGuid Overseer::getGuid() { return guid; } diff --git a/src/back/backlasses.h b/src/back/backlasses.h index f70e6d1..8796466 100644 --- a/src/back/backlasses.h +++ b/src/back/backlasses.h @@ -106,6 +106,7 @@ class Overseer { //TODO singleton? public: Overseer(); + void openControlPanel(); std::vector getPlaybackEndpoints(); std::vector getCaptureEndpoints(); diff --git a/src/back/msinclude.h b/src/back/msinclude.h index fc7beac..7bc7f4e 100644 --- a/src/back/msinclude.h +++ b/src/back/msinclude.h @@ -6,6 +6,7 @@ //done by qt by def #define UNICODE #include +#include #include #include #include diff --git a/src/cont/contclasses.cpp b/src/cont/contclasses.cpp index 38c30b1..d9fe2d0 100644 --- a/src/cont/contclasses.cpp +++ b/src/cont/contclasses.cpp @@ -201,6 +201,10 @@ OverseerHandler::OverseerHandler() { this->os = new Overseer(); } +void OverseerHandler::openControlPanel() { + this->os->openControlPanel(); +} + std::vector OverseerHandler::getPlaybackEndpoints() { return this->os->getPlaybackEndpoints(); } diff --git a/src/cont/contclasses.h b/src/cont/contclasses.h index 25fcaea..e46fc34 100644 --- a/src/cont/contclasses.h +++ b/src/cont/contclasses.h @@ -97,6 +97,8 @@ class OverseerHandler { public: OverseerHandler(); + void openControlPanel(); + void setChangeFrontDefaultsFunction(std::function changeFrontDefaults); void changeFrontDefaultsCallback(Roles role, std::wstring endpointId); diff --git a/src/global.h b/src/global.h index 035c95b..85f203a 100644 --- a/src/global.h +++ b/src/global.h @@ -22,6 +22,10 @@ #define STRING_SYSTEM_SOUNDS "System Sounds" #define LSTRING_SYSTEM_SOUNDS L"System Sounds" + +#define STRING_CP "Open Control Panel" +#define STRING_ABOUT "About" +#define STRING_STARTUP "Run at startup" //INIT BACK enum AudioChannel { diff --git a/src/qt/qtclasses.cpp b/src/qt/qtclasses.cpp index a9da261..125352b 100644 --- a/src/qt/qtclasses.cpp +++ b/src/qt/qtclasses.cpp @@ -6,7 +6,7 @@ CustomWidgetEvent::CustomWidgetEvent(QEvent::Type type, T payload) : QEvent(t } void ExtendedCheckBox::customEvent(QEvent* ev) { - QEvent::Type tipo = ev->type(); + //QEvent::Type tipo = ev->type(); if (ev->type() == (QEvent::Type)CustomQEvent::EndpointDefaultChange) { //todo: still prone to bugs; whack-a-mole to come ev->setAccepted(true); @@ -56,6 +56,8 @@ SessionWidget::SessionWidget(uint64_t idx, SessionHandler* sh, QWidget *parent) layout->addWidget(muteButton, 0, 1, Qt::AlignLeft | Qt::AlignBottom); layout->addWidget(mainSlider, 0, 2, 1, 2); + layout->setSizeConstraint(QLayout::SetMinAndMaxSize); + //TODO:0 = mute and muted, change volume = unmuted are client side tricks = 2 callbacks, one for volume, one for mute state. Implement as an user selectable option? connect(mainSlider, &QSlider::valueChanged, this,&SessionWidget::updateMainVolume); connect(muteButton, &QCheckBox::stateChanged, this, (&SessionWidget::updateMute)); @@ -108,6 +110,7 @@ EndpointWidget::EndpointWidget(uint64_t idx, EndpointHandler* eph, QWidget *pare //todo: sussy this->eph->setState(EndpointState::ENDPOINT_ACTIVE, idx); + //setAttribute(Qt::WA_TranslucentBackground); layout = new QGridLayout(this); //this->setLayout(layout); log_debugcpp("epw main layout parent: " + std::to_string((intptr_t)(layout->parent()))); @@ -149,9 +152,11 @@ EndpointWidget::EndpointWidget(uint64_t idx, EndpointHandler* eph, QWidget *pare //tip: would need to be new widget with layout in it //mainMuteLayout = new QGridLayout(); - layout->addWidget(mainLabel, row, 0, Qt::AlignLeft | Qt::AlignBottom); - layout->addWidget(muteButton, row, 1, Qt::AlignLeft | Qt::AlignBottom); - layout->addWidget(mainSlider, row, 2, 1, 2); + layout->addWidget(mainLabel, row, 0, Qt::AlignLeft | Qt::AlignVCenter); + layout->addWidget(muteButton, row, 1, Qt::AlignLeft | Qt::AlignVCenter); + layout->addWidget(mainSlider, row, 2, 1, 2, Qt::AlignLeft | Qt::AlignVCenter); + layout->setSizeConstraint(QLayout::SetMinAndMaxSize); + int debug2 = this->minimumWidth(); row++; //TODO:0 = mute and muted, change volume = unmuted are client side tricks = 2 callbacks, one for volume, one for mute state. Implement as an user selectable option? @@ -176,7 +181,7 @@ EndpointWidget::EndpointWidget(uint64_t idx, EndpointHandler* eph, QWidget *pare tmpLb->setText(QString::number(volume)); this->channelSliders.push_back(tmp); this->channelLabels.push_back(tmpLb); - layout->addWidget(tmp, row + 1, i); + layout->addWidget(tmp, row + 1, i); layout->addWidget(tmpLb, row + 2, i); //TODO: check if there's a need to prevent deadlocks; probably this will eventually turn into its own func @@ -263,7 +268,7 @@ EndpointWidget::EndpointWidget(uint64_t idx, EndpointHandler* eph, QWidget *pare /* First SessionWidget batch */ for (size_t i = 0; i < eph->getSessionCount(); i++) { SessionWidget* sessionWidget = new SessionWidget(i, eph->getSessionHandlers().at(i), this); - layout->addWidget(sessionWidget, row, 4); + layout->addWidget(sessionWidget, row, 1, 1, 4); row++; sessionWidgets.push_back(sessionWidget); eph->getSessionHandlers().at(i)->setFrontIndex(i); @@ -290,7 +295,7 @@ void EndpointWidget::addSessionWidget(CustomWidgetEvent* ev){ uint64_t index = this->sessionWidgets.size(); SessionWidget* sw = new SessionWidget(index, ev->payload, this); ev->payload->setFrontIndex(index); - this->layout->addWidget(sw, row, 4); + this->layout->addWidget(sw, row, 1, 1, 4); row++; sessionWidgets.push_back(sw); return; @@ -326,7 +331,7 @@ EndpointWidget::~EndpointWidget() { } void MainWindow::customEvent(QEvent* ev) { - if (ev->type() == CustomQEvent::EndpointWidgetObsolete) { + if (ev->type() == (QEvent::Type)CustomQEvent::EndpointWidgetObsolete) { ev->setAccepted(true); this->removeEndpointWidget((CustomWidgetEvent*)ev); } else if (ev->type() == (QEvent::Type)CustomQEvent::EndpointWidgetCreated) { @@ -448,6 +453,23 @@ std::map EndpointWidget::getDefaultRolesWidgets() { return defaultRolesCheckBoxes; } +HeaderWidget::HeaderWidget(QWidget *parent) : QWidget(parent) { + layout = new QGridLayout(this); + QString text = "&" STRING_ABOUT; + about = new QPushButton(text, this); + #ifdef WIN32 + text = "&" STRING_CP; + openCP = new QPushButton(text, this); + connect(openCP, &QPushButton::clicked, [this](){ osh->openControlPanel(); }); + text = "&" STRING_STARTUP; + startup = new QPushButton(text, this); + + layout->addWidget(openCP , 0, 0); + layout->addWidget(startup, 0, 1); + #endif + layout->addWidget(about , 0, 2); + this->setLayout(layout); +} MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) { // setWindowState(Qt::WindowFullScreen); @@ -459,7 +481,13 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) { QEvent::registerEventType(CustomQEvent::EndpointWidgetObsolete); QEvent::registerEventType(CustomQEvent::EndpointWidgetCreated); QEvent::registerEventType(CustomQEvent::EndpointDefaultChange); + QEvent::registerEventType(CustomQEvent::SessionWidgetObsolete); + QEvent::registerEventType(CustomQEvent::SessionWidgetCreated); + //setWindowFlags(Qt::FramelessWindowHint); + //setParent(0); // Create TopLevel-Widget + //setAttribute(Qt::WA_NoSystemBackground, true); + //setAttribute(Qt::WA_TranslucentBackground, true); ewsUpdateTimer = new QTimer(this); widget = new QWidget(); layout = new QGridLayout(); @@ -470,13 +498,34 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) { ewsUpdateTimer->setSingleShot(true); ewsUpdateTimer->setInterval(ewsUpdateTimerFrequency); connect(ewsUpdateTimer, &QTimer::timeout, this, &MainWindow::reorderEndpointWidgetCollection); + //widget->setMinimumSize(QSize(300,300)); widget->setLayout(layout); - setCentralWidget(widget); + /* + * Scroll bar code + */ + scrollArea = new QScrollArea(this); + scrollArea->setWidget(widget); + scrollArea->setWidgetResizable(true); + scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn); + scrollArea->setMinimumWidth(500); + setCentralWidget(scrollArea); + + /* + * Menu bar code + */ + QMenuBar* menuBar = (this->menuBar)(); + hw = new HeaderWidget(this); + menuBar->setCornerWidget(hw,Qt::TopLeftCorner); + menuBar->show(); + this->setMenuBar(menuBar); + + //setCentralWidget(widget); //layout->addWidget(pintas, 0, 0); setWindowTitle(STRING_TITLE); reloadEndpointWidgets(); - + scrollArea->setMinimumWidth(ews.at(0)->minimumWidth()); + int debug = scrollArea->minimumWidth(); /* * Tray Icon code */ diff --git a/src/qt/qtclasses.h b/src/qt/qtclasses.h index bec8f5e..7a89400 100644 --- a/src/qt/qtclasses.h +++ b/src/qt/qtclasses.h @@ -18,6 +18,12 @@ #include #include #include +#include +#include +#include +#include + +//#include /* * #else * class QSlider; @@ -142,6 +148,7 @@ private slots: private: int row; + const int sessionCol = 2; QCheckBox *muteButton = nullptr; QLabel *mainLabel = nullptr, *leftChannelLabel = nullptr, *rightChannelLabel = nullptr; QSlider *mainSlider = nullptr; @@ -164,6 +171,38 @@ private: }; +class HeaderWidget : public QWidget { +Q_OBJECT + +public: + HeaderWidget(QWidget *parent = nullptr); + + + //~HeaderWidget(); + //void updateMainVolume(float newValue); + //void updateVolume(uint32_t channel, float newValue); + //void updateMute(bool muted); + + //void populateEndpointWidget(EndpointHandler *eph); + //void setEndpointHandlers(std::vector *ephs); + +//public slots: + +//protected: + //void customEvent(QEvent* ev) override; + +//private slots: + //void addSessionWidget(CustomWidgetEvent* ev); + //void removeSessionWidget(CustomWidgetEvent* ev); + +private: + QGridLayout *layout; + QPushButton *about; + #ifdef WIN32 + QPushButton *openCP; + QPushButton *startup; + #endif +}; class MainWindow : public QMainWindow { Q_OBJECT @@ -196,6 +235,10 @@ private: QAction *trayIconMenuQuit; QTimer *ewsUpdateTimer; static constexpr uint64_t ewsUpdateTimerFrequency = 500; + + QScrollArea *scrollArea; + HeaderWidget* hw; + //QMenuBar *menuBar; //public slots: // void setEndpointHandlers(std::vector *ephs); diff --git a/src/qtestmain.cpp b/src/qtestmain.cpp index 19cf627..14c1aa8 100644 --- a/src/qtestmain.cpp +++ b/src/qtestmain.cpp @@ -10,6 +10,7 @@ #include #include #include +#include //#include "contclasses.h" #include "qtclasses.h" #include "global.h" @@ -55,9 +56,16 @@ int main (int argc, char* argv[]) { //INIT FRONT QScopedPointer app(createApplication(argc, argv)); MainWindow window = MainWindow(); - //window.setEndpointHandlers(ephs); + QApplication::setQuitOnLastWindowClosed(false); - app->setStyle("windowsvista"); + /* + * QFile styleFile(":/assets/style.qss"); + * styleFile.open(QFile::ReadOnly); + * QString styleSheet { QLatin1String(styleFile.readAll()) }; + */ + + //app->setStyleSheet(styleSheet); + //window.setMinimumSize(100, 100); window.show(); return app->exec(); }