UI/libobs: Undo/Redo Sources and Scenes

Implements the Undo/Redo for scenes and sources, ranging from renaming,
deletion, addition. It also adds several elements to libobs that were
designed to facilitate undo/redo, and should not affect the rest of
libobs.
This commit is contained in:
Ford Smith
2021-03-22 00:39:02 -04:00
committed by Ford Smith
parent eced5a320b
commit 60d95cb5bd
11 changed files with 564 additions and 37 deletions

View File

@@ -28,6 +28,9 @@ struct AddSourceData {
bool OBSBasicSourceSelect::EnumSources(void *data, obs_source_t *source)
{
if (obs_source_is_hidden(source))
return false;
OBSBasicSourceSelect *window =
static_cast<OBSBasicSourceSelect *>(data);
const char *name = obs_source_get_name(source);
@@ -179,7 +182,7 @@ bool AddNew(QWidget *parent, const char *id, const char *name,
return false;
obs_source_t *source = obs_get_source_by_name(name);
if (source) {
if (source && parent) {
OBSMessageBox::information(parent, QTStr("NameExists.Title"),
QTStr("NameExists.Text"));
@@ -236,6 +239,63 @@ void OBSBasicSourceSelect::on_buttonBox_accepted()
if (!AddNew(this, id, QT_TO_UTF8(ui->sourceName->text()),
visible, newSource))
return;
OBSBasic *main =
reinterpret_cast<OBSBasic *>(App()->GetMainWindow());
std::string scene_name =
obs_source_get_name(main->GetCurrentSceneSource());
auto undo = [scene_name, main](const std::string &data) {
obs_source_t *source =
obs_get_source_by_name(data.c_str());
obs_source_release(source);
obs_source_remove(source);
obs_source_t *scene_source =
obs_get_source_by_name(scene_name.c_str());
main->SetCurrentScene(scene_source);
obs_source_release(scene_source);
main->RefreshSources(main->GetCurrentScene());
};
obs_data_t *wrapper = obs_data_create();
obs_data_set_string(wrapper, "id", id);
obs_sceneitem_t *item = obs_scene_sceneitem_from_source(
main->GetCurrentScene(), newSource);
obs_data_set_int(wrapper, "item_id",
obs_sceneitem_get_id(item));
obs_data_set_string(
wrapper, "name",
ui->sourceName->text().toUtf8().constData());
obs_data_set_bool(wrapper, "visible", visible);
auto redo = [scene_name, main](const std::string &data) {
obs_data_t *dat =
obs_data_create_from_json(data.c_str());
OBSSource source;
AddNew(NULL, obs_data_get_string(dat, "id"),
obs_data_get_string(dat, "name"),
obs_data_get_bool(dat, "visible"), source);
obs_sceneitem_t *item = obs_scene_sceneitem_from_source(
main->GetCurrentScene(), source);
obs_sceneitem_set_id(item, (int64_t)obs_data_get_int(
dat, "item_id"));
obs_source_t *scene_source =
obs_get_source_by_name(scene_name.c_str());
main->SetCurrentScene(scene_source);
obs_source_release(scene_source);
main->RefreshSources(main->GetCurrentScene());
obs_data_release(dat);
obs_sceneitem_release(item);
};
undo_s.add_action(QTStr("Undo.Add").arg(ui->sourceName->text()),
undo, redo,
std::string(obs_source_get_name(newSource)),
std::string(obs_data_get_json(wrapper)),
NULL);
obs_data_release(wrapper);
obs_sceneitem_release(item);
}
done(DialogCode::Accepted);
@@ -261,8 +321,12 @@ template<typename T> static inline T GetOBSRef(QListWidgetItem *item)
return item->data(static_cast<int>(QtDataRole::OBSRef)).value<T>();
}
OBSBasicSourceSelect::OBSBasicSourceSelect(OBSBasic *parent, const char *id_)
: QDialog(parent), ui(new Ui::OBSBasicSourceSelect), id(id_)
OBSBasicSourceSelect::OBSBasicSourceSelect(OBSBasic *parent, const char *id_,
undo_stack &undo_s)
: QDialog(parent),
ui(new Ui::OBSBasicSourceSelect),
id(id_),
undo_s(undo_s)
{
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);