generated from obsproject/obs-plugintemplate
-
-
Notifications
You must be signed in to change notification settings - Fork 18
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Refactor URL source callbacks and add mapping data (#91)
* Refactor URL source callbacks and add mapping data (#91) * Refactor URL source callbacks and fix error messages * Refactor URL source thread and remove unused variables
- Loading branch information
Showing
11 changed files
with
703 additions
and
307 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
|
||
#include "mapping-data.h" | ||
#include <nlohmann/json.hpp> | ||
|
||
std::string serialize_output_mapping_data(const output_mapping_data &data) | ||
{ | ||
nlohmann::json j; | ||
for (const auto &mapping : data.mappings) { | ||
nlohmann::json j_mapping; | ||
j_mapping["name"] = mapping.name; | ||
j_mapping["output_source"] = mapping.output_source; | ||
j_mapping["template_string"] = mapping.template_string; | ||
j_mapping["css_props"] = mapping.css_props; | ||
j_mapping["unhide_output_source"] = mapping.unhide_output_source; | ||
j.push_back(j_mapping); | ||
} | ||
return j.dump(); | ||
} | ||
|
||
output_mapping_data deserialize_output_mapping_data(const std::string &data) | ||
{ | ||
output_mapping_data result; | ||
nlohmann::json j = nlohmann::json::parse(data); | ||
for (const auto &j_mapping : j) { | ||
output_mapping mapping; | ||
mapping.name = j_mapping.value("name", ""); | ||
mapping.output_source = j_mapping.value("output_source", ""); | ||
mapping.template_string = j_mapping.value("template_string", ""); | ||
mapping.css_props = j_mapping.value("css_props", ""); | ||
mapping.unhide_output_source = j_mapping.value("unhide_output_source", false); | ||
result.mappings.push_back(mapping); | ||
} | ||
return result; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
#ifndef MAPPING_DATA_H | ||
#define MAPPING_DATA_H | ||
|
||
#include <string> | ||
#include <vector> | ||
|
||
const std::string none_internal_rendering = "None / Internal rendering"; | ||
|
||
struct output_mapping { | ||
std::string name; | ||
std::string output_source; | ||
std::string template_string; | ||
std::string css_props; | ||
bool unhide_output_source = false; | ||
}; | ||
|
||
struct output_mapping_data { | ||
std::vector<output_mapping> mappings; | ||
}; | ||
|
||
std::string serialize_output_mapping_data(const output_mapping_data &data); | ||
output_mapping_data deserialize_output_mapping_data(const std::string &data); | ||
|
||
#endif // MAPPING_DATA_H |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,204 @@ | ||
#include "outputmapping.h" | ||
#include "ui_outputmapping.h" | ||
|
||
#include <QComboBox> | ||
#include <QHeaderView> | ||
#include <QStandardItem> | ||
|
||
#include <obs.h> | ||
#include <obs-module.h> | ||
|
||
namespace { | ||
// add_sources_to_list is a helper function that adds all text and media sources to the list | ||
bool add_sources_to_list(void *list_property, obs_source_t *source) | ||
{ | ||
// add all text and media sources to the list | ||
auto source_id = obs_source_get_id(source); | ||
if (strcmp(source_id, "text_ft2_source_v2") != 0 && | ||
strcmp(source_id, "text_gdiplus_v2") != 0 && strcmp(source_id, "ffmpeg_source") != 0 && | ||
strcmp(source_id, "image_source") != 0) { | ||
return true; | ||
} | ||
|
||
QComboBox *sources = static_cast<QComboBox *>(list_property); | ||
const char *name = obs_source_get_name(source); | ||
std::string name_with_prefix; | ||
// add a prefix to the name to indicate the source type | ||
if (strcmp(source_id, "text_ft2_source_v2") == 0 || | ||
strcmp(source_id, "text_gdiplus_v2") == 0) { | ||
name_with_prefix = std::string("(Text) ").append(name); | ||
} else if (strcmp(source_id, "image_source") == 0) { | ||
name_with_prefix = std::string("(Image) ").append(name); | ||
} else if (strcmp(source_id, "ffmpeg_source") == 0) { | ||
name_with_prefix = std::string("(Media) ").append(name); | ||
} | ||
sources->addItem(name_with_prefix.c_str()); | ||
return true; | ||
} | ||
|
||
const std::string default_css_props = R"(background-color: transparent; | ||
color: #FFFFFF; | ||
font-size: 48px; | ||
)"; | ||
const std::string default_template_string = R"({{output}})"; | ||
} // namespace | ||
|
||
OutputMapping::OutputMapping(output_mapping_data *mapping_data_in, | ||
std::function<void()> update_handler_in, QWidget *parent) | ||
: QDialog(parent), | ||
ui(new Ui::OutputMapping), | ||
mapping_data(mapping_data_in), | ||
update_handler(update_handler_in) | ||
{ | ||
ui->setupUi(this); | ||
|
||
model.setHorizontalHeaderLabels(QStringList() << "Mapping Name" | ||
<< "Output"); | ||
ui->tableView->setModel(&model); | ||
ui->tableView->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch); | ||
|
||
// if an item is selected in the tableView, enable the remove button | ||
connect(ui->tableView->selectionModel(), &QItemSelectionModel::selectionChanged, | ||
[this](const QItemSelection &selected) { | ||
const bool enable = !selected.indexes().isEmpty(); | ||
ui->toolButton_removeMapping->setEnabled(enable); | ||
ui->plainTextEdit_template->setEnabled(enable); | ||
ui->plainTextEdit_cssProps->setEnabled(enable); | ||
|
||
if (enable) { | ||
// get the selected row | ||
const auto row = selected.indexes().first().row(); | ||
// get the data and output_source of the selected row | ||
const auto data = model.item(row, 0)->text(); | ||
const auto output_source = model.item(row, 1)->text(); | ||
ui->plainTextEdit_template->blockSignals(true); | ||
ui->plainTextEdit_cssProps->blockSignals(true); | ||
ui->checkBox_unhide_Source->blockSignals(true); | ||
// set the plainTextEdit_template and plainTextEdit_cssProps to the template_string and css_props of the selected row | ||
ui->plainTextEdit_template->setPlainText( | ||
this->mapping_data->mappings[row].template_string.c_str()); | ||
ui->plainTextEdit_cssProps->setPlainText( | ||
this->mapping_data->mappings[row].css_props.c_str()); | ||
ui->checkBox_unhide_Source->setChecked( | ||
this->mapping_data->mappings[row].unhide_output_source); | ||
ui->plainTextEdit_template->blockSignals(false); | ||
ui->plainTextEdit_cssProps->blockSignals(false); | ||
ui->checkBox_unhide_Source->blockSignals(false); | ||
} | ||
}); | ||
|
||
// connect toolButton_addMapping to addMapping | ||
connect(ui->toolButton_addMapping, &QToolButton::clicked, this, &OutputMapping::addMapping); | ||
// connect toolButton_removeMapping to removeMapping | ||
connect(ui->toolButton_removeMapping, &QToolButton::clicked, this, | ||
&OutputMapping::removeMapping); | ||
|
||
// connect plainTextEdit_template textChanged to update the mapping template_string | ||
connect(ui->plainTextEdit_template, &QPlainTextEdit::textChanged, [this]() { | ||
// get the selected row | ||
const auto row = ui->tableView->currentIndex().row(); | ||
// set the template_string of the selected row to the plainTextEdit_template text | ||
this->mapping_data->mappings[row].template_string = | ||
ui->plainTextEdit_template->toPlainText().toStdString(); | ||
// call update_handler | ||
this->update_handler(); | ||
}); | ||
connect(ui->plainTextEdit_cssProps, &QPlainTextEdit::textChanged, [this]() { | ||
// get the selected row | ||
const auto row = ui->tableView->currentIndex().row(); | ||
// set the css_props of the selected row to the plainTextEdit_cssProps text | ||
this->mapping_data->mappings[row].css_props = | ||
ui->plainTextEdit_cssProps->toPlainText().toStdString(); | ||
// call update_handler | ||
this->update_handler(); | ||
}); | ||
|
||
// populate the model with the mapping data | ||
for (const auto &mapping : mapping_data->mappings) { | ||
model.appendRow(QList<QStandardItem *>() << new QStandardItem(mapping.name.c_str()) | ||
<< new QStandardItem("")); | ||
QComboBox *comboBox = createSourcesComboBox(); | ||
if (!mapping.output_source.empty()) { | ||
// select the output_source of the mapping in the comboBox | ||
comboBox->blockSignals(true); | ||
comboBox->setCurrentText(mapping.output_source.c_str()); | ||
comboBox->blockSignals(false); | ||
} | ||
// add a row to the model with the data and output_source of the mapping | ||
// set comboBox as the index widget of the last item in the model | ||
ui->tableView->setIndexWidget(model.index(model.rowCount() - 1, 1), comboBox); | ||
} | ||
|
||
// connect item edit on tableView | ||
connect(&model, &QStandardItemModel::itemChanged, [this](QStandardItem *item) { | ||
// update mapping name | ||
if (item->column() == 0) { | ||
this->mapping_data->mappings[item->row()].name = item->text().toStdString(); | ||
} | ||
}); | ||
} | ||
|
||
OutputMapping::~OutputMapping() | ||
{ | ||
delete ui; | ||
} | ||
|
||
/// @brief a helper function that creates a comboBox and adds all text and media sources to the list. | ||
/// The sources are added with a prefix to indicate the source type (Text, Image, or Media). | ||
/// @return a pointer to the comboBox | ||
QComboBox *OutputMapping::createSourcesComboBox() | ||
{ | ||
QComboBox *comboBox = new QComboBox(this); | ||
// add "Internal Renderer" to the comboBox | ||
comboBox->addItem(QString::fromStdString(none_internal_rendering)); | ||
// add all text and media sources to the comboBox | ||
obs_enum_sources(add_sources_to_list, comboBox); | ||
// connect comboBox to update_handler | ||
connect(comboBox, &QComboBox::currentIndexChanged, [this, comboBox]() { | ||
// get the selected row | ||
const auto row = ui->tableView->currentIndex().row(); | ||
// get the output_name of the selected item in the comboBox | ||
const auto output_name = comboBox->currentText().toStdString(); | ||
// remove the prefix from the output_name if it exists | ||
std::string output_name_without_prefix = output_name; | ||
if (output_name.find("(Text) ") == 0) { | ||
output_name_without_prefix = output_name.substr(7); | ||
} else if (output_name.find("(Image) ") == 0) { | ||
output_name_without_prefix = output_name.substr(8); | ||
} else if (output_name.find("(Media) ") == 0) { | ||
output_name_without_prefix = output_name.substr(8); | ||
} | ||
// set the css_props of the selected row to the plainTextEdit_cssProps text | ||
this->mapping_data->mappings[row].output_source = output_name_without_prefix; | ||
// call update_handler | ||
this->update_handler(); | ||
}); | ||
|
||
return comboBox; | ||
} | ||
|
||
void OutputMapping::addMapping() | ||
{ | ||
// add row to model | ||
model.appendRow(QList<QStandardItem *>() | ||
<< new QStandardItem("Mapping") << new QStandardItem("Output")); | ||
QComboBox *comboBox = createSourcesComboBox(); | ||
// set comboBox as the index widget of the last item in the model | ||
ui->tableView->setIndexWidget(model.index(model.rowCount() - 1, 1), comboBox); | ||
// add a new mapping to the mapping_data | ||
this->mapping_data->mappings.push_back(output_mapping{ | ||
"Mapping", none_internal_rendering, default_template_string, default_css_props}); | ||
// call update_handler | ||
this->update_handler(); | ||
} | ||
|
||
void OutputMapping::removeMapping() | ||
{ | ||
// remove the mapping from the mapping_data | ||
this->mapping_data->mappings.erase(this->mapping_data->mappings.begin() + | ||
ui->tableView->currentIndex().row()); | ||
// remove row from model | ||
model.removeRow(ui->tableView->currentIndex().row()); | ||
// call update_handler | ||
this->update_handler(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
#ifndef OUTPUTMAPPING_H | ||
#define OUTPUTMAPPING_H | ||
|
||
#include <QDialog> | ||
#include <QStandardItemModel> | ||
#include <QComboBox> | ||
#include <functional> | ||
|
||
#include "mapping-data.h" | ||
|
||
namespace Ui { | ||
class OutputMapping; | ||
} | ||
|
||
class OutputMapping : public QDialog { | ||
Q_OBJECT | ||
|
||
public: | ||
explicit OutputMapping(output_mapping_data *mapping_data_in, | ||
std::function<void()> update_handler, QWidget *parent = nullptr); | ||
~OutputMapping(); | ||
|
||
OutputMapping(const OutputMapping &) = delete; | ||
OutputMapping &operator=(const OutputMapping &) = delete; | ||
|
||
private: | ||
Ui::OutputMapping *ui; | ||
QStandardItemModel model; | ||
output_mapping_data *mapping_data; | ||
QComboBox *createSourcesComboBox(); | ||
std::function<void()> update_handler; | ||
|
||
private slots: | ||
void addMapping(); | ||
void removeMapping(); | ||
}; | ||
|
||
#endif // OUTPUTMAPPING_H |
Oops, something went wrong.