#include "item-selection-helpers.hpp" #include "name-dialog.hpp" #include "obs-module-helper.hpp" #include "ui-helpers.hpp" #include #include #include #include #include Q_DECLARE_METATYPE(advss::Item *); namespace advss { Item::Item(std::string name) : _name(name) {} static Item *GetItemByName(const std::string &name, std::deque> &items) { for (auto &item : items) { if (item->Name() == name) { return item.get(); } } return nullptr; } static Item *GetItemByName(const QString &name, std::deque> &items) { return GetItemByName(name.toStdString(), items); } static bool ItemNameAvailable(const QString &name, std::deque> &items) { return !GetItemByName(name, items); } static bool ItemNameAvailable(const std::string &name, std::deque> &items) { return ItemNameAvailable(QString::fromStdString(name), items); } ItemSelection::ItemSelection(std::deque> &items, CreateItemFunc create, SettingsCallback callback, std::string_view select, std::string_view add, std::string_view conflict, std::string_view configureTooltip, QWidget *parent) : QWidget(parent), _selection(new FilterComboBox(this, obs_module_text(select.data()))), _modify(new QPushButton), _create(create), _askForSettings(callback), _items(items), _selectStr(select), _addStr(add), _conflictStr(conflict) { _modify->setMaximumWidth(22); SetButtonIcon(_modify, GetThemeTypeName() == "Light" ? ":/settings/images/settings/general.svg" : "theme:Dark/settings/general.svg"); _modify->setFlat(true); if (!configureTooltip.empty()) { _modify->setToolTip(obs_module_text(configureTooltip.data())); } // Connect to slots QWidget::connect(_selection, SIGNAL(currentTextChanged(const QString &)), this, SLOT(ChangeSelection(const QString &))); QWidget::connect(_modify, SIGNAL(clicked()), this, SLOT(ModifyButtonClicked())); QHBoxLayout *layout = new QHBoxLayout; layout->addWidget(_selection); layout->addWidget(_modify); layout->setContentsMargins(0, 0, 0, 0); setLayout(layout); for (const auto &i : items) { _selection->addItem(QString::fromStdString(i->_name)); } _selection->model()->sort(0); _selection->insertSeparator(_selection->count()); _selection->addItem(obs_module_text(_addStr.data())); } void ItemSelection::SetItem(const std::string &item) { if (!!GetItemByName(item, _items)) { _selection->setCurrentText(QString::fromStdString(item)); if (_selection->lineEdit()) { _selection->lineEdit()->setText( QString::fromStdString(item)); } } else { _selection->setCurrentIndex(-1); } } void ItemSelection::ShowRenameContextMenu(bool value) { _showRenameContextMenu = value; } void ItemSelection::ChangeSelection(const QString &sel) { if (sel == obs_module_text(_addStr.data())) { auto item = _create(); bool accepted = _askForSettings(this, *item.get()); if (!accepted) { _selection->setCurrentIndex(-1); return; } _items.emplace_back(item); const QString name = QString::fromStdString(item->_name); AddItem(name); _selection->setCurrentText(name); emit ItemAdded(name); emit SelectionChanged(name); return; } auto item = GetCurrentItem(); if (item) { emit SelectionChanged(QString::fromStdString(item->_name)); } else { emit SelectionChanged(""); } } void ItemSelection::ModifyButtonClicked() { auto item = GetCurrentItem(); if (!item) { return; } auto properties = [&]() { const auto oldName = item->_name; bool accepted = _askForSettings(this, *item); if (!accepted) { return; } if (oldName != item->_name) { emit ItemRenamed(QString::fromStdString(oldName), QString::fromStdString(item->_name)); } }; QMenu menu(this); QAction *action; if (_showRenameContextMenu) { action = new QAction( obs_module_text("AdvSceneSwitcher.item.rename"), &menu); connect(action, SIGNAL(triggered()), this, SLOT(RenameItem())); action->setProperty("item", QVariant::fromValue(item)); menu.addAction(action); } action = new QAction(obs_module_text("AdvSceneSwitcher.item.remove"), &menu); connect(action, SIGNAL(triggered()), this, SLOT(RemoveItem())); menu.addAction(action); action = new QAction( obs_module_text("AdvSceneSwitcher.item.properties"), &menu); connect(action, &QAction::triggered, properties); menu.addAction(action); menu.exec(QCursor::pos()); } void ItemSelection::RenameItem() { QAction *action = reinterpret_cast(sender()); QVariant variant = action->property("item"); Item *item = variant.value(); std::string name; bool accepted = NameDialog::AskForName( this, obs_module_text("AdvSceneSwitcher.windowTitle"), obs_module_text("AdvSceneSwitcher.item.newName"), name, QString::fromStdString(item->Name())); if (!accepted) { return; } if (name.empty()) { DisplayMessage( obs_module_text("AdvSceneSwitcher.item.emptyName")); return; } if (_selection->currentText().toStdString() != name && !ItemNameAvailable(name, _items)) { DisplayMessage(obs_module_text(_conflictStr.data())); return; } const auto oldName = item->_name; item->_name = name; SetItem(name); emit ItemRenamed(QString::fromStdString(oldName), QString::fromStdString(name)); } void ItemSelection::RenameItem(const QString &oldName, const QString &name) { int idx = _selection->findText(oldName); if (idx == -1) { return; } auto currentText = _selection->currentText(); _selection->setItemText(idx, name); if (oldName == currentText) { SetItem(name.toStdString()); } } void ItemSelection::AddItem(const QString &name) { if (_selection->findText(name) == -1) { _selection->insertItem(1, name); } } void ItemSelection::RemoveItem() { auto item = GetCurrentItem(); if (!item) { return; } int idx = _selection->findText(QString::fromStdString(item->_name)); if (idx == -1 || idx == _selection->count()) { return; } auto name = item->_name; for (auto it = _items.begin(); it != _items.end(); ++it) { if (it->get()->_name == item->_name) { _items.erase(it); break; } } emit ItemRemoved(QString::fromStdString(name)); } void ItemSelection::RemoveItem(const QString &name) { auto currentText = _selection->currentText(); const int idx = _selection->findText(name); if (currentText == name) { SetItem(""); } _selection->removeItem(idx); } Item *ItemSelection::GetCurrentItem() { return GetItemByName(_selection->currentText(), _items); } ItemSettingsDialog::ItemSettingsDialog(const Item &settings, std::deque> &items, std::string_view select, std::string_view add, std::string_view nameConflict, bool showNameEmptyWarning, QWidget *parent) : QDialog(parent), _name(new QLineEdit()), _nameHint(new QLabel), _buttonbox(new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel)), _items(items), _selectStr(select), _addStr(add), _conflictStr(nameConflict), _showNameEmptyWarning(showNameEmptyWarning) { setModal(true); setWindowModality(Qt::WindowModality::WindowModal); setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); setMinimumWidth(555); setMinimumHeight(100); _buttonbox->setCenterButtons(true); _buttonbox->button(QDialogButtonBox::Ok)->setDisabled(true); _originalName = QString::fromStdString(settings._name); _name->setText(_originalName); QWidget::connect(_name, SIGNAL(textEdited(const QString &)), this, SLOT(NameChanged(const QString &))); QWidget::connect(_buttonbox, &QDialogButtonBox::accepted, this, &QDialog::accept); QWidget::connect(_buttonbox, &QDialogButtonBox::rejected, this, &QDialog::reject); NameChanged(_name->text()); } void ItemSettingsDialog::NameChanged(const QString &text) { if (text != _originalName && !ItemNameAvailable(text, _items)) { SetNameWarning(obs_module_text(_conflictStr.data())); return; } if (text.isEmpty()) { if (_showNameEmptyWarning) { SetNameWarning(obs_module_text( "AdvSceneSwitcher.item.emptyName")); return; } _nameHint->setText(""); _nameHint->hide(); _buttonbox->button(QDialogButtonBox::Ok)->setDisabled(true); return; } if (text == obs_module_text(_selectStr.data()) || text == obs_module_text(_addStr.data())) { SetNameWarning( obs_module_text("AdvSceneSwitcher.item.nameReserved")); return; } SetNameWarning(""); } void ItemSettingsDialog::showEvent(QShowEvent *) { if (_showNameEmptyWarning && _name->text().isEmpty()) { _name->setFocus(Qt::OtherFocusReason); } } void ItemSettingsDialog::SetNameWarning(const QString warn) { if (warn.isEmpty()) { _nameHint->hide(); _buttonbox->button(QDialogButtonBox::Ok)->setDisabled(false); return; } _nameHint->setText(warn); _nameHint->show(); _buttonbox->button(QDialogButtonBox::Ok)->setDisabled(true); } void Item::Load(obs_data_t *obj) { _name = obs_data_get_string(obj, "name"); } void Item::Save(obs_data_t *obj) const { obs_data_set_string(obj, "name", _name.c_str()); } void RemoveItemsByName(std::deque> &items, const QStringList &names) { for (const auto &name : names) { items.erase(std::remove_if( items.begin(), items.end(), [name](const std::shared_ptr &item) { return item->Name() == name.toStdString(); }), items.end()); } } } // namespace advss