#include "macro-condition-clipboard.hpp" #include "layout-helpers.hpp" #include #include #include namespace advss { const std::string MacroConditionClipboard::id = "clipboard"; bool MacroConditionClipboard::_registered = MacroConditionFactory::Register( MacroConditionClipboard::id, {MacroConditionClipboard::Create, MacroConditionClipboardEdit::Create, "AdvSceneSwitcher.condition.clipboard"}); const static std::map conditionTypes = { {MacroConditionClipboard::Condition::CHANGED, "AdvSceneSwitcher.condition.clipboard.condition.changed"}, {MacroConditionClipboard::Condition::IS_TEXT, "AdvSceneSwitcher.condition.clipboard.condition.isText"}, {MacroConditionClipboard::Condition::IS_IMAGE, "AdvSceneSwitcher.condition.clipboard.condition.isImage"}, {MacroConditionClipboard::Condition::IS_URL, "AdvSceneSwitcher.condition.clipboard.condition.isURL"}, {MacroConditionClipboard::Condition::MATCHES, "AdvSceneSwitcher.condition.clipboard.condition.matches"}, }; ClipboardMessageBuffer ClipboardListener::RegisterForClipboardChanges() { return Instance()->_dispatcher.RegisterClient(); } ClipboardListener *ClipboardListener::Instance() { static ClipboardListener instance; return &instance; } ClipboardListener::ClipboardListener() : QObject(nullptr) { if (!QApplication::clipboard()) { return; } QObject::connect(QApplication::clipboard(), &QClipboard::dataChanged, this, &ClipboardListener::ClipboardDataChanged); } void ClipboardListener::ClipboardDataChanged() { auto text = QApplication::clipboard()->text(); _dispatcher.DispatchMessage(text.toStdString()); } MacroConditionClipboard::MacroConditionClipboard(Macro *m) : MacroCondition(m) { _messageBuffer = ClipboardListener::RegisterForClipboardChanges(); } std::shared_ptr MacroConditionClipboard::Create(Macro *m) { return std::make_shared(m); } static bool clipboardContainsImage() { const QClipboard *clipboard = QApplication::clipboard(); const QMimeData *mimeData = clipboard->mimeData(); return mimeData->hasImage(); } static bool clipboardContainsText() { const QClipboard *clipboard = QApplication::clipboard(); const QMimeData *mimeData = clipboard->mimeData(); return mimeData->hasText(); } static bool clipboardContainsUrl() { const QClipboard *clipboard = QApplication::clipboard(); const QMimeData *mimeData = clipboard->mimeData(); return mimeData->hasUrls(); } static std::string getCurrentClipboardText() { auto clipboard = QApplication::clipboard(); if (!clipboard) { return ""; } return clipboard->text().toStdString(); } bool MacroConditionClipboard::CheckCondition() { switch (_condition) { case Condition::CHANGED: while (!_messageBuffer->Empty()) { auto message = _messageBuffer->ConsumeMessage(); if (!message) { continue; } SetTempVarValue("text", *message); return true; } return false; case Condition::IS_TEXT: if (clipboardContainsText()) { SetTempVarValue("text", getCurrentClipboardText()); return true; } return false; case Condition::IS_IMAGE: return clipboardContainsImage(); case Condition::IS_URL: if (clipboardContainsUrl()) { SetTempVarValue("text", getCurrentClipboardText()); return true; } return false; case Condition::MATCHES: if (_regex.Enabled()) { auto text = getCurrentClipboardText(); if (_regex.Matches(text, _text)) { SetTempVarValue("text", text); return true; } } else { auto text = getCurrentClipboardText(); if (text == std::string(_text)) { SetTempVarValue("text", text); return true; } } return false; default: break; } return false; } void MacroConditionClipboard::SetCondition(Condition condition) { _condition = condition; _messageBuffer.reset(); if (_condition == Condition::CHANGED) { _messageBuffer = ClipboardListener::RegisterForClipboardChanges(); } } void MacroConditionClipboard::SetupTempVars() { MacroCondition::SetupTempVars(); AddTempvar( "text", obs_module_text("AdvSceneSwitcher.tempVar.clipboard.text"), obs_module_text( "AdvSceneSwitcher.tempVar.clipboard.text.description")); } bool MacroConditionClipboard::Save(obs_data_t *obj) const { MacroCondition::Save(obj); obs_data_set_int(obj, "condition", static_cast(_condition)); _text.Save(obj, "text"); _regex.Save(obj); return true; } bool MacroConditionClipboard::Load(obs_data_t *obj) { MacroCondition::Load(obj); _text.Load(obj, "text"); _regex.Load(obj); SetCondition( static_cast(obs_data_get_int(obj, "condition"))); return true; } static void populateCompareModeselection(QComboBox *list) { for (const auto &[_, name] : conditionTypes) { list->addItem(obs_module_text(name.c_str())); } } MacroConditionClipboardEdit::MacroConditionClipboardEdit( QWidget *parent, std::shared_ptr entryData) : QWidget(parent), _conditions(new QComboBox(this)), _text(new VariableTextEdit(this)), _regex(new RegexConfigWidget(parent)), _urlInfo(new HelpIcon(obs_module_text( "AdvSceneSwitcher.condition.clipboard.urlTooltip"))) { populateCompareModeselection(_conditions); _urlInfo->hide(); QWidget::connect(_conditions, SIGNAL(currentIndexChanged(int)), this, SLOT(ConditionChanged(int))); QWidget::connect(_text, SIGNAL(textChanged()), this, SLOT(TextChanged())); QWidget::connect(_regex, SIGNAL(RegexConfigChanged(const RegexConfig &)), this, SLOT(RegexChanged(const RegexConfig &))); auto layout = new QHBoxLayout(); PlaceWidgets( obs_module_text( "AdvSceneSwitcher.condition.clipboard.condition.entry"), layout, {{"{{conditions}}", _conditions}, {"{{regex}}", _regex}, {"{{urlInfo}}", _urlInfo}}); auto mainLayout = new QVBoxLayout(); mainLayout->addLayout(layout); mainLayout->addWidget(_text); setLayout(mainLayout); _entryData = entryData; UpdateEntryData(); _loading = false; } QWidget * MacroConditionClipboardEdit::Create(QWidget *parent, std::shared_ptr action) { return new MacroConditionClipboardEdit( parent, std::dynamic_pointer_cast(action)); } void MacroConditionClipboardEdit::ConditionChanged(int value) { if (_loading || !_entryData) { return; } auto lock = LockContext(); _entryData->SetCondition( static_cast(value)); SetWidgetVisibility(); } void MacroConditionClipboardEdit::TextChanged() { if (_loading || !_entryData) { return; } auto lock = LockContext(); _entryData->_text = _text->toPlainText().toStdString(); adjustSize(); updateGeometry(); } void MacroConditionClipboardEdit::RegexChanged(const RegexConfig &conf) { if (_loading || !_entryData) { return; } auto lock = LockContext(); _entryData->_regex = conf; adjustSize(); updateGeometry(); } void MacroConditionClipboardEdit::UpdateEntryData() { if (!_entryData) { return; } _conditions->setCurrentIndex( static_cast(_entryData->GetCondition())); _text->setPlainText(_entryData->_text); _regex->SetRegexConfig(_entryData->_regex); SetWidgetVisibility(); } void MacroConditionClipboardEdit::SetWidgetVisibility() { const bool requiresTextInput = _entryData->GetCondition() == MacroConditionClipboard::Condition::MATCHES; _regex->setVisible(requiresTextInput); _text->setVisible(requiresTextInput); _urlInfo->setVisible(_entryData->GetCondition() == MacroConditionClipboard::Condition::IS_URL); adjustSize(); updateGeometry(); } } // namespace advss