mirror of
https://github.com/WarmUpTill/SceneSwitcher.git
synced 2026-08-29 04:36:21 -05:00
Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2af0735a2f | ||
|
|
556943c293 | ||
|
|
e3004184c4 | ||
|
|
7b2c2e91db | ||
|
|
06ea7bf1d9 |
@@ -185,8 +185,12 @@ AdvSceneSwitcher.condition.replay.state.started="Replay buffer started"
|
||||
AdvSceneSwitcher.condition.replay.state.saved="Replay buffer saved"
|
||||
AdvSceneSwitcher.condition.replay.entry="{{state}}"
|
||||
AdvSceneSwitcher.condition.date="Date"
|
||||
AdvSceneSwitcher.condition.date.entry.line1="{{dateTime}} {{ignoreDate}} Ignore date selection {{ignoreTime}} Ignore time selection"
|
||||
AdvSceneSwitcher.condition.date.entry.line2="{{repeat}} Repeat every {{duration}}"
|
||||
AdvSceneSwitcher.condition.date.state.at="At"
|
||||
AdvSceneSwitcher.condition.date.state.after="After"
|
||||
AdvSceneSwitcher.condition.date.state.before="Before"
|
||||
AdvSceneSwitcher.condition.date.state.between="Between"
|
||||
AdvSceneSwitcher.condition.date.entry.line1="{{condition}} {{dateTime}} {{dateTime2}} {{ignoreDate}} Ignore date component {{ignoreTime}} Ignore time component"
|
||||
AdvSceneSwitcher.condition.date.entry.line2="{{repeat}} Reschedule {{duration}} later when matching"
|
||||
|
||||
; Macro Actions
|
||||
AdvSceneSwitcher.action.switchScene="Switch scene"
|
||||
|
||||
@@ -424,8 +424,9 @@ void SwitcherData::Stop()
|
||||
{
|
||||
if (th && th->isRunning()) {
|
||||
stop = true;
|
||||
transitionCv.notify_one();
|
||||
cv.notify_one();
|
||||
abortMacroWait = true;
|
||||
macroWaitCv.notify_one();
|
||||
th->wait();
|
||||
delete th;
|
||||
th = nullptr;
|
||||
|
||||
@@ -4,6 +4,14 @@
|
||||
|
||||
#include <QCheckBox>
|
||||
#include <QDateTimeEdit>
|
||||
#include <QComboBox>
|
||||
|
||||
enum class DateCondition {
|
||||
AT,
|
||||
AFTER,
|
||||
BEFORE,
|
||||
BETWEEN,
|
||||
};
|
||||
|
||||
class MacroConditionDate : public MacroCondition {
|
||||
public:
|
||||
@@ -18,10 +26,12 @@ public:
|
||||
}
|
||||
|
||||
QDateTime _dateTime;
|
||||
QDateTime _dateTime2;
|
||||
bool _ignoreDate = false;
|
||||
bool _ignoreTime = false;
|
||||
bool _repeat = false;
|
||||
Duration _duration;
|
||||
DateCondition _condition = DateCondition::AT;
|
||||
|
||||
private:
|
||||
static bool _registered;
|
||||
@@ -45,7 +55,9 @@ public:
|
||||
}
|
||||
|
||||
private slots:
|
||||
void ConditionChanged(int cond);
|
||||
void DateTimeChanged(const QDateTime &datetime);
|
||||
void DateTime2Changed(const QDateTime &datetime);
|
||||
void IgnoreDateChanged(int state);
|
||||
void IgnoreTimeChanged(int state);
|
||||
void RepeatChanged(int state);
|
||||
@@ -55,7 +67,9 @@ signals:
|
||||
void HeaderInfoChanged(const QString &);
|
||||
|
||||
protected:
|
||||
QComboBox *_condition;
|
||||
QDateTimeEdit *_dateTime;
|
||||
QDateTimeEdit *_dateTime2;
|
||||
QCheckBox *_ignoreDate;
|
||||
QCheckBox *_ignoreTime;
|
||||
QCheckBox *_repeat;
|
||||
@@ -63,5 +77,6 @@ protected:
|
||||
std::shared_ptr<MacroConditionDate> _entryData;
|
||||
|
||||
private:
|
||||
void ShowSecondDateSelection(bool visible);
|
||||
bool _loading = true;
|
||||
};
|
||||
|
||||
@@ -67,7 +67,6 @@ struct SwitcherData {
|
||||
std::mutex m;
|
||||
bool transitionActive = false;
|
||||
bool waitForTransition = false;
|
||||
std::condition_variable transitionCv;
|
||||
bool stop = false;
|
||||
bool verbose = false;
|
||||
bool disableHints = false;
|
||||
@@ -92,6 +91,8 @@ struct SwitcherData {
|
||||
std::chrono::high_resolution_clock::time_point lastMatchTime;
|
||||
|
||||
std::deque<Macro> macros;
|
||||
std::condition_variable macroWaitCv;
|
||||
std::atomic_bool abortMacroWait = {false};
|
||||
bool macroSceneSwitched = false;
|
||||
bool replayBufferSaved = false;
|
||||
|
||||
|
||||
@@ -30,8 +30,8 @@ bool compareSourceSettings(const OBSWeakSource &source,
|
||||
std::vector<obs_scene_item *> getSceneItemsWithName(OBSScene scene,
|
||||
std::string &name);
|
||||
std::string getDataFilePath(const std::string &file);
|
||||
QString fromatJsonString(std::string);
|
||||
QString fromatJsonString(const char *);
|
||||
QString formatJsonString(std::string);
|
||||
QString formatJsonString(const char *);
|
||||
|
||||
/**
|
||||
* Populate layout with labels and widgets based on provided text
|
||||
|
||||
@@ -174,6 +174,8 @@ void AdvSceneSwitcher::RemoveMacroAction(int idx)
|
||||
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
macro->Actions().erase(macro->Actions().begin() + idx);
|
||||
switcher->abortMacroWait = true;
|
||||
switcher->macroWaitCv.notify_one();
|
||||
macro->UpdateActionIndices();
|
||||
|
||||
// All entry pointers in existing edit widgets after the new entry will
|
||||
|
||||
@@ -198,7 +198,7 @@ void MacroActionFilterEdit::GetSettingsClicked()
|
||||
}
|
||||
|
||||
_settings->setPlainText(
|
||||
fromatJsonString(getSourceSettings(_entryData->_filter)));
|
||||
formatJsonString(getSourceSettings(_entryData->_filter)));
|
||||
}
|
||||
|
||||
void MacroActionFilterEdit::SettingsChanged()
|
||||
|
||||
@@ -201,7 +201,7 @@ void MacroActionSceneTransformEdit::UpdateEntryData()
|
||||
GetWeakSourceName(_entryData->_source).c_str());
|
||||
if (_entryData->_source) {
|
||||
_settings->setPlainText(
|
||||
fromatJsonString(_entryData->GetSettings()));
|
||||
formatJsonString(_entryData->GetSettings()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -255,7 +255,7 @@ void MacroActionSceneTransformEdit::GetSettingsClicked()
|
||||
auto data = obs_data_create();
|
||||
save_transform_state(data, info, crop);
|
||||
auto json = obs_data_get_json(data);
|
||||
_settings->setPlainText(fromatJsonString(json));
|
||||
_settings->setPlainText(formatJsonString(json));
|
||||
obs_data_release(data);
|
||||
}
|
||||
|
||||
|
||||
@@ -173,7 +173,7 @@ void MacroActionSourceEdit::GetSettingsClicked()
|
||||
}
|
||||
|
||||
_settings->setPlainText(
|
||||
fromatJsonString(getSourceSettings(_entryData->_source)));
|
||||
formatJsonString(getSourceSettings(_entryData->_source)));
|
||||
}
|
||||
|
||||
void MacroActionSourceEdit::SettingsChanged()
|
||||
|
||||
@@ -38,10 +38,12 @@ bool MacroActionWait::PerformAction()
|
||||
sleep_duration);
|
||||
|
||||
std::unique_lock<std::mutex> lock(switcher->m);
|
||||
auto r = switcher->cv.wait_for(
|
||||
switcher->abortMacroWait = false;
|
||||
switcher->macroWaitCv.wait_for(
|
||||
lock,
|
||||
std::chrono::milliseconds((long long)(sleep_duration * 1000)));
|
||||
return r == std::cv_status::timeout;
|
||||
std::chrono::milliseconds((long long)(sleep_duration * 1000)),
|
||||
[] { return switcher->abortMacroWait.load(); });
|
||||
return !switcher->abortMacroWait;
|
||||
}
|
||||
|
||||
bool MacroActionWait::Save(obs_data_t *obj)
|
||||
|
||||
@@ -10,21 +10,52 @@ bool MacroConditionDate::_registered = MacroConditionFactory::Register(
|
||||
{MacroConditionDate::Create, MacroConditionDateEdit::Create,
|
||||
"AdvSceneSwitcher.condition.date", false});
|
||||
|
||||
static std::map<DateCondition, std::string> dateConditionTypes = {
|
||||
{DateCondition::AT, "AdvSceneSwitcher.condition.date.state.at"},
|
||||
{DateCondition::AFTER, "AdvSceneSwitcher.condition.date.state.after"},
|
||||
{DateCondition::BEFORE, "AdvSceneSwitcher.condition.date.state.before"},
|
||||
{DateCondition::BETWEEN,
|
||||
"AdvSceneSwitcher.condition.date.state.between"},
|
||||
};
|
||||
|
||||
bool MacroConditionDate::CheckCondition()
|
||||
{
|
||||
bool match = false;
|
||||
QDateTime cur = QDateTime::currentDateTime();
|
||||
if (_ignoreDate) {
|
||||
_dateTime.setDate(cur.date());
|
||||
_dateTime2.setDate(cur.date());
|
||||
}
|
||||
if (_ignoreTime) {
|
||||
_dateTime.setTime(cur.time());
|
||||
_dateTime2.setTime(cur.time());
|
||||
}
|
||||
|
||||
switch (_condition) {
|
||||
case DateCondition::AT:
|
||||
match = _dateTime >= cur &&
|
||||
_dateTime <= cur.addMSecs(switcher->interval);
|
||||
break;
|
||||
case DateCondition::AFTER:
|
||||
match = cur >= _dateTime;
|
||||
break;
|
||||
case DateCondition::BEFORE:
|
||||
match = cur <= _dateTime;
|
||||
break;
|
||||
case DateCondition::BETWEEN:
|
||||
if (_dateTime2 > _dateTime) {
|
||||
match = cur >= _dateTime && cur <= _dateTime2;
|
||||
} else {
|
||||
match = cur >= _dateTime2 && cur <= _dateTime;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
match = _dateTime >= cur &&
|
||||
_dateTime <= cur.addMSecs(switcher->interval);
|
||||
if (match && _repeat) {
|
||||
_dateTime = _dateTime.addSecs(_duration.seconds);
|
||||
_dateTime2 = _dateTime2.addSecs(_duration.seconds);
|
||||
}
|
||||
|
||||
return match;
|
||||
@@ -33,8 +64,11 @@ bool MacroConditionDate::CheckCondition()
|
||||
bool MacroConditionDate::Save(obs_data_t *obj)
|
||||
{
|
||||
MacroCondition::Save(obj);
|
||||
obs_data_set_int(obj, "condition", static_cast<int>(_condition));
|
||||
obs_data_set_string(obj, "dateTime",
|
||||
_dateTime.toString().toStdString().c_str());
|
||||
obs_data_set_string(obj, "dateTime2",
|
||||
_dateTime2.toString().toStdString().c_str());
|
||||
obs_data_set_bool(obj, "ignoreDate", _ignoreDate);
|
||||
obs_data_set_bool(obj, "ignoreTime", _ignoreTime);
|
||||
obs_data_set_bool(obj, "repeat", _repeat);
|
||||
@@ -46,8 +80,12 @@ bool MacroConditionDate::Save(obs_data_t *obj)
|
||||
bool MacroConditionDate::Load(obs_data_t *obj)
|
||||
{
|
||||
MacroCondition::Load(obj);
|
||||
_condition =
|
||||
static_cast<DateCondition>(obs_data_get_int(obj, "condition"));
|
||||
_dateTime = QDateTime::fromString(
|
||||
QString::fromStdString(obs_data_get_string(obj, "dateTime")));
|
||||
_dateTime2 = QDateTime::fromString(
|
||||
QString::fromStdString(obs_data_get_string(obj, "dateTime2")));
|
||||
_ignoreDate = obs_data_get_bool(obj, "ignoreDate");
|
||||
_ignoreTime = obs_data_get_bool(obj, "ignoreTime");
|
||||
_repeat = obs_data_get_bool(obj, "repeat");
|
||||
@@ -60,20 +98,35 @@ std::string MacroConditionDate::GetShortDesc()
|
||||
return _dateTime.toString().toStdString();
|
||||
}
|
||||
|
||||
static inline void populateConditionSelection(QComboBox *list)
|
||||
{
|
||||
for (auto entry : dateConditionTypes) {
|
||||
list->addItem(obs_module_text(entry.second.c_str()));
|
||||
}
|
||||
}
|
||||
|
||||
MacroConditionDateEdit::MacroConditionDateEdit(
|
||||
QWidget *parent, std::shared_ptr<MacroConditionDate> entryData)
|
||||
: QWidget(parent)
|
||||
{
|
||||
_condition = new QComboBox();
|
||||
_dateTime = new QDateTimeEdit();
|
||||
_dateTime->setCalendarPopup(true);
|
||||
_dateTime->setDisplayFormat("yyyy.MM.dd hh:mm:ss");
|
||||
_dateTime2 = new QDateTimeEdit();
|
||||
_dateTime2->setCalendarPopup(true);
|
||||
_dateTime2->setDisplayFormat("yyyy.MM.dd hh:mm:ss");
|
||||
_ignoreDate = new QCheckBox();
|
||||
_ignoreTime = new QCheckBox();
|
||||
_repeat = new QCheckBox();
|
||||
_duration = new DurationSelection();
|
||||
|
||||
QWidget::connect(_condition, SIGNAL(currentIndexChanged(int)), this,
|
||||
SLOT(ConditionChanged(int)));
|
||||
QWidget::connect(_dateTime, SIGNAL(dateTimeChanged(const QDateTime &)),
|
||||
this, SLOT(DateTimeChanged(const QDateTime &)));
|
||||
QWidget::connect(_dateTime2, SIGNAL(dateTimeChanged(const QDateTime &)),
|
||||
this, SLOT(DateTime2Changed(const QDateTime &)));
|
||||
QWidget::connect(_ignoreDate, SIGNAL(stateChanged(int)), this,
|
||||
SLOT(IgnoreDateChanged(int)));
|
||||
QWidget::connect(_ignoreTime, SIGNAL(stateChanged(int)), this,
|
||||
@@ -85,9 +138,13 @@ MacroConditionDateEdit::MacroConditionDateEdit(
|
||||
QWidget::connect(_duration, SIGNAL(UnitChanged(DurationUnit)), this,
|
||||
SLOT(DurationUnitChanged(DurationUnit)));
|
||||
|
||||
populateConditionSelection(_condition);
|
||||
|
||||
auto line1Layout = new QHBoxLayout;
|
||||
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
|
||||
{"{{condition}}", _condition},
|
||||
{"{{dateTime}}", _dateTime},
|
||||
{"{{dateTime2}}", _dateTime2},
|
||||
{"{{ignoreDate}}", _ignoreDate},
|
||||
{"{{ignoreTime}}", _ignoreTime},
|
||||
{"{{repeat}}", _repeat},
|
||||
@@ -111,6 +168,18 @@ MacroConditionDateEdit::MacroConditionDateEdit(
|
||||
_loading = false;
|
||||
}
|
||||
|
||||
void MacroConditionDateEdit::ConditionChanged(int cond)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
_entryData->_condition = static_cast<DateCondition>(cond);
|
||||
ShowSecondDateSelection(_entryData->_condition ==
|
||||
DateCondition::BETWEEN);
|
||||
}
|
||||
|
||||
void MacroConditionDateEdit::DateTimeChanged(const QDateTime &datetime)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
@@ -124,6 +193,16 @@ void MacroConditionDateEdit::DateTimeChanged(const QDateTime &datetime)
|
||||
QString::fromStdString(_entryData->GetShortDesc()));
|
||||
}
|
||||
|
||||
void MacroConditionDateEdit::DateTime2Changed(const QDateTime &datetime)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
_entryData->_dateTime2 = datetime;
|
||||
}
|
||||
|
||||
void MacroConditionDateEdit::IgnoreDateChanged(int state)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
@@ -180,10 +259,21 @@ void MacroConditionDateEdit::UpdateEntryData()
|
||||
if (!_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
_condition->setCurrentIndex(static_cast<int>(_entryData->_condition));
|
||||
_dateTime->setDateTime(_entryData->_dateTime);
|
||||
_dateTime2->setDateTime(_entryData->_dateTime2);
|
||||
_ignoreDate->setChecked(_entryData->_ignoreDate);
|
||||
_ignoreTime->setChecked(_entryData->_ignoreTime);
|
||||
_repeat->setChecked(_entryData->_repeat);
|
||||
_duration->SetDuration(_entryData->_duration);
|
||||
_duration->setDisabled(!_entryData->_repeat);
|
||||
ShowSecondDateSelection(_entryData->_condition ==
|
||||
DateCondition::BETWEEN);
|
||||
}
|
||||
|
||||
void MacroConditionDateEdit::ShowSecondDateSelection(bool visible)
|
||||
{
|
||||
_dateTime2->setVisible(visible);
|
||||
adjustSize();
|
||||
}
|
||||
|
||||
@@ -192,7 +192,7 @@ void MacroConditionFilterEdit::GetSettingsClicked()
|
||||
}
|
||||
|
||||
_settings->setPlainText(
|
||||
fromatJsonString(getSourceSettings(_entryData->_filter)));
|
||||
formatJsonString(getSourceSettings(_entryData->_filter)));
|
||||
}
|
||||
|
||||
void MacroConditionFilterEdit::SettingsChanged()
|
||||
|
||||
@@ -171,7 +171,7 @@ void MacroConditionSourceEdit::GetSettingsClicked()
|
||||
}
|
||||
|
||||
_settings->setPlainText(
|
||||
fromatJsonString(getSourceSettings(_entryData->_source)));
|
||||
formatJsonString(getSourceSettings(_entryData->_source)));
|
||||
}
|
||||
|
||||
void MacroConditionSourceEdit::SettingsChanged()
|
||||
|
||||
@@ -80,6 +80,8 @@ void AdvSceneSwitcher::on_macroRemove_clicked()
|
||||
QString name;
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
switcher->abortMacroWait = true;
|
||||
switcher->macroWaitCv.notify_one();
|
||||
int idx = ui->macros->currentRow();
|
||||
QString::fromStdString(switcher->macros[idx].Name());
|
||||
switcher->macros.erase(switcher->macros.begin() + idx);
|
||||
|
||||
@@ -107,8 +107,8 @@ bool Macro::PerformAction()
|
||||
{
|
||||
bool ret = true;
|
||||
for (auto &a : _actions) {
|
||||
ret = ret && a->PerformAction();
|
||||
a->LogAction();
|
||||
ret = ret && a->PerformAction();
|
||||
if (!ret) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -92,7 +92,11 @@ void SwitcherData::writeSceneInfoToFile()
|
||||
|
||||
QFile file(QString::fromStdString(fileIO.writePath));
|
||||
if (file.open(QIODevice::WriteOnly)) {
|
||||
const char *msg = GetWeakSourceName(currentScene).c_str();
|
||||
// switcher->currentScene cannot be used here as scene might
|
||||
// have changed already
|
||||
obs_source_t *source = obs_frontend_get_current_scene();
|
||||
auto msg = obs_source_get_name(source);
|
||||
obs_source_release(source);
|
||||
file.write(msg, qstrlen(msg));
|
||||
file.close();
|
||||
}
|
||||
|
||||
@@ -283,14 +283,22 @@ bool compareSourceSettings(const OBSWeakSource &source,
|
||||
{
|
||||
bool ret = false;
|
||||
std::string currentSettings = getSourceSettings(source);
|
||||
// User input and source settings might be formatted differently
|
||||
currentSettings = formatJsonString(currentSettings).toStdString();
|
||||
std::string userSettings = formatJsonString(settings).toStdString();
|
||||
|
||||
if (userSettings.empty()) {
|
||||
userSettings = settings;
|
||||
}
|
||||
|
||||
if (useRegex) {
|
||||
try {
|
||||
std::regex expr(settings);
|
||||
std::regex expr(userSettings);
|
||||
ret = std::regex_match(currentSettings, expr);
|
||||
} catch (const std::regex_error &) {
|
||||
}
|
||||
} else {
|
||||
ret = currentSettings == settings;
|
||||
ret = currentSettings == userSettings;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
@@ -304,12 +312,12 @@ std::string getDataFilePath(const std::string &file)
|
||||
return "";
|
||||
}
|
||||
|
||||
QString fromatJsonString(std::string s)
|
||||
QString formatJsonString(std::string s)
|
||||
{
|
||||
return fromatJsonString(s.c_str());
|
||||
return formatJsonString(s.c_str());
|
||||
}
|
||||
|
||||
QString fromatJsonString(const char *json)
|
||||
QString formatJsonString(const char *json)
|
||||
{
|
||||
QJsonDocument doc = QJsonDocument::fromJson(json);
|
||||
return doc.toJson(QJsonDocument::Indented);
|
||||
|
||||
Reference in New Issue
Block a user