#pragma once #include "headers/utility.hpp" #include "headers/platform-funcs.hpp" #include #include #include #include #include #include #include #include #include #include #include #include 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 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 placeholders, bool addStretch) { std::vector> 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(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(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 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 *list = reinterpret_cast *>(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 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 *list = reinterpret_cast *>(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 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 *list = reinterpret_cast *>(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 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 *sceneGroups, bool addSelect, std::string selectText, bool selectable) { BPtr 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; }