SceneSwitcher/src/utility.cpp

595 lines
14 KiB
C++

#pragma once
#include "headers/utility.hpp"
#include "headers/platform-funcs.hpp"
#include <QTextStream>
#include <QLabel>
#include <QMessageBox>
#include <QStandardItemModel>
#include <QtGui/qstandarditemmodel.h>
#include <QPropertyAnimation>
#include <QGraphicsColorizeEffect>
#include <QTimer>
#include <QMessageBox>
#include <unordered_map>
#include <obs-module.h>
#include <util/util.hpp>
bool WeakSourceValid(obs_weak_source_t *ws)
{
obs_source_t *source = obs_weak_source_get_source(ws);
if (source) {
obs_source_release(source);
}
return !!source;
}
std::string GetWeakSourceName(obs_weak_source_t *weak_source)
{
std::string name;
obs_source_t *source = obs_weak_source_get_source(weak_source);
if (source) {
name = obs_source_get_name(source);
obs_source_release(source);
}
return name;
}
OBSWeakSource GetWeakSourceByName(const char *name)
{
OBSWeakSource weak;
obs_source_t *source = obs_get_source_by_name(name);
if (source) {
weak = obs_source_get_weak_source(source);
obs_weak_source_release(weak);
obs_source_release(source);
}
return weak;
}
OBSWeakSource GetWeakSourceByQString(const QString &name)
{
return GetWeakSourceByName(name.toUtf8().constData());
}
OBSWeakSource GetWeakTransitionByName(const char *transitionName)
{
OBSWeakSource weak;
obs_source_t *source = nullptr;
if (strcmp(transitionName, "Default") == 0) {
source = obs_frontend_get_current_transition();
weak = obs_source_get_weak_source(source);
obs_source_release(source);
obs_weak_source_release(weak);
return weak;
}
obs_frontend_source_list *transitions = new obs_frontend_source_list();
obs_frontend_get_transitions(transitions);
bool match = false;
for (size_t i = 0; i < transitions->sources.num; i++) {
const char *name =
obs_source_get_name(transitions->sources.array[i]);
if (strcmp(transitionName, name) == 0) {
match = true;
source = transitions->sources.array[i];
break;
}
}
if (match) {
weak = obs_source_get_weak_source(source);
obs_weak_source_release(weak);
}
obs_frontend_source_list_free(transitions);
return weak;
}
OBSWeakSource GetWeakTransitionByQString(const QString &name)
{
return GetWeakTransitionByName(name.toUtf8().constData());
}
OBSWeakSource GetWeakFilterByName(OBSWeakSource source, const char *name)
{
OBSWeakSource weak;
auto s = obs_weak_source_get_source(source);
if (s) {
auto filterSource = obs_source_get_filter_by_name(s, name);
weak = obs_source_get_weak_source(filterSource);
obs_weak_source_release(weak);
obs_source_release(filterSource);
obs_source_release(s);
}
return weak;
}
OBSWeakSource GetWeakFilterByQString(OBSWeakSource source, const QString &name)
{
return GetWeakFilterByName(source, name.toUtf8().constData());
}
std::string
getNextDelim(const std::string &text,
std::unordered_map<std::string, QWidget *> placeholders)
{
size_t pos = std::string::npos;
std::string res = "";
for (const auto &ph : placeholders) {
size_t newPos = text.find(ph.first);
if (newPos <= pos) {
pos = newPos;
res = ph.first;
}
}
if (pos == std::string::npos) {
return "";
}
return res;
}
void placeWidgets(std::string text, QBoxLayout *layout,
std::unordered_map<std::string, QWidget *> placeholders,
bool addStretch)
{
std::vector<std::pair<std::string, QWidget *>> labelsWidgetsPairs;
std::string delim = getNextDelim(text, placeholders);
while (delim != "") {
size_t pos = text.find(delim);
if (pos != std::string::npos) {
labelsWidgetsPairs.emplace_back(text.substr(0, pos),
placeholders[delim]);
text.erase(0, pos + delim.length());
}
delim = getNextDelim(text, placeholders);
}
if (text != "") {
labelsWidgetsPairs.emplace_back(text, nullptr);
}
for (auto &lw : labelsWidgetsPairs) {
if (lw.first != "") {
layout->addWidget(new QLabel(lw.first.c_str()));
}
if (lw.second) {
layout->addWidget(lw.second);
}
}
if (addStretch) {
layout->addStretch();
}
}
void clearLayout(QLayout *layout)
{
QLayoutItem *item;
while ((item = layout->takeAt(0))) {
if (item->layout()) {
clearLayout(item->layout());
delete item->layout();
}
if (item->widget()) {
delete item->widget();
}
delete item;
}
}
bool compareIgnoringLineEnding(QString &s1, QString &s2)
{
// Let QT deal with different types of lineendings
QTextStream s1stream(&s1);
QTextStream s2stream(&s2);
while (!s1stream.atEnd() || !s2stream.atEnd()) {
QString s1s = s1stream.readLine();
QString s2s = s2stream.readLine();
if (s1s != s2s) {
return false;
}
}
if (!s1stream.atEnd() && !s2stream.atEnd()) {
return false;
}
return true;
}
std::string getSourceSettings(OBSWeakSource ws)
{
auto s = obs_weak_source_get_source(ws);
obs_data_t *data = obs_source_get_settings(s);
std::string settings = obs_data_get_json(data);
obs_data_release(data);
obs_source_release(s);
return settings;
}
std::string getDataFilePath(const std::string &file)
{
std::string root_path = obs_get_module_data_path(obs_current_module());
if (!root_path.empty()) {
return root_path + "/" + file;
}
return "";
}
bool DisplayMessage(const QString &msg, bool question)
{
if (question) {
QMessageBox::StandardButton reply;
reply = QMessageBox::question(
nullptr, "Advanced Scene Switcher", msg,
QMessageBox::Yes | QMessageBox::No);
if (reply == QMessageBox::Yes) {
return true;
} else {
return false;
}
} else {
QMessageBox Msgbox;
Msgbox.setWindowTitle("Advanced Scene Switcher");
Msgbox.setText(msg);
Msgbox.exec();
}
return false;
}
void addSelectionEntry(QComboBox *sel, const char *description, bool selectable,
const char *tooltip)
{
sel->insertItem(0, description);
if (strcmp(tooltip, "") != 0) {
sel->setItemData(0, tooltip, Qt::ToolTipRole);
}
QStandardItemModel *model =
qobject_cast<QStandardItemModel *>(sel->model());
QModelIndex firstIndex =
model->index(0, sel->modelColumn(), sel->rootModelIndex());
QStandardItem *firstItem = model->itemFromIndex(firstIndex);
if (!selectable) {
firstItem->setSelectable(false);
firstItem->setEnabled(false);
}
}
void populateSourceSelection(QComboBox *list, bool addSelect)
{
auto enumSourcesWithSources = [](void *param, obs_source_t *source) {
if (!source) {
return true;
}
QComboBox *list = reinterpret_cast<QComboBox *>(param);
list->addItem(obs_source_get_name(source));
return true;
};
obs_enum_sources(enumSourcesWithSources, list);
list->model()->sort(0);
if (addSelect) {
addSelectionEntry(
list, obs_module_text("AdvSceneSwitcher.selectSource"),
false);
}
list->setCurrentIndex(0);
}
void populateTransitionSelection(QComboBox *sel, bool addCurrent,
bool addSelect, bool selectable)
{
obs_frontend_source_list *transitions = new obs_frontend_source_list();
obs_frontend_get_transitions(transitions);
for (size_t i = 0; i < transitions->sources.num; i++) {
const char *name =
obs_source_get_name(transitions->sources.array[i]);
sel->addItem(name);
}
obs_frontend_source_list_free(transitions);
sel->model()->sort(0);
if (addCurrent) {
sel->insertItem(
0,
obs_module_text("AdvSceneSwitcher.currentTransition"));
}
if (addSelect) {
addSelectionEntry(
sel,
obs_module_text("AdvSceneSwitcher.selectTransition"),
selectable);
}
sel->setCurrentIndex(0);
}
void populateWindowSelection(QComboBox *sel, bool addSelect)
{
std::vector<std::string> windows;
GetWindowList(windows);
for (std::string &window : windows) {
sel->addItem(window.c_str());
}
sel->model()->sort(0);
if (addSelect) {
addSelectionEntry(
sel, obs_module_text("AdvSceneSwitcher.selectWindow"));
}
sel->setCurrentIndex(0);
#ifdef WIN32
sel->setItemData(0, obs_module_text("AdvSceneSwitcher.selectWindowTip"),
Qt::ToolTipRole);
#endif
}
void populateAudioSelection(QComboBox *sel, bool addSelect)
{
auto sourceEnum = [](void *data, obs_source_t *source) -> bool /* -- */
{
std::vector<std::string> *list =
reinterpret_cast<std::vector<std::string> *>(data);
uint32_t flags = obs_source_get_output_flags(source);
if ((flags & OBS_SOURCE_AUDIO) != 0) {
list->push_back(obs_source_get_name(source));
}
return true;
};
std::vector<std::string> audioSources;
obs_enum_sources(sourceEnum, &audioSources);
for (std::string &source : audioSources) {
sel->addItem(source.c_str());
}
sel->model()->sort(0);
if (addSelect) {
addSelectionEntry(
sel,
obs_module_text("AdvSceneSwitcher.selectAudioSource"),
false,
obs_module_text(
"AdvSceneSwitcher.invaildEntriesWillNotBeSaved"));
}
sel->setCurrentIndex(0);
}
void populateVideoSelection(QComboBox *sel, bool addSelect)
{
auto sourceEnum = [](void *data, obs_source_t *source) -> bool /* -- */
{
std::vector<std::string> *list =
reinterpret_cast<std::vector<std::string> *>(data);
uint32_t flags = obs_source_get_output_flags(source);
std::string test = obs_source_get_name(source);
if ((flags & (OBS_SOURCE_VIDEO | OBS_SOURCE_ASYNC)) != 0) {
list->push_back(obs_source_get_name(source));
}
return true;
};
std::vector<std::string> videoSources;
obs_enum_sources(sourceEnum, &videoSources);
sort(videoSources.begin(), videoSources.end());
for (std::string &source : videoSources) {
sel->addItem(source.c_str());
}
sel->model()->sort(0);
if (addSelect) {
addSelectionEntry(
sel,
obs_module_text("AdvSceneSwitcher.selectVideoSource"),
false,
obs_module_text(
"AdvSceneSwitcher.invaildEntriesWillNotBeSaved"));
}
sel->setCurrentIndex(0);
}
void populateMediaSelection(QComboBox *sel, bool addSelect)
{
auto sourceEnum = [](void *data, obs_source_t *source) -> bool /* -- */
{
std::vector<std::string> *list =
reinterpret_cast<std::vector<std::string> *>(data);
std::string sourceId = obs_source_get_id(source);
if (sourceId.compare("ffmpeg_source") == 0 ||
sourceId.compare("vlc_source") == 0) {
list->push_back(obs_source_get_name(source));
}
return true;
};
std::vector<std::string> mediaSources;
obs_enum_sources(sourceEnum, &mediaSources);
for (std::string &source : mediaSources) {
sel->addItem(source.c_str());
}
sel->model()->sort(0);
if (addSelect) {
addSelectionEntry(
sel,
obs_module_text("AdvSceneSwitcher.selectMediaSource"),
false,
obs_module_text(
"AdvSceneSwitcher.invaildEntriesWillNotBeSaved"));
}
sel->setCurrentIndex(0);
}
void populateProcessSelection(QComboBox *sel, bool addSelect)
{
QStringList processes;
GetProcessList(processes);
processes.sort();
for (QString &process : processes) {
sel->addItem(process);
}
sel->model()->sort(0);
if (addSelect) {
addSelectionEntry(
sel, obs_module_text("AdvSceneSwitcher.selectProcess"));
}
sel->setCurrentIndex(0);
}
void populateSceneSelection(QComboBox *sel, bool addPrevious,
bool addSceneGroup,
std::deque<SceneGroup> *sceneGroups, bool addSelect,
std::string selectText, bool selectable)
{
BPtr<char *> scenes = obs_frontend_get_scene_names();
char **temp = scenes;
while (*temp) {
const char *name = *temp;
sel->addItem(name);
temp++;
}
if (addPrevious) {
sel->addItem(obs_module_text(
"AdvSceneSwitcher.selectPreviousScene"));
}
if (addSceneGroup && sceneGroups) {
for (auto &sg : *sceneGroups) {
sel->addItem(QString::fromStdString(sg.name));
}
}
sel->model()->sort(0);
if (addSelect) {
if (selectText.empty()) {
addSelectionEntry(
sel,
obs_module_text("AdvSceneSwitcher.selectScene"),
selectable,
obs_module_text(
"AdvSceneSwitcher.invaildEntriesWillNotBeSaved"));
} else {
addSelectionEntry(sel, selectText.c_str(), selectable);
}
}
sel->setCurrentIndex(0);
}
QMetaObject::Connection PulseWidget(QWidget *widget, QColor endColor,
QColor startColor, QString specifier)
{
widget->setStyleSheet(specifier + "{ \
border-style: outset; \
border-width: 2px; \
border-radius: 10px; \
border-color: rgb(0,0,0,0) \
}");
QGraphicsColorizeEffect *eEffect = new QGraphicsColorizeEffect(widget);
widget->setGraphicsEffect(eEffect);
QPropertyAnimation *paAnimation =
new QPropertyAnimation(eEffect, "color");
paAnimation->setStartValue(startColor);
paAnimation->setEndValue(endColor);
paAnimation->setDuration(1000);
// Play backwards to return to original state on timer end
paAnimation->setDirection(QAbstractAnimation::Backward);
auto con = QWidget::connect(
paAnimation, &QPropertyAnimation::finished, [paAnimation]() {
QTimer::singleShot(1000, [paAnimation] {
paAnimation->start();
});
});
paAnimation->start();
return con;
}
void listAddClicked(QListWidget *list, QWidget *newWidget,
QPushButton *addButton,
QMetaObject::Connection *addHighlight)
{
if (!list || !newWidget) {
blog(LOG_WARNING,
"listAddClicked called without valid list or widget");
return;
}
if (addButton && addHighlight) {
addButton->disconnect(*addHighlight);
}
QListWidgetItem *item;
item = new QListWidgetItem(list);
list->addItem(item);
item->setSizeHint(newWidget->minimumSizeHint());
list->setItemWidget(item, newWidget);
list->scrollToItem(item);
}
bool listMoveUp(QListWidget *list)
{
int index = list->currentRow();
if (index == -1 || index == 0) {
return false;
}
QWidget *row = list->itemWidget(list->currentItem());
QListWidgetItem *itemN = list->currentItem()->clone();
list->insertItem(index - 1, itemN);
list->setItemWidget(itemN, row);
list->takeItem(index + 1);
list->setCurrentRow(index - 1);
return true;
}
bool listMoveDown(QListWidget *list)
{
int index = list->currentRow();
if (index == -1 || index == list->count() - 1) {
return false;
}
QWidget *row = list->itemWidget(list->currentItem());
QListWidgetItem *itemN = list->currentItem()->clone();
list->insertItem(index + 2, itemN);
list->setItemWidget(itemN, row);
list->takeItem(index);
list->setCurrentRow(index + 1);
return true;
}