Compare commits

...

4 Commits
1.17 ... 1.17.1

Author SHA1 Message Date
WarmUpTill
16ee789c82 Add option to perform macro actions only on condition change 2022-01-06 08:41:18 -08:00
WarmUpTill
d040a01016 Reintroduce checkbox to change current scene check transition behaviour 2022-01-06 08:41:18 -08:00
WarmUpTill
eb952afe58 Enable time constraints for transition condition 2022-01-06 08:41:18 -08:00
WarmUpTill
34cff925fc CI: No longer query for 32 bit OBS install path 2022-01-05 20:21:03 +01:00
10 changed files with 90 additions and 47 deletions

View File

@@ -14,7 +14,7 @@ AppVersion={#MyAppVersion}
AppPublisherURL={#MyAppURL} AppPublisherURL={#MyAppURL}
AppSupportURL={#MyAppURL} AppSupportURL={#MyAppURL}
AppUpdatesURL={#MyAppURL} AppUpdatesURL={#MyAppURL}
DefaultDirName={code:GetDirName} DefaultDirName={code:GetDefaultDirectory}
DefaultGroupName={#MyAppName} DefaultGroupName={#MyAppName}
AllowNoIcons=yes AllowNoIcons=yes
; Uncomment the following line to run in non administrative install mode (install for current user only.) ; Uncomment the following line to run in non administrative install mode (install for current user only.)
@@ -38,18 +38,18 @@ Source: "@ISS_PLUGIN_FILES_DIR@\*"; DestDir: "{app}"; Flags: ignoreversion recur
Name: "{group}\{cm:UninstallProgram,{#MyAppName}}"; Filename: "{uninstallexe}" Name: "{group}\{cm:UninstallProgram,{#MyAppName}}"; Filename: "{uninstallexe}"
[Code] [Code]
// credit where it's due: function GetDefaultDirectory(Value: String): String;
// following function comes from https://github.com/Xaymar/obs-studio_amf-encoder-plugin/blob/master/%23Resources/Installer.in.iss#L45
function GetDirName(Value: string): string;
var var
InstallPath: string; sInstallPath: String;
begin begin
// initialize default path, which will be returned when the following registry sInstallPath := Value;
// key queries fail due to missing keys or for some different reason if (sInstallPath = '') then
Result := ExpandConstant('{pf}\obs-studio'); RegQueryStringValue(HKLM64, 'SOFTWARE\OBS Studio', '', sInstallPath);
// query the first registry value; if this succeeds, return the obtained value if (sInstallPath = '') then
if RegQueryStringValue(HKLM32, 'SOFTWARE\OBS Studio', '', InstallPath) then RegQueryStringValue(HKCU64, 'SOFTWARE\OBS Studio', '', sInstallPath);
Result := InstallPath if (sInstallPath = '') then
sInstallPath := ExpandConstant('{commonpf}\obs-studio');
Result := sInstallPath
end; end;
procedure CurStepChanged(CurStep: TSetupStep); procedure CurStepChanged(CurStep: TSetupStep);

View File

@@ -70,6 +70,7 @@ AdvSceneSwitcher.macroTab.name="Name:"
AdvSceneSwitcher.macroTab.run="Run macro" AdvSceneSwitcher.macroTab.run="Run macro"
AdvSceneSwitcher.macroTab.runFail="Running \"%1\" failed!\nEither one of the actions failed or the macro is running already." AdvSceneSwitcher.macroTab.runFail="Running \"%1\" failed!\nEither one of the actions failed or the macro is running already."
AdvSceneSwitcher.macroTab.runInParallel="Run macro in parallel to other macros" AdvSceneSwitcher.macroTab.runInParallel="Run macro in parallel to other macros"
AdvSceneSwitcher.macroTab.onChange="Perform actions only on condition change"
AdvSceneSwitcher.macroTab.defaultname="Macro %1" AdvSceneSwitcher.macroTab.defaultname="Macro %1"
AdvSceneSwitcher.macroTab.exists="Macro name exists already" AdvSceneSwitcher.macroTab.exists="Macro name exists already"
AdvSceneSwitcher.macroTab.copy="Create copy" AdvSceneSwitcher.macroTab.copy="Create copy"
@@ -104,8 +105,9 @@ AdvSceneSwitcher.condition.scene.type.current="Current scene is"
AdvSceneSwitcher.condition.scene.type.previous="Previous scene is" AdvSceneSwitcher.condition.scene.type.previous="Previous scene is"
AdvSceneSwitcher.condition.scene.type.changed="Scene changed" AdvSceneSwitcher.condition.scene.type.changed="Scene changed"
AdvSceneSwitcher.condition.scene.type.notChanged="Scene has not changed" AdvSceneSwitcher.condition.scene.type.notChanged="Scene has not changed"
AdvSceneSwitcher.condition.scene.waitForTransition="Wait for transition to complete" AdvSceneSwitcher.condition.scene.currentSceneTransitionBehaviour="During transition check for transition target scene"
AdvSceneSwitcher.condition.scene.entry="{{sceneType}} {{scenes}} {{waitForTransition}}" AdvSceneSwitcher.condition.scene.entry.line1="{{sceneType}} {{scenes}}"
AdvSceneSwitcher.condition.scene.entry.line2="{{useTransitionTargetScene}}"
AdvSceneSwitcher.condition.window="Window" AdvSceneSwitcher.condition.window="Window"
AdvSceneSwitcher.condition.window.entry.line1="{{windows}} exist and ..." AdvSceneSwitcher.condition.window.entry.line1="{{windows}} exist and ..."
AdvSceneSwitcher.condition.window.entry.line2="... is {{fullscreen}} fullscreen {{maximized}} maximized {{focused}} focused {{windowFocusChanged}} foreground window changed" AdvSceneSwitcher.condition.window.entry.line2="... is {{fullscreen}} fullscreen {{maximized}} maximized {{focused}} focused {{windowFocusChanged}} foreground window changed"

View File

@@ -729,7 +729,7 @@
</property> </property>
<layout class="QVBoxLayout" name="verticalLayout_34"> <layout class="QVBoxLayout" name="verticalLayout_34">
<item> <item>
<layout class="QHBoxLayout" name="horizontalLayout_18" stretch="0,0,0,0,0"> <layout class="QHBoxLayout" name="horizontalLayout_18" stretch="0,0,0,0,0,0">
<item> <item>
<widget class="QLabel" name="label_20"> <widget class="QLabel" name="label_20">
<property name="text"> <property name="text">
@@ -754,6 +754,13 @@
</property> </property>
</widget> </widget>
</item> </item>
<item>
<widget class="QCheckBox" name="runMacroOnChange">
<property name="text">
<string>AdvSceneSwitcher.macroTab.onChange</string>
</property>
</widget>
</item>
<item> <item>
<spacer name="horizontalSpacer_13"> <spacer name="horizontalSpacer_13">
<property name="orientation"> <property name="orientation">
@@ -783,7 +790,7 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>767</width> <width>792</width>
<height>218</height> <height>218</height>
</rect> </rect>
</property> </property>
@@ -882,7 +889,7 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>767</width> <width>792</width>
<height>218</height> <height>218</height>
</rect> </rect>
</property> </property>

View File

@@ -120,6 +120,7 @@ public slots:
void on_macroName_editingFinished(); void on_macroName_editingFinished();
void on_runMacro_clicked(); void on_runMacro_clicked();
void on_runMacroInParallel_stateChanged(int value); void on_runMacroInParallel_stateChanged(int value);
void on_runMacroOnChange_stateChanged(int value);
void on_macros_currentRowChanged(int idx); void on_macros_currentRowChanged(int idx);
void on_macros_itemChanged(QListWidgetItem *); void on_macros_itemChanged(QListWidgetItem *);
void on_conditionAdd_clicked(); void on_conditionAdd_clicked();

View File

@@ -25,12 +25,12 @@ public:
return std::make_shared<MacroConditionScene>(); return std::make_shared<MacroConditionScene>();
} }
// This option is to be removed in a future version and be replaced by
// transition specific conditions
bool _waitForTransition = true;
SceneSelection _scene; SceneSelection _scene;
SceneType _type = SceneType::CURRENT; SceneType _type = SceneType::CURRENT;
// During a transition "current" scene could either stand for the scene
// being transitioned to or the scene still being transitioned away
// from.
bool _useTransitionTargetScene = false;
private: private:
std::chrono::high_resolution_clock::time_point _lastSceneChangeTime{}; std::chrono::high_resolution_clock::time_point _lastSceneChangeTime{};
@@ -57,14 +57,14 @@ public:
private slots: private slots:
void SceneChanged(const SceneSelection &); void SceneChanged(const SceneSelection &);
void TypeChanged(int value); void TypeChanged(int value);
void WaitForTransitionChanged(int state); void UseTransitionTargetSceneChanged(int state);
signals: signals:
void HeaderInfoChanged(const QString &); void HeaderInfoChanged(const QString &);
protected: protected:
SceneSelectionWidget *_scenes; SceneSelectionWidget *_scenes;
QComboBox *_sceneType; QComboBox *_sceneType;
QCheckBox *_waitForTransition; QCheckBox *_useTransitionTargetScene;
std::shared_ptr<MacroConditionScene> _entryData; std::shared_ptr<MacroConditionScene> _entryData;
private: private:

View File

@@ -82,6 +82,8 @@ public:
bool RunInParallel() { return _runInParallel; } bool RunInParallel() { return _runInParallel; }
void SetPaused(bool pause = true); void SetPaused(bool pause = true);
bool Paused() { return _paused; } bool Paused() { return _paused; }
void SetMatchOnChange(bool onChange) { _matchOnChange = onChange; }
bool MatchOnChange() { return _matchOnChange; }
int GetCount() { return _count; }; int GetCount() { return _count; };
void ResetCount() { _count = 0; }; void ResetCount() { _count = 0; };
std::deque<std::shared_ptr<MacroCondition>> &Conditions() std::deque<std::shared_ptr<MacroCondition>> &Conditions()
@@ -114,6 +116,8 @@ private:
std::deque<std::shared_ptr<MacroAction>> _actions; std::deque<std::shared_ptr<MacroAction>> _actions;
bool _runInParallel = false; bool _runInParallel = false;
bool _matched = false; bool _matched = false;
bool _lastMatched = false;
bool _matchOnChange = false;
bool _paused = false; bool _paused = false;
int _count = 0; int _count = 0;
obs_hotkey_id _pauseHotkey = OBS_INVALID_HOTKEY_ID; obs_hotkey_id _pauseHotkey = OBS_INVALID_HOTKEY_ID;

View File

@@ -28,7 +28,7 @@ bool MacroConditionScene::CheckCondition()
switch (_type) { switch (_type) {
case SceneType::CURRENT: case SceneType::CURRENT:
if (_waitForTransition) { if (!_useTransitionTargetScene) {
return switcher->currentScene == _scene.GetScene(false); return switcher->currentScene == _scene.GetScene(false);
} else { } else {
@@ -58,7 +58,8 @@ bool MacroConditionScene::Save(obs_data_t *obj)
MacroCondition::Save(obj); MacroCondition::Save(obj);
_scene.Save(obj); _scene.Save(obj);
obs_data_set_int(obj, "type", static_cast<int>(_type)); obs_data_set_int(obj, "type", static_cast<int>(_type));
obs_data_set_bool(obj, "waitForTransition", _waitForTransition); obs_data_set_bool(obj, "useTransitionTargetScene",
_useTransitionTargetScene);
return true; return true;
} }
@@ -67,11 +68,12 @@ bool MacroConditionScene::Load(obs_data_t *obj)
MacroCondition::Load(obj); MacroCondition::Load(obj);
_scene.Load(obj); _scene.Load(obj);
_type = static_cast<SceneType>(obs_data_get_int(obj, "type")); _type = static_cast<SceneType>(obs_data_get_int(obj, "type"));
if (!obs_data_has_user_value(obj, "waitForTransition")) { if (obs_data_has_user_value(obj, "waitForTransition")) {
_waitForTransition = true; _useTransitionTargetScene =
!obs_data_get_bool(obj, "waitForTransition");
} else { } else {
_waitForTransition = _useTransitionTargetScene =
obs_data_get_bool(obj, "waitForTransition"); obs_data_get_bool(obj, "useTransitionTargetScene");
} }
return true; return true;
} }
@@ -94,26 +96,34 @@ MacroConditionSceneEdit::MacroConditionSceneEdit(
{ {
_scenes = new SceneSelectionWidget(window(), false, false, false); _scenes = new SceneSelectionWidget(window(), false, false, false);
_sceneType = new QComboBox(); _sceneType = new QComboBox();
_waitForTransition = new QCheckBox(obs_module_text( _useTransitionTargetScene = new QCheckBox(obs_module_text(
"AdvSceneSwitcher.condition.scene.waitForTransition")); "AdvSceneSwitcher.condition.scene.currentSceneTransitionBehaviour"));
QWidget::connect(_scenes, SIGNAL(SceneChanged(const SceneSelection &)), QWidget::connect(_scenes, SIGNAL(SceneChanged(const SceneSelection &)),
this, SLOT(SceneChanged(const SceneSelection &))); this, SLOT(SceneChanged(const SceneSelection &)));
QWidget::connect(_sceneType, SIGNAL(currentIndexChanged(int)), this, QWidget::connect(_sceneType, SIGNAL(currentIndexChanged(int)), this,
SLOT(TypeChanged(int))); SLOT(TypeChanged(int)));
QWidget::connect(_waitForTransition, SIGNAL(stateChanged(int)), this, QWidget::connect(_useTransitionTargetScene, SIGNAL(stateChanged(int)),
SLOT(WaitForTransitionChanged(int))); this, SLOT(UseTransitionTargetSceneChanged(int)));
populateTypeSelection(_sceneType); populateTypeSelection(_sceneType);
QHBoxLayout *mainLayout = new QHBoxLayout;
std::unordered_map<std::string, QWidget *> widgetPlaceholders = { std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
{"{{scenes}}", _scenes}, {"{{scenes}}", _scenes},
{"{{sceneType}}", _sceneType}, {"{{sceneType}}", _sceneType},
{"{{waitForTransition}}", _waitForTransition}, {"{{useTransitionTargetScene}}", _useTransitionTargetScene},
}; };
placeWidgets(obs_module_text("AdvSceneSwitcher.condition.scene.entry"), QHBoxLayout *line1Layout = new QHBoxLayout;
mainLayout, widgetPlaceholders); placeWidgets(
obs_module_text("AdvSceneSwitcher.condition.scene.entry.line1"),
line1Layout, widgetPlaceholders);
QHBoxLayout *line2Layout = new QHBoxLayout;
placeWidgets(
obs_module_text("AdvSceneSwitcher.condition.scene.entry.line2"),
line2Layout, widgetPlaceholders);
QVBoxLayout *mainLayout = new QVBoxLayout;
mainLayout->addLayout(line1Layout);
mainLayout->addLayout(line2Layout);
setLayout(mainLayout); setLayout(mainLayout);
_entryData = entryData; _entryData = entryData;
@@ -144,26 +154,23 @@ void MacroConditionSceneEdit::TypeChanged(int value)
SetWidgetVisibility(); SetWidgetVisibility();
} }
void MacroConditionSceneEdit::WaitForTransitionChanged(int state) void MacroConditionSceneEdit::UseTransitionTargetSceneChanged(int state)
{ {
if (_loading || !_entryData) { if (_loading || !_entryData) {
return; return;
} }
std::lock_guard<std::mutex> lock(switcher->m); std::lock_guard<std::mutex> lock(switcher->m);
_entryData->_waitForTransition = state; _entryData->_useTransitionTargetScene = state;
} }
void MacroConditionSceneEdit::SetWidgetVisibility() void MacroConditionSceneEdit::SetWidgetVisibility()
{ {
_scenes->setVisible(_entryData->_type == SceneType::CURRENT || _scenes->setVisible(_entryData->_type == SceneType::CURRENT ||
_entryData->_type == SceneType::PREVIOUS); _entryData->_type == SceneType::PREVIOUS);
_useTransitionTargetScene->setVisible(_entryData->_type ==
// The waitForTransition option shall be slowly faded out over time and SceneType::CURRENT);
// be replaced by the transition source and target scene checks adjustSize();
_waitForTransition->setVisible(_entryData->_type ==
SceneType::CURRENT &&
!_entryData->_waitForTransition);
} }
void MacroConditionSceneEdit::UpdateEntryData() void MacroConditionSceneEdit::UpdateEntryData()
@@ -174,6 +181,7 @@ void MacroConditionSceneEdit::UpdateEntryData()
_scenes->SetScene(_entryData->_scene); _scenes->SetScene(_entryData->_scene);
_sceneType->setCurrentIndex(static_cast<int>(_entryData->_type)); _sceneType->setCurrentIndex(static_cast<int>(_entryData->_type));
_waitForTransition->setChecked(_entryData->_waitForTransition); _useTransitionTargetScene->setChecked(
_entryData->_useTransitionTargetScene);
SetWidgetVisibility(); SetWidgetVisibility();
} }

View File

@@ -8,7 +8,7 @@ const std::string MacroConditionTransition::id = "transition";
bool MacroConditionTransition::_registered = MacroConditionFactory::Register( bool MacroConditionTransition::_registered = MacroConditionFactory::Register(
MacroConditionTransition::id, MacroConditionTransition::id,
{MacroConditionTransition::Create, MacroConditionTransitionEdit::Create, {MacroConditionTransition::Create, MacroConditionTransitionEdit::Create,
"AdvSceneSwitcher.condition.transition", false}); "AdvSceneSwitcher.condition.transition"});
static std::map<TransitionCondition, std::string> filterConditionTypes = { static std::map<TransitionCondition, std::string> filterConditionTypes = {
{TransitionCondition::CURRENT, {TransitionCondition::CURRENT,

View File

@@ -198,6 +198,16 @@ void AdvSceneSwitcher::on_runMacroInParallel_stateChanged(int value)
macro->SetRunInParallel(value); macro->SetRunInParallel(value);
} }
void AdvSceneSwitcher::on_runMacroOnChange_stateChanged(int value)
{
Macro *macro = getSelectedMacro();
if (!macro) {
return;
}
std::lock_guard<std::mutex> lock(switcher->m);
macro->SetMatchOnChange(value);
}
void AdvSceneSwitcher::PopulateMacroActions(Macro &m, uint32_t afterIdx) void AdvSceneSwitcher::PopulateMacroActions(Macro &m, uint32_t afterIdx)
{ {
auto &actions = m.Actions(); auto &actions = m.Actions();
@@ -232,8 +242,10 @@ void AdvSceneSwitcher::SetEditMacro(Macro &m)
{ {
const QSignalBlocker b1(ui->macroName); const QSignalBlocker b1(ui->macroName);
const QSignalBlocker b2(ui->runMacroInParallel); const QSignalBlocker b2(ui->runMacroInParallel);
const QSignalBlocker b3(ui->runMacroOnChange);
ui->macroName->setText(m.Name().c_str()); ui->macroName->setText(m.Name().c_str());
ui->runMacroInParallel->setChecked(m.RunInParallel()); ui->runMacroInParallel->setChecked(m.RunInParallel());
ui->runMacroOnChange->setChecked(m.MatchOnChange());
} }
clearLayout(ui->macroEditConditionLayout); clearLayout(ui->macroEditConditionLayout);
clearLayout(ui->macroEditActionLayout); clearLayout(ui->macroEditActionLayout);

View File

@@ -95,9 +95,16 @@ bool Macro::CeckMatch()
vblog(LOG_INFO, "condition %s returned %d", c->GetId().c_str(), vblog(LOG_INFO, "condition %s returned %d", c->GetId().c_str(),
cond); cond);
} }
vblog(LOG_INFO, "Macro %s returned %d", _name.c_str(), _matched); vblog(LOG_INFO, "Macro %s returned %d", _name.c_str(), _matched);
bool newLastMatched = _matched;
if (_matched && _matchOnChange && _lastMatched == _matched) {
vblog(LOG_INFO, "ignore match for Macro %s (on change)",
_name.c_str());
_matched = false;
}
_lastMatched = newLastMatched;
// TODO: Move back to PerformAction() once new scene collection frontend // TODO: Move back to PerformAction() once new scene collection frontend
// events are available - see: // events are available - see:
// https://github.com/obsproject/obs-studio/commit/feda1aaa283e8a99f6ba1159cfe6b9c1f2934a61 // https://github.com/obsproject/obs-studio/commit/feda1aaa283e8a99f6ba1159cfe6b9c1f2934a61
@@ -194,6 +201,7 @@ bool Macro::Save(obs_data_t *obj)
obs_data_set_string(obj, "name", _name.c_str()); obs_data_set_string(obj, "name", _name.c_str());
obs_data_set_bool(obj, "pause", _paused); obs_data_set_bool(obj, "pause", _paused);
obs_data_set_bool(obj, "parallel", _runInParallel); obs_data_set_bool(obj, "parallel", _runInParallel);
obs_data_set_bool(obj, "onChange", _matchOnChange);
obs_data_array_t *pauseHotkey = obs_hotkey_save(_pauseHotkey); obs_data_array_t *pauseHotkey = obs_hotkey_save(_pauseHotkey);
obs_data_set_array(obj, "pauseHotkey", pauseHotkey); obs_data_set_array(obj, "pauseHotkey", pauseHotkey);
@@ -272,6 +280,7 @@ bool Macro::Load(obs_data_t *obj)
_name = obs_data_get_string(obj, "name"); _name = obs_data_get_string(obj, "name");
_paused = obs_data_get_bool(obj, "pause"); _paused = obs_data_get_bool(obj, "pause");
_runInParallel = obs_data_get_bool(obj, "parallel"); _runInParallel = obs_data_get_bool(obj, "parallel");
_matchOnChange = obs_data_get_bool(obj, "onChange");
obs_data_array_t *pauseHotkey = obs_data_get_array(obj, "pauseHotkey"); obs_data_array_t *pauseHotkey = obs_data_get_array(obj, "pauseHotkey");
obs_hotkey_load(_pauseHotkey, pauseHotkey); obs_hotkey_load(_pauseHotkey, pauseHotkey);