mirror of
https://github.com/WarmUpTill/SceneSwitcher.git
synced 2026-09-01 22:25:36 -05:00
Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ccb0e7c1e4 | ||
|
|
e11499c308 |
@@ -173,8 +173,6 @@ target_sources(
|
|||||||
lib/macro/macro-signals.hpp
|
lib/macro/macro-signals.hpp
|
||||||
lib/macro/macro-tab.cpp
|
lib/macro/macro-tab.cpp
|
||||||
lib/macro/macro-tree.cpp
|
lib/macro/macro-tree.cpp
|
||||||
lib/macro/macro-undo-redo.cpp
|
|
||||||
lib/macro/macro-undo-redo.hpp
|
|
||||||
lib/macro/macro-tree.hpp
|
lib/macro/macro-tree.hpp
|
||||||
lib/macro/macro-websocket-trigger.cpp
|
lib/macro/macro-websocket-trigger.cpp
|
||||||
lib/macro/macro.cpp
|
lib/macro/macro.cpp
|
||||||
|
|||||||
@@ -198,19 +198,6 @@ AdvSceneSwitcher.macroTab.groupNameExists="The name \"%1\" is already used by a
|
|||||||
AdvSceneSwitcher.macroTab.removeSingleMacroPopup.text="Are you sure you want to remove \"%1\"?"
|
AdvSceneSwitcher.macroTab.removeSingleMacroPopup.text="Are you sure you want to remove \"%1\"?"
|
||||||
AdvSceneSwitcher.macroTab.removeMultipleMacrosPopup.text="Are you sure you want to remove %1 macros/groups?"
|
AdvSceneSwitcher.macroTab.removeMultipleMacrosPopup.text="Are you sure you want to remove %1 macros/groups?"
|
||||||
AdvSceneSwitcher.macroTab.removeGroupPopup.text="Are you sure you want to remove \"%1\" group and all its elements?"
|
AdvSceneSwitcher.macroTab.removeGroupPopup.text="Are you sure you want to remove \"%1\" group and all its elements?"
|
||||||
AdvSceneSwitcher.undo.renameMacro="Rename Macro '%1'"
|
|
||||||
AdvSceneSwitcher.undo.modifyMacro="Modify Macro '%1'"
|
|
||||||
AdvSceneSwitcher.undo.addMacro="Add Macro '%1'"
|
|
||||||
AdvSceneSwitcher.undo.removeMacro="Remove Macro '%1'"
|
|
||||||
AdvSceneSwitcher.undo.addSegment="Add %1 in '%2'"
|
|
||||||
AdvSceneSwitcher.undo.removeSegment="Remove %1 in '%2'"
|
|
||||||
AdvSceneSwitcher.undo.changeSegmentType="Change %1 Type in '%2'"
|
|
||||||
AdvSceneSwitcher.undo.groupMacros="Group Macros '%1'"
|
|
||||||
AdvSceneSwitcher.undo.ungroupMacros="Ungroup Macros '%1'"
|
|
||||||
AdvSceneSwitcher.undo.removeMacroGroup="Remove Macro Group '%1'"
|
|
||||||
AdvSceneSwitcher.undo.segment.action="Action"
|
|
||||||
AdvSceneSwitcher.undo.segment.elseAction="Else Action"
|
|
||||||
AdvSceneSwitcher.undo.segment.condition="Condition"
|
|
||||||
AdvSceneSwitcher.macroTab.contextMenuAdd="Add"
|
AdvSceneSwitcher.macroTab.contextMenuAdd="Add"
|
||||||
AdvSceneSwitcher.macroTab.copy="Duplicate Macro"
|
AdvSceneSwitcher.macroTab.copy="Duplicate Macro"
|
||||||
AdvSceneSwitcher.macroTab.group="Group Selected Macros"
|
AdvSceneSwitcher.macroTab.group="Group Selected Macros"
|
||||||
@@ -917,9 +904,19 @@ AdvSceneSwitcher.condition.streamDeck.stopListen="Stop listening"
|
|||||||
AdvSceneSwitcher.condition.streamDeck.pluginDownload="<html><head/><body><p>The Stream Deck plugin can be found <a href=\"https://github.com/WarmUpTill/advanced-scene-switcher-streamdeck-plugin/releases\"><span style=\" text-decoration: underline; color:#268bd2;\">here on GitHub</span></a>.</p></body></html>"
|
AdvSceneSwitcher.condition.streamDeck.pluginDownload="<html><head/><body><p>The Stream Deck plugin can be found <a href=\"https://github.com/WarmUpTill/advanced-scene-switcher-streamdeck-plugin/releases\"><span style=\" text-decoration: underline; color:#268bd2;\">here on GitHub</span></a>.</p></body></html>"
|
||||||
AdvSceneSwitcher.condition.gameCapture="Game capture"
|
AdvSceneSwitcher.condition.gameCapture="Game capture"
|
||||||
AdvSceneSwitcher.condition.gameCapture.entry="{{sources}}hooked a game."
|
AdvSceneSwitcher.condition.gameCapture.entry="{{sources}}hooked a game."
|
||||||
|
|
||||||
AdvSceneSwitcher.condition.screenshot="Screenshot"
|
AdvSceneSwitcher.condition.screenshot="Screenshot"
|
||||||
AdvSceneSwitcher.condition.screenshot.entry="A screenshot was taken"
|
AdvSceneSwitcher.condition.screenshot.entry="A screenshot was taken"
|
||||||
|
AdvSceneSwitcher.condition.nowPlaying="Now Playing"
|
||||||
|
AdvSceneSwitcher.condition.nowPlaying.checkType.playbackState="Playback state"
|
||||||
|
AdvSceneSwitcher.condition.nowPlaying.checkType.title="Title"
|
||||||
|
AdvSceneSwitcher.condition.nowPlaying.checkType.artist="Artist"
|
||||||
|
AdvSceneSwitcher.condition.nowPlaying.checkType.album="Album"
|
||||||
|
AdvSceneSwitcher.condition.nowPlaying.checkType.appName="App name"
|
||||||
|
AdvSceneSwitcher.condition.nowPlaying.playbackState.playing="Playing"
|
||||||
|
AdvSceneSwitcher.condition.nowPlaying.playbackState.paused="Paused"
|
||||||
|
AdvSceneSwitcher.condition.nowPlaying.playbackState.stopped="Stopped"
|
||||||
|
AdvSceneSwitcher.condition.nowPlaying.playbackState.opening="Opening"
|
||||||
|
AdvSceneSwitcher.condition.nowPlaying.playbackState.changing="Changing"
|
||||||
AdvSceneSwitcher.condition.mqtt="MQTT"
|
AdvSceneSwitcher.condition.mqtt="MQTT"
|
||||||
AdvSceneSwitcher.condition.mqtt.layout.match="Message was received from{{connection}} which matches{{regex}}:"
|
AdvSceneSwitcher.condition.mqtt.layout.match="Message was received from{{connection}} which matches{{regex}}:"
|
||||||
AdvSceneSwitcher.condition.mqtt.layout.listen="Set message selection to incoming message:{{listenButton}}"
|
AdvSceneSwitcher.condition.mqtt.layout.listen="Set message selection to incoming message:{{listenButton}}"
|
||||||
@@ -2612,6 +2609,12 @@ AdvSceneSwitcher.tempVar.gameCapture.class.description="Window class of the appl
|
|||||||
AdvSceneSwitcher.tempVar.gameCapture.executable="Executable"
|
AdvSceneSwitcher.tempVar.gameCapture.executable="Executable"
|
||||||
AdvSceneSwitcher.tempVar.gameCapture.executable.description="Executable name of the application captured by the source."
|
AdvSceneSwitcher.tempVar.gameCapture.executable.description="Executable name of the application captured by the source."
|
||||||
|
|
||||||
|
AdvSceneSwitcher.tempVar.nowPlaying.title="Title"
|
||||||
|
AdvSceneSwitcher.tempVar.nowPlaying.artist="Artist"
|
||||||
|
AdvSceneSwitcher.tempVar.nowPlaying.album="Album"
|
||||||
|
AdvSceneSwitcher.tempVar.nowPlaying.appName="App name"
|
||||||
|
AdvSceneSwitcher.tempVar.nowPlaying.playbackStatus="Playback status"
|
||||||
|
|
||||||
AdvSceneSwitcher.tempVar.http.status="Status code"
|
AdvSceneSwitcher.tempVar.http.status="Status code"
|
||||||
AdvSceneSwitcher.tempVar.http.error="Error"
|
AdvSceneSwitcher.tempVar.http.error="Error"
|
||||||
AdvSceneSwitcher.tempVar.http.error.description="Empty when no error occurred.\nOther possible values:\n\n * Could not establish connection\n * Failed to bind IP address\n * Failed to read connection\n * Failed to write connection\n * Maximum redirect count exceeded\n * Connection handling canceled\n * SSL connection failed\n * SSL certificate loading failed\n * SSL server verification failed\n * Unsupported HTTP multipart boundary characters\n * Compression failed\n * Connection timed out\n * Proxy connection failed\n * Unknown"
|
AdvSceneSwitcher.tempVar.http.error.description="Empty when no error occurred.\nOther possible values:\n\n * Could not establish connection\n * Failed to bind IP address\n * Failed to read connection\n * Failed to write connection\n * Maximum redirect count exceeded\n * Connection handling canceled\n * SSL connection failed\n * SSL certificate loading failed\n * SSL server verification failed\n * Unsupported HTTP multipart boundary characters\n * Compression failed\n * Connection timed out\n * Proxy connection failed\n * Unknown"
|
||||||
@@ -3120,3 +3123,6 @@ AdvSceneSwitcher.sceneGroupTab.defaultname="Scene Group %1"
|
|||||||
AdvSceneSwitcher.sceneGroupTab.exists="Scene Group or Scene name exists already"
|
AdvSceneSwitcher.sceneGroupTab.exists="Scene Group or Scene name exists already"
|
||||||
AdvSceneSwitcher.sceneGroupTab.help="Scene Groups can be selected as a target just like a regular scene.\n\nAs the name suggests a scene group is a collection of multiple scenes.\nThe scene group will advance through the list of its assigned scenes depending on the configured settings, which can be found on the right side.\n\nYou can configure the scene group to advance to the next scene in the list:\nAfter a number of times the scene group is selected as a target.\nAfter a certain amount of time has passed.\nOr randomly.\n\nFor example, a scene group containing the scenes ...\nScene 1\nScene 2\nScene 3 \n... will activate \"Scene 1\" the first time it is selected as a target.\nThe second time it will activate \"Scene 2\".\nThe remaining times \"Scene 3\" will be activated.\n\nClick the highlighted plus symbol below to add a new scene group."
|
AdvSceneSwitcher.sceneGroupTab.help="Scene Groups can be selected as a target just like a regular scene.\n\nAs the name suggests a scene group is a collection of multiple scenes.\nThe scene group will advance through the list of its assigned scenes depending on the configured settings, which can be found on the right side.\n\nYou can configure the scene group to advance to the next scene in the list:\nAfter a number of times the scene group is selected as a target.\nAfter a certain amount of time has passed.\nOr randomly.\n\nFor example, a scene group containing the scenes ...\nScene 1\nScene 2\nScene 3 \n... will activate \"Scene 1\" the first time it is selected as a target.\nThe second time it will activate \"Scene 2\".\nThe remaining times \"Scene 3\" will be activated.\n\nClick the highlighted plus symbol below to add a new scene group."
|
||||||
AdvSceneSwitcher.sceneGroupTab.scenes.help="Select the scene group you want to modify on the left.\n\nSelect a scene to add to this scene group by selecting the scene above and clicking the plus symbol below.\n\nA scene can be added multiple times to the same scene group."
|
AdvSceneSwitcher.sceneGroupTab.scenes.help="Select the scene group you want to modify on the left.\n\nSelect a scene to add to this scene group by selecting the scene above and clicking the plus symbol below.\n\nA scene can be added multiple times to the same scene group."
|
||||||
|
AdvSceneSwitcher.kwin.flatpakPermissionWarning="Window detection via KWin is unavailable.\nThe OBS Studio Flatpak sandbox is missing the 'org.kde.KWin' D-Bus permission this feature needs.\nRun the following, then restart OBS:\nflatpak override --user --talk-name=org.kde.KWin com.obsproject.Studio"
|
||||||
|
AdvSceneSwitcher.wayland.flatpakPermissionWarning="Window detection is unavailable.\nThe OBS Studio Flatpak has no X11 access on this Wayland session, and no compatible integration exists yet for this desktop.\nRunning OBS under an X11 session, or a non-Flatpak install, allows this feature to work."
|
||||||
|
AdvSceneSwitcher.flatpakWindowDetectionWarning.doNotShowAgain="Don't show this warning again"
|
||||||
|
|||||||
@@ -1,5 +1,13 @@
|
|||||||
#include "platform-funcs.hpp"
|
#include "platform-funcs.hpp"
|
||||||
|
|
||||||
#include "log-helper.hpp"
|
#include "log-helper.hpp"
|
||||||
|
#include "obs-module-helper.hpp"
|
||||||
|
#include "plugin-state-helpers.hpp"
|
||||||
|
#include "ui-helpers.hpp"
|
||||||
|
|
||||||
|
#include <obs-frontend-api.h>
|
||||||
|
#include <QCheckBox>
|
||||||
|
#include <QMessageBox>
|
||||||
|
|
||||||
#include <X11/Xlib.h>
|
#include <X11/Xlib.h>
|
||||||
#include <X11/Xatom.h>
|
#include <X11/Xatom.h>
|
||||||
@@ -628,27 +636,88 @@ int ignoreXerror(Display *d, XErrorEvent *e)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool warnAboutWindowDetectionUnavailable = true;
|
||||||
|
|
||||||
|
static bool setupWindowDetectionWarningPersistence = []() {
|
||||||
|
AddSaveStep([](obs_data_t *obj) {
|
||||||
|
obs_data_set_bool(obj, "warnAboutFlatpakWindowDetection",
|
||||||
|
warnAboutWindowDetectionUnavailable);
|
||||||
|
});
|
||||||
|
AddLoadStep([](obs_data_t *obj) {
|
||||||
|
obs_data_set_default_bool(
|
||||||
|
obj, "warnAboutFlatpakWindowDetection", true);
|
||||||
|
warnAboutWindowDetectionUnavailable = obs_data_get_bool(
|
||||||
|
obj, "warnAboutFlatpakWindowDetection");
|
||||||
|
});
|
||||||
|
return true;
|
||||||
|
}();
|
||||||
|
|
||||||
|
static void showWindowDetectionWarning(const char *messageId)
|
||||||
|
{
|
||||||
|
auto mainWindow =
|
||||||
|
static_cast<QWidget *>(obs_frontend_get_main_window());
|
||||||
|
QMessageBox msgBox(QMessageBox::Warning,
|
||||||
|
obs_module_text("AdvSceneSwitcher.pluginName"),
|
||||||
|
obs_module_text(messageId), QMessageBox::Ok,
|
||||||
|
mainWindow);
|
||||||
|
auto checkbox = new QCheckBox(
|
||||||
|
obs_module_text(
|
||||||
|
"AdvSceneSwitcher.flatpakWindowDetectionWarning.doNotShowAgain"));
|
||||||
|
msgBox.setCheckBox(checkbox);
|
||||||
|
msgBox.exec();
|
||||||
|
warnAboutWindowDetectionUnavailable = !checkbox->isChecked();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handleWindowDetectionUnavailable(bool hasX11)
|
||||||
|
{
|
||||||
|
if (hasX11 || KWin || !warnAboutWindowDetectionUnavailable) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!qEnvironmentVariableIsSet("FLATPAK_ID")) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const bool onKDE = qEnvironmentVariable("XDG_CURRENT_DESKTOP")
|
||||||
|
.contains("KDE", Qt::CaseInsensitive);
|
||||||
|
const char *messageId = onKDE
|
||||||
|
? "AdvSceneSwitcher.kwin.flatpakPermissionWarning"
|
||||||
|
: "AdvSceneSwitcher.wayland.flatpakPermissionWarning";
|
||||||
|
|
||||||
|
blog(LOG_WARNING,
|
||||||
|
"window detection unavailable: OBS Flatpak sandbox has no X11 "
|
||||||
|
"access on this Wayland session and %s",
|
||||||
|
onKDE ? "the KWin D-Bus compat call was blocked (missing "
|
||||||
|
"'org.kde.KWin' talk-name permission)"
|
||||||
|
: "no compatible native Wayland integration exists for "
|
||||||
|
"this desktop");
|
||||||
|
|
||||||
|
AddFinishedLoadingStep([messageId]() {
|
||||||
|
showWindowDetectionWarning(messageId);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
void PlatformInit()
|
void PlatformInit()
|
||||||
{
|
{
|
||||||
|
const bool kwinAvailable = isKWinAvailable();
|
||||||
|
KWin = kwinAvailable && registerKWinDBusListener(¬ifier) &&
|
||||||
|
startKWinScript(KWinScriptObjectPath);
|
||||||
|
if (KWin) {
|
||||||
|
blog(LOG_INFO, "using KWin compat");
|
||||||
|
} else {
|
||||||
|
blog(LOG_INFO, "not using KWin compat");
|
||||||
|
}
|
||||||
|
|
||||||
|
initProcps();
|
||||||
|
initProc2();
|
||||||
|
|
||||||
auto display = disp();
|
auto display = disp();
|
||||||
|
handleWindowDetectionUnavailable(display != nullptr);
|
||||||
if (!display) {
|
if (!display) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
KWin = isKWinAvailable();
|
|
||||||
if (!(KWin && startKWinScript(KWinScriptObjectPath) &&
|
|
||||||
registerKWinDBusListener(¬ifier))) {
|
|
||||||
// something bad happened while trying to initialize
|
|
||||||
// the KWin script/dbus so disable it
|
|
||||||
KWin = false;
|
|
||||||
blog(LOG_INFO, "not using KWin compat");
|
|
||||||
} else {
|
|
||||||
blog(LOG_INFO, "using KWin compat");
|
|
||||||
}
|
|
||||||
|
|
||||||
initXss();
|
initXss();
|
||||||
initProcps();
|
|
||||||
initProc2();
|
|
||||||
XSetErrorHandler(ignoreXerror);
|
XSetErrorHandler(ignoreXerror);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
#include <QDir>
|
#include <QDir>
|
||||||
#include <QFile>
|
#include <QFile>
|
||||||
#include <QFileDevice>
|
#include <QFileDevice>
|
||||||
|
#include <QStandardPaths>
|
||||||
#include <QTextStream>
|
#include <QTextStream>
|
||||||
#include <QtDBus/QDBusConnectionInterface>
|
#include <QtDBus/QDBusConnectionInterface>
|
||||||
#include <QtDBus/QDBusInterface>
|
#include <QtDBus/QDBusInterface>
|
||||||
@@ -96,12 +97,16 @@ bool isKWinAvailable()
|
|||||||
|
|
||||||
bool startKWinScript(QString &scriptObjectPath)
|
bool startKWinScript(QString &scriptObjectPath)
|
||||||
{
|
{
|
||||||
|
// Not RuntimeLocation: under Flatpak, $XDG_RUNTIME_DIR is private to
|
||||||
|
// the sandbox, so the unsandboxed KWin process can't read it back.
|
||||||
const QString scriptPath =
|
const QString scriptPath =
|
||||||
"/tmp/AdvancedSceneSwitcher/KWinFocusNotifier.js";
|
QStandardPaths::writableLocation(
|
||||||
|
QStandardPaths::CacheLocation) +
|
||||||
|
"/AdvancedSceneSwitcher/KWinFocusNotifier.js";
|
||||||
|
|
||||||
const QString script =
|
const QString script =
|
||||||
R"(var adss = "com.github.AdvancedSceneSwitcher";
|
R"(var adss = "com.obsproject.Studio.Plugin.SceneSwitcher";
|
||||||
var adssPath = "/com/github/AdvancedSceneSwitcher";
|
var adssPath = "/com/obsproject/Studio/Plugin/SceneSwitcher";
|
||||||
|
|
||||||
function trackWindow(window) {
|
function trackWindow(window) {
|
||||||
var id = window.internalId.toString();
|
var id = window.internalId.toString();
|
||||||
@@ -129,7 +134,8 @@ workspace.windowActivated.connect(function(client) {
|
|||||||
}))";
|
}))";
|
||||||
|
|
||||||
if (const QDir dir; !dir.mkpath(QFileInfo(scriptPath).absolutePath())) {
|
if (const QDir dir; !dir.mkpath(QFileInfo(scriptPath).absolutePath())) {
|
||||||
blog(LOG_ERROR, "error creating /tmp/AdvancedSceneSwitcher");
|
blog(LOG_ERROR,
|
||||||
|
"error creating KWinFocusNotifier script directory");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -198,8 +204,8 @@ bool stopKWinScript(const QString &scriptObjectPath)
|
|||||||
|
|
||||||
bool registerKWinDBusListener(FocusNotifier *notifier)
|
bool registerKWinDBusListener(FocusNotifier *notifier)
|
||||||
{
|
{
|
||||||
static const QString serviceName = "com.github.AdvancedSceneSwitcher";
|
static const QString serviceName = "com.obsproject.Studio.Plugin.SceneSwitcher";
|
||||||
static const QString objectPath = "/com/github/AdvancedSceneSwitcher";
|
static const QString objectPath = "/com/obsproject/Studio/Plugin/SceneSwitcher";
|
||||||
auto bus = QDBusConnection::sessionBus();
|
auto bus = QDBusConnection::sessionBus();
|
||||||
|
|
||||||
if (bus.objectRegisteredAt(objectPath)) {
|
if (bus.objectRegisteredAt(objectPath)) {
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ namespace advss {
|
|||||||
|
|
||||||
class FocusNotifier final : public QObject {
|
class FocusNotifier final : public QObject {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
Q_CLASSINFO("D-Bus Interface", "com.github.AdvancedSceneSwitcher")
|
Q_CLASSINFO("D-Bus Interface", "com.obsproject.Studio.Plugin.SceneSwitcher")
|
||||||
|
|
||||||
static std::mutex _mutex;
|
static std::mutex _mutex;
|
||||||
static int activePID;
|
static int activePID;
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
#include "macro-action-edit.hpp"
|
#include "macro-action-edit.hpp"
|
||||||
#include "macro-undo-redo.hpp"
|
|
||||||
#include "advanced-scene-switcher.hpp"
|
#include "advanced-scene-switcher.hpp"
|
||||||
#include "macro-helpers.hpp"
|
#include "macro-helpers.hpp"
|
||||||
#include "macro-settings.hpp"
|
#include "macro-settings.hpp"
|
||||||
@@ -112,32 +111,9 @@ void MacroActionEdit::ActionSelectionChanged(const QString &text)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Macro *const parentMacro =
|
|
||||||
(*_entryData)->GetMacro()->GetNestedParentMacro();
|
|
||||||
OBSDataAutoRelease parentBeforeData;
|
|
||||||
if (parentMacro) {
|
|
||||||
parentBeforeData = obs_data_create();
|
|
||||||
parentMacro->Save(parentBeforeData);
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::string oldId = (*_entryData)->GetId();
|
|
||||||
OBSDataAutoRelease oldData = obs_data_create();
|
|
||||||
(*_entryData)->Save(oldData);
|
|
||||||
|
|
||||||
HeaderInfoChanged("");
|
HeaderInfoChanged("");
|
||||||
auto idx = _entryData->get()->GetIndex();
|
auto idx = _entryData->get()->GetIndex();
|
||||||
auto macro = _entryData->get()->GetMacro();
|
auto macro = _entryData->get()->GetMacro();
|
||||||
|
|
||||||
// Determine whether this is an action or else-action before resetting.
|
|
||||||
const auto *rawPtr = (*_entryData).get();
|
|
||||||
const auto &elseActions = macro->ElseActions();
|
|
||||||
const bool isElse = std::any_of(elseActions.begin(), elseActions.end(),
|
|
||||||
[rawPtr](const auto &a) {
|
|
||||||
return a.get() == rawPtr;
|
|
||||||
});
|
|
||||||
const auto segmentType = isElse ? MacroEdit::SegmentType::ELSE_ACTION
|
|
||||||
: MacroEdit::SegmentType::ACTION;
|
|
||||||
|
|
||||||
{
|
{
|
||||||
auto lock = LockContext();
|
auto lock = LockContext();
|
||||||
_entryData->reset();
|
_entryData->reset();
|
||||||
@@ -146,16 +122,6 @@ void MacroActionEdit::ActionSelectionChanged(const QString &text)
|
|||||||
(*_entryData)->PostLoad();
|
(*_entryData)->PostLoad();
|
||||||
RunAndClearPostLoadSteps();
|
RunAndClearPostLoadSteps();
|
||||||
}
|
}
|
||||||
|
|
||||||
OBSDataAutoRelease newData = obs_data_create();
|
|
||||||
(*_entryData)->Save(newData);
|
|
||||||
if (parentMacro) {
|
|
||||||
RegisterMacroModifyUndoRedo(parentMacro, parentBeforeData);
|
|
||||||
} else {
|
|
||||||
RegisterSegmentTypeChangeUndoRedo(macro, segmentType, idx,
|
|
||||||
oldId, oldData, 0, id,
|
|
||||||
newData, 0);
|
|
||||||
}
|
|
||||||
auto widget = MacroActionFactory::CreateWidget(id, this, *_entryData);
|
auto widget = MacroActionFactory::CreateWidget(id, this, *_entryData);
|
||||||
QWidget::connect(widget, SIGNAL(HeaderInfoChanged(const QString &)),
|
QWidget::connect(widget, SIGNAL(HeaderInfoChanged(const QString &)),
|
||||||
this, SLOT(HeaderInfoChanged(const QString &)));
|
this, SLOT(HeaderInfoChanged(const QString &)));
|
||||||
|
|||||||
@@ -83,7 +83,6 @@ bool MacroActionLoop::PostLoad()
|
|||||||
MacroAction::PostLoad();
|
MacroAction::PostLoad();
|
||||||
_loopMacro->PostLoad();
|
_loopMacro->PostLoad();
|
||||||
_loopMacro->SetActionTriggerMode(Macro::ActionTriggerMode::ALWAYS);
|
_loopMacro->SetActionTriggerMode(Macro::ActionTriggerMode::ALWAYS);
|
||||||
_loopMacro->SetNestedParentMacro(GetMacro());
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -281,7 +281,6 @@ bool MacroActionMacro::PostLoad()
|
|||||||
MacroAction::PostLoad();
|
MacroAction::PostLoad();
|
||||||
_runOptions.macro.PostLoad();
|
_runOptions.macro.PostLoad();
|
||||||
_nestedMacro->PostLoad();
|
_nestedMacro->PostLoad();
|
||||||
_nestedMacro->SetNestedParentMacro(GetMacro());
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
#include "macro-condition-edit.hpp"
|
#include "macro-condition-edit.hpp"
|
||||||
#include "macro-undo-redo.hpp"
|
|
||||||
|
|
||||||
#include "advanced-scene-switcher.hpp"
|
#include "advanced-scene-switcher.hpp"
|
||||||
#include "condition-logic.hpp"
|
#include "condition-logic.hpp"
|
||||||
@@ -251,19 +250,6 @@ void MacroConditionEdit::ConditionSelectionChanged(const QString &text)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Macro *const parentMacro =
|
|
||||||
(*_entryData)->GetMacro()->GetNestedParentMacro();
|
|
||||||
OBSDataAutoRelease parentBeforeData;
|
|
||||||
if (parentMacro) {
|
|
||||||
parentBeforeData = obs_data_create();
|
|
||||||
parentMacro->Save(parentBeforeData);
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::string oldId = (*_entryData)->GetId();
|
|
||||||
const int oldLogic = (int)(*_entryData)->GetLogicType();
|
|
||||||
OBSDataAutoRelease oldData = obs_data_create();
|
|
||||||
(*_entryData)->Save(oldData);
|
|
||||||
|
|
||||||
auto temp = DurationModifier();
|
auto temp = DurationModifier();
|
||||||
_dur->SetValue(temp);
|
_dur->SetValue(temp);
|
||||||
HeaderInfoChanged("");
|
HeaderInfoChanged("");
|
||||||
@@ -281,17 +267,6 @@ void MacroConditionEdit::ConditionSelectionChanged(const QString &text)
|
|||||||
(*_entryData)->PostLoad();
|
(*_entryData)->PostLoad();
|
||||||
RunAndClearPostLoadSteps();
|
RunAndClearPostLoadSteps();
|
||||||
}
|
}
|
||||||
|
|
||||||
OBSDataAutoRelease newData = obs_data_create();
|
|
||||||
(*_entryData)->Save(newData);
|
|
||||||
if (parentMacro) {
|
|
||||||
RegisterMacroModifyUndoRedo(parentMacro, parentBeforeData);
|
|
||||||
} else {
|
|
||||||
RegisterSegmentTypeChangeUndoRedo(
|
|
||||||
macro, MacroEdit::SegmentType::CONDITION, idx, oldId,
|
|
||||||
oldData, oldLogic, id, newData,
|
|
||||||
(int)(*_entryData)->GetLogicType());
|
|
||||||
}
|
|
||||||
auto widget =
|
auto widget =
|
||||||
MacroConditionFactory::CreateWidget(id, this, *_entryData);
|
MacroConditionFactory::CreateWidget(id, this, *_entryData);
|
||||||
QWidget::connect(widget, SIGNAL(HeaderInfoChanged(const QString &)),
|
QWidget::connect(widget, SIGNAL(HeaderInfoChanged(const QString &)),
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
#include "macro-edit.hpp"
|
#include "macro-edit.hpp"
|
||||||
|
|
||||||
#include "condition-logic.hpp"
|
#include "condition-logic.hpp"
|
||||||
#include "macro-undo-redo.hpp"
|
|
||||||
#include "cursor-shape-changer.hpp"
|
#include "cursor-shape-changer.hpp"
|
||||||
#include "macro-action-edit.hpp"
|
#include "macro-action-edit.hpp"
|
||||||
#include "macro-action-macro.hpp"
|
#include "macro-action-macro.hpp"
|
||||||
@@ -258,92 +257,6 @@ std::shared_ptr<Macro> MacroEdit::GetMacro() const
|
|||||||
return _currentMacro;
|
return _currentMacro;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MacroEdit::InsertSegmentWidget(SegmentType type, int idx)
|
|
||||||
{
|
|
||||||
auto macro = _currentMacro;
|
|
||||||
if (!macro) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (type) {
|
|
||||||
case SegmentType::ACTION: {
|
|
||||||
if (idx < 0 || idx > (int)macro->Actions().size()) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
ui->actionsList->Insert(
|
|
||||||
idx, new MacroActionEdit(this, ¯o->Actions()[idx]));
|
|
||||||
SetActionData(*macro);
|
|
||||||
ui->actionsList->SetHelpMsgVisible(false);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case SegmentType::ELSE_ACTION: {
|
|
||||||
if (idx < 0 || idx > (int)macro->ElseActions().size()) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
ui->elseActionsList->Insert(
|
|
||||||
idx,
|
|
||||||
new MacroActionEdit(this, ¯o->ElseActions()[idx]));
|
|
||||||
SetElseActionData(*macro);
|
|
||||||
ui->elseActionsList->SetHelpMsgVisible(false);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case SegmentType::CONDITION: {
|
|
||||||
if (idx < 0 || idx > (int)macro->Conditions().size()) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
ui->conditionsList->Insert(
|
|
||||||
idx,
|
|
||||||
new MacroConditionEdit(this, ¯o->Conditions()[idx],
|
|
||||||
idx == 0));
|
|
||||||
if (idx == 0 && macro->Conditions().size() > 1) {
|
|
||||||
static_cast<MacroConditionEdit *>(
|
|
||||||
ui->conditionsList->WidgetAt(1))
|
|
||||||
->SetRootNode(false);
|
|
||||||
}
|
|
||||||
SetConditionData(*macro);
|
|
||||||
ui->conditionsList->SetHelpMsgVisible(false);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void MacroEdit::RemoveSegmentWidget(SegmentType type, int idx)
|
|
||||||
{
|
|
||||||
auto macro = _currentMacro;
|
|
||||||
if (!macro) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (type) {
|
|
||||||
case SegmentType::ACTION:
|
|
||||||
if (idx >= 0 &&
|
|
||||||
idx < ui->actionsList->ContentLayout()->count()) {
|
|
||||||
ui->actionsList->Remove(idx);
|
|
||||||
SetActionData(*macro);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case SegmentType::ELSE_ACTION:
|
|
||||||
if (idx >= 0 &&
|
|
||||||
idx < ui->elseActionsList->ContentLayout()->count()) {
|
|
||||||
ui->elseActionsList->Remove(idx);
|
|
||||||
SetElseActionData(*macro);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case SegmentType::CONDITION:
|
|
||||||
if (idx >= 0 &&
|
|
||||||
idx < ui->conditionsList->ContentLayout()->count()) {
|
|
||||||
ui->conditionsList->Remove(idx);
|
|
||||||
if (idx == 0 && !macro->Conditions().empty()) {
|
|
||||||
static_cast<MacroConditionEdit *>(
|
|
||||||
ui->conditionsList->WidgetAt(0))
|
|
||||||
->SetRootNode(true);
|
|
||||||
}
|
|
||||||
SetConditionData(*macro);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void MacroEdit::ClearSegmentWidgetCacheFor(Macro *macro) const
|
void MacroEdit::ClearSegmentWidgetCacheFor(Macro *macro) const
|
||||||
{
|
{
|
||||||
ui->conditionsList->ClearWidgetsFromCacheFor(macro);
|
ui->conditionsList->ClearWidgetsFromCacheFor(macro);
|
||||||
@@ -382,7 +295,7 @@ isValidMacroSegmentIdx(const std::deque<std::shared_ptr<MacroSegment>> &list,
|
|||||||
return (idx > 0 || (unsigned)idx < list.size());
|
return (idx > 0 || (unsigned)idx < list.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
void MacroEdit::SetupMacroSegmentSelection(SegmentType type, int idx)
|
void MacroEdit::SetupMacroSegmentSelection(MacroSection type, int idx)
|
||||||
{
|
{
|
||||||
auto macro = _currentMacro;
|
auto macro = _currentMacro;
|
||||||
if (!macro) {
|
if (!macro) {
|
||||||
@@ -395,7 +308,7 @@ void MacroEdit::SetupMacroSegmentSelection(SegmentType type, int idx)
|
|||||||
std::deque<std::shared_ptr<MacroSegment>> segments;
|
std::deque<std::shared_ptr<MacroSegment>> segments;
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case MacroEdit::SegmentType::CONDITION:
|
case MacroEdit::MacroSection::CONDITIONS:
|
||||||
setList = ui->conditionsList;
|
setList = ui->conditionsList;
|
||||||
setIdx = ¤tConditionIdx;
|
setIdx = ¤tConditionIdx;
|
||||||
segments = {macro->Conditions().begin(),
|
segments = {macro->Conditions().begin(),
|
||||||
@@ -406,7 +319,7 @@ void MacroEdit::SetupMacroSegmentSelection(SegmentType type, int idx)
|
|||||||
resetIdx1 = ¤tActionIdx;
|
resetIdx1 = ¤tActionIdx;
|
||||||
resetIdx2 = ¤tElseActionIdx;
|
resetIdx2 = ¤tElseActionIdx;
|
||||||
break;
|
break;
|
||||||
case MacroEdit::SegmentType::ACTION:
|
case MacroEdit::MacroSection::ACTIONS:
|
||||||
setList = ui->actionsList;
|
setList = ui->actionsList;
|
||||||
setIdx = ¤tActionIdx;
|
setIdx = ¤tActionIdx;
|
||||||
segments = {macro->Actions().begin(), macro->Actions().end()};
|
segments = {macro->Actions().begin(), macro->Actions().end()};
|
||||||
@@ -416,7 +329,7 @@ void MacroEdit::SetupMacroSegmentSelection(SegmentType type, int idx)
|
|||||||
resetIdx1 = ¤tConditionIdx;
|
resetIdx1 = ¤tConditionIdx;
|
||||||
resetIdx2 = ¤tElseActionIdx;
|
resetIdx2 = ¤tElseActionIdx;
|
||||||
break;
|
break;
|
||||||
case MacroEdit::SegmentType::ELSE_ACTION:
|
case MacroEdit::MacroSection::ELSE_ACTIONS:
|
||||||
setList = ui->elseActionsList;
|
setList = ui->elseActionsList;
|
||||||
setIdx = ¤tElseActionIdx;
|
setIdx = ¤tElseActionIdx;
|
||||||
segments = {macro->ElseActions().begin(),
|
segments = {macro->ElseActions().begin(),
|
||||||
@@ -1052,7 +965,7 @@ void MacroEdit::UpMacroSegmentHotkey()
|
|||||||
int conditionSize = macro->Conditions().size();
|
int conditionSize = macro->Conditions().size();
|
||||||
|
|
||||||
if (currentActionIdx == -1 && currentConditionIdx == -1) {
|
if (currentActionIdx == -1 && currentConditionIdx == -1) {
|
||||||
if (lastInteracted == SegmentType::CONDITION) {
|
if (lastInteracted == MacroSection::CONDITIONS) {
|
||||||
if (conditionSize == 0) {
|
if (conditionSize == 0) {
|
||||||
MacroActionSelectionChanged(0);
|
MacroActionSelectionChanged(0);
|
||||||
} else {
|
} else {
|
||||||
@@ -1108,7 +1021,7 @@ void MacroEdit::DownMacroSegmentHotkey()
|
|||||||
int conditionSize = macro->Conditions().size();
|
int conditionSize = macro->Conditions().size();
|
||||||
|
|
||||||
if (currentActionIdx == -1 && currentConditionIdx == -1) {
|
if (currentActionIdx == -1 && currentConditionIdx == -1) {
|
||||||
if (lastInteracted == SegmentType::CONDITION) {
|
if (lastInteracted == MacroSection::CONDITIONS) {
|
||||||
if (conditionSize == 0) {
|
if (conditionSize == 0) {
|
||||||
MacroActionSelectionChanged(0);
|
MacroActionSelectionChanged(0);
|
||||||
} else {
|
} else {
|
||||||
@@ -1171,13 +1084,6 @@ void MacroEdit::AddMacroAction(Macro *macro, int idx, const std::string &id,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Macro *const parentMacro = macro->GetNestedParentMacro();
|
|
||||||
OBSDataAutoRelease parentBeforeData;
|
|
||||||
if (parentMacro) {
|
|
||||||
parentBeforeData = obs_data_create();
|
|
||||||
parentMacro->Save(parentBeforeData);
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
{
|
||||||
auto lock = LockContext();
|
auto lock = LockContext();
|
||||||
macro->Actions().emplace(macro->Actions().begin() + idx,
|
macro->Actions().emplace(macro->Actions().begin() + idx,
|
||||||
@@ -1192,11 +1098,6 @@ void MacroEdit::AddMacroAction(Macro *macro, int idx, const std::string &id,
|
|||||||
idx, new MacroActionEdit(this, ¯o->Actions()[idx]));
|
idx, new MacroActionEdit(this, ¯o->Actions()[idx]));
|
||||||
SetActionData(*macro);
|
SetActionData(*macro);
|
||||||
}
|
}
|
||||||
if (parentMacro) {
|
|
||||||
RegisterMacroModifyUndoRedo(parentMacro, parentBeforeData);
|
|
||||||
} else {
|
|
||||||
RegisterSegmentAddUndoRedo(macro, SegmentType::ACTION, idx);
|
|
||||||
}
|
|
||||||
HighlightAction(idx);
|
HighlightAction(idx);
|
||||||
ui->actionsList->SetHelpMsgVisible(false);
|
ui->actionsList->SetHelpMsgVisible(false);
|
||||||
emit(MacroSegmentOrderChanged());
|
emit(MacroSegmentOrderChanged());
|
||||||
@@ -1262,24 +1163,6 @@ void MacroEdit::RemoveMacroAction(int idx)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Macro *const parentMacro = macro->GetNestedParentMacro();
|
|
||||||
OBSDataAutoRelease parentBeforeData;
|
|
||||||
if (parentMacro) {
|
|
||||||
parentBeforeData = obs_data_create();
|
|
||||||
parentMacro->Save(parentBeforeData);
|
|
||||||
} else {
|
|
||||||
OBSDataAutoRelease segData = obs_data_create();
|
|
||||||
std::string segId;
|
|
||||||
{
|
|
||||||
auto lock = LockContext();
|
|
||||||
macro->Actions().at(idx)->Save(segData);
|
|
||||||
segId = macro->Actions().at(idx)->GetId();
|
|
||||||
}
|
|
||||||
RegisterSegmentRemoveUndoRedo(macro.get(), SegmentType::ACTION,
|
|
||||||
idx, segId, segData,
|
|
||||||
(int)Logic::Type::ROOT_NONE);
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
{
|
||||||
auto lock = LockContext();
|
auto lock = LockContext();
|
||||||
ui->actionsList->Remove(idx);
|
ui->actionsList->Remove(idx);
|
||||||
@@ -1289,11 +1172,8 @@ void MacroEdit::RemoveMacroAction(int idx)
|
|||||||
macro->UpdateActionIndices();
|
macro->UpdateActionIndices();
|
||||||
SetActionData(*macro);
|
SetActionData(*macro);
|
||||||
}
|
}
|
||||||
if (parentMacro) {
|
|
||||||
RegisterMacroModifyUndoRedo(parentMacro, parentBeforeData);
|
|
||||||
}
|
|
||||||
MacroActionSelectionChanged(-1);
|
MacroActionSelectionChanged(-1);
|
||||||
lastInteracted = SegmentType::ACTION;
|
lastInteracted = MacroSection::ACTIONS;
|
||||||
emit(MacroSegmentOrderChanged());
|
emit(MacroSegmentOrderChanged());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1473,7 +1353,7 @@ void MacroEdit::MoveMacroActionDown(int idx)
|
|||||||
|
|
||||||
void MacroEdit::MacroElseActionSelectionChanged(int idx)
|
void MacroEdit::MacroElseActionSelectionChanged(int idx)
|
||||||
{
|
{
|
||||||
SetupMacroSegmentSelection(SegmentType::ELSE_ACTION, idx);
|
SetupMacroSegmentSelection(MacroSection::ELSE_ACTIONS, idx);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MacroEdit::MacroElseActionReorder(int to, int from)
|
void MacroEdit::MacroElseActionReorder(int to, int from)
|
||||||
@@ -1510,13 +1390,6 @@ void MacroEdit::AddMacroElseAction(Macro *macro, int idx, const std::string &id,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Macro *const parentMacro = macro->GetNestedParentMacro();
|
|
||||||
OBSDataAutoRelease parentBeforeData;
|
|
||||||
if (parentMacro) {
|
|
||||||
parentBeforeData = obs_data_create();
|
|
||||||
parentMacro->Save(parentBeforeData);
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
{
|
||||||
auto lock = LockContext();
|
auto lock = LockContext();
|
||||||
macro->ElseActions().emplace(macro->ElseActions().begin() + idx,
|
macro->ElseActions().emplace(macro->ElseActions().begin() + idx,
|
||||||
@@ -1533,12 +1406,6 @@ void MacroEdit::AddMacroElseAction(Macro *macro, int idx, const std::string &id,
|
|||||||
new MacroActionEdit(this, ¯o->ElseActions()[idx]));
|
new MacroActionEdit(this, ¯o->ElseActions()[idx]));
|
||||||
SetElseActionData(*macro);
|
SetElseActionData(*macro);
|
||||||
}
|
}
|
||||||
if (parentMacro) {
|
|
||||||
RegisterMacroModifyUndoRedo(parentMacro, parentBeforeData);
|
|
||||||
} else {
|
|
||||||
RegisterSegmentAddUndoRedo(macro, SegmentType::ELSE_ACTION,
|
|
||||||
idx);
|
|
||||||
}
|
|
||||||
HighlightElseAction(idx);
|
HighlightElseAction(idx);
|
||||||
ui->elseActionsList->SetHelpMsgVisible(false);
|
ui->elseActionsList->SetHelpMsgVisible(false);
|
||||||
emit(MacroSegmentOrderChanged());
|
emit(MacroSegmentOrderChanged());
|
||||||
@@ -1588,25 +1455,6 @@ void MacroEdit::RemoveMacroElseAction(int idx)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Macro *const parentMacro = macro->GetNestedParentMacro();
|
|
||||||
OBSDataAutoRelease parentBeforeData;
|
|
||||||
if (parentMacro) {
|
|
||||||
parentBeforeData = obs_data_create();
|
|
||||||
parentMacro->Save(parentBeforeData);
|
|
||||||
} else {
|
|
||||||
OBSDataAutoRelease segData = obs_data_create();
|
|
||||||
std::string segId;
|
|
||||||
{
|
|
||||||
auto lock = LockContext();
|
|
||||||
macro->ElseActions().at(idx)->Save(segData);
|
|
||||||
segId = macro->ElseActions().at(idx)->GetId();
|
|
||||||
}
|
|
||||||
RegisterSegmentRemoveUndoRedo(macro.get(),
|
|
||||||
SegmentType::ELSE_ACTION, idx,
|
|
||||||
segId, segData,
|
|
||||||
(int)Logic::Type::ROOT_NONE);
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
{
|
||||||
auto lock = LockContext();
|
auto lock = LockContext();
|
||||||
ui->elseActionsList->Remove(idx);
|
ui->elseActionsList->Remove(idx);
|
||||||
@@ -1616,11 +1464,8 @@ void MacroEdit::RemoveMacroElseAction(int idx)
|
|||||||
macro->UpdateElseActionIndices();
|
macro->UpdateElseActionIndices();
|
||||||
SetElseActionData(*macro);
|
SetElseActionData(*macro);
|
||||||
}
|
}
|
||||||
if (parentMacro) {
|
|
||||||
RegisterMacroModifyUndoRedo(parentMacro, parentBeforeData);
|
|
||||||
}
|
|
||||||
MacroElseActionSelectionChanged(-1);
|
MacroElseActionSelectionChanged(-1);
|
||||||
lastInteracted = SegmentType::ELSE_ACTION;
|
lastInteracted = MacroSection::ELSE_ACTIONS;
|
||||||
emit(MacroSegmentOrderChanged());
|
emit(MacroSegmentOrderChanged());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1681,7 +1526,7 @@ void MacroEdit::MoveMacroElseActionDown(int idx)
|
|||||||
|
|
||||||
void MacroEdit::MacroActionSelectionChanged(int idx)
|
void MacroEdit::MacroActionSelectionChanged(int idx)
|
||||||
{
|
{
|
||||||
SetupMacroSegmentSelection(SegmentType::ACTION, idx);
|
SetupMacroSegmentSelection(MacroSection::ACTIONS, idx);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MacroEdit::MacroActionReorder(int to, int from)
|
void MacroEdit::MacroActionReorder(int to, int from)
|
||||||
@@ -1754,13 +1599,6 @@ void MacroEdit::AddMacroCondition(Macro *macro, int idx, const std::string &id,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Macro *const parentMacro = macro->GetNestedParentMacro();
|
|
||||||
OBSDataAutoRelease parentBeforeData;
|
|
||||||
if (parentMacro) {
|
|
||||||
parentBeforeData = obs_data_create();
|
|
||||||
parentMacro->Save(parentBeforeData);
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
{
|
||||||
auto lock = LockContext();
|
auto lock = LockContext();
|
||||||
auto cond = macro->Conditions().emplace(
|
auto cond = macro->Conditions().emplace(
|
||||||
@@ -1779,11 +1617,6 @@ void MacroEdit::AddMacroCondition(Macro *macro, int idx, const std::string &id,
|
|||||||
idx == 0));
|
idx == 0));
|
||||||
SetConditionData(*macro);
|
SetConditionData(*macro);
|
||||||
}
|
}
|
||||||
if (parentMacro) {
|
|
||||||
RegisterMacroModifyUndoRedo(parentMacro, parentBeforeData);
|
|
||||||
} else {
|
|
||||||
RegisterSegmentAddUndoRedo(macro, SegmentType::CONDITION, idx);
|
|
||||||
}
|
|
||||||
HighlightCondition(idx);
|
HighlightCondition(idx);
|
||||||
ui->conditionsList->SetHelpMsgVisible(false);
|
ui->conditionsList->SetHelpMsgVisible(false);
|
||||||
emit(MacroSegmentOrderChanged());
|
emit(MacroSegmentOrderChanged());
|
||||||
@@ -1819,26 +1652,6 @@ void MacroEdit::RemoveMacroCondition(int idx)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Macro *const parentMacro = macro->GetNestedParentMacro();
|
|
||||||
OBSDataAutoRelease parentBeforeData;
|
|
||||||
if (parentMacro) {
|
|
||||||
parentBeforeData = obs_data_create();
|
|
||||||
parentMacro->Save(parentBeforeData);
|
|
||||||
} else {
|
|
||||||
OBSDataAutoRelease segData = obs_data_create();
|
|
||||||
std::string segId;
|
|
||||||
int logic;
|
|
||||||
{
|
|
||||||
auto lock = LockContext();
|
|
||||||
macro->Conditions().at(idx)->Save(segData);
|
|
||||||
segId = macro->Conditions().at(idx)->GetId();
|
|
||||||
logic = (int)macro->Conditions().at(idx)->GetLogicType();
|
|
||||||
}
|
|
||||||
RegisterSegmentRemoveUndoRedo(macro.get(),
|
|
||||||
SegmentType::CONDITION, idx,
|
|
||||||
segId, segData, logic);
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
{
|
||||||
auto lock = LockContext();
|
auto lock = LockContext();
|
||||||
ui->conditionsList->Remove(idx);
|
ui->conditionsList->Remove(idx);
|
||||||
@@ -1853,11 +1666,8 @@ void MacroEdit::RemoveMacroCondition(int idx)
|
|||||||
}
|
}
|
||||||
SetConditionData(*macro);
|
SetConditionData(*macro);
|
||||||
}
|
}
|
||||||
if (parentMacro) {
|
|
||||||
RegisterMacroModifyUndoRedo(parentMacro, parentBeforeData);
|
|
||||||
}
|
|
||||||
MacroConditionSelectionChanged(-1);
|
MacroConditionSelectionChanged(-1);
|
||||||
lastInteracted = SegmentType::CONDITION;
|
lastInteracted = MacroSection::CONDITIONS;
|
||||||
emit(MacroSegmentOrderChanged());
|
emit(MacroSegmentOrderChanged());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1982,7 +1792,7 @@ void MacroEdit::MoveMacroConditionDown(int idx)
|
|||||||
|
|
||||||
void MacroEdit::MacroConditionSelectionChanged(int idx)
|
void MacroEdit::MacroConditionSelectionChanged(int idx)
|
||||||
{
|
{
|
||||||
SetupMacroSegmentSelection(SegmentType::CONDITION, idx);
|
SetupMacroSegmentSelection(MacroSection::CONDITIONS, idx);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MacroEdit::MacroConditionReorder(int to, int from)
|
void MacroEdit::MacroConditionReorder(int to, int from)
|
||||||
|
|||||||
@@ -12,15 +12,11 @@ class MacroEdit : public QWidget {
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
enum class SegmentType { CONDITION, ACTION, ELSE_ACTION };
|
|
||||||
|
|
||||||
MacroEdit(QWidget *parent, QStringList helpMsg = {});
|
MacroEdit(QWidget *parent, QStringList helpMsg = {});
|
||||||
void SetMacro(const std::shared_ptr<Macro> &);
|
void SetMacro(const std::shared_ptr<Macro> &);
|
||||||
std::shared_ptr<Macro> GetMacro() const;
|
std::shared_ptr<Macro> GetMacro() const;
|
||||||
void ClearSegmentWidgetCacheFor(Macro *) const;
|
void ClearSegmentWidgetCacheFor(Macro *) const;
|
||||||
void SetControlsDisabled(bool disable) const;
|
void SetControlsDisabled(bool disable) const;
|
||||||
void InsertSegmentWidget(SegmentType type, int idx);
|
|
||||||
void RemoveSegmentWidget(SegmentType type, int idx);
|
|
||||||
void HighlightAction(int idx, QColor color = QColor(Qt::green)) const;
|
void HighlightAction(int idx, QColor color = QColor(Qt::green)) const;
|
||||||
void HighlightElseAction(int idx,
|
void HighlightElseAction(int idx,
|
||||||
QColor color = QColor(Qt::green)) const;
|
QColor color = QColor(Qt::green)) const;
|
||||||
@@ -116,12 +112,14 @@ protected:
|
|||||||
bool eventFilter(QObject *obj, QEvent *event) override;
|
bool eventFilter(QObject *obj, QEvent *event) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
enum class MacroSection { CONDITIONS, ACTIONS, ELSE_ACTIONS };
|
||||||
|
|
||||||
void PopulateMacroActions(Macro &m, uint32_t afterIdx = 0);
|
void PopulateMacroActions(Macro &m, uint32_t afterIdx = 0);
|
||||||
void PopulateMacroElseActions(Macro &m, uint32_t afterIdx = 0);
|
void PopulateMacroElseActions(Macro &m, uint32_t afterIdx = 0);
|
||||||
void PopulateMacroConditions(Macro &m, uint32_t afterIdx = 0);
|
void PopulateMacroConditions(Macro &m, uint32_t afterIdx = 0);
|
||||||
void ScrollAndFocusNewSegment(MacroSegmentList *list, int newIdx,
|
void ScrollAndFocusNewSegment(MacroSegmentList *list, int newIdx,
|
||||||
int *currentIdx);
|
int *currentIdx);
|
||||||
void SetupMacroSegmentSelection(SegmentType type, int idx);
|
void SetupMacroSegmentSelection(MacroSection type, int idx);
|
||||||
void
|
void
|
||||||
SetupContextMenu(const QPoint &pos,
|
SetupContextMenu(const QPoint &pos,
|
||||||
const std::function<void(MacroEdit *, int)> &remove,
|
const std::function<void(MacroEdit *, int)> &remove,
|
||||||
@@ -133,7 +131,7 @@ private:
|
|||||||
void RunSegmentHighlightChecks();
|
void RunSegmentHighlightChecks();
|
||||||
bool ElseSectionIsVisible() const;
|
bool ElseSectionIsVisible() const;
|
||||||
|
|
||||||
SegmentType lastInteracted = SegmentType::CONDITION;
|
MacroSection lastInteracted = MacroSection::CONDITIONS;
|
||||||
int currentConditionIdx = -1;
|
int currentConditionIdx = -1;
|
||||||
int currentActionIdx = -1;
|
int currentActionIdx = -1;
|
||||||
int currentElseActionIdx = -1;
|
int currentElseActionIdx = -1;
|
||||||
|
|||||||
@@ -201,8 +201,6 @@ bool MacroSegmentList::PopulateWidgetsFromCache(const Macro *macro)
|
|||||||
_contentLayout->addWidget(widget);
|
_contentLayout->addWidget(widget);
|
||||||
widget->show();
|
widget->show();
|
||||||
}
|
}
|
||||||
// Widgets are now owned by the layout again, so the cache entry is stale.
|
|
||||||
_widgetCache.erase(it);
|
|
||||||
|
|
||||||
adjustSize();
|
adjustSize();
|
||||||
updateGeometry();
|
updateGeometry();
|
||||||
@@ -465,17 +463,7 @@ void MacroSegmentList::SetupVisibleMacroSegmentWidgets()
|
|||||||
|
|
||||||
const auto viewportRect = viewport()->rect();
|
const auto viewportRect = viewport()->rect();
|
||||||
|
|
||||||
for (int i = 0; i < _contentLayout->count(); ++i) {
|
for (auto segment : widget()->findChildren<MacroSegmentEdit *>()) {
|
||||||
auto item = _contentLayout->itemAt(i);
|
|
||||||
if (!item) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto segment = dynamic_cast<MacroSegmentEdit *>(item->widget());
|
|
||||||
if (!segment) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto pos = segment->mapTo(viewport(), QPoint(0, 0));
|
const auto pos = segment->mapTo(viewport(), QPoint(0, 0));
|
||||||
const QRect rect(pos, segment->size());
|
const QRect rect(pos, segment->size());
|
||||||
if (!viewportRect.intersects(rect)) {
|
if (!viewportRect.intersects(rect)) {
|
||||||
|
|||||||
@@ -7,7 +7,6 @@
|
|||||||
#include "macro-settings.hpp"
|
#include "macro-settings.hpp"
|
||||||
#include "macro-signals.hpp"
|
#include "macro-signals.hpp"
|
||||||
#include "macro-tree.hpp"
|
#include "macro-tree.hpp"
|
||||||
#include "macro-undo-redo.hpp"
|
|
||||||
#include "macro.hpp"
|
#include "macro.hpp"
|
||||||
#include "math-helpers.hpp"
|
#include "math-helpers.hpp"
|
||||||
#include "name-dialog.hpp"
|
#include "name-dialog.hpp"
|
||||||
@@ -123,7 +122,6 @@ void AdvSceneSwitcher::on_macroAdd_clicked()
|
|||||||
ui->macros->Add(newMacro);
|
ui->macros->Add(newMacro);
|
||||||
MacroSignalManager::Instance()->Add(
|
MacroSignalManager::Instance()->Add(
|
||||||
QString::fromStdString(name));
|
QString::fromStdString(name));
|
||||||
RegisterMacroAddUndoRedo(name);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -133,7 +131,6 @@ void AdvSceneSwitcher::on_macroAdd_clicked()
|
|||||||
ui->macros->AddToGroup(newMacro, selectedMacro);
|
ui->macros->AddToGroup(newMacro, selectedMacro);
|
||||||
MacroSignalManager::Instance()->Add(
|
MacroSignalManager::Instance()->Add(
|
||||||
QString::fromStdString(name));
|
QString::fromStdString(name));
|
||||||
RegisterMacroAddUndoRedo(name);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -142,14 +139,12 @@ void AdvSceneSwitcher::on_macroAdd_clicked()
|
|||||||
ui->macros->Add(newMacro, selectedMacro);
|
ui->macros->Add(newMacro, selectedMacro);
|
||||||
MacroSignalManager::Instance()->Add(
|
MacroSignalManager::Instance()->Add(
|
||||||
QString::fromStdString(name));
|
QString::fromStdString(name));
|
||||||
RegisterMacroAddUndoRedo(name);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Macro::PrepareMoveToGroup(selectedMacroGroup, newMacro);
|
Macro::PrepareMoveToGroup(selectedMacroGroup, newMacro);
|
||||||
ui->macros->Add(newMacro, selectedMacro);
|
ui->macros->Add(newMacro, selectedMacro);
|
||||||
MacroSignalManager::Instance()->Add(QString::fromStdString(name));
|
MacroSignalManager::Instance()->Add(QString::fromStdString(name));
|
||||||
RegisterMacroAddUndoRedo(name);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void addGroupSubitems(std::vector<std::shared_ptr<Macro>> ¯os,
|
static void addGroupSubitems(std::vector<std::shared_ptr<Macro>> ¯os,
|
||||||
@@ -190,12 +185,6 @@ void AdvSceneSwitcher::RemoveMacro(std::shared_ptr<Macro> ¯o)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (macro->IsGroup()) {
|
|
||||||
RegisterGroupDeleteUndoRedo(macro.get());
|
|
||||||
} else {
|
|
||||||
RegisterMacroRemoveUndoRedo(macro.get());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (macro->IsGroup()) {
|
if (macro->IsGroup()) {
|
||||||
std::vector<std::shared_ptr<Macro>> macros = {macro};
|
std::vector<std::shared_ptr<Macro>> macros = {macro};
|
||||||
addGroupSubitems(macros, macro);
|
addGroupSubitems(macros, macro);
|
||||||
@@ -252,16 +241,13 @@ void AdvSceneSwitcher::RemoveSelectedMacros()
|
|||||||
void AdvSceneSwitcher::RenameMacro(std::shared_ptr<Macro> ¯o,
|
void AdvSceneSwitcher::RenameMacro(std::shared_ptr<Macro> ¯o,
|
||||||
const QString &name)
|
const QString &name)
|
||||||
{
|
{
|
||||||
const std::string oldName = macro->Name();
|
auto oldName = QString::fromStdString(macro->Name());
|
||||||
const std::string newName = name.toStdString();
|
|
||||||
{
|
{
|
||||||
auto lock = LockContext();
|
auto lock = LockContext();
|
||||||
macro->SetName(newName);
|
macro->SetName(name.toStdString());
|
||||||
}
|
}
|
||||||
|
|
||||||
RegisterMacroRenameUndoRedo(oldName, newName);
|
MacroSignalManager::Instance()->Rename(oldName, name);
|
||||||
MacroSignalManager::Instance()->Rename(QString::fromStdString(oldName),
|
|
||||||
name);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AdvSceneSwitcher::on_macroRemove_clicked()
|
void AdvSceneSwitcher::on_macroRemove_clicked()
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
#include "macro-tree.hpp"
|
#include "macro-tree.hpp"
|
||||||
#include "macro-undo-redo.hpp"
|
|
||||||
|
|
||||||
#include "macro-helpers.hpp"
|
#include "macro-helpers.hpp"
|
||||||
#include "macro-search.hpp"
|
#include "macro-search.hpp"
|
||||||
@@ -825,8 +824,6 @@ void MacroTreeModel::GroupSelectedItems(QModelIndexList &indices)
|
|||||||
|
|
||||||
Reset(_macros);
|
Reset(_macros);
|
||||||
assert(IsInValidState());
|
assert(IsInValidState());
|
||||||
|
|
||||||
RegisterGroupCreateUndoRedo(name.toStdString());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MacroTreeModel::UngroupSelectedGroups(QModelIndexList &indices)
|
void MacroTreeModel::UngroupSelectedGroups(QModelIndexList &indices)
|
||||||
@@ -840,7 +837,6 @@ void MacroTreeModel::UngroupSelectedGroups(QModelIndexList &indices)
|
|||||||
std::shared_ptr<Macro> item = _macros[ModelIndexToMacroIndex(
|
std::shared_ptr<Macro> item = _macros[ModelIndexToMacroIndex(
|
||||||
indices[i].row(), _macros)];
|
indices[i].row(), _macros)];
|
||||||
if (item->IsGroup()) {
|
if (item->IsGroup()) {
|
||||||
RegisterGroupRemoveUndoRedo(item->Name());
|
|
||||||
Macro::RemoveGroup(item);
|
Macro::RemoveGroup(item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,31 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include "macro-edit.hpp"
|
|
||||||
|
|
||||||
#include <obs-data.h>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
namespace advss {
|
|
||||||
|
|
||||||
class Macro;
|
|
||||||
|
|
||||||
void RegisterMacroAddUndoRedo(const std::string ¯oName);
|
|
||||||
bool RegisterMacroRemoveUndoRedo(Macro *macro);
|
|
||||||
void RegisterSegmentAddUndoRedo(Macro *macro, MacroEdit::SegmentType type,
|
|
||||||
int index);
|
|
||||||
void RegisterSegmentTypeChangeUndoRedo(Macro *macro,
|
|
||||||
MacroEdit::SegmentType type, int index,
|
|
||||||
const std::string &oldId,
|
|
||||||
obs_data_t *oldData, int oldLogic,
|
|
||||||
const std::string &newId,
|
|
||||||
obs_data_t *newData, int newLogic);
|
|
||||||
void RegisterSegmentRemoveUndoRedo(Macro *macro, MacroEdit::SegmentType type,
|
|
||||||
int index, const std::string &segmentId,
|
|
||||||
obs_data_t *segmentData, int logic);
|
|
||||||
void RegisterMacroRenameUndoRedo(const std::string &oldName,
|
|
||||||
const std::string &newName);
|
|
||||||
void RegisterGroupCreateUndoRedo(const std::string &groupName);
|
|
||||||
void RegisterGroupRemoveUndoRedo(const std::string &groupName);
|
|
||||||
void RegisterGroupDeleteUndoRedo(Macro *macro);
|
|
||||||
void RegisterMacroModifyUndoRedo(Macro *parentMacro, obs_data_t *beforeData);
|
|
||||||
|
|
||||||
} // namespace advss
|
|
||||||
@@ -130,13 +130,6 @@ public:
|
|||||||
void SetParent(std::shared_ptr<Macro> m) { _parent = m; }
|
void SetParent(std::shared_ptr<Macro> m) { _parent = m; }
|
||||||
std::shared_ptr<Macro> Parent() const;
|
std::shared_ptr<Macro> Parent() const;
|
||||||
|
|
||||||
// For nested macros embedded in actions (e.g. loop, nested-macro action)
|
|
||||||
void SetNestedParentMacro(Macro *parent)
|
|
||||||
{
|
|
||||||
_nestedParentMacro = parent;
|
|
||||||
}
|
|
||||||
Macro *GetNestedParentMacro() const { return _nestedParentMacro; }
|
|
||||||
|
|
||||||
// Saving and loading
|
// Saving and loading
|
||||||
bool Save(obs_data_t *obj, bool saveForCopy = false) const;
|
bool Save(obs_data_t *obj, bool saveForCopy = false) const;
|
||||||
bool Load(obs_data_t *obj);
|
bool Load(obs_data_t *obj);
|
||||||
@@ -194,7 +187,6 @@ private:
|
|||||||
std::deque<std::shared_ptr<MacroAction>> _elseActions;
|
std::deque<std::shared_ptr<MacroAction>> _elseActions;
|
||||||
|
|
||||||
std::weak_ptr<Macro> _parent;
|
std::weak_ptr<Macro> _parent;
|
||||||
Macro *_nestedParentMacro = nullptr;
|
|
||||||
uint32_t _groupSize = 0;
|
uint32_t _groupSize = 0;
|
||||||
bool _isGroup = false;
|
bool _isGroup = false;
|
||||||
bool _isCollapsed = false;
|
bool _isCollapsed = false;
|
||||||
|
|||||||
@@ -42,6 +42,7 @@ add_plugin(twitch)
|
|||||||
add_plugin(usb)
|
add_plugin(usb)
|
||||||
add_plugin(video)
|
add_plugin(video)
|
||||||
add_plugin(speech)
|
add_plugin(speech)
|
||||||
|
add_plugin(now-playing)
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------- #
|
# ---------------------------------------------------------------------------- #
|
||||||
|
|
||||||
|
|||||||
17
plugins/now-playing/CMakeLists.txt
Normal file
17
plugins/now-playing/CMakeLists.txt
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.14)
|
||||||
|
project(advanced-scene-switcher-now-playing)
|
||||||
|
|
||||||
|
if(NOT WIN32)
|
||||||
|
message(WARNING "Now playing condition is only supported on Windows.")
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
add_library(${PROJECT_NAME} MODULE)
|
||||||
|
target_sources(${PROJECT_NAME} PRIVATE macro-condition-now-playing.cpp
|
||||||
|
macro-condition-now-playing.hpp)
|
||||||
|
|
||||||
|
target_link_libraries(${PROJECT_NAME} PRIVATE windowsapp)
|
||||||
|
|
||||||
|
setup_advss_plugin(${PROJECT_NAME})
|
||||||
|
set_target_properties(${PROJECT_NAME} PROPERTIES PREFIX "")
|
||||||
|
install_advss_plugin(${PROJECT_NAME})
|
||||||
338
plugins/now-playing/macro-condition-now-playing.cpp
Normal file
338
plugins/now-playing/macro-condition-now-playing.cpp
Normal file
@@ -0,0 +1,338 @@
|
|||||||
|
#include "macro-condition-now-playing.hpp"
|
||||||
|
#include "layout-helpers.hpp"
|
||||||
|
#include "sync-helpers.hpp"
|
||||||
|
|
||||||
|
#include <util/base.h>
|
||||||
|
|
||||||
|
#include <roapi.h>
|
||||||
|
#include <winrt/Windows.Foundation.h>
|
||||||
|
#include <winrt/Windows.Media.Control.h>
|
||||||
|
|
||||||
|
namespace advss {
|
||||||
|
|
||||||
|
using namespace winrt::Windows::Media::Control;
|
||||||
|
|
||||||
|
const std::string MacroConditionNowPlaying::id = "now_playing";
|
||||||
|
|
||||||
|
bool MacroConditionNowPlaying::_registered = MacroConditionFactory::Register(
|
||||||
|
MacroConditionNowPlaying::id,
|
||||||
|
{MacroConditionNowPlaying::Create, MacroConditionNowPlayingEdit::Create,
|
||||||
|
"AdvSceneSwitcher.condition.nowPlaying"});
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
struct SessionInfo {
|
||||||
|
bool hasSession = false;
|
||||||
|
std::string title;
|
||||||
|
std::string artist;
|
||||||
|
std::string album;
|
||||||
|
std::string appName;
|
||||||
|
GlobalSystemMediaTransportControlsSessionPlaybackStatus playbackStatus =
|
||||||
|
GlobalSystemMediaTransportControlsSessionPlaybackStatus::Closed;
|
||||||
|
};
|
||||||
|
|
||||||
|
static bool initWinRT()
|
||||||
|
{
|
||||||
|
HRESULT hr = RoInitialize(RO_INIT_MULTITHREADED);
|
||||||
|
// S_OK: initialized, S_FALSE: already initialized with same type,
|
||||||
|
// RPC_E_CHANGED_MODE: thread is STA (OBS UI thread) - WinRT still usable
|
||||||
|
return SUCCEEDED(hr) || hr == RPC_E_CHANGED_MODE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static SessionInfo getCurrentSessionInfo()
|
||||||
|
{
|
||||||
|
thread_local bool initialized = initWinRT();
|
||||||
|
(void)initialized;
|
||||||
|
|
||||||
|
SessionInfo info;
|
||||||
|
|
||||||
|
try {
|
||||||
|
auto manager =
|
||||||
|
GlobalSystemMediaTransportControlsSessionManager::
|
||||||
|
RequestAsync()
|
||||||
|
.get();
|
||||||
|
auto session = manager.GetCurrentSession();
|
||||||
|
if (!session) {
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
|
||||||
|
info.hasSession = true;
|
||||||
|
info.appName = winrt::to_string(session.SourceAppUserModelId());
|
||||||
|
|
||||||
|
auto playbackInfo = session.GetPlaybackInfo();
|
||||||
|
info.playbackStatus = playbackInfo.PlaybackStatus();
|
||||||
|
|
||||||
|
auto props = session.TryGetMediaPropertiesAsync().get();
|
||||||
|
if (props) {
|
||||||
|
info.title = winrt::to_string(props.Title());
|
||||||
|
info.artist = winrt::to_string(props.Artist());
|
||||||
|
info.album = winrt::to_string(props.AlbumTitle());
|
||||||
|
}
|
||||||
|
} catch (const winrt::hresult_error &e) {
|
||||||
|
blog(LOG_WARNING, "now playing: WinRT error 0x%08X",
|
||||||
|
static_cast<uint32_t>(e.code()));
|
||||||
|
}
|
||||||
|
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string PlaybackStatusToString(
|
||||||
|
GlobalSystemMediaTransportControlsSessionPlaybackStatus status)
|
||||||
|
{
|
||||||
|
switch (status) {
|
||||||
|
case GlobalSystemMediaTransportControlsSessionPlaybackStatus::Playing:
|
||||||
|
return "Playing";
|
||||||
|
case GlobalSystemMediaTransportControlsSessionPlaybackStatus::Paused:
|
||||||
|
return "Paused";
|
||||||
|
case GlobalSystemMediaTransportControlsSessionPlaybackStatus::Stopped:
|
||||||
|
return "Stopped";
|
||||||
|
case GlobalSystemMediaTransportControlsSessionPlaybackStatus::Opened:
|
||||||
|
return "Opening";
|
||||||
|
case GlobalSystemMediaTransportControlsSessionPlaybackStatus::Changing:
|
||||||
|
return "Changing";
|
||||||
|
default:
|
||||||
|
return "Closed";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
bool MacroConditionNowPlaying::CheckCondition()
|
||||||
|
{
|
||||||
|
const auto info = getCurrentSessionInfo();
|
||||||
|
|
||||||
|
SetTempVarValue("title", info.title);
|
||||||
|
SetTempVarValue("artist", info.artist);
|
||||||
|
SetTempVarValue("album", info.album);
|
||||||
|
SetTempVarValue("appName", info.appName);
|
||||||
|
SetTempVarValue("playbackStatus",
|
||||||
|
PlaybackStatusToString(info.playbackStatus));
|
||||||
|
|
||||||
|
if (!info.hasSession) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto textMatches = [this](const std::string &field) -> bool {
|
||||||
|
const QString pattern = QString::fromStdString(_matchText);
|
||||||
|
const QString value = QString::fromStdString(field);
|
||||||
|
if (_regex.Enabled()) {
|
||||||
|
return _regex.Matches(value, pattern);
|
||||||
|
}
|
||||||
|
return value == pattern;
|
||||||
|
};
|
||||||
|
|
||||||
|
switch (_checkType) {
|
||||||
|
case CheckType::PLAYBACK_STATE: {
|
||||||
|
using S =
|
||||||
|
GlobalSystemMediaTransportControlsSessionPlaybackStatus;
|
||||||
|
switch (_playbackState) {
|
||||||
|
case PlaybackState::PLAYING:
|
||||||
|
return info.playbackStatus == S::Playing;
|
||||||
|
case PlaybackState::PAUSED:
|
||||||
|
return info.playbackStatus == S::Paused;
|
||||||
|
case PlaybackState::STOPPED:
|
||||||
|
return info.playbackStatus == S::Stopped;
|
||||||
|
case PlaybackState::OPENING:
|
||||||
|
return info.playbackStatus == S::Opened;
|
||||||
|
case PlaybackState::CHANGING:
|
||||||
|
return info.playbackStatus == S::Changing;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case CheckType::TITLE:
|
||||||
|
return textMatches(info.title);
|
||||||
|
case CheckType::ARTIST:
|
||||||
|
return textMatches(info.artist);
|
||||||
|
case CheckType::ALBUM:
|
||||||
|
return textMatches(info.album);
|
||||||
|
case CheckType::APP_NAME:
|
||||||
|
return textMatches(info.appName);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MacroConditionNowPlaying::Save(obs_data_t *obj) const
|
||||||
|
{
|
||||||
|
MacroCondition::Save(obj);
|
||||||
|
obs_data_set_int(obj, "checkType", static_cast<int>(_checkType));
|
||||||
|
obs_data_set_int(obj, "playbackState",
|
||||||
|
static_cast<int>(_playbackState));
|
||||||
|
_matchText.Save(obj, "matchText");
|
||||||
|
_regex.Save(obj);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MacroConditionNowPlaying::Load(obs_data_t *obj)
|
||||||
|
{
|
||||||
|
MacroCondition::Load(obj);
|
||||||
|
_checkType = static_cast<CheckType>(obs_data_get_int(obj, "checkType"));
|
||||||
|
_playbackState = static_cast<PlaybackState>(
|
||||||
|
obs_data_get_int(obj, "playbackState"));
|
||||||
|
_matchText.Load(obj, "matchText");
|
||||||
|
_regex.Load(obj);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MacroConditionNowPlaying::SetupTempVars()
|
||||||
|
{
|
||||||
|
AddTempvar(
|
||||||
|
"title",
|
||||||
|
obs_module_text("AdvSceneSwitcher.tempVar.nowPlaying.title"));
|
||||||
|
AddTempvar(
|
||||||
|
"artist",
|
||||||
|
obs_module_text("AdvSceneSwitcher.tempVar.nowPlaying.artist"));
|
||||||
|
AddTempvar(
|
||||||
|
"album",
|
||||||
|
obs_module_text("AdvSceneSwitcher.tempVar.nowPlaying.album"));
|
||||||
|
AddTempvar(
|
||||||
|
"appName",
|
||||||
|
obs_module_text("AdvSceneSwitcher.tempVar.nowPlaying.appName"));
|
||||||
|
AddTempvar(
|
||||||
|
"playbackStatus",
|
||||||
|
obs_module_text(
|
||||||
|
"AdvSceneSwitcher.tempVar.nowPlaying.playbackStatus"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
static void populateCheckTypeSelection(QComboBox *list)
|
||||||
|
{
|
||||||
|
static const std::map<MacroConditionNowPlaying::CheckType, std::string> checkTypes = {
|
||||||
|
{MacroConditionNowPlaying::CheckType::PLAYBACK_STATE,
|
||||||
|
"AdvSceneSwitcher.condition.nowPlaying.checkType.playbackState"},
|
||||||
|
{MacroConditionNowPlaying::CheckType::TITLE,
|
||||||
|
"AdvSceneSwitcher.condition.nowPlaying.checkType.title"},
|
||||||
|
{MacroConditionNowPlaying::CheckType::ARTIST,
|
||||||
|
"AdvSceneSwitcher.condition.nowPlaying.checkType.artist"},
|
||||||
|
{MacroConditionNowPlaying::CheckType::ALBUM,
|
||||||
|
"AdvSceneSwitcher.condition.nowPlaying.checkType.album"},
|
||||||
|
{MacroConditionNowPlaying::CheckType::APP_NAME,
|
||||||
|
"AdvSceneSwitcher.condition.nowPlaying.checkType.appName"},
|
||||||
|
};
|
||||||
|
|
||||||
|
for (const auto &[type, name] : checkTypes) {
|
||||||
|
list->addItem(obs_module_text(name.c_str()),
|
||||||
|
static_cast<int>(type));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void populatePlaybackStateSelection(QComboBox *list)
|
||||||
|
{
|
||||||
|
static const std::map<MacroConditionNowPlaying::PlaybackState, std::string> playbackStates = {
|
||||||
|
{MacroConditionNowPlaying::PlaybackState::PLAYING,
|
||||||
|
"AdvSceneSwitcher.condition.nowPlaying.playbackState.playing"},
|
||||||
|
{MacroConditionNowPlaying::PlaybackState::PAUSED,
|
||||||
|
"AdvSceneSwitcher.condition.nowPlaying.playbackState.paused"},
|
||||||
|
{MacroConditionNowPlaying::PlaybackState::STOPPED,
|
||||||
|
"AdvSceneSwitcher.condition.nowPlaying.playbackState.stopped"},
|
||||||
|
{MacroConditionNowPlaying::PlaybackState::OPENING,
|
||||||
|
"AdvSceneSwitcher.condition.nowPlaying.playbackState.opening"},
|
||||||
|
{MacroConditionNowPlaying::PlaybackState::CHANGING,
|
||||||
|
"AdvSceneSwitcher.condition.nowPlaying.playbackState.changing"},
|
||||||
|
};
|
||||||
|
|
||||||
|
for (const auto &[state, name] : playbackStates) {
|
||||||
|
list->addItem(obs_module_text(name.c_str()),
|
||||||
|
static_cast<int>(state));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MacroConditionNowPlayingEdit::MacroConditionNowPlayingEdit(
|
||||||
|
QWidget *parent, std::shared_ptr<MacroConditionNowPlaying> entryData)
|
||||||
|
: QWidget(parent),
|
||||||
|
_checkType(new QComboBox(this)),
|
||||||
|
_playbackState(new QComboBox(this)),
|
||||||
|
_matchText(new VariableLineEdit(this)),
|
||||||
|
_regex(new RegexConfigWidget(this))
|
||||||
|
{
|
||||||
|
populateCheckTypeSelection(_checkType);
|
||||||
|
populatePlaybackStateSelection(_playbackState);
|
||||||
|
|
||||||
|
connect(_checkType, QOverload<int>::of(&QComboBox::currentIndexChanged),
|
||||||
|
this, &MacroConditionNowPlayingEdit::CheckTypeChanged);
|
||||||
|
connect(_playbackState,
|
||||||
|
QOverload<int>::of(&QComboBox::currentIndexChanged), this,
|
||||||
|
&MacroConditionNowPlayingEdit::PlaybackStateChanged);
|
||||||
|
connect(_matchText, &VariableLineEdit::textEdited, this,
|
||||||
|
&MacroConditionNowPlayingEdit::MatchTextChanged);
|
||||||
|
connect(_regex, &RegexConfigWidget::RegexConfigChanged, this,
|
||||||
|
&MacroConditionNowPlayingEdit::RegexChanged);
|
||||||
|
|
||||||
|
_layout = new QHBoxLayout();
|
||||||
|
_layout->addWidget(_checkType);
|
||||||
|
_layout->addWidget(_playbackState);
|
||||||
|
_layout->addWidget(_matchText);
|
||||||
|
_layout->addWidget(_regex);
|
||||||
|
setLayout(_layout);
|
||||||
|
|
||||||
|
_entryData = entryData;
|
||||||
|
UpdateEntryData();
|
||||||
|
_loading = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MacroConditionNowPlayingEdit::UpdateEntryData()
|
||||||
|
{
|
||||||
|
if (!_entryData) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_checkType->setCurrentIndex(
|
||||||
|
_checkType->findData(static_cast<int>(_entryData->_checkType)));
|
||||||
|
_playbackState->setCurrentIndex(_playbackState->findData(
|
||||||
|
static_cast<int>(_entryData->_playbackState)));
|
||||||
|
_matchText->setText(QString::fromStdString(_entryData->_matchText));
|
||||||
|
_regex->SetRegexConfig(_entryData->_regex);
|
||||||
|
|
||||||
|
SetWidgetVisibility();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MacroConditionNowPlayingEdit::CheckTypeChanged(int)
|
||||||
|
{
|
||||||
|
GUARD_LOADING_AND_LOCK();
|
||||||
|
_entryData->_checkType =
|
||||||
|
static_cast<MacroConditionNowPlaying::CheckType>(
|
||||||
|
_checkType->currentData().toInt());
|
||||||
|
SetWidgetVisibility();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MacroConditionNowPlayingEdit::PlaybackStateChanged(int)
|
||||||
|
{
|
||||||
|
GUARD_LOADING_AND_LOCK();
|
||||||
|
_entryData->_playbackState =
|
||||||
|
static_cast<MacroConditionNowPlaying::PlaybackState>(
|
||||||
|
_playbackState->currentData().toInt());
|
||||||
|
}
|
||||||
|
|
||||||
|
void MacroConditionNowPlayingEdit::MatchTextChanged(const QString &text)
|
||||||
|
{
|
||||||
|
GUARD_LOADING_AND_LOCK();
|
||||||
|
_entryData->_matchText = text.toStdString();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MacroConditionNowPlayingEdit::RegexChanged(const RegexConfig ®ex)
|
||||||
|
{
|
||||||
|
GUARD_LOADING_AND_LOCK();
|
||||||
|
_entryData->_regex = regex;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MacroConditionNowPlayingEdit::SetWidgetVisibility()
|
||||||
|
{
|
||||||
|
const bool isStateCheck =
|
||||||
|
_entryData->_checkType ==
|
||||||
|
MacroConditionNowPlaying::CheckType::PLAYBACK_STATE;
|
||||||
|
_playbackState->setVisible(isStateCheck);
|
||||||
|
_matchText->setVisible(!isStateCheck);
|
||||||
|
_regex->setVisible(!isStateCheck);
|
||||||
|
|
||||||
|
if (isStateCheck) {
|
||||||
|
AddStretchIfNecessary(_layout);
|
||||||
|
} else {
|
||||||
|
RemoveStretchIfPresent(_layout);
|
||||||
|
}
|
||||||
|
|
||||||
|
adjustSize();
|
||||||
|
updateGeometry();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace advss
|
||||||
86
plugins/now-playing/macro-condition-now-playing.hpp
Normal file
86
plugins/now-playing/macro-condition-now-playing.hpp
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "macro-condition-edit.hpp"
|
||||||
|
#include "regex-config.hpp"
|
||||||
|
#include "variable-line-edit.hpp"
|
||||||
|
|
||||||
|
#include <QComboBox>
|
||||||
|
|
||||||
|
namespace advss {
|
||||||
|
|
||||||
|
class MacroConditionNowPlaying : public MacroCondition {
|
||||||
|
public:
|
||||||
|
enum class CheckType {
|
||||||
|
PLAYBACK_STATE,
|
||||||
|
TITLE,
|
||||||
|
ARTIST,
|
||||||
|
ALBUM,
|
||||||
|
APP_NAME,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class PlaybackState {
|
||||||
|
PLAYING,
|
||||||
|
PAUSED,
|
||||||
|
STOPPED,
|
||||||
|
OPENING,
|
||||||
|
CHANGING,
|
||||||
|
};
|
||||||
|
|
||||||
|
MacroConditionNowPlaying(Macro *m) : MacroCondition(m) {}
|
||||||
|
bool CheckCondition();
|
||||||
|
bool Save(obs_data_t *obj) const;
|
||||||
|
bool Load(obs_data_t *obj);
|
||||||
|
std::string GetId() const { return id; }
|
||||||
|
static std::shared_ptr<MacroCondition> Create(Macro *m)
|
||||||
|
{
|
||||||
|
return std::make_shared<MacroConditionNowPlaying>(m);
|
||||||
|
}
|
||||||
|
|
||||||
|
CheckType _checkType = CheckType::PLAYBACK_STATE;
|
||||||
|
PlaybackState _playbackState = PlaybackState::PLAYING;
|
||||||
|
StringVariable _matchText;
|
||||||
|
RegexConfig _regex;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void SetupTempVars();
|
||||||
|
|
||||||
|
static bool _registered;
|
||||||
|
static const std::string id;
|
||||||
|
};
|
||||||
|
|
||||||
|
class MacroConditionNowPlayingEdit : public QWidget {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
MacroConditionNowPlayingEdit(
|
||||||
|
QWidget *parent,
|
||||||
|
std::shared_ptr<MacroConditionNowPlaying> cond = nullptr);
|
||||||
|
void UpdateEntryData();
|
||||||
|
static QWidget *Create(QWidget *parent,
|
||||||
|
std::shared_ptr<MacroCondition> cond)
|
||||||
|
{
|
||||||
|
return new MacroConditionNowPlayingEdit(
|
||||||
|
parent,
|
||||||
|
std::dynamic_pointer_cast<MacroConditionNowPlaying>(
|
||||||
|
cond));
|
||||||
|
}
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void CheckTypeChanged(int);
|
||||||
|
void PlaybackStateChanged(int);
|
||||||
|
void MatchTextChanged(const QString &);
|
||||||
|
void RegexChanged(const RegexConfig &);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void SetWidgetVisibility();
|
||||||
|
|
||||||
|
QHBoxLayout *_layout;
|
||||||
|
QComboBox *_checkType;
|
||||||
|
QComboBox *_playbackState;
|
||||||
|
VariableLineEdit *_matchText;
|
||||||
|
RegexConfigWidget *_regex;
|
||||||
|
|
||||||
|
std::shared_ptr<MacroConditionNowPlaying> _entryData;
|
||||||
|
bool _loading = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace advss
|
||||||
@@ -110,9 +110,7 @@ void MacroEdit::HighlightControls() const {}
|
|||||||
void MacroEdit::PopulateMacroActions(Macro &, uint32_t) {}
|
void MacroEdit::PopulateMacroActions(Macro &, uint32_t) {}
|
||||||
void MacroEdit::PopulateMacroElseActions(Macro &, uint32_t) {}
|
void MacroEdit::PopulateMacroElseActions(Macro &, uint32_t) {}
|
||||||
void MacroEdit::PopulateMacroConditions(Macro &, uint32_t) {}
|
void MacroEdit::PopulateMacroConditions(Macro &, uint32_t) {}
|
||||||
void MacroEdit::InsertSegmentWidget(SegmentType, int) {}
|
void MacroEdit::SetupMacroSegmentSelection(MacroSection, int) {}
|
||||||
void MacroEdit::RemoveSegmentWidget(SegmentType, int) {}
|
|
||||||
void MacroEdit::SetupMacroSegmentSelection(SegmentType, int) {}
|
|
||||||
void MacroEdit::SetupContextMenu(const QPoint &,
|
void MacroEdit::SetupContextMenu(const QPoint &,
|
||||||
const std::function<void(MacroEdit *, int)> &,
|
const std::function<void(MacroEdit *, int)> &,
|
||||||
const std::function<void(MacroEdit *)> &,
|
const std::function<void(MacroEdit *)> &,
|
||||||
|
|||||||
Reference in New Issue
Block a user