Add action queue tab

This commit is contained in:
WarmUpTill 2024-04-29 19:28:56 +02:00 committed by WarmUpTill
parent 604a27141f
commit 44fc5177d6
6 changed files with 305 additions and 2 deletions

View File

@ -145,8 +145,10 @@ target_sources(
# Utility function sources
target_sources(
${LIB_NAME}
PRIVATE lib/utils/action-queue.cpp
lib/utils/action-queue.hpp
PRIVATE lib/queue/action-queue.cpp
lib/queue/action-queue.hpp
lib/queue/action-queue-tab.cpp
lib/queue/action-queue-tab.hpp
lib/utils/backup.cpp
lib/utils/backup.hpp
lib/utils/curl-helper.cpp
@ -275,6 +277,7 @@ target_include_directories(
PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/lib"
"${CMAKE_CURRENT_SOURCE_DIR}/lib/legacy"
"${CMAKE_CURRENT_SOURCE_DIR}/lib/macro"
"${CMAKE_CURRENT_SOURCE_DIR}/lib/queue"
"${CMAKE_CURRENT_SOURCE_DIR}/lib/utils"
"${CMAKE_CURRENT_SOURCE_DIR}/lib/variables"
"${CMAKE_CURRENT_BINARY_DIR}/forms")

View File

@ -88,6 +88,20 @@ AdvSceneSwitcher.variableTab.lastChanged.text="%1 seconds ago"
AdvSceneSwitcher.variableTab.lastChanged.text.none="No change since launch"
AdvSceneSwitcher.variableTab.lastChanged.tooltip="Times changed: %1\n\nPrevious value: %2"
; Action Queue Tab
AdvSceneSwitcher.actionQueueTab.title="Action Queues"
AdvSceneSwitcher.actionQueueTab.help="Action queues are executed sequentially but in parallel to the reset of the macro system.\nThe first action added to the queue will be the first one to be processed.\n\nClick on the highlighted plus symbol to add a new queue."
AdvSceneSwitcher.actionQueueTab.queueAddButton.tooltip="Add new action queue"
AdvSceneSwitcher.actionQueueTab.queueRemoveButton.tooltip="Remove selected action queues"
AdvSceneSwitcher.actionQueueTab.name.header="Name"
AdvSceneSwitcher.actionQueueTab.size.header="Size"
AdvSceneSwitcher.actionQueueTab.isRunning.header="Is running"
AdvSceneSwitcher.actionQueueTab.runOnStartup.header="Run on startup"
AdvSceneSwitcher.actionQueueTab.yes="Yes"
AdvSceneSwitcher.actionQueueTab.no="No"
AdvSceneSwitcher.actionQueueTab.removeSingleConnectionPopup.text="Are you sure you want to remove \"%1\"?"
AdvSceneSwitcher.actionQueueTab.removeMultipleConnectionsPopup.text="Are you sure you want to remove %1 action queues?"
; Websocket Connections Tab
AdvSceneSwitcher.websocketConnectionTab.title="Websocket Connections"
AdvSceneSwitcher.websocketConnectionTab.help="Websocket connections can be used to communicate with other OBS instances or programs.\n\nClick on the highlighted plus symbol to add a new connection."

View File

@ -0,0 +1,260 @@
#include "action-queue-tab.hpp"
#include "action-queue.hpp"
#include "log-helper.hpp"
#include "obs-module-helper.hpp"
#include "plugin-state-helpers.hpp"
#include "sync-helpers.hpp"
#include "tab-helpers.hpp"
#include "ui-helpers.hpp"
#include <QTimer>
namespace advss {
static bool registerTab();
static void setupTab(QTabWidget *);
static bool registerTabDone = registerTab();
static ActionQueueTable *tabWidget = nullptr;
static bool registerTab()
{
AddPluginInitStep([]() {
AddSetupTabCallback("actionQueueTab", ActionQueueTable::Create,
setupTab);
});
return true;
}
static void setTabVisible(QTabWidget *tabWidget, bool visible)
{
SetTabVisibleByName(
tabWidget, visible,
obs_module_text("AdvSceneSwitcher.actionQueueTab.title"));
}
ActionQueueTable *ActionQueueTable::Create()
{
tabWidget = new ActionQueueTable();
return tabWidget;
}
void ActionQueueTable::Add()
{
auto newQueue = std::make_shared<ActionQueue>();
auto accepted =
ActionQueueSettingsDialog::AskForSettings(this, *newQueue);
if (!accepted) {
return;
}
{
auto lock = LockContext();
auto &queues = GetActionQueues();
queues.emplace_back(newQueue);
}
ActionQueueSignalManager::Instance()->Add(
QString::fromStdString(newQueue->Name()));
}
static QStringList getCellLabels(ActionQueue *queue, bool addName = true)
{
assert(queue);
auto result = QStringList();
if (addName) {
result << QString::fromStdString(queue->Name());
}
result << QString::number(queue->Size())
<< QString::fromStdString(obs_module_text(
queue->IsRunning()
? "AdvSceneSwitcher.actionQueueTab.yes"
: "AdvSceneSwitcher.actionQueueTab.yes"))
<< QString::fromStdString(obs_module_text(
queue->RunsOnStartup()
? "AdvSceneSwitcher.actionQueueTab.yes"
: "AdvSceneSwitcher.actionQueueTab.yes"));
return result;
}
static void updateQueueStatus(QTableWidget *table)
{
for (int row = 0; row < table->rowCount(); row++) {
auto item = table->item(row, 0);
if (!item) {
continue;
}
auto weakQueue = GetWeakActionQueueByQString(item->text());
auto queue = weakQueue.lock();
if (!queue) {
continue;
}
UpdateItemTableRow(table, row,
getCellLabels(queue.get(), false));
}
}
static void openSettingsDialog()
{
auto selectedRows =
tabWidget->Table()->selectionModel()->selectedRows();
if (selectedRows.empty()) {
return;
}
auto cell = tabWidget->Table()->item(selectedRows.last().row(), 0);
if (!cell) {
return;
}
auto weakQueue = GetWeakActionQueueByQString(cell->text());
auto queue = weakQueue.lock();
if (!queue) {
return;
}
auto oldName = queue->Name();
bool accepted = ActionQueueSettingsDialog::AskForSettings(
tabWidget->Table(), *queue.get());
if (accepted && oldName != queue->Name()) {
ActionQueueSignalManager::Instance()->Rename(
QString::fromStdString(oldName),
QString::fromStdString(queue->Name()));
}
}
static void removeQueuesWithNames(const QStringList &queueNames)
{
for (const auto &name : queueNames) {
auto queue = GetWeakActionQueueByQString(name).lock();
if (!queue) {
continue;
}
auto &queues = GetActionQueues();
queues.erase(
std::remove_if(
queues.begin(), queues.end(),
[queue](const std::shared_ptr<Item> &item) {
return item == queue;
}),
queues.end());
}
}
void ActionQueueTable::Remove()
{
auto selectedRows =
tabWidget->Table()->selectionModel()->selectedRows();
if (selectedRows.empty()) {
return;
}
QStringList queueNames;
for (const auto &row : selectedRows) {
auto cell = tabWidget->Table()->item(row.row(), 0);
if (!cell) {
continue;
}
queueNames << cell->text();
}
int queueNameCount = queueNames.size();
if (queueNameCount == 1) {
QString deleteWarning = obs_module_text(
"AdvSceneSwitcher.actionQueueTab.removeSingleQueuePopup.text");
if (!DisplayMessage(deleteWarning.arg(queueNames.at(0)),
true)) {
return;
}
} else {
QString deleteWarning = obs_module_text(
"AdvSceneSwitcher.actionQueueTab.removeMultipleQueuesPopup.text");
if (!DisplayMessage(deleteWarning.arg(queueNameCount), true)) {
return;
}
}
{
auto lock = LockContext();
RemoveItemsByName(GetActionQueues(), queueNames);
}
for (const auto &name : queueNames) {
ActionQueueSignalManager::Instance()->Remove(name);
}
}
ActionQueueTable::ActionQueueTable(QTabWidget *parent)
: ResourceTable(
parent,
obs_module_text("AdvSceneSwitcher.actionQueueTab.help"),
obs_module_text(
"AdvSceneSwitcher.actionQueueTab.queueAddButton.tooltip"),
obs_module_text(
"AdvSceneSwitcher.actionQueueTab.queueRemoveButton.tooltip"),
QStringList()
<< obs_module_text(
"AdvSceneSwitcher.actionQueueTab.name.header")
<< obs_module_text(
"AdvSceneSwitcher.actionQueueTab.size.header")
<< obs_module_text(
"AdvSceneSwitcher.actionQueueTab.isRunning.header")
<< obs_module_text(
"AdvSceneSwitcher.actionQueueTab.runOnStartup.header"),
openSettingsDialog)
{
for (const auto &queue : GetActionQueues()) {
auto q = std::static_pointer_cast<ActionQueue>(queue);
AddItemTableRow(Table(), getCellLabels(q.get()));
}
SetHelpVisible(GetActionQueues().empty());
}
static void setupTab(QTabWidget *tab)
{
if (GetActionQueues().empty()) {
setTabVisible(tab, false);
}
QWidget::connect(ActionQueueSignalManager::Instance(),
&ActionQueueSignalManager::Rename,
[](const QString &oldName, const QString &newName) {
RenameItemTableRow(tabWidget->Table(), oldName,
newName);
});
QWidget::connect(
ActionQueueSignalManager::Instance(),
&ActionQueueSignalManager::Add, [tab](const QString &name) {
AddItemTableRow(
tabWidget->Table(),
getCellLabels(GetWeakActionQueueByQString(name)
.lock()
.get()));
tabWidget->SetHelpVisible(false);
tabWidget->HighlightAddButton(false);
setTabVisible(tab, true);
});
QWidget::connect(ActionQueueSignalManager::Instance(),
&ActionQueueSignalManager::Remove,
[](const QString &name) {
RemoveItemTableRow(tabWidget->Table(), name);
if (tabWidget->Table()->rowCount() == 0) {
tabWidget->SetHelpVisible(true);
tabWidget->HighlightAddButton(true);
}
});
auto timer = new QTimer(tabWidget);
timer->setInterval(1000);
QWidget::connect(timer, &QTimer::timeout,
[]() { updateQueueStatus(tabWidget->Table()); });
timer->start();
}
} // namespace advss

View File

@ -0,0 +1,20 @@
#pragma once
#include "resource-table.hpp"
namespace advss {
class ActionQueueTable final : public ResourceTable {
Q_OBJECT
public:
static ActionQueueTable *Create();
private slots:
void Add();
void Remove();
private:
ActionQueueTable(QTabWidget *parent = nullptr);
};
} // namespace advss

View File

@ -6,6 +6,11 @@ namespace advss {
static std::deque<std::shared_ptr<Item>> queues;
std::deque<std::shared_ptr<Item>> &GetActionQueues()
{
return queues;
}
void SetupActionQueues()
{
static bool done = false;

View File

@ -95,6 +95,7 @@ signals:
void Remove(const QString &);
};
std::deque<std::shared_ptr<Item>> &GetActionQueues();
void SetupActionQueues();
void SaveActionQueues(obs_data_t *);
void LoadActionQueues(obs_data_t *);