Compare commits

..

1 Commits
1.26.0 ... midi

Author SHA1 Message Date
WarmUpTill
c7afdd817b Add MIDI device name check 2024-05-10 01:15:16 +02:00
29 changed files with 601 additions and 801 deletions

View File

@@ -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

View File

@@ -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:"

View File

@@ -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:"

View File

@@ -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:"

View File

@@ -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 à"

View File

@@ -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:"

View File

@@ -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="没有匹配项时:"

View File

@@ -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);
}
}

View File

@@ -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);

View File

@@ -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;

View File

@@ -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

View File

@@ -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;
};

View File

@@ -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)

View File

@@ -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

View File

@@ -1,8 +0,0 @@
namespace advss {
class AdvSceneSwitcher;
bool MacroSegmentIsInClipboard();
void SetupSegmentCopyPasteShortcutHandlers(AdvSceneSwitcher *window);
} // namespace advss

View File

@@ -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

View File

@@ -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 *>();

View File

@@ -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;
};

View File

@@ -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();
}
}

View File

@@ -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();
}
}

View File

@@ -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()

View File

@@ -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;
};

View File

@@ -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;
}

View File

@@ -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;

View File

@@ -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;

View File

@@ -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

View File

@@ -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;

View File

@@ -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;

View File

@@ -171,6 +171,8 @@ private:
const MidiDeviceType _type;
};
std::vector<std::string> GetDeviceNames();
QStringList GetDeviceNamesAsQStringList();
QStringList GetAllNotes();
} // namespace advss