mirror of
https://github.com/WarmUpTill/SceneSwitcher.git
synced 2026-08-29 12:45:28 -05:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c7afdd817b |
@@ -128,8 +128,6 @@ target_sources(
|
||||
lib/macro/macro-ref.hpp
|
||||
lib/macro/macro-run-button.cpp
|
||||
lib/macro/macro-run-button.hpp
|
||||
lib/macro/macro-segment-copy-paste.cpp
|
||||
lib/macro/macro-segment-copy-paste.hpp
|
||||
lib/macro/macro-segment-list.cpp
|
||||
lib/macro/macro-segment-list.hpp
|
||||
lib/macro/macro-segment-selection.cpp
|
||||
|
||||
@@ -469,6 +469,7 @@ AdvSceneSwitcher.action.macro.type.unpause="Nicht mehr pausieren"
|
||||
AdvSceneSwitcher.action.macro.type.resetCounter="Zähler zurücksetzen"
|
||||
AdvSceneSwitcher.action.macro.type.run="Aktionen ausführen"
|
||||
AdvSceneSwitcher.action.macro.type.stop="Aktionen stoppen"
|
||||
AdvSceneSwitcher.action.macro.entry="{{actions}}{{actionIndex}}{{macros}}"
|
||||
AdvSceneSwitcher.action.pluginState="Plugin-Status"
|
||||
AdvSceneSwitcher.action.pluginState.type.stop="Erweiterten Automatischen Szenenwechsler stoppen"
|
||||
AdvSceneSwitcher.action.pluginState.type.noMatch="Ändern des Nichtübereinstimmungsverhaltens:"
|
||||
|
||||
@@ -177,8 +177,6 @@ AdvSceneSwitcher.macroTab.minimize="Minimize"
|
||||
AdvSceneSwitcher.macroTab.segment.useCustomLabel="Use custom label"
|
||||
AdvSceneSwitcher.macroTab.segment.defaultCustomLabel="My label"
|
||||
AdvSceneSwitcher.macroTab.segment.setCustomLabel="Set label ..."
|
||||
AdvSceneSwitcher.macroTab.segment.copy="Copy"
|
||||
AdvSceneSwitcher.macroTab.segment.paste="Paste"
|
||||
AdvSceneSwitcher.macroTab.highlightSettings="Visual settings"
|
||||
AdvSceneSwitcher.macroTab.hotkeySettings="Hotkey settings"
|
||||
AdvSceneSwitcher.macroTab.generalSettings="General settings"
|
||||
@@ -594,7 +592,15 @@ AdvSceneSwitcher.condition.run="Run"
|
||||
AdvSceneSwitcher.condition.run.entry="Process exits before timeout of{{timeout}}seconds"
|
||||
AdvSceneSwitcher.condition.run.entry.exit="{{checkExitCode}}Check for exit code{{exitCode}}"
|
||||
AdvSceneSwitcher.condition.midi="MIDI"
|
||||
<<<<<<< HEAD
|
||||
AdvSceneSwitcher.condition.midi.entry="Message was received from{{device}}which matches:"
|
||||
=======
|
||||
AdvSceneSwitcher.condition.midi.condition.message="MIDI message was received"
|
||||
AdvSceneSwitcher.condition.midi.condition.deviceName="MIDI device is connected"
|
||||
AdvSceneSwitcher.condition.midi.condition.deviceName.info="On some platforms with certain APIs dynamic MIDI device detection might not function.\nSo this type of check might not be 100% reliable in all circumstances."
|
||||
AdvSceneSwitcher.condition.midi.entry.message="{{conditions}}from{{device}}which matches:"
|
||||
AdvSceneSwitcher.condition.midi.entry.deviceName="{{conditions}}{{deviceNames}}{{regex}}{{deviceListInfo}}"
|
||||
>>>>>>> c4e35d1a (Add MIDI device name check)
|
||||
AdvSceneSwitcher.condition.midi.entry.listen="Set MIDI message selection to messages incoming on selected device:{{listenButton}}"
|
||||
AdvSceneSwitcher.condition.display="Display"
|
||||
AdvSceneSwitcher.condition.display.type.displayName="Name of connected displays matches"
|
||||
@@ -814,20 +820,12 @@ AdvSceneSwitcher.action.macro="Macro"
|
||||
AdvSceneSwitcher.action.macro.type.pause="Pause"
|
||||
AdvSceneSwitcher.action.macro.type.unpause="Unpause"
|
||||
AdvSceneSwitcher.action.macro.type.resetCounter="Reset counter"
|
||||
AdvSceneSwitcher.action.macro.type.run="Run macro"
|
||||
AdvSceneSwitcher.action.macro.type.run.conditions.ignore="Do not consider condition state"
|
||||
AdvSceneSwitcher.action.macro.type.run.conditions.true="Only if conditions evaluate to true"
|
||||
AdvSceneSwitcher.action.macro.type.run.conditions.false="Only if conditions evaluate to false"
|
||||
AdvSceneSwitcher.action.macro.type.run.actionType.regular="actions"
|
||||
AdvSceneSwitcher.action.macro.type.run.actionType.else="else-actions"
|
||||
AdvSceneSwitcher.action.macro.type.run.skipWhenPaused="Skip execution when macro is paused"
|
||||
AdvSceneSwitcher.action.macro.type.run="Run actions"
|
||||
AdvSceneSwitcher.action.macro.type.stop="Stop actions"
|
||||
AdvSceneSwitcher.action.macro.type.disableAction="Disable action"
|
||||
AdvSceneSwitcher.action.macro.type.enableAction="Enable action"
|
||||
AdvSceneSwitcher.action.macro.type.toggleAction="Toggle action"
|
||||
AdvSceneSwitcher.action.macro.entry.run="{{actions}}{{actionTypes}}of{{macros}}"
|
||||
AdvSceneSwitcher.action.macro.entry.run.condition="{{conditionBehaviors}}of{{conditionMacros}}"
|
||||
AdvSceneSwitcher.action.macro.entry.other="{{actions}}{{actionIndex}}{{macros}}"
|
||||
AdvSceneSwitcher.action.macro.entry="{{actions}}{{actionIndex}}{{macros}}"
|
||||
AdvSceneSwitcher.action.pluginState="Plugin state"
|
||||
AdvSceneSwitcher.action.pluginState.type.stop="Stop the Advanced Scene Switcher plugin"
|
||||
AdvSceneSwitcher.action.pluginState.type.noMatch="Change the no-match behaviour:"
|
||||
|
||||
@@ -386,6 +386,7 @@ AdvSceneSwitcher.action.macro.type.unpause="Reanudar"
|
||||
AdvSceneSwitcher.action.macro.type.resetCounter="Reiniciar contador"
|
||||
AdvSceneSwitcher.action.macro.type.run="Ejecutar"
|
||||
AdvSceneSwitcher.action.macro.type.stop="Detener"
|
||||
AdvSceneSwitcher.action.macro.entry="{{actions}}{{actionIndex}}{{macros}}"
|
||||
AdvSceneSwitcher.action.pluginState="Estado del complemento"
|
||||
AdvSceneSwitcher.action.pluginState.type.stop="Detener el complemento Advanced Scene Switcher"
|
||||
AdvSceneSwitcher.action.pluginState.type.noMatch="Cambiar el comportamiento de no coincidencia:"
|
||||
|
||||
@@ -446,7 +446,6 @@ AdvSceneSwitcher.condition.run="Exécution"
|
||||
AdvSceneSwitcher.condition.run.entry="Le processus se termine avant le délai de{{timeout}}secondes"
|
||||
AdvSceneSwitcher.condition.run.entry.exit="{{checkExitCode}}Vérifier le code de sortie{{exitCode}}
|
||||
AdvSceneSwitcher.condition.midi="MIDI"
|
||||
AdvSceneSwitcher.condition.midi.entry="Message reçu depuis{{device}}qui correspond à :"
|
||||
AdvSceneSwitcher.condition.midi.entry.listen="Définir la sélection des messages MIDI pour les messages entrants sur l'appareil sélectionné :{{listenButton}}"
|
||||
AdvSceneSwitcher.condition.display="Affichage"
|
||||
AdvSceneSwitcher.condition.display.type.displayName="Le nom des écrans connectés correspond à"
|
||||
|
||||
@@ -315,6 +315,7 @@ AdvSceneSwitcher.action.macro.type.pause="Duraklat"
|
||||
AdvSceneSwitcher.action.macro.type.unpause="Duraklatma"
|
||||
AdvSceneSwitcher.action.macro.type.resetCounter="Sayacı sıfırla"
|
||||
AdvSceneSwitcher.action.macro.type.run="Çalıştır"
|
||||
AdvSceneSwitcher.action.macro.entry="{{actions}}{{actionIndex}}{{macros}}"
|
||||
AdvSceneSwitcher.action.pluginState="Eklenti durumu"
|
||||
AdvSceneSwitcher.action.pluginState.type.stop="Advanced Scene Switcher eklentisini durdurun"
|
||||
AdvSceneSwitcher.action.pluginState.type.noMatch="Eşleşmeme davranışını değiştirin:"
|
||||
|
||||
@@ -434,7 +434,6 @@ AdvSceneSwitcher.condition.run="运行"
|
||||
AdvSceneSwitcher.condition.run.entry="进程在超时 {{timeout}} 秒之前退出"
|
||||
AdvSceneSwitcher.condition.run.entry.exit="{{checkExitCode}}检查退出代码{{exitCode}}"
|
||||
AdvSceneSwitcher.condition.midi="MIDI"
|
||||
AdvSceneSwitcher.condition.midi.entry="从{{device}} 收到的信息,符合:(从不咕咕的阿坤:这个好像是声卡工作是录音相关的功能,英文太抽象了,我就硬译过来了,如有相关设备,音乐好的,可以根据英文翻译好发给我!)"
|
||||
AdvSceneSwitcher.condition.midi.entry.listen="将MIDI信息选择设置为从选定设备上接收的信息: {{listenButton}}"
|
||||
AdvSceneSwitcher.condition.display="显示器"
|
||||
AdvSceneSwitcher.condition.display.type.displayName="连接的显示器的名称匹配"
|
||||
@@ -524,6 +523,7 @@ AdvSceneSwitcher.action.macro.type.unpause="取消暂停"
|
||||
AdvSceneSwitcher.action.macro.type.resetCounter="复位计数器"
|
||||
AdvSceneSwitcher.action.macro.type.run="运行操作"
|
||||
AdvSceneSwitcher.action.macro.type.stop="停止操作"
|
||||
AdvSceneSwitcher.action.macro.entry="{{actions}}{{actionIndex}}{{macros}}"
|
||||
AdvSceneSwitcher.action.pluginState="插件状态"
|
||||
AdvSceneSwitcher.action.pluginState.type.stop="停止高级场景切换插件"
|
||||
AdvSceneSwitcher.action.pluginState.type.noMatch="没有匹配项时:"
|
||||
|
||||
@@ -240,7 +240,7 @@ void SwitcherData::Thread()
|
||||
if (duration.count() < 1) {
|
||||
blog(LOG_INFO,
|
||||
"detected busy loop - refusing to sleep less than 1ms");
|
||||
duration = std::chrono::milliseconds(10);
|
||||
duration = std::chrono::milliseconds(50);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -12,7 +12,6 @@ class MacroActionEdit;
|
||||
class MacroConditionEdit;
|
||||
class Duration;
|
||||
class SequenceWidget;
|
||||
enum class LogicType;
|
||||
struct SceneGroup;
|
||||
|
||||
/*******************************************************************************
|
||||
@@ -153,16 +152,12 @@ public slots:
|
||||
void SetElseActionsStateToVisible();
|
||||
void MacroActionSelectionChanged(int idx);
|
||||
void MacroActionReorder(int to, int target);
|
||||
void AddMacroAction(Macro *macro, int idx, const std::string &id,
|
||||
obs_data_t *data);
|
||||
void AddMacroAction(int idx);
|
||||
void RemoveMacroAction(int idx);
|
||||
void MoveMacroActionUp(int idx);
|
||||
void MoveMacroActionDown(int idx);
|
||||
void MacroElseActionSelectionChanged(int idx);
|
||||
void MacroElseActionReorder(int to, int target);
|
||||
void AddMacroElseAction(Macro *macro, int idx, const std::string &id,
|
||||
obs_data_t *data);
|
||||
void AddMacroElseAction(int idx);
|
||||
void RemoveMacroElseAction(int idx);
|
||||
void SwapElseActions(Macro *m, int pos1, int pos2);
|
||||
@@ -171,16 +166,16 @@ public slots:
|
||||
void MacroConditionSelectionChanged(int idx);
|
||||
void MacroConditionReorder(int to, int target);
|
||||
void AddMacroCondition(int idx);
|
||||
void AddMacroCondition(Macro *macro, int idx, const std::string &id,
|
||||
obs_data_t *data, LogicType logic);
|
||||
void RemoveMacroCondition(int idx);
|
||||
void MoveMacroConditionUp(int idx);
|
||||
void MoveMacroConditionDown(int idx);
|
||||
void FadeOutActionControls();
|
||||
void FadeOutConditionControls();
|
||||
void ResetOpacityActionControls();
|
||||
void ResetOpacityConditionControls();
|
||||
void HighlightControls();
|
||||
void HighlightOnChange();
|
||||
void on_macroProperties_clicked();
|
||||
void CopyMacroSegment();
|
||||
void PasteMacroSegment();
|
||||
|
||||
signals:
|
||||
void MacroAdded(const QString &name);
|
||||
@@ -189,6 +184,9 @@ signals:
|
||||
void MacroSegmentOrderChanged();
|
||||
void SegmentTempVarsChanged();
|
||||
void HighlightMacrosChanged(bool value);
|
||||
void HighlightActionsChanged(bool value);
|
||||
void HighlightElseActionsChanged(bool value);
|
||||
void HighlightConditionsChanged(bool value);
|
||||
|
||||
void ConnectionAdded(const QString &);
|
||||
void ConnectionRenamed(const QString &oldName, const QString &newName);
|
||||
|
||||
@@ -29,7 +29,8 @@ static inline void populateActionSelection(QComboBox *list)
|
||||
MacroActionEdit::MacroActionEdit(QWidget *parent,
|
||||
std::shared_ptr<MacroAction> *entryData,
|
||||
const std::string &id)
|
||||
: MacroSegmentEdit(parent),
|
||||
: MacroSegmentEdit(GetGlobalMacroProperties()._highlightActions,
|
||||
parent),
|
||||
_actionSelection(new FilterComboBox()),
|
||||
_enable(new SwitchButton()),
|
||||
_entryData(entryData)
|
||||
@@ -39,6 +40,8 @@ MacroActionEdit::MacroActionEdit(QWidget *parent,
|
||||
SLOT(ActionSelectionChanged(const QString &)));
|
||||
QWidget::connect(_enable, SIGNAL(checked(bool)), this,
|
||||
SLOT(ActionEnableChanged(bool)));
|
||||
QWidget::connect(window(), SIGNAL(HighlightActionsChanged(bool)), this,
|
||||
SLOT(EnableHighlight(bool)));
|
||||
QWidget::connect(&_actionStateTimer, SIGNAL(timeout()), this,
|
||||
SLOT(UpdateActionState()));
|
||||
|
||||
@@ -158,20 +161,33 @@ std::shared_ptr<MacroSegment> MacroActionEdit::Data() const
|
||||
return *_entryData;
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::AddMacroAction(Macro *macro, int idx,
|
||||
const std::string &id, obs_data_t *data)
|
||||
void AdvSceneSwitcher::AddMacroAction(int idx)
|
||||
{
|
||||
if (idx < 0 || idx > (int)macro->Actions().size()) {
|
||||
assert(false);
|
||||
auto macro = GetSelectedMacro();
|
||||
if (!macro) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (idx < 0 || idx > (int)macro->Actions().size()) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::string id;
|
||||
if (idx - 1 >= 0) {
|
||||
id = macro->Actions().at(idx - 1)->GetId();
|
||||
} else {
|
||||
id = MacroAction::GetDefaultID();
|
||||
}
|
||||
{
|
||||
auto lock = LockContext();
|
||||
macro->Actions().emplace(macro->Actions().begin() + idx,
|
||||
MacroActionFactory::Create(id, macro));
|
||||
if (data) {
|
||||
macro->Actions().emplace(
|
||||
macro->Actions().begin() + idx,
|
||||
MacroActionFactory::Create(id, macro.get()));
|
||||
if (idx - 1 >= 0) {
|
||||
auto data = obs_data_create();
|
||||
macro->Actions().at(idx - 1)->Save(data);
|
||||
macro->Actions().at(idx)->Load(data);
|
||||
obs_data_release(data);
|
||||
}
|
||||
macro->Actions().at(idx)->PostLoad();
|
||||
RunPostLoadSteps();
|
||||
@@ -182,37 +198,9 @@ void AdvSceneSwitcher::AddMacroAction(Macro *macro, int idx,
|
||||
SetActionData(*macro);
|
||||
}
|
||||
HighlightAction(idx);
|
||||
ui->actionsList->SetHelpMsgVisible(false);
|
||||
emit(MacroSegmentOrderChanged());
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::AddMacroAction(int idx)
|
||||
{
|
||||
auto macro = GetSelectedMacro();
|
||||
if (!macro) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (idx < 0 || idx > (int)macro->Actions().size()) {
|
||||
assert(false);
|
||||
return;
|
||||
}
|
||||
|
||||
std::string id;
|
||||
if (idx - 1 >= 0) {
|
||||
id = macro->Actions().at(idx - 1)->GetId();
|
||||
} else {
|
||||
id = MacroAction::GetDefaultID();
|
||||
}
|
||||
|
||||
OBSDataAutoRelease data;
|
||||
if (idx - 1 >= 0) {
|
||||
data = obs_data_create();
|
||||
macro->Actions().at(idx - 1)->Save(data);
|
||||
}
|
||||
AddMacroAction(macro.get(), idx, id, data);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_actionAdd_clicked()
|
||||
{
|
||||
auto macro = GetSelectedMacro();
|
||||
@@ -228,6 +216,7 @@ void AdvSceneSwitcher::on_actionAdd_clicked()
|
||||
if (currentActionIdx != -1) {
|
||||
MacroActionSelectionChanged(currentActionIdx + 1);
|
||||
}
|
||||
ui->actionsList->SetHelpMsgVisible(false);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::RemoveMacroAction(int idx)
|
||||
@@ -322,6 +311,7 @@ void AdvSceneSwitcher::on_elseActionAdd_clicked()
|
||||
if (currentElseActionIdx != -1) {
|
||||
MacroElseActionSelectionChanged(currentElseActionIdx + 1);
|
||||
}
|
||||
ui->elseActionsList->SetHelpMsgVisible(false);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_elseActionRemove_clicked()
|
||||
@@ -460,21 +450,31 @@ void AdvSceneSwitcher::MacroElseActionReorder(int to, int from)
|
||||
emit(MacroSegmentOrderChanged());
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::AddMacroElseAction(Macro *macro, int idx,
|
||||
const std::string &id,
|
||||
obs_data_t *data)
|
||||
void AdvSceneSwitcher::AddMacroElseAction(int idx)
|
||||
{
|
||||
if (idx < 0 || idx > (int)macro->ElseActions().size()) {
|
||||
assert(false);
|
||||
auto macro = GetSelectedMacro();
|
||||
if (!macro) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (idx < 0 || idx > (int)macro->ElseActions().size()) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::string id;
|
||||
if (idx - 1 >= 0) {
|
||||
id = macro->ElseActions().at(idx - 1)->GetId();
|
||||
} else {
|
||||
id = MacroAction::GetDefaultID();
|
||||
}
|
||||
{
|
||||
auto lock = LockContext();
|
||||
macro->ElseActions().emplace(macro->ElseActions().begin() + idx,
|
||||
MacroActionFactory::Create(id,
|
||||
macro));
|
||||
if (data) {
|
||||
macro->ElseActions().emplace(
|
||||
macro->ElseActions().begin() + idx,
|
||||
MacroActionFactory::Create(id, macro.get()));
|
||||
if (idx - 1 >= 0) {
|
||||
OBSDataAutoRelease data = obs_data_create();
|
||||
macro->ElseActions().at(idx - 1)->Save(data);
|
||||
macro->ElseActions().at(idx)->Load(data);
|
||||
}
|
||||
macro->ElseActions().at(idx)->PostLoad();
|
||||
@@ -486,37 +486,9 @@ void AdvSceneSwitcher::AddMacroElseAction(Macro *macro, int idx,
|
||||
SetElseActionData(*macro);
|
||||
}
|
||||
HighlightElseAction(idx);
|
||||
ui->elseActionsList->SetHelpMsgVisible(false);
|
||||
emit(MacroSegmentOrderChanged());
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::AddMacroElseAction(int idx)
|
||||
{
|
||||
auto macro = GetSelectedMacro();
|
||||
if (!macro) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (idx < 0 || idx > (int)macro->ElseActions().size()) {
|
||||
assert(false);
|
||||
return;
|
||||
}
|
||||
|
||||
std::string id;
|
||||
if (idx - 1 >= 0) {
|
||||
id = macro->ElseActions().at(idx - 1)->GetId();
|
||||
} else {
|
||||
id = MacroAction::GetDefaultID();
|
||||
}
|
||||
|
||||
OBSDataAutoRelease data;
|
||||
if (idx - 1 >= 0) {
|
||||
data = obs_data_create();
|
||||
macro->ElseActions().at(idx - 1)->Save(data);
|
||||
}
|
||||
AddMacroElseAction(macro.get(), idx, id, data);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::RemoveMacroElseAction(int idx)
|
||||
{
|
||||
auto macro = GetSelectedMacro();
|
||||
@@ -535,7 +507,7 @@ void AdvSceneSwitcher::RemoveMacroElseAction(int idx)
|
||||
SetMacroAbortWait(true);
|
||||
GetMacroWaitCV().notify_all();
|
||||
macro->UpdateElseActionIndices();
|
||||
SetElseActionData(*macro);
|
||||
SetActionData(*macro);
|
||||
}
|
||||
MacroElseActionSelectionChanged(-1);
|
||||
lastInteracted = MacroSection::ELSE_ACTIONS;
|
||||
|
||||
@@ -48,7 +48,9 @@ bool MacroActionMacro::PerformAction()
|
||||
macro->ResetRunCount();
|
||||
break;
|
||||
case Action::RUN:
|
||||
RunActions(macro.get());
|
||||
if (!macro->Paused()) {
|
||||
macro->PerformActions(true, false, true);
|
||||
}
|
||||
break;
|
||||
case Action::STOP:
|
||||
macro->Stop();
|
||||
@@ -125,7 +127,6 @@ bool MacroActionMacro::Save(obs_data_t *obj) const
|
||||
_macro.Save(obj);
|
||||
_actionIndex.Save(obj, "actionIndex");
|
||||
obs_data_set_int(obj, "action", static_cast<int>(_action));
|
||||
_runOptions.Save(obj);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -136,15 +137,6 @@ bool MacroActionMacro::Load(obs_data_t *obj)
|
||||
_actionIndex.Load(obj, "actionIndex");
|
||||
_action = static_cast<MacroActionMacro::Action>(
|
||||
obs_data_get_int(obj, "action"));
|
||||
_runOptions.Load(obj);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MacroActionMacro::PostLoad()
|
||||
{
|
||||
MacroRefAction::PostLoad();
|
||||
MacroAction::PostLoad();
|
||||
_runOptions.macro.PostLoad();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -168,55 +160,11 @@ void MacroActionMacro::ResolveVariablesToFixedValues()
|
||||
_actionIndex.ResolveVariables();
|
||||
}
|
||||
|
||||
void MacroActionMacro::RunActions(Macro *actionMacro) const
|
||||
static inline void populateActionSelection(QComboBox *list)
|
||||
{
|
||||
if (_runOptions.skipWhenPaused && actionMacro->Paused()) {
|
||||
return;
|
||||
for (auto entry : actionTypes) {
|
||||
list->addItem(obs_module_text(entry.second.c_str()));
|
||||
}
|
||||
|
||||
if (_runOptions.logic == RunOptions::Logic::IGNORE_CONDITIONS) {
|
||||
actionMacro->PerformActions(!_runOptions.runElseActions, false,
|
||||
true);
|
||||
return;
|
||||
}
|
||||
|
||||
auto conditionMacro = _runOptions.macro.GetMacro();
|
||||
if (!conditionMacro) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ((_runOptions.logic == RunOptions::Logic::CONDITIONS &&
|
||||
conditionMacro->Matched()) ||
|
||||
(_runOptions.logic == RunOptions::Logic::INVERT_CONDITIONS &&
|
||||
!conditionMacro->Matched())) {
|
||||
actionMacro->PerformActions(!_runOptions.runElseActions, false,
|
||||
true);
|
||||
}
|
||||
}
|
||||
|
||||
static void populateActionSelection(QComboBox *list)
|
||||
{
|
||||
for (const auto &[_, name] : actionTypes) {
|
||||
list->addItem(obs_module_text(name.c_str()));
|
||||
}
|
||||
}
|
||||
|
||||
static void populateConditionBehaviorSelection(QComboBox *list)
|
||||
{
|
||||
list->addItem(obs_module_text(
|
||||
"AdvSceneSwitcher.action.macro.type.run.conditions.ignore"));
|
||||
list->addItem(obs_module_text(
|
||||
"AdvSceneSwitcher.action.macro.type.run.conditions.true"));
|
||||
list->addItem(obs_module_text(
|
||||
"AdvSceneSwitcher.action.macro.type.run.conditions.false"));
|
||||
}
|
||||
|
||||
static void populateActionTypeSelection(QComboBox *list)
|
||||
{
|
||||
list->addItem(obs_module_text(
|
||||
"AdvSceneSwitcher.action.macro.type.run.actionType.regular"));
|
||||
list->addItem(obs_module_text(
|
||||
"AdvSceneSwitcher.action.macro.type.run.actionType.else"));
|
||||
}
|
||||
|
||||
MacroActionMacroEdit::MacroActionMacroEdit(
|
||||
@@ -225,20 +173,9 @@ MacroActionMacroEdit::MacroActionMacroEdit(
|
||||
_macros(new MacroSelection(parent)),
|
||||
_actionIndex(new MacroSegmentSelection(
|
||||
this, MacroSegmentSelection::Type::ACTION)),
|
||||
_actions(new QComboBox()),
|
||||
_conditionMacros(new MacroSelection(parent)),
|
||||
_conditionBehaviors(new QComboBox()),
|
||||
_actionTypes(new QComboBox()),
|
||||
_skipWhenPaused(new QCheckBox(obs_module_text(
|
||||
"AdvSceneSwitcher.action.macro.type.run.skipWhenPaused"))),
|
||||
_entryLayout(new QHBoxLayout()),
|
||||
_conditionLayout(new QHBoxLayout())
|
||||
_actions(new QComboBox())
|
||||
{
|
||||
populateActionSelection(_actions);
|
||||
populateConditionBehaviorSelection(_conditionBehaviors);
|
||||
populateActionTypeSelection(_actionTypes);
|
||||
|
||||
_conditionMacros->HideSelectedMacro();
|
||||
|
||||
QWidget::connect(_macros, SIGNAL(currentTextChanged(const QString &)),
|
||||
this, SLOT(MacroChanged(const QString &)));
|
||||
@@ -247,21 +184,15 @@ MacroActionMacroEdit::MacroActionMacroEdit(
|
||||
QWidget::connect(_actionIndex,
|
||||
SIGNAL(SelectionChanged(const IntVariable &)), this,
|
||||
SLOT(ActionIndexChanged(const IntVariable &)));
|
||||
QWidget::connect(_conditionMacros,
|
||||
SIGNAL(currentTextChanged(const QString &)), this,
|
||||
SLOT(ConditionMacroChanged(const QString &)));
|
||||
QWidget::connect(_conditionBehaviors, SIGNAL(currentIndexChanged(int)),
|
||||
this, SLOT(ConditionBehaviorChanged(int)));
|
||||
QWidget::connect(_actionTypes, SIGNAL(currentIndexChanged(int)), this,
|
||||
SLOT(ActionTypeChanged(int)));
|
||||
QWidget::connect(_skipWhenPaused, SIGNAL(stateChanged(int)), this,
|
||||
SLOT(SkipWhenPausedChanged(int)));
|
||||
|
||||
auto layout = new QVBoxLayout();
|
||||
layout->addLayout(_entryLayout);
|
||||
layout->addLayout(_conditionLayout);
|
||||
layout->addWidget(_skipWhenPaused);
|
||||
setLayout(layout);
|
||||
auto mainLayout = new QHBoxLayout;
|
||||
PlaceWidgets(obs_module_text("AdvSceneSwitcher.action.macro.entry"),
|
||||
mainLayout,
|
||||
{{"{{actions}}", _actions},
|
||||
{"{{actionIndex}}", _actionIndex},
|
||||
{"{{macros}}", _macros}});
|
||||
setLayout(mainLayout);
|
||||
|
||||
_entryData = entryData;
|
||||
UpdateEntryData();
|
||||
_loading = false;
|
||||
@@ -276,12 +207,6 @@ void MacroActionMacroEdit::UpdateEntryData()
|
||||
_actionIndex->SetValue(_entryData->_actionIndex);
|
||||
_actionIndex->SetMacro(_entryData->_macro.GetMacro());
|
||||
_macros->SetCurrentMacro(_entryData->_macro);
|
||||
_conditionMacros->SetCurrentMacro(_entryData->_runOptions.macro);
|
||||
_conditionBehaviors->setCurrentIndex(
|
||||
static_cast<int>(_entryData->_runOptions.logic));
|
||||
_actionTypes->setCurrentIndex(
|
||||
_entryData->_runOptions.runElseActions ? 1 : 0);
|
||||
_skipWhenPaused->setChecked(_entryData->_runOptions.skipWhenPaused);
|
||||
SetWidgetVisibility();
|
||||
}
|
||||
|
||||
@@ -319,88 +244,8 @@ void MacroActionMacroEdit::ActionIndexChanged(const IntVariable &value)
|
||||
_entryData->_actionIndex = value;
|
||||
}
|
||||
|
||||
void MacroActionMacroEdit::ConditionMacroChanged(const QString &text)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
_entryData->_runOptions.macro = text;
|
||||
}
|
||||
|
||||
void MacroActionMacroEdit::ConditionBehaviorChanged(int value)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
_entryData->_runOptions.logic =
|
||||
static_cast<MacroActionMacro::RunOptions::Logic>(value);
|
||||
SetWidgetVisibility();
|
||||
}
|
||||
|
||||
void MacroActionMacroEdit::ActionTypeChanged(int value)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
_entryData->_runOptions.runElseActions = value;
|
||||
}
|
||||
|
||||
void MacroActionMacroEdit::SkipWhenPausedChanged(int value)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
_entryData->_runOptions.skipWhenPaused = value;
|
||||
}
|
||||
|
||||
void MacroActionMacroEdit::SetWidgetVisibility()
|
||||
{
|
||||
_entryLayout->removeWidget(_actions);
|
||||
_entryLayout->removeWidget(_actionIndex);
|
||||
_entryLayout->removeWidget(_macros);
|
||||
_entryLayout->removeWidget(_actionTypes);
|
||||
_conditionLayout->removeWidget(_conditionBehaviors);
|
||||
_conditionLayout->removeWidget(_conditionMacros);
|
||||
|
||||
ClearLayout(_entryLayout);
|
||||
ClearLayout(_conditionLayout);
|
||||
|
||||
const std::unordered_map<std::string, QWidget *> placeholders = {
|
||||
{"{{actions}}", _actions},
|
||||
{"{{actionIndex}}", _actionIndex},
|
||||
{"{{macros}}", _macros},
|
||||
{"{{actionTypes}}", _actionTypes},
|
||||
{"{{conditionBehaviors}}", _conditionBehaviors},
|
||||
{"{{conditionMacros}}", _conditionMacros},
|
||||
|
||||
};
|
||||
|
||||
PlaceWidgets(
|
||||
obs_module_text(
|
||||
_entryData->_action == MacroActionMacro::Action::RUN
|
||||
? "AdvSceneSwitcher.action.macro.entry.run"
|
||||
: "AdvSceneSwitcher.action.macro.entry.other"),
|
||||
_entryLayout, placeholders);
|
||||
|
||||
if (_entryData->_runOptions.logic ==
|
||||
MacroActionMacro::RunOptions::Logic::IGNORE_CONDITIONS) {
|
||||
_conditionLayout->addWidget(_conditionBehaviors);
|
||||
_conditionLayout->addStretch();
|
||||
} else {
|
||||
PlaceWidgets(
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.action.macro.entry.run.condition"),
|
||||
_conditionLayout, placeholders);
|
||||
}
|
||||
|
||||
if (_entryData->_action == MacroActionMacro::Action::RUN ||
|
||||
_entryData->_action == MacroActionMacro::Action::STOP) {
|
||||
_macros->HideSelectedMacro();
|
||||
@@ -415,42 +260,6 @@ void MacroActionMacroEdit::SetWidgetVisibility()
|
||||
MacroActionMacro::Action::ENABLE_ACTION ||
|
||||
_entryData->_action == MacroActionMacro::Action::TOGGLE_ACTION;
|
||||
_actionIndex->setVisible(isModifyingActionState);
|
||||
|
||||
SetLayoutVisible(_conditionLayout,
|
||||
_entryData->_action == MacroActionMacro::Action::RUN);
|
||||
_conditionMacros->setVisible(
|
||||
_entryData->_action == MacroActionMacro::Action::RUN &&
|
||||
_entryData->_runOptions.logic !=
|
||||
MacroActionMacro::RunOptions::Logic::IGNORE_CONDITIONS);
|
||||
_actionTypes->setVisible(_entryData->_action ==
|
||||
MacroActionMacro::Action::RUN);
|
||||
_skipWhenPaused->setVisible(_entryData->_action ==
|
||||
MacroActionMacro::Action::RUN);
|
||||
|
||||
adjustSize();
|
||||
updateGeometry();
|
||||
}
|
||||
|
||||
void MacroActionMacro::RunOptions::Save(obs_data_t *obj) const
|
||||
{
|
||||
OBSDataAutoRelease data = obs_data_create();
|
||||
obs_data_set_int(data, "logic", static_cast<int>(logic));
|
||||
obs_data_set_bool(data, "runElseActions", runElseActions);
|
||||
obs_data_set_bool(data, "skipWhenPaused", skipWhenPaused);
|
||||
macro.Save(data);
|
||||
obs_data_set_obj(obj, "runOptions", data);
|
||||
}
|
||||
|
||||
void MacroActionMacro::RunOptions::Load(obs_data_t *obj)
|
||||
{
|
||||
if (!obs_data_has_user_value(obj, "runOptions")) {
|
||||
return;
|
||||
}
|
||||
OBSDataAutoRelease data = obs_data_get_obj(obj, "runOptions");
|
||||
logic = static_cast<Logic>(obs_data_get_int(data, "logic"));
|
||||
runElseActions = obs_data_get_bool(data, "runElseActions");
|
||||
skipWhenPaused = obs_data_get_bool(data, "skipWhenPaused");
|
||||
macro.Load(data);
|
||||
}
|
||||
|
||||
} // namespace advss
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
#include "macro-selection.hpp"
|
||||
#include "macro-segment-selection.hpp"
|
||||
|
||||
#include <QCheckBox>
|
||||
#include <QHBoxLayout>
|
||||
|
||||
namespace advss {
|
||||
@@ -15,27 +14,12 @@ public:
|
||||
void LogAction() const;
|
||||
bool Save(obs_data_t *obj) const;
|
||||
bool Load(obs_data_t *obj);
|
||||
bool PostLoad();
|
||||
std::string GetShortDesc() const;
|
||||
std::string GetId() const { return id; };
|
||||
static std::shared_ptr<MacroAction> Create(Macro *m);
|
||||
std::shared_ptr<MacroAction> Copy() const;
|
||||
void ResolveVariablesToFixedValues();
|
||||
|
||||
struct RunOptions {
|
||||
void Save(obs_data_t *obj) const;
|
||||
void Load(obs_data_t *obj);
|
||||
enum class Logic {
|
||||
IGNORE_CONDITIONS,
|
||||
CONDITIONS,
|
||||
INVERT_CONDITIONS,
|
||||
};
|
||||
Logic logic;
|
||||
bool runElseActions = false;
|
||||
bool skipWhenPaused = true;
|
||||
MacroRef macro;
|
||||
};
|
||||
|
||||
enum class Action {
|
||||
PAUSE,
|
||||
UNPAUSE,
|
||||
@@ -48,11 +32,8 @@ public:
|
||||
};
|
||||
Action _action = Action::PAUSE;
|
||||
IntVariable _actionIndex = 1;
|
||||
RunOptions _runOptions = {};
|
||||
|
||||
private:
|
||||
void RunActions(Macro *actionMacro) const;
|
||||
|
||||
static bool _registered;
|
||||
static const std::string id;
|
||||
};
|
||||
@@ -77,28 +58,18 @@ private slots:
|
||||
void MacroChanged(const QString &text);
|
||||
void ActionChanged(int value);
|
||||
void ActionIndexChanged(const IntVariable &value);
|
||||
void ConditionMacroChanged(const QString &text);
|
||||
void ConditionBehaviorChanged(int value);
|
||||
void ActionTypeChanged(int value);
|
||||
void SkipWhenPausedChanged(int value);
|
||||
|
||||
signals:
|
||||
void HeaderInfoChanged(const QString &);
|
||||
|
||||
protected:
|
||||
MacroSelection *_macros;
|
||||
MacroSegmentSelection *_actionIndex;
|
||||
QComboBox *_actions;
|
||||
std::shared_ptr<MacroActionMacro> _entryData;
|
||||
|
||||
private:
|
||||
void SetWidgetVisibility();
|
||||
|
||||
MacroSelection *_macros;
|
||||
MacroSegmentSelection *_actionIndex;
|
||||
QComboBox *_actions;
|
||||
MacroSelection *_conditionMacros;
|
||||
QComboBox *_conditionBehaviors;
|
||||
QComboBox *_actionTypes;
|
||||
QCheckBox *_skipWhenPaused;
|
||||
QHBoxLayout *_entryLayout;
|
||||
QHBoxLayout *_conditionLayout;
|
||||
|
||||
std::shared_ptr<MacroActionMacro> _entryData;
|
||||
bool _loading = true;
|
||||
};
|
||||
|
||||
|
||||
@@ -121,7 +121,8 @@ void DurationModifierEdit::Collapse(bool collapse)
|
||||
MacroConditionEdit::MacroConditionEdit(
|
||||
QWidget *parent, std::shared_ptr<MacroCondition> *entryData,
|
||||
const std::string &id, bool root)
|
||||
: MacroSegmentEdit(parent),
|
||||
: MacroSegmentEdit(GetGlobalMacroProperties()._highlightConditions,
|
||||
parent),
|
||||
_logicSelection(new QComboBox()),
|
||||
_conditionSelection(new FilterComboBox()),
|
||||
_dur(new DurationModifierEdit()),
|
||||
@@ -138,6 +139,8 @@ MacroConditionEdit::MacroConditionEdit(
|
||||
QWidget::connect(_dur, SIGNAL(ModifierChanged(DurationModifier::Type)),
|
||||
this,
|
||||
SLOT(DurationModifierChanged(DurationModifier::Type)));
|
||||
QWidget::connect(window(), SIGNAL(HighlightConditionsChanged(bool)),
|
||||
this, SLOT(EnableHighlight(bool)));
|
||||
|
||||
populateLogicSelection(_logicSelection, root);
|
||||
populateConditionSelection(_conditionSelection);
|
||||
@@ -296,7 +299,6 @@ void AdvSceneSwitcher::AddMacroCondition(int idx)
|
||||
}
|
||||
|
||||
if (idx < 0 || idx > (int)macro->Conditions().size()) {
|
||||
assert(false);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -313,31 +315,16 @@ void AdvSceneSwitcher::AddMacroCondition(int idx)
|
||||
id = MacroCondition::GetDefaultID();
|
||||
logic = LogicType::ROOT_NONE;
|
||||
}
|
||||
|
||||
OBSDataAutoRelease data;
|
||||
if (idx - 1 >= 0) {
|
||||
data = obs_data_create();
|
||||
macro->Conditions().at(idx - 1)->Save(data);
|
||||
}
|
||||
AddMacroCondition(macro.get(), idx, id, data.Get(), logic);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::AddMacroCondition(Macro *macro, int idx,
|
||||
const std::string &id,
|
||||
obs_data_t *data, LogicType logic)
|
||||
{
|
||||
if (idx < 0 || idx > (int)macro->Conditions().size()) {
|
||||
assert(false);
|
||||
return;
|
||||
}
|
||||
|
||||
{
|
||||
auto lock = LockContext();
|
||||
auto cond = macro->Conditions().emplace(
|
||||
macro->Conditions().begin() + idx,
|
||||
MacroConditionFactory::Create(id, macro));
|
||||
if (data) {
|
||||
MacroConditionFactory::Create(id, macro.get()));
|
||||
if (idx - 1 >= 0) {
|
||||
auto data = obs_data_create();
|
||||
macro->Conditions().at(idx - 1)->Save(data);
|
||||
macro->Conditions().at(idx)->Load(data);
|
||||
obs_data_release(data);
|
||||
}
|
||||
macro->Conditions().at(idx)->PostLoad();
|
||||
RunPostLoadSteps();
|
||||
@@ -350,7 +337,6 @@ void AdvSceneSwitcher::AddMacroCondition(Macro *macro, int idx,
|
||||
SetConditionData(*macro);
|
||||
}
|
||||
HighlightCondition(idx);
|
||||
ui->conditionsList->SetHelpMsgVisible(false);
|
||||
emit(MacroSegmentOrderChanged());
|
||||
}
|
||||
|
||||
@@ -369,6 +355,7 @@ void AdvSceneSwitcher::on_conditionAdd_clicked()
|
||||
if (currentConditionIdx != -1) {
|
||||
MacroConditionSelectionChanged(currentConditionIdx + 1);
|
||||
}
|
||||
ui->conditionsList->SetHelpMsgVisible(false);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::RemoveMacroCondition(int idx)
|
||||
|
||||
@@ -1,104 +0,0 @@
|
||||
#include "advanced-scene-switcher.hpp"
|
||||
#include "macro.hpp"
|
||||
|
||||
#include <QShortcut>
|
||||
|
||||
namespace advss {
|
||||
|
||||
struct MacroSegmentCopyInfo {
|
||||
enum class Type { NONE, CONDITION, ACTION, ELSE };
|
||||
Type type = Type::NONE;
|
||||
std::shared_ptr<MacroSegment> segment;
|
||||
};
|
||||
static MacroSegmentCopyInfo copyInfo;
|
||||
|
||||
void AdvSceneSwitcher::CopyMacroSegment()
|
||||
{
|
||||
copyInfo.segment.reset();
|
||||
copyInfo.type = MacroSegmentCopyInfo::Type::NONE;
|
||||
|
||||
if (currentConditionIdx == -1 && currentActionIdx == -1 &&
|
||||
currentElseActionIdx == -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto macro = GetSelectedMacro();
|
||||
if (!macro) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (currentConditionIdx != -1) {
|
||||
copyInfo.type = MacroSegmentCopyInfo::Type::CONDITION;
|
||||
copyInfo.segment = macro->Conditions().at(currentConditionIdx);
|
||||
} else if (currentActionIdx != -1) {
|
||||
copyInfo.type = MacroSegmentCopyInfo::Type::ACTION;
|
||||
copyInfo.segment = macro->Actions().at(currentActionIdx);
|
||||
} else if (currentElseActionIdx != -1) {
|
||||
copyInfo.type = MacroSegmentCopyInfo::Type::ELSE;
|
||||
copyInfo.segment =
|
||||
macro->ElseActions().at(currentElseActionIdx);
|
||||
} else {
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::PasteMacroSegment()
|
||||
{
|
||||
if (copyInfo.type == MacroSegmentCopyInfo::Type::NONE) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto macro = GetSelectedMacro();
|
||||
if (!macro || !copyInfo.segment) {
|
||||
return;
|
||||
}
|
||||
|
||||
OBSDataAutoRelease data = obs_data_create();
|
||||
copyInfo.segment->Save(data);
|
||||
|
||||
switch (copyInfo.type) {
|
||||
case MacroSegmentCopyInfo::Type::CONDITION: {
|
||||
const auto condition = std::static_pointer_cast<MacroCondition>(
|
||||
copyInfo.segment);
|
||||
auto logic = condition->GetLogicType();
|
||||
if (logic > LogicType::ROOT_LAST &&
|
||||
macro->Conditions().empty()) {
|
||||
logic = LogicType::ROOT_NONE;
|
||||
}
|
||||
if (logic < LogicType::ROOT_LAST &&
|
||||
!macro->Conditions().empty()) {
|
||||
logic = LogicType::OR;
|
||||
}
|
||||
AddMacroCondition(macro.get(), macro->Conditions().size(),
|
||||
copyInfo.segment->GetId(), data.Get(), logic);
|
||||
break;
|
||||
}
|
||||
case MacroSegmentCopyInfo::Type::ACTION:
|
||||
AddMacroAction(macro.get(), macro->Actions().size(),
|
||||
copyInfo.segment->GetId(), data.Get());
|
||||
break;
|
||||
case MacroSegmentCopyInfo::Type::ELSE:
|
||||
AddMacroElseAction(macro.get(), macro->ElseActions().size(),
|
||||
copyInfo.segment->GetId(), data.Get());
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool MacroSegmentIsInClipboard()
|
||||
{
|
||||
return copyInfo.type != MacroSegmentCopyInfo::Type::NONE;
|
||||
}
|
||||
|
||||
void SetupSegmentCopyPasteShortcutHandlers(AdvSceneSwitcher *window)
|
||||
{
|
||||
auto copyShortcut = new QShortcut(QKeySequence("Ctrl+C"), window);
|
||||
QWidget::connect(copyShortcut, &QShortcut::activated, window,
|
||||
&AdvSceneSwitcher::CopyMacroSegment);
|
||||
auto pasteShortcut = new QShortcut(QKeySequence("Ctrl+V"), window);
|
||||
QWidget::connect(pasteShortcut, &QShortcut::activated, window,
|
||||
&AdvSceneSwitcher::PasteMacroSegment);
|
||||
}
|
||||
|
||||
} // namespace advss
|
||||
@@ -1,8 +0,0 @@
|
||||
namespace advss {
|
||||
|
||||
class AdvSceneSwitcher;
|
||||
|
||||
bool MacroSegmentIsInClipboard();
|
||||
void SetupSegmentCopyPasteShortcutHandlers(AdvSceneSwitcher *window);
|
||||
|
||||
} // namespace advss
|
||||
@@ -176,8 +176,7 @@ bool MacroSegmentList::eventFilter(QObject *object, QEvent *event)
|
||||
|
||||
void MacroSegmentList::mousePressEvent(QMouseEvent *event)
|
||||
{
|
||||
if (event->button() == Qt::LeftButton ||
|
||||
event->button() == Qt::RightButton) {
|
||||
if (event->button() == Qt::LeftButton) {
|
||||
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
|
||||
_dragPosition = GetDragIndex(event->globalPos());
|
||||
#else
|
||||
|
||||
@@ -59,12 +59,12 @@ std::string MacroSegment::GetShortDesc() const
|
||||
return "";
|
||||
}
|
||||
|
||||
void MacroSegment::EnableHighlight()
|
||||
void MacroSegment::SetHighlight()
|
||||
{
|
||||
_highlight = true;
|
||||
}
|
||||
|
||||
bool MacroSegment::GetHighlightAndReset()
|
||||
bool MacroSegment::Highlight()
|
||||
{
|
||||
if (_highlight) {
|
||||
_highlight = false;
|
||||
@@ -194,7 +194,7 @@ void DecrementVariableRef(MacroSegment *segment)
|
||||
segment->_variableRefs--;
|
||||
}
|
||||
|
||||
MacroSegmentEdit::MacroSegmentEdit(QWidget *parent)
|
||||
MacroSegmentEdit::MacroSegmentEdit(bool highlight, QWidget *parent)
|
||||
: QWidget(parent),
|
||||
_section(new Section(300)),
|
||||
_headerInfo(new QLabel()),
|
||||
@@ -203,7 +203,8 @@ MacroSegmentEdit::MacroSegmentEdit(QWidget *parent)
|
||||
_noBorderframe(new QFrame),
|
||||
_borderFrame(new QFrame),
|
||||
_dropLineAbove(new QFrame),
|
||||
_dropLineBelow(new QFrame)
|
||||
_dropLineBelow(new QFrame),
|
||||
_showHighlight(highlight)
|
||||
{
|
||||
_dropLineAbove->setLineWidth(3);
|
||||
_dropLineAbove->setFixedHeight(11);
|
||||
@@ -281,6 +282,10 @@ MacroSegmentEdit::MacroSegmentEdit(QWidget *parent)
|
||||
|
||||
// Enable dragging while clicking on the header text
|
||||
_headerInfo->installEventFilter(this);
|
||||
|
||||
_timer.setInterval(1500);
|
||||
connect(&_timer, SIGNAL(timeout()), this, SLOT(Highlight()));
|
||||
_timer.start();
|
||||
}
|
||||
|
||||
bool MacroSegmentEdit::eventFilter(QObject *obj, QEvent *ev)
|
||||
@@ -325,6 +330,22 @@ void MacroSegmentEdit::Collapsed(bool collapsed)
|
||||
}
|
||||
}
|
||||
|
||||
void MacroSegmentEdit::Highlight()
|
||||
{
|
||||
if (!Data()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (_showHighlight && Data()->Highlight()) {
|
||||
PulseWidget(this, Qt::green, QColor(0, 0, 0, 0), true);
|
||||
}
|
||||
}
|
||||
|
||||
void MacroSegmentEdit::EnableHighlight(bool value)
|
||||
{
|
||||
_showHighlight = value;
|
||||
}
|
||||
|
||||
void MacroSegmentEdit::SetFocusPolicyOfWidgets()
|
||||
{
|
||||
QList<QWidget *> widgets = this->findChildren<QWidget *>();
|
||||
|
||||
@@ -37,8 +37,8 @@ public:
|
||||
virtual bool PostLoad();
|
||||
virtual std::string GetShortDesc() const;
|
||||
virtual std::string GetId() const = 0;
|
||||
void EnableHighlight();
|
||||
bool GetHighlightAndReset();
|
||||
void SetHighlight();
|
||||
bool Highlight();
|
||||
virtual std::string GetVariableValue() const;
|
||||
|
||||
protected:
|
||||
@@ -87,7 +87,7 @@ class MacroSegmentEdit : public QWidget {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
MacroSegmentEdit(QWidget *parent = nullptr);
|
||||
MacroSegmentEdit(bool highlight, QWidget *parent = nullptr);
|
||||
// Use this function to avoid accidental edits when scrolling through
|
||||
// list of actions and conditions
|
||||
void SetFocusPolicyOfWidgets();
|
||||
@@ -100,6 +100,8 @@ public slots:
|
||||
|
||||
protected slots:
|
||||
void Collapsed(bool);
|
||||
void Highlight();
|
||||
void EnableHighlight(bool);
|
||||
signals:
|
||||
void MacroAdded(const QString &name);
|
||||
void MacroRemoved(const QString &name);
|
||||
@@ -141,6 +143,9 @@ private:
|
||||
QFrame *_dropLineAbove;
|
||||
QFrame *_dropLineBelow;
|
||||
|
||||
bool _showHighlight;
|
||||
QTimer _timer;
|
||||
|
||||
friend class MacroSegmentList;
|
||||
};
|
||||
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
#include "macro-condition-edit.hpp"
|
||||
#include "macro-export-import-dialog.hpp"
|
||||
#include "macro-properties.hpp"
|
||||
#include "macro-segment-copy-paste.hpp"
|
||||
#include "macro-tree.hpp"
|
||||
#include "macro.hpp"
|
||||
#include "math-helpers.hpp"
|
||||
@@ -768,6 +767,8 @@ void AdvSceneSwitcher::on_macroProperties_clicked()
|
||||
}
|
||||
GetGlobalMacroProperties() = prop;
|
||||
emit HighlightMacrosChanged(prop._highlightExecuted);
|
||||
emit HighlightActionsChanged(prop._highlightActions);
|
||||
emit HighlightConditionsChanged(prop._highlightConditions);
|
||||
}
|
||||
|
||||
static void moveControlsToSplitter(QSplitter *splitter, int idx,
|
||||
@@ -782,7 +783,7 @@ static void moveControlsToSplitter(QSplitter *splitter, int idx,
|
||||
splitter->setStyleSheet("QSplitter::handle {background: transparent;}");
|
||||
}
|
||||
|
||||
static bool shouldRestoreSplitter(const QList<int> &pos)
|
||||
bool shouldRestoreSplitter(const QList<int> &pos)
|
||||
{
|
||||
if (pos.size() == 0) {
|
||||
return false;
|
||||
@@ -796,36 +797,6 @@ static bool shouldRestoreSplitter(const QList<int> &pos)
|
||||
return true;
|
||||
}
|
||||
|
||||
static void runSegmentHighligtChecksHelper(MacroSegmentList *list)
|
||||
{
|
||||
MacroSegmentEdit *widget = nullptr;
|
||||
for (int i = 0; (widget = list->WidgetAt(i)); i++) {
|
||||
if (widget->Data() && widget->Data()->GetHighlightAndReset()) {
|
||||
list->Highlight(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void runSegmentHighligtChecks(AdvSceneSwitcher *ss)
|
||||
{
|
||||
if (!ss || !HighlightUIElementsEnabled()) {
|
||||
return;
|
||||
}
|
||||
auto macro = ss->GetSelectedMacro();
|
||||
if (!macro) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto &properties = GetGlobalMacroProperties();
|
||||
if (properties._highlightConditions) {
|
||||
runSegmentHighligtChecksHelper(ss->ui->conditionsList);
|
||||
}
|
||||
if (properties._highlightActions) {
|
||||
runSegmentHighligtChecksHelper(ss->ui->actionsList);
|
||||
runSegmentHighligtChecksHelper(ss->ui->elseActionsList);
|
||||
}
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::SetupMacroTab()
|
||||
{
|
||||
ui->macroElseActions->installEventFilter(this);
|
||||
@@ -920,14 +891,6 @@ void AdvSceneSwitcher::SetupMacroTab()
|
||||
switcher->macroListMacroEditSplitterPosition);
|
||||
}
|
||||
}
|
||||
|
||||
SetupSegmentCopyPasteShortcutHandlers(this);
|
||||
|
||||
// Macro segment highlight
|
||||
auto timer = new QTimer(this);
|
||||
connect(timer, &QTimer::timeout,
|
||||
[this]() { runSegmentHighligtChecks(this); });
|
||||
timer->start(1500);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::ShowMacroContextMenu(const QPoint &pos)
|
||||
@@ -1015,19 +978,16 @@ static void setupConextMenu(AdvSceneSwitcher *ss, const QPoint &pos,
|
||||
MacroSegmentList *list)
|
||||
{
|
||||
QMenu menu;
|
||||
menu.addAction(obs_module_text("AdvSceneSwitcher.macroTab.expandAll"),
|
||||
ss, [ss, expand]() { expand(ss); });
|
||||
menu.addAction(obs_module_text("AdvSceneSwitcher.macroTab.collapseAll"),
|
||||
ss, [ss, collapse]() { collapse(ss); });
|
||||
menu.addAction(obs_module_text("AdvSceneSwitcher.macroTab.maximize"),
|
||||
ss, [ss, maximize]() { maximize(ss); });
|
||||
menu.addAction(obs_module_text("AdvSceneSwitcher.macroTab.minimize"),
|
||||
ss, [ss, minimize]() { minimize(ss); });
|
||||
|
||||
auto segmentEdit = list->WidgetAt(pos);
|
||||
|
||||
auto copy = menu.addAction(
|
||||
obs_module_text("AdvSceneSwitcher.macroTab.segment.copy"), ss,
|
||||
[ss]() { ss->CopyMacroSegment(); });
|
||||
copy->setEnabled(!!segmentEdit);
|
||||
auto paste = menu.addAction(
|
||||
obs_module_text("AdvSceneSwitcher.macroTab.segment.paste"), ss,
|
||||
[ss]() { ss->PasteMacroSegment(); });
|
||||
paste->setEnabled(MacroSegmentIsInClipboard());
|
||||
|
||||
menu.addSeparator();
|
||||
|
||||
if (segmentEdit) {
|
||||
auto customLabel = menu.addAction(obs_module_text(
|
||||
"AdvSceneSwitcher.macroTab.segment.useCustomLabel"));
|
||||
@@ -1039,21 +999,6 @@ static void setupConextMenu(AdvSceneSwitcher *ss, const QPoint &pos,
|
||||
std::bind(handleCustomLabelChange, segmentEdit,
|
||||
customLabel));
|
||||
}
|
||||
|
||||
menu.addSeparator();
|
||||
|
||||
menu.addAction(obs_module_text("AdvSceneSwitcher.macroTab.expandAll"),
|
||||
ss, [ss, expand]() { expand(ss); });
|
||||
menu.addAction(obs_module_text("AdvSceneSwitcher.macroTab.collapseAll"),
|
||||
ss, [ss, collapse]() { collapse(ss); });
|
||||
|
||||
menu.addSeparator();
|
||||
|
||||
menu.addAction(obs_module_text("AdvSceneSwitcher.macroTab.maximize"),
|
||||
ss, [ss, maximize]() { maximize(ss); });
|
||||
menu.addAction(obs_module_text("AdvSceneSwitcher.macroTab.minimize"),
|
||||
ss, [ss, minimize]() { minimize(ss); });
|
||||
|
||||
menu.exec(list->mapToGlobal(pos));
|
||||
}
|
||||
|
||||
@@ -1398,47 +1343,58 @@ static void fade(QWidget *widget, bool fadeOut)
|
||||
animation->start(QPropertyAnimation::DeleteWhenStopped);
|
||||
}
|
||||
|
||||
void fadeWidgets(const std::vector<QWidget *> &widgets, bool fadeOut)
|
||||
void AdvSceneSwitcher::FadeOutActionControls()
|
||||
{
|
||||
for (const auto &widget : widgets) {
|
||||
fade(widget, fadeOut);
|
||||
}
|
||||
fade(ui->actionAdd, true);
|
||||
fade(ui->actionRemove, true);
|
||||
fade(ui->actionTop, true);
|
||||
fade(ui->actionUp, true);
|
||||
fade(ui->actionDown, true);
|
||||
fade(ui->actionBottom, true);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::FadeOutConditionControls()
|
||||
{
|
||||
fade(ui->conditionAdd, true);
|
||||
fade(ui->conditionRemove, true);
|
||||
fade(ui->conditionTop, true);
|
||||
fade(ui->conditionUp, true);
|
||||
fade(ui->conditionDown, true);
|
||||
fade(ui->conditionBottom, true);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::ResetOpacityActionControls()
|
||||
{
|
||||
fade(ui->actionAdd, false);
|
||||
fade(ui->actionRemove, false);
|
||||
fade(ui->actionTop, false);
|
||||
fade(ui->actionUp, false);
|
||||
fade(ui->actionDown, false);
|
||||
fade(ui->actionBottom, false);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::ResetOpacityConditionControls()
|
||||
{
|
||||
fade(ui->conditionAdd, false);
|
||||
fade(ui->conditionRemove, false);
|
||||
fade(ui->conditionTop, false);
|
||||
fade(ui->conditionUp, false);
|
||||
fade(ui->conditionDown, false);
|
||||
fade(ui->conditionBottom, false);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::HighlightControls()
|
||||
{
|
||||
const std::vector<QWidget *> conditionControls{
|
||||
ui->conditionAdd, ui->conditionRemove, ui->conditionTop,
|
||||
ui->conditionUp, ui->conditionDown, ui->conditionBottom,
|
||||
};
|
||||
const std::vector<QWidget *> actionControls{
|
||||
ui->actionAdd, ui->actionRemove, ui->actionTop,
|
||||
ui->actionUp, ui->actionDown, ui->actionBottom,
|
||||
};
|
||||
const std::vector<QWidget *> elseActionControls{
|
||||
ui->elseActionAdd, ui->elseActionRemove, ui->elseActionTop,
|
||||
ui->elseActionUp, ui->elseActionDown, ui->elseActionBottom,
|
||||
};
|
||||
|
||||
if ((currentActionIdx == -1 && currentConditionIdx == -1 &&
|
||||
currentElseActionIdx == -1)) {
|
||||
fadeWidgets(conditionControls, false);
|
||||
fadeWidgets(actionControls, false);
|
||||
fadeWidgets(elseActionControls, false);
|
||||
} else if (currentConditionIdx != -1) {
|
||||
fadeWidgets(conditionControls, false);
|
||||
fadeWidgets(actionControls, true);
|
||||
fadeWidgets(elseActionControls, true);
|
||||
if ((currentActionIdx == -1 && currentConditionIdx == -1) ||
|
||||
(currentActionIdx != -1 && currentConditionIdx != -1)) {
|
||||
ResetOpacityActionControls();
|
||||
ResetOpacityConditionControls();
|
||||
} else if (currentActionIdx != -1) {
|
||||
fadeWidgets(conditionControls, true);
|
||||
fadeWidgets(actionControls, false);
|
||||
fadeWidgets(elseActionControls, true);
|
||||
} else if (currentElseActionIdx != -1) {
|
||||
fadeWidgets(conditionControls, true);
|
||||
fadeWidgets(actionControls, true);
|
||||
fadeWidgets(elseActionControls, false);
|
||||
FadeOutConditionControls();
|
||||
ResetOpacityActionControls();
|
||||
} else {
|
||||
assert(false);
|
||||
FadeOutActionControls();
|
||||
ResetOpacityConditionControls();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -137,37 +137,37 @@ bool Macro::CeckMatch()
|
||||
case LogicType::AND:
|
||||
_matched = _matched && cond;
|
||||
if (cond) {
|
||||
c->EnableHighlight();
|
||||
c->SetHighlight();
|
||||
}
|
||||
break;
|
||||
case LogicType::OR:
|
||||
_matched = _matched || cond;
|
||||
if (cond) {
|
||||
c->EnableHighlight();
|
||||
c->SetHighlight();
|
||||
}
|
||||
break;
|
||||
case LogicType::AND_NOT:
|
||||
_matched = _matched && !cond;
|
||||
if (!cond) {
|
||||
c->EnableHighlight();
|
||||
c->SetHighlight();
|
||||
}
|
||||
break;
|
||||
case LogicType::OR_NOT:
|
||||
_matched = _matched || !cond;
|
||||
if (!cond) {
|
||||
c->EnableHighlight();
|
||||
c->SetHighlight();
|
||||
}
|
||||
break;
|
||||
case LogicType::ROOT_NONE:
|
||||
_matched = cond;
|
||||
if (cond) {
|
||||
c->EnableHighlight();
|
||||
c->SetHighlight();
|
||||
}
|
||||
break;
|
||||
case LogicType::ROOT_NOT:
|
||||
_matched = !cond;
|
||||
if (!cond) {
|
||||
c->EnableHighlight();
|
||||
c->SetHighlight();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@@ -313,7 +313,7 @@ bool Macro::RunActionsHelper(
|
||||
break;
|
||||
}
|
||||
if (action->Enabled()) {
|
||||
action->EnableHighlight();
|
||||
action->SetHighlight();
|
||||
}
|
||||
}
|
||||
_done = true;
|
||||
@@ -819,10 +819,10 @@ void Macro::ResetUIHelpers()
|
||||
{
|
||||
_onPreventedActionExecution = false;
|
||||
for (auto c : _conditions) {
|
||||
c->GetHighlightAndReset();
|
||||
c->Highlight();
|
||||
}
|
||||
for (auto a : _actions) {
|
||||
a->GetHighlightAndReset();
|
||||
a->Highlight();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -67,21 +67,7 @@ bool MacroConditionAudio::CheckOutputCondition()
|
||||
OBSSourceAutoRelease source =
|
||||
obs_weak_source_get_source(_audioSource.GetSource());
|
||||
|
||||
// OBS might very rarely not update _peak quickly enough when very low
|
||||
// intervals are configured on the General tab.
|
||||
// In that case _peak might be set to negative infinity still, which
|
||||
// will result in unexpected behavior, so we use the previously valid
|
||||
// peak value instead.
|
||||
float peak;
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(_peakMutex);
|
||||
peak = _peakUpdated ? _peak : _previousPeak;
|
||||
_previousPeak = peak;
|
||||
_peak = -std::numeric_limits<float>::infinity();
|
||||
_peakUpdated = false;
|
||||
}
|
||||
|
||||
double curVolume = _useDb ? peak : DecibelToPercent(peak) * 100;
|
||||
double curVolume = _useDb ? _peak : DecibelToPercent(_peak) * 100;
|
||||
|
||||
switch (_outputCondition) {
|
||||
case OutputCondition::ABOVE:
|
||||
@@ -106,6 +92,7 @@ bool MacroConditionAudio::CheckOutputCondition()
|
||||
SetTempVarValue("output_volume", std::to_string(curVolume));
|
||||
|
||||
// Reset for next check
|
||||
_peak = -std::numeric_limits<float>::infinity();
|
||||
if (_audioSource.GetType() == SourceSelection::Type::VARIABLE) {
|
||||
ResetVolmeter();
|
||||
}
|
||||
@@ -342,13 +329,11 @@ void MacroConditionAudio::SetVolumeLevel(void *data, const float *,
|
||||
return;
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> lock(c->_peakMutex);
|
||||
for (int i = 0; i < MAX_AUDIO_CHANNELS; i++) {
|
||||
if (peak[i] > c->_peak) {
|
||||
c->_peak = peak[i];
|
||||
}
|
||||
}
|
||||
c->_peakUpdated = true;
|
||||
}
|
||||
|
||||
void MacroConditionAudio::ResetVolmeter()
|
||||
|
||||
@@ -73,10 +73,7 @@ private:
|
||||
void SetupTempVars();
|
||||
|
||||
Type _checkType = Type::OUTPUT_VOLUME;
|
||||
std::mutex _peakMutex;
|
||||
float _peak = -std::numeric_limits<float>::infinity();
|
||||
float _previousPeak = -std::numeric_limits<float>::infinity();
|
||||
bool _peakUpdated = false;
|
||||
static bool _registered;
|
||||
static const std::string id;
|
||||
};
|
||||
|
||||
@@ -45,13 +45,11 @@ static bool setupReplayBufferEventHandler()
|
||||
|
||||
bool MacroConditionReplayBuffer::ReplayBufferWasSaved()
|
||||
{
|
||||
if (!_saveTimeInitialized) {
|
||||
_saveTime = replayBufferSaveTime;
|
||||
_saveTimeInitialized = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool newSaveOccurred = _saveTime != replayBufferSaveTime;
|
||||
bool timersAreInitialized =
|
||||
_saveTime.time_since_epoch().count() != 0 &&
|
||||
replayBufferSaveTime.time_since_epoch().count() != 0;
|
||||
bool newSaveOccurred = timersAreInitialized &&
|
||||
_saveTime != replayBufferSaveTime;
|
||||
_saveTime = replayBufferSaveTime;
|
||||
return newSaveOccurred;
|
||||
}
|
||||
|
||||
@@ -29,7 +29,6 @@ public:
|
||||
private:
|
||||
bool ReplayBufferWasSaved();
|
||||
|
||||
bool _saveTimeInitialized = false;
|
||||
std::chrono::high_resolution_clock::time_point _saveTime = {};
|
||||
static bool _registered;
|
||||
static const std::string id;
|
||||
|
||||
@@ -175,49 +175,22 @@ void PressKeys(const std::vector<HotkeyType> keys, int duration)
|
||||
}
|
||||
}
|
||||
|
||||
static bool windowIsValid(HWND window)
|
||||
static HWND getHWNDfromTitle(const std::string &title)
|
||||
{
|
||||
if (!IsWindowVisible(window)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
DWORD id;
|
||||
GetWindowThreadProcessId(window, &id);
|
||||
if (id == GetCurrentProcessId()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Only accept for top level windows and not controls within them
|
||||
if (window != GetAncestor(window, GA_ROOT)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static std::vector<HWND> getHWNDfromTitle(const std::string &title)
|
||||
{
|
||||
HWND hwnd = nullptr;
|
||||
HWND hPrevWnd = nullptr;
|
||||
std::vector<HWND> hwnds;
|
||||
HWND hwnd = NULL;
|
||||
wchar_t wTitle[512];
|
||||
os_utf8_to_wcs(title.c_str(), 0, wTitle, 512);
|
||||
while ((hwnd = FindWindowEx(NULL, hPrevWnd, NULL, wTitle)) != nullptr) {
|
||||
if (windowIsValid(hwnd)) {
|
||||
hwnds.emplace_back(hwnd);
|
||||
}
|
||||
hPrevWnd = hwnd;
|
||||
}
|
||||
return hwnds;
|
||||
hwnd = FindWindowEx(NULL, NULL, NULL, wTitle);
|
||||
return hwnd;
|
||||
}
|
||||
|
||||
std::string GetWindowClassByWindowTitle(const std::string &window)
|
||||
{
|
||||
auto hwnds = getHWNDfromTitle(window);
|
||||
if (hwnds.empty()) {
|
||||
HWND hwnd = NULL;
|
||||
hwnd = getHWNDfromTitle(window);
|
||||
if (!hwnd) {
|
||||
return "";
|
||||
}
|
||||
auto hwnd = hwnds.at(0);
|
||||
std::wstring wClass;
|
||||
wClass.resize(1024);
|
||||
if (!GetClassNameW(hwnd, &wClass[0], wClass.capacity())) {
|
||||
@@ -233,54 +206,41 @@ std::string GetWindowClassByWindowTitle(const std::string &window)
|
||||
|
||||
void SetFocusWindow(const std::string &title)
|
||||
{
|
||||
auto hwnds = getHWNDfromTitle(title);
|
||||
if (hwnds.empty()) {
|
||||
auto handle = getHWNDfromTitle(title);
|
||||
if (!handle) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (const auto &handle : hwnds) {
|
||||
const bool isMinimized = IsIconic(handle);
|
||||
ShowWindow(handle, isMinimized ? SW_RESTORE : SW_SHOW);
|
||||
SetForegroundWindow(handle);
|
||||
SetFocus(handle);
|
||||
SetActiveWindow(handle);
|
||||
}
|
||||
ShowWindow(handle, SW_RESTORE);
|
||||
SetForegroundWindow(handle);
|
||||
SetFocus(handle);
|
||||
SetActiveWindow(handle);
|
||||
}
|
||||
|
||||
void CloseWindow(const std::string &title)
|
||||
{
|
||||
auto hwnds = getHWNDfromTitle(title);
|
||||
if (hwnds.empty()) {
|
||||
auto handle = getHWNDfromTitle(title);
|
||||
if (!handle) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (const auto &handle : hwnds) {
|
||||
SendMessage(handle, WM_CLOSE, 0, 0);
|
||||
}
|
||||
SendMessage(handle, WM_CLOSE, 0, 0);
|
||||
}
|
||||
|
||||
void MaximizeWindow(const std::string &title)
|
||||
{
|
||||
auto hwnds = getHWNDfromTitle(title);
|
||||
if (hwnds.empty()) {
|
||||
auto handle = getHWNDfromTitle(title);
|
||||
if (!handle) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (const auto &handle : hwnds) {
|
||||
ShowWindow(handle, SW_MAXIMIZE);
|
||||
}
|
||||
ShowWindow(handle, SW_MAXIMIZE);
|
||||
}
|
||||
|
||||
void MinimizeWindow(const std::string &title)
|
||||
{
|
||||
auto hwnds = getHWNDfromTitle(title);
|
||||
if (hwnds.empty()) {
|
||||
auto handle = getHWNDfromTitle(title);
|
||||
if (!handle) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (const auto &handle : hwnds) {
|
||||
ShowWindow(handle, SW_MINIMIZE);
|
||||
}
|
||||
ShowWindow(handle, SW_MINIMIZE);
|
||||
}
|
||||
|
||||
class RawMouseInputFilter;
|
||||
|
||||
@@ -12,7 +12,73 @@ bool MacroConditionMidi::_registered = MacroConditionFactory::Register(
|
||||
{MacroConditionMidi::Create, MacroConditionMidiEdit::Create,
|
||||
"AdvSceneSwitcher.condition.midi"});
|
||||
|
||||
static const std::map<MacroConditionMidi::Condition, std::string>
|
||||
conditionTypes = {
|
||||
{MacroConditionMidi::Condition::MIDI_MESSAGE,
|
||||
"AdvSceneSwitcher.condition.midi.condition.message"},
|
||||
{MacroConditionMidi::Condition::MIDI_CONNECTED_DEVICE_NAMES,
|
||||
"AdvSceneSwitcher.condition.midi.condition.deviceName"},
|
||||
};
|
||||
|
||||
bool MacroConditionMidi::CheckCondition()
|
||||
{
|
||||
switch (_condition) {
|
||||
case Condition::MIDI_MESSAGE:
|
||||
return CheckMessage();
|
||||
case Condition::MIDI_CONNECTED_DEVICE_NAMES:
|
||||
return CheckConnectedDevcieNames();
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MacroConditionMidi::Save(obs_data_t *obj) const
|
||||
{
|
||||
MacroCondition::Save(obj);
|
||||
obs_data_set_int(obj, "condition", static_cast<int>(_condition));
|
||||
_message.Save(obj);
|
||||
_device.Save(obj);
|
||||
_deviceName.Save(obj, "deviceName");
|
||||
_regex.Save(obj);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MacroConditionMidi::Load(obs_data_t *obj)
|
||||
{
|
||||
MacroCondition::Load(obj);
|
||||
_message.Load(obj);
|
||||
_device.Load(obj);
|
||||
_deviceName.Load(obj, "deviceName");
|
||||
_regex.Load(obj);
|
||||
SetCondition(
|
||||
static_cast<Condition>(obs_data_get_int(obj, "condition")));
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string MacroConditionMidi::GetShortDesc() const
|
||||
{
|
||||
return _condition == MacroConditionMidi::Condition::MIDI_MESSAGE
|
||||
? _device.Name()
|
||||
: "";
|
||||
}
|
||||
|
||||
void MacroConditionMidi::SetDevice(const MidiDevice &dev)
|
||||
{
|
||||
_device = dev;
|
||||
_messageBuffer = dev.RegisterForMidiMessages();
|
||||
}
|
||||
|
||||
void MacroConditionMidi::SetCondition(Condition condition)
|
||||
{
|
||||
_condition = condition;
|
||||
if (_condition == Condition::MIDI_MESSAGE) {
|
||||
_messageBuffer = _device.RegisterForMidiMessages();
|
||||
}
|
||||
SetupTempVars();
|
||||
}
|
||||
|
||||
bool MacroConditionMidi::CheckMessage()
|
||||
{
|
||||
if (!_messageBuffer) {
|
||||
return false;
|
||||
@@ -40,37 +106,27 @@ bool MacroConditionMidi::CheckCondition()
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MacroConditionMidi::Save(obs_data_t *obj) const
|
||||
bool MacroConditionMidi::CheckConnectedDevcieNames()
|
||||
{
|
||||
MacroCondition::Save(obj);
|
||||
_message.Save(obj);
|
||||
_device.Save(obj);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MacroConditionMidi::Load(obs_data_t *obj)
|
||||
{
|
||||
MacroCondition::Load(obj);
|
||||
_message.Load(obj);
|
||||
_device.Load(obj);
|
||||
_messageBuffer = _device.RegisterForMidiMessages();
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string MacroConditionMidi::GetShortDesc() const
|
||||
{
|
||||
return _device.Name();
|
||||
}
|
||||
|
||||
void MacroConditionMidi::SetDevice(const MidiDevice &dev)
|
||||
{
|
||||
_device = dev;
|
||||
_messageBuffer = dev.RegisterForMidiMessages();
|
||||
auto deviceNames = GetDeviceNames();
|
||||
if (!_regex.Enabled()) {
|
||||
return std::find(deviceNames.begin(), deviceNames.end(),
|
||||
std::string(_deviceName)) != deviceNames.end();
|
||||
}
|
||||
for (const auto &deviceName : deviceNames) {
|
||||
if (_regex.Matches(deviceName, _deviceName)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void MacroConditionMidi::SetupTempVars()
|
||||
{
|
||||
MacroCondition::SetupTempVars();
|
||||
if (_condition == Condition::MIDI_CONNECTED_DEVICE_NAMES) {
|
||||
return;
|
||||
}
|
||||
AddTempvar("type",
|
||||
obs_module_text("AdvSceneSwitcher.tempVar.midi.type"));
|
||||
AddTempvar("channel",
|
||||
@@ -98,16 +154,45 @@ void MacroConditionMidi::SetVariableValues(const MidiMessage &m)
|
||||
SetTempVarValue("value2", std::to_string(m.Value()));
|
||||
}
|
||||
|
||||
static void populateConditionSelection(QComboBox *list)
|
||||
{
|
||||
for (const auto &[_, name] : conditionTypes) {
|
||||
list->addItem(obs_module_text(name.c_str()));
|
||||
}
|
||||
}
|
||||
|
||||
MacroConditionMidiEdit::MacroConditionMidiEdit(
|
||||
QWidget *parent, std::shared_ptr<MacroConditionMidi> entryData)
|
||||
: QWidget(parent),
|
||||
_conditions(new QComboBox()),
|
||||
_devices(new MidiDeviceSelection(this, MidiDeviceType::INPUT)),
|
||||
_message(new MidiMessageSelection(this)),
|
||||
_resetMidiDevices(new QPushButton(
|
||||
obs_module_text("AdvSceneSwitcher.midi.resetDevices"))),
|
||||
_listen(new QPushButton(
|
||||
obs_module_text("AdvSceneSwitcher.midi.startListen")))
|
||||
obs_module_text("AdvSceneSwitcher.midi.startListen"))),
|
||||
_deviceNames(new QComboBox()),
|
||||
_regex(new RegexConfigWidget()),
|
||||
_deviceListInfo(new QLabel()),
|
||||
_listenLayout(new QHBoxLayout()),
|
||||
_entryLayout(new QHBoxLayout())
|
||||
{
|
||||
_deviceNames->addItems(GetDeviceNamesAsQStringList());
|
||||
_deviceNames->setEditable(true);
|
||||
|
||||
QString path = GetThemeTypeName() == "Light"
|
||||
? ":/res/images/help.svg"
|
||||
: ":/res/images/help_light.svg";
|
||||
QIcon icon(path);
|
||||
QPixmap pixmap = icon.pixmap(QSize(16, 16));
|
||||
_deviceListInfo->setPixmap(pixmap);
|
||||
_deviceListInfo->setToolTip(obs_module_text(
|
||||
"AdvSceneSwitcher.condition.midi.condition.deviceName.info"));
|
||||
|
||||
populateConditionSelection(_conditions);
|
||||
|
||||
QWidget::connect(_conditions, SIGNAL(currentIndexChanged(int)), this,
|
||||
SLOT(ConditionChanged(int)));
|
||||
QWidget::connect(_devices,
|
||||
SIGNAL(DeviceSelectionChanged(const MidiDevice &)),
|
||||
this,
|
||||
@@ -121,19 +206,21 @@ MacroConditionMidiEdit::MacroConditionMidiEdit(
|
||||
SLOT(ToggleListen()));
|
||||
QWidget::connect(&_listenTimer, SIGNAL(timeout()), this,
|
||||
SLOT(SetMessageSelectionToLastReceived()));
|
||||
QWidget::connect(_deviceNames,
|
||||
SIGNAL(currentTextChanged(const QString &)), this,
|
||||
SLOT(DeviceNameChanged(const QString &)));
|
||||
QWidget::connect(_regex,
|
||||
SIGNAL(RegexConfigChanged(const RegexConfig &)), this,
|
||||
SLOT(RegexChanged(const RegexConfig &)));
|
||||
|
||||
auto entryLayout = new QHBoxLayout;
|
||||
PlaceWidgets(obs_module_text("AdvSceneSwitcher.condition.midi.entry"),
|
||||
entryLayout, {{"{{device}}", _devices}});
|
||||
auto listenLayout = new QHBoxLayout;
|
||||
PlaceWidgets(
|
||||
obs_module_text("AdvSceneSwitcher.condition.midi.entry.listen"),
|
||||
listenLayout, {{"{{listenButton}}", _listen}});
|
||||
_listenLayout, {{"{{listenButton}}", _listen}});
|
||||
|
||||
auto mainLayout = new QVBoxLayout;
|
||||
mainLayout->addLayout(entryLayout);
|
||||
mainLayout->addLayout(_entryLayout);
|
||||
mainLayout->addWidget(_message);
|
||||
mainLayout->addLayout(listenLayout);
|
||||
mainLayout->addLayout(_listenLayout);
|
||||
mainLayout->addWidget(_resetMidiDevices);
|
||||
setLayout(mainLayout);
|
||||
|
||||
@@ -155,11 +242,14 @@ void MacroConditionMidiEdit::UpdateEntryData()
|
||||
return;
|
||||
}
|
||||
|
||||
_conditions->setCurrentIndex(
|
||||
static_cast<int>(_entryData->GetCondition()));
|
||||
_message->SetMessage(_entryData->_message);
|
||||
_devices->SetDevice(_entryData->GetDevice());
|
||||
|
||||
adjustSize();
|
||||
updateGeometry();
|
||||
_deviceNames->setCurrentText(QString::fromStdString(
|
||||
_entryData->_deviceName.UnresolvedValue()));
|
||||
_regex->SetRegexConfig(_entryData->_regex);
|
||||
SetWidgetVisibility();
|
||||
}
|
||||
|
||||
void MacroConditionMidiEdit::DeviceSelectionChanged(const MidiDevice &device)
|
||||
@@ -211,6 +301,46 @@ void MacroConditionMidiEdit::EnableListening(bool enable)
|
||||
}
|
||||
}
|
||||
|
||||
void MacroConditionMidiEdit::SetWidgetVisibility()
|
||||
{
|
||||
_entryLayout->removeWidget(_conditions);
|
||||
_entryLayout->removeWidget(_devices);
|
||||
_entryLayout->removeWidget(_deviceNames);
|
||||
_entryLayout->removeWidget(_regex);
|
||||
|
||||
ClearLayout(_entryLayout);
|
||||
|
||||
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
|
||||
{"{{conditions}}", _conditions},
|
||||
{"{{device}}", _devices},
|
||||
{"{{deviceNames}}", _deviceNames},
|
||||
{"{{regex}}", _regex},
|
||||
{"{{deviceListInfo}}", _deviceListInfo},
|
||||
};
|
||||
|
||||
const bool isMessageCheck = _entryData->GetCondition() ==
|
||||
MacroConditionMidi::Condition::MIDI_MESSAGE;
|
||||
|
||||
auto layoutString =
|
||||
isMessageCheck
|
||||
? "AdvSceneSwitcher.condition.midi.entry.message"
|
||||
: "AdvSceneSwitcher.condition.midi.entry.deviceName";
|
||||
|
||||
PlaceWidgets(obs_module_text(layoutString), _entryLayout,
|
||||
widgetPlaceholders);
|
||||
|
||||
SetLayoutVisible(_listenLayout, isMessageCheck);
|
||||
_devices->setVisible(isMessageCheck);
|
||||
_message->setVisible(isMessageCheck);
|
||||
_resetMidiDevices->setVisible(isMessageCheck);
|
||||
_deviceNames->setVisible(!isMessageCheck);
|
||||
_regex->setVisible(!isMessageCheck);
|
||||
_deviceListInfo->setVisible(!isMessageCheck);
|
||||
|
||||
adjustSize();
|
||||
updateGeometry();
|
||||
}
|
||||
|
||||
void MacroConditionMidiEdit::ToggleListen()
|
||||
{
|
||||
if (!_entryData) {
|
||||
@@ -249,4 +379,41 @@ void MacroConditionMidiEdit::SetMessageSelectionToLastReceived()
|
||||
_entryData->_message = *message;
|
||||
}
|
||||
|
||||
void MacroConditionMidiEdit::ConditionChanged(int value)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
_entryData->SetCondition(
|
||||
static_cast<MacroConditionMidi::Condition>(value));
|
||||
SetWidgetVisibility();
|
||||
emit HeaderInfoChanged(
|
||||
QString::fromStdString(_entryData->GetShortDesc()));
|
||||
}
|
||||
|
||||
void MacroConditionMidiEdit::DeviceNameChanged(const QString &deviceName)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
_entryData->_deviceName = deviceName.toStdString();
|
||||
}
|
||||
|
||||
void MacroConditionMidiEdit::RegexChanged(const RegexConfig &conf)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
_entryData->_regex = conf;
|
||||
|
||||
adjustSize();
|
||||
updateGeometry();
|
||||
}
|
||||
|
||||
} // namespace advss
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
#pragma once
|
||||
#include "macro-condition-edit.hpp"
|
||||
#include "midi-helpers.hpp"
|
||||
#include "regex-config.hpp"
|
||||
#include "variable-line-edit.hpp"
|
||||
|
||||
#include <QPushButton>
|
||||
#include <QTimer>
|
||||
@@ -23,11 +25,23 @@ public:
|
||||
void SetDevice(const MidiDevice &dev);
|
||||
const MidiDevice &GetDevice() const { return _device; }
|
||||
MidiMessage _message;
|
||||
StringVariable _deviceName;
|
||||
RegexConfig _regex;
|
||||
|
||||
enum class Condition {
|
||||
MIDI_MESSAGE,
|
||||
MIDI_CONNECTED_DEVICE_NAMES,
|
||||
};
|
||||
void SetCondition(Condition);
|
||||
Condition GetCondition() const { return _condition; }
|
||||
|
||||
private:
|
||||
bool CheckMessage();
|
||||
bool CheckConnectedDevcieNames();
|
||||
void SetupTempVars();
|
||||
void SetVariableValues(const MidiMessage &);
|
||||
|
||||
Condition _condition = Condition::MIDI_MESSAGE;
|
||||
MidiDevice _device;
|
||||
MidiMessageBuffer _messageBuffer;
|
||||
std::chrono::high_resolution_clock::time_point _lastCheck{};
|
||||
@@ -58,18 +72,29 @@ private slots:
|
||||
void ResetMidiDevices();
|
||||
void ToggleListen();
|
||||
void SetMessageSelectionToLastReceived();
|
||||
void ConditionChanged(int);
|
||||
void DeviceNameChanged(const QString &);
|
||||
void RegexChanged(const RegexConfig &);
|
||||
signals:
|
||||
void HeaderInfoChanged(const QString &);
|
||||
|
||||
private:
|
||||
void EnableListening(bool);
|
||||
void SetWidgetVisibility();
|
||||
|
||||
std::shared_ptr<MacroConditionMidi> _entryData;
|
||||
|
||||
QComboBox *_conditions;
|
||||
MidiDeviceSelection *_devices;
|
||||
MidiMessageSelection *_message;
|
||||
QPushButton *_resetMidiDevices;
|
||||
QPushButton *_listen;
|
||||
QComboBox *_deviceNames;
|
||||
RegexConfigWidget *_regex;
|
||||
QLabel *_deviceListInfo;
|
||||
QHBoxLayout *_listenLayout;
|
||||
QHBoxLayout *_entryLayout;
|
||||
|
||||
QTimer _listenTimer;
|
||||
MidiMessageBuffer _messageBuffer;
|
||||
bool _currentlyListening = false;
|
||||
|
||||
@@ -20,56 +20,47 @@ std::map<std::pair<MidiDeviceType, std::string>, MidiDeviceInstance *>
|
||||
static bool setupDeviceObservers()
|
||||
{
|
||||
static std::vector<libremidi::observer> observers;
|
||||
try {
|
||||
for (auto api : libremidi::available_apis()) {
|
||||
libremidi::observer_configuration cbs;
|
||||
cbs.input_added = [=](const libremidi::input_port &p) {
|
||||
auto dev = MidiDeviceInstance::GetDevice(p);
|
||||
if (!dev) {
|
||||
return;
|
||||
}
|
||||
blog(LOG_INFO, "MIDI input connected: %s",
|
||||
p.port_name.c_str());
|
||||
dev->ClosePort();
|
||||
dev->OpenPort();
|
||||
};
|
||||
cbs.input_removed = [=](const libremidi::input_port &p) {
|
||||
auto dev = MidiDeviceInstance::GetDevice(p);
|
||||
if (!dev) {
|
||||
return;
|
||||
}
|
||||
blog(LOG_INFO, "MIDI input removed: %s",
|
||||
p.port_name.c_str());
|
||||
};
|
||||
cbs.output_added = [=](const libremidi::output_port &p) {
|
||||
auto dev = MidiDeviceInstance::GetDevice(p);
|
||||
if (!dev) {
|
||||
return;
|
||||
}
|
||||
blog(LOG_INFO, "MIDI output connected: %s",
|
||||
p.port_name.c_str());
|
||||
dev->ClosePort();
|
||||
dev->OpenPort();
|
||||
};
|
||||
cbs.output_removed =
|
||||
[=](const libremidi::output_port &p) {
|
||||
auto dev =
|
||||
MidiDeviceInstance::GetDevice(
|
||||
p);
|
||||
if (!dev) {
|
||||
return;
|
||||
}
|
||||
blog(LOG_INFO,
|
||||
"MIDI output removed: %s",
|
||||
p.port_name.c_str());
|
||||
};
|
||||
observers.emplace_back(
|
||||
cbs,
|
||||
libremidi::observer_configuration_for(api));
|
||||
}
|
||||
} catch (const libremidi::driver_error &error) {
|
||||
blog(LOG_WARNING, "Failed to setup midi device observers: %s",
|
||||
error.what());
|
||||
for (auto api : libremidi::available_apis()) {
|
||||
libremidi::observer_configuration cbs;
|
||||
cbs.track_virtual = true;
|
||||
cbs.input_added = [](const libremidi::input_port &p) {
|
||||
auto dev = MidiDeviceInstance::GetDevice(p);
|
||||
if (!dev) {
|
||||
return;
|
||||
}
|
||||
blog(LOG_INFO, "MIDI input connected: %s",
|
||||
p.port_name.c_str());
|
||||
dev->ClosePort();
|
||||
dev->OpenPort();
|
||||
};
|
||||
cbs.input_removed = [](const libremidi::input_port &p) {
|
||||
auto dev = MidiDeviceInstance::GetDevice(p);
|
||||
if (!dev) {
|
||||
return;
|
||||
}
|
||||
blog(LOG_INFO, "MIDI input removed: %s",
|
||||
p.port_name.c_str());
|
||||
};
|
||||
cbs.output_added = [](const libremidi::output_port &p) {
|
||||
auto dev = MidiDeviceInstance::GetDevice(p);
|
||||
if (!dev) {
|
||||
return;
|
||||
}
|
||||
blog(LOG_INFO, "MIDI output connected: %s",
|
||||
p.port_name.c_str());
|
||||
dev->ClosePort();
|
||||
dev->OpenPort();
|
||||
};
|
||||
cbs.output_removed = [](const libremidi::output_port &p) {
|
||||
auto dev = MidiDeviceInstance::GetDevice(p);
|
||||
if (!dev) {
|
||||
return;
|
||||
}
|
||||
blog(LOG_INFO, "MIDI output removed: %s",
|
||||
p.port_name.c_str());
|
||||
};
|
||||
observers.emplace_back(
|
||||
cbs, libremidi::observer_configuration_for(api));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -338,35 +329,95 @@ advss::MidiDeviceInstance::GetDevice(const libremidi::output_port &p)
|
||||
|
||||
static inline QStringList getInputDeviceNames()
|
||||
{
|
||||
QStringList devices;
|
||||
static QStringList devices;
|
||||
static std::mutex m;
|
||||
static std::vector<libremidi::observer> observers;
|
||||
static bool setupDone = false;
|
||||
|
||||
if (setupDone) {
|
||||
std::lock_guard<std::mutex> lock(m);
|
||||
return devices;
|
||||
}
|
||||
|
||||
// Set up observers
|
||||
try {
|
||||
libremidi::observer obs;
|
||||
for (const libremidi::input_port &port :
|
||||
obs.get_input_ports()) {
|
||||
devices << QString::fromStdString(
|
||||
getNameFromPortInformation(port));
|
||||
for (auto api : libremidi::available_apis()) {
|
||||
libremidi::observer_configuration cbs;
|
||||
cbs.track_virtual = true;
|
||||
cbs.input_added = [](const libremidi::input_port &p) {
|
||||
std::lock_guard<std::mutex> lock(m);
|
||||
auto device = QString::fromStdString(
|
||||
getNameFromPortInformation(p));
|
||||
if (devices.indexOf(device) == -1) {
|
||||
devices << device;
|
||||
}
|
||||
};
|
||||
cbs.input_removed = [](const libremidi::input_port &p) {
|
||||
std::lock_guard<std::mutex> lock(m);
|
||||
auto device = QString::fromStdString(
|
||||
getNameFromPortInformation(p));
|
||||
if (int i = devices.indexOf(device) != -1) {
|
||||
devices.removeAt(i);
|
||||
}
|
||||
};
|
||||
observers.emplace_back(
|
||||
cbs,
|
||||
libremidi::observer_configuration_for(api));
|
||||
}
|
||||
} catch (const libremidi::driver_error &error) {
|
||||
blog(LOG_WARNING, "Failed to get midi input devices: %s",
|
||||
error.what());
|
||||
}
|
||||
|
||||
setupDone = true;
|
||||
return devices;
|
||||
}
|
||||
|
||||
static inline QStringList getOutputDeviceNames()
|
||||
{
|
||||
QStringList devices;
|
||||
static QStringList devices;
|
||||
static std::mutex m;
|
||||
static std::vector<libremidi::observer> observers;
|
||||
static bool setupDone = false;
|
||||
|
||||
if (setupDone) {
|
||||
std::lock_guard<std::mutex> lock(m);
|
||||
return devices;
|
||||
}
|
||||
|
||||
// Set up observers
|
||||
try {
|
||||
libremidi::observer obs;
|
||||
for (const libremidi::output_port &port :
|
||||
obs.get_output_ports()) {
|
||||
devices << QString::fromStdString(
|
||||
getNameFromPortInformation(port));
|
||||
for (auto api : libremidi::available_apis()) {
|
||||
libremidi::observer_configuration cbs;
|
||||
cbs.track_virtual = true;
|
||||
cbs.output_added = [](const libremidi::output_port &p) {
|
||||
std::lock_guard<std::mutex> lock(m);
|
||||
auto device = QString::fromStdString(
|
||||
getNameFromPortInformation(p));
|
||||
if (devices.indexOf(device) == -1) {
|
||||
devices << device;
|
||||
}
|
||||
};
|
||||
cbs.output_removed =
|
||||
[](const libremidi::output_port &p) {
|
||||
std::lock_guard<std::mutex> lock(m);
|
||||
auto device = QString::fromStdString(
|
||||
getNameFromPortInformation(p));
|
||||
if (int i = devices.indexOf(device) !=
|
||||
-1) {
|
||||
devices.removeAt(i);
|
||||
}
|
||||
};
|
||||
observers.emplace_back(
|
||||
cbs,
|
||||
libremidi::observer_configuration_for(api));
|
||||
}
|
||||
} catch (const libremidi::driver_error &error) {
|
||||
blog(LOG_WARNING, "Failed to get midi output devices: %s",
|
||||
error.what());
|
||||
}
|
||||
|
||||
setupDone = true;
|
||||
return devices;
|
||||
}
|
||||
|
||||
@@ -434,16 +485,11 @@ bool MidiDevice::SendMessge(const MidiMessage &m) const
|
||||
static std::optional<libremidi::output_port>
|
||||
getOutPortFromName(const std::string &name)
|
||||
{
|
||||
try {
|
||||
libremidi::observer obs;
|
||||
for (const libremidi::output_port &port :
|
||||
obs.get_output_ports()) {
|
||||
if (getNameFromPortInformation(port) == name) {
|
||||
return port;
|
||||
}
|
||||
libremidi::observer obs;
|
||||
for (const libremidi::output_port &port : obs.get_output_ports()) {
|
||||
if (getNameFromPortInformation(port) == name) {
|
||||
return port;
|
||||
}
|
||||
} catch (const libremidi::driver_error &error) {
|
||||
blog(LOG_WARNING, "%s: %s", __func__, error.what());
|
||||
}
|
||||
return {};
|
||||
}
|
||||
@@ -451,16 +497,11 @@ getOutPortFromName(const std::string &name)
|
||||
static std::optional<libremidi::input_port>
|
||||
getInPortFromName(const std::string &name)
|
||||
{
|
||||
try {
|
||||
libremidi::observer obs;
|
||||
for (const libremidi::input_port &port :
|
||||
obs.get_input_ports()) {
|
||||
if (getNameFromPortInformation(port) == name) {
|
||||
return port;
|
||||
}
|
||||
libremidi::observer obs;
|
||||
for (const libremidi::input_port &port : obs.get_input_ports()) {
|
||||
if (getNameFromPortInformation(port) == name) {
|
||||
return port;
|
||||
}
|
||||
} catch (const libremidi::driver_error &error) {
|
||||
blog(LOG_WARNING, "%s: %s", __func__, error.what());
|
||||
}
|
||||
return {};
|
||||
}
|
||||
@@ -1017,6 +1058,28 @@ void MidiMessageSelection::ValueChanged(const NumberVariable<int> &v)
|
||||
emit MidiMessageChanged((_currentSelection));
|
||||
}
|
||||
|
||||
std::vector<std::string> GetDeviceNames()
|
||||
{
|
||||
std::vector<std::string> result;
|
||||
const auto names = GetDeviceNamesAsQStringList();
|
||||
for (const auto &name : names) {
|
||||
result.emplace_back(name.toStdString());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
QStringList GetDeviceNamesAsQStringList()
|
||||
{
|
||||
QStringList result;
|
||||
for (const auto &input : getInputDeviceNames()) {
|
||||
result << input;
|
||||
}
|
||||
for (const auto &output : getOutputDeviceNames()) {
|
||||
result << output;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
QStringList GetAllNotes()
|
||||
{
|
||||
static bool done = false;
|
||||
|
||||
@@ -171,6 +171,8 @@ private:
|
||||
const MidiDeviceType _type;
|
||||
};
|
||||
|
||||
std::vector<std::string> GetDeviceNames();
|
||||
QStringList GetDeviceNamesAsQStringList();
|
||||
QStringList GetAllNotes();
|
||||
|
||||
} // namespace advss
|
||||
|
||||
Reference in New Issue
Block a user