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:
parent
eced5a320b
commit
60d95cb5bd
@ -256,7 +256,8 @@ set(obs_SOURCES
|
|||||||
obs-proxy-style.cpp
|
obs-proxy-style.cpp
|
||||||
locked-checkbox.cpp
|
locked-checkbox.cpp
|
||||||
visibility-checkbox.cpp
|
visibility-checkbox.cpp
|
||||||
media-slider.cpp)
|
media-slider.cpp
|
||||||
|
undo-stack-obs.cpp)
|
||||||
|
|
||||||
set(obs_HEADERS
|
set(obs_HEADERS
|
||||||
${obs_PLATFORM_HEADERS}
|
${obs_PLATFORM_HEADERS}
|
||||||
@ -327,7 +328,8 @@ set(obs_HEADERS
|
|||||||
log-viewer.hpp
|
log-viewer.hpp
|
||||||
obs-proxy-style.hpp
|
obs-proxy-style.hpp
|
||||||
obs-proxy-style.hpp
|
obs-proxy-style.hpp
|
||||||
media-slider.hpp)
|
media-slider.hpp
|
||||||
|
undo-stack-obs.hpp)
|
||||||
|
|
||||||
set(obs_importers_HEADERS
|
set(obs_importers_HEADERS
|
||||||
importers/importers.hpp)
|
importers/importers.hpp)
|
||||||
|
@ -586,6 +586,9 @@
|
|||||||
<string>Paste.Filters</string>
|
<string>Paste.Filters</string>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
|
<addaction name="actionMainUndo"/>
|
||||||
|
<addaction name="actionMainRedo"/>
|
||||||
|
<addaction name="separator"/>
|
||||||
<addaction name="actionCopySource"/>
|
<addaction name="actionCopySource"/>
|
||||||
<addaction name="actionPasteRef"/>
|
<addaction name="actionPasteRef"/>
|
||||||
<addaction name="actionPasteDup"/>
|
<addaction name="actionPasteDup"/>
|
||||||
@ -599,6 +602,7 @@
|
|||||||
<addaction name="actionLockPreview"/>
|
<addaction name="actionLockPreview"/>
|
||||||
<addaction name="separator"/>
|
<addaction name="separator"/>
|
||||||
<addaction name="actionAdvAudioProperties"/>
|
<addaction name="actionAdvAudioProperties"/>
|
||||||
|
<addaction name="separator"/>
|
||||||
</widget>
|
</widget>
|
||||||
<widget class="QMenu" name="profileMenu">
|
<widget class="QMenu" name="profileMenu">
|
||||||
<property name="title">
|
<property name="title">
|
||||||
@ -2034,7 +2038,23 @@
|
|||||||
<string>Basic.MainMenu.View.ContextBar</string>
|
<string>Basic.MainMenu.View.ContextBar</string>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
</widget>
|
<action name="actionMainUndo">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Undo</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionMainRedo">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Redo</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
</widget>
|
||||||
<customwidgets>
|
<customwidgets>
|
||||||
<customwidget>
|
<customwidget>
|
||||||
<class>OBSBasicPreview</class>
|
<class>OBSBasicPreview</class>
|
||||||
|
@ -403,6 +403,34 @@ void SourceTreeItem::ExitEditMode(bool save)
|
|||||||
/* rename */
|
/* rename */
|
||||||
|
|
||||||
SignalBlocker sourcesSignalBlocker(this);
|
SignalBlocker sourcesSignalBlocker(this);
|
||||||
|
std::string prevName(obs_source_get_name(source));
|
||||||
|
std::string scene_name =
|
||||||
|
obs_source_get_name(main->GetCurrentSceneSource());
|
||||||
|
auto undo = [scene_name, prevName, main](const std::string &data) {
|
||||||
|
obs_source_t *source = obs_get_source_by_name(data.c_str());
|
||||||
|
obs_source_set_name(source, prevName.c_str());
|
||||||
|
obs_source_release(source);
|
||||||
|
|
||||||
|
obs_source_t *scene_source =
|
||||||
|
obs_get_source_by_name(scene_name.c_str());
|
||||||
|
main->SetCurrentScene(scene_source);
|
||||||
|
obs_source_release(scene_source);
|
||||||
|
};
|
||||||
|
|
||||||
|
auto redo = [scene_name, main, newName](const std::string &data) {
|
||||||
|
obs_source_t *source = obs_get_source_by_name(data.c_str());
|
||||||
|
obs_source_set_name(source, newName.c_str());
|
||||||
|
obs_source_release(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->undo_s.add_action(QTStr("Undo.Rename").arg(newName.c_str()), undo,
|
||||||
|
redo, newName, prevName, NULL);
|
||||||
|
|
||||||
obs_source_set_name(source, newName.c_str());
|
obs_source_set_name(source, newName.c_str());
|
||||||
label->setText(QT_UTF8(newName.c_str()));
|
label->setText(QT_UTF8(newName.c_str()));
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,10 @@
|
|||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
#include <ctime>
|
#include <ctime>
|
||||||
|
#include <obs-data.h>
|
||||||
|
#include <obs.h>
|
||||||
#include <obs.hpp>
|
#include <obs.hpp>
|
||||||
#include <QGuiApplication>
|
#include <QGuiApplication>
|
||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
@ -58,6 +61,7 @@
|
|||||||
#include "remote-text.hpp"
|
#include "remote-text.hpp"
|
||||||
#include "ui-validation.hpp"
|
#include "ui-validation.hpp"
|
||||||
#include "media-controls.hpp"
|
#include "media-controls.hpp"
|
||||||
|
#include "undo-stack-obs.hpp"
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
||||||
@ -203,7 +207,7 @@ extern void RegisterTwitchAuth();
|
|||||||
extern void RegisterRestreamAuth();
|
extern void RegisterRestreamAuth();
|
||||||
|
|
||||||
OBSBasic::OBSBasic(QWidget *parent)
|
OBSBasic::OBSBasic(QWidget *parent)
|
||||||
: OBSMainWindow(parent), ui(new Ui::OBSBasic)
|
: OBSMainWindow(parent), undo_s(ui), ui(new Ui::OBSBasic)
|
||||||
{
|
{
|
||||||
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
|
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
|
||||||
qRegisterMetaTypeStreamOperators<SignalContainer<OBSScene>>(
|
qRegisterMetaTypeStreamOperators<SignalContainer<OBSScene>>(
|
||||||
@ -366,6 +370,16 @@ OBSBasic::OBSBasic(QWidget *parent)
|
|||||||
assignDockToggle(ui->controlsDock, ui->toggleControls);
|
assignDockToggle(ui->controlsDock, ui->toggleControls);
|
||||||
assignDockToggle(statsDock, ui->toggleStats);
|
assignDockToggle(statsDock, ui->toggleStats);
|
||||||
|
|
||||||
|
// Register shortcuts for Undo/Redo
|
||||||
|
ui->actionMainUndo->setShortcut(Qt::CTRL + Qt::Key_Z);
|
||||||
|
QList<QKeySequence> shrt;
|
||||||
|
shrt << QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_Z)
|
||||||
|
<< QKeySequence(Qt::CTRL + Qt::Key_Y);
|
||||||
|
ui->actionMainRedo->setShortcuts(shrt);
|
||||||
|
|
||||||
|
ui->actionMainUndo->setShortcutContext(Qt::ApplicationShortcut);
|
||||||
|
ui->actionMainRedo->setShortcutContext(Qt::ApplicationShortcut);
|
||||||
|
|
||||||
//hide all docking panes
|
//hide all docking panes
|
||||||
ui->toggleScenes->setChecked(false);
|
ui->toggleScenes->setChecked(false);
|
||||||
ui->toggleSources->setChecked(false);
|
ui->toggleSources->setChecked(false);
|
||||||
@ -3622,6 +3636,33 @@ void OBSBasic::DuplicateSelectedScene()
|
|||||||
OBS_SCENE_DUP_REFS);
|
OBS_SCENE_DUP_REFS);
|
||||||
source = obs_scene_get_source(scene);
|
source = obs_scene_get_source(scene);
|
||||||
SetCurrentScene(source, true);
|
SetCurrentScene(source, true);
|
||||||
|
|
||||||
|
auto undo = [](const std::string &data) {
|
||||||
|
obs_source_t *source =
|
||||||
|
obs_get_source_by_name(data.c_str());
|
||||||
|
obs_source_remove(source);
|
||||||
|
obs_source_release(source);
|
||||||
|
};
|
||||||
|
|
||||||
|
auto redo = [this, name](const std::string &data) {
|
||||||
|
obs_source_t *source =
|
||||||
|
obs_get_source_by_name(data.c_str());
|
||||||
|
obs_scene_t *scene = obs_scene_from_source(source);
|
||||||
|
obs_source_release(source);
|
||||||
|
scene = obs_scene_duplicate(scene, name.c_str(),
|
||||||
|
OBS_SCENE_DUP_REFS);
|
||||||
|
source = obs_scene_get_source(scene);
|
||||||
|
SetCurrentScene(source, true);
|
||||||
|
obs_scene_release(scene);
|
||||||
|
};
|
||||||
|
|
||||||
|
undo_s.add_action(
|
||||||
|
QTStr("Undo.Scene.Duplicate")
|
||||||
|
.arg(obs_source_get_name(source)),
|
||||||
|
undo, redo, obs_source_get_name(source),
|
||||||
|
obs_source_get_name(obs_scene_get_source(curScene)),
|
||||||
|
NULL);
|
||||||
|
|
||||||
obs_scene_release(scene);
|
obs_scene_release(scene);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
@ -3631,15 +3672,107 @@ void OBSBasic::DuplicateSelectedScene()
|
|||||||
void OBSBasic::RemoveSelectedScene()
|
void OBSBasic::RemoveSelectedScene()
|
||||||
{
|
{
|
||||||
OBSScene scene = GetCurrentScene();
|
OBSScene scene = GetCurrentScene();
|
||||||
if (scene) {
|
obs_source_t *source = obs_scene_get_source(scene);
|
||||||
obs_source_t *source = obs_scene_get_source(scene);
|
|
||||||
if (QueryRemoveSource(source)) {
|
|
||||||
obs_source_remove(source);
|
|
||||||
|
|
||||||
if (api)
|
OBSSource curProgramScene = OBSGetStrongRef(programScene);
|
||||||
api->on_event(
|
|
||||||
OBS_FRONTEND_EVENT_SCENE_LIST_CHANGED);
|
if (source && QueryRemoveSource(source)) {
|
||||||
}
|
vector<std::string> item_ids;
|
||||||
|
obs_data_t *wrapper = obs_save_source(source);
|
||||||
|
obs_data_array_t *arr = obs_data_array_create();
|
||||||
|
struct wrap {
|
||||||
|
obs_data_array_t *arr;
|
||||||
|
vector<std::string> &items;
|
||||||
|
};
|
||||||
|
|
||||||
|
wrap passthrough = {arr, item_ids};
|
||||||
|
obs_scene_enum_items(
|
||||||
|
scene,
|
||||||
|
[](obs_scene_t *, obs_sceneitem_t *item,
|
||||||
|
void *vp_wrap) {
|
||||||
|
wrap *passthrough = (wrap *)vp_wrap;
|
||||||
|
passthrough->items.push_back(obs_source_get_name(
|
||||||
|
obs_sceneitem_get_source(item)));
|
||||||
|
obs_data_array_t *arr = passthrough->arr;
|
||||||
|
obs_sceneitem_save(item, arr);
|
||||||
|
obs_source_addref(
|
||||||
|
obs_sceneitem_get_source(item));
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
(void *)&passthrough);
|
||||||
|
obs_data_array_t *list_order = SaveSceneListOrder();
|
||||||
|
obs_data_set_array(wrapper, "arr", arr);
|
||||||
|
obs_data_set_array(wrapper, "list_order", list_order);
|
||||||
|
obs_data_set_string(wrapper, "name",
|
||||||
|
obs_source_get_name(source));
|
||||||
|
|
||||||
|
auto d = [item_ids](bool remove_ref) {
|
||||||
|
for (auto &item : item_ids) {
|
||||||
|
obs_source_t *source =
|
||||||
|
obs_get_source_by_name(item.c_str());
|
||||||
|
blog(LOG_INFO, "%s", item.c_str());
|
||||||
|
if (remove_ref) {
|
||||||
|
obs_source_release(source);
|
||||||
|
obs_source_release(source);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
auto undo = [this, d](const std::string &data) {
|
||||||
|
obs_data_t *dat =
|
||||||
|
obs_data_create_from_json(data.c_str());
|
||||||
|
obs_source_release(obs_load_source(dat));
|
||||||
|
obs_data_array_t *arr = obs_data_get_array(dat, "arr");
|
||||||
|
obs_data_array_t *list_order =
|
||||||
|
obs_data_get_array(dat, "list_order");
|
||||||
|
const char *sname = obs_data_get_string(dat, "name");
|
||||||
|
obs_source_t *source = obs_get_source_by_name(sname);
|
||||||
|
obs_scene_t *scene = obs_scene_from_source(source);
|
||||||
|
|
||||||
|
obs_sceneitems_add(scene, arr);
|
||||||
|
LoadSceneListOrder(list_order);
|
||||||
|
SetCurrentScene(source);
|
||||||
|
|
||||||
|
obs_data_release(dat);
|
||||||
|
obs_data_array_release(arr);
|
||||||
|
obs_data_array_release(list_order);
|
||||||
|
obs_source_release(source);
|
||||||
|
|
||||||
|
d(true);
|
||||||
|
};
|
||||||
|
obs_data_t *rwrapper = obs_data_create();
|
||||||
|
obs_data_set_string(rwrapper, "name",
|
||||||
|
obs_source_get_name(source));
|
||||||
|
auto redo = [d](const std::string &data) {
|
||||||
|
obs_data_t *dat =
|
||||||
|
obs_data_create_from_json(data.c_str());
|
||||||
|
obs_source_t *source = obs_get_source_by_name(
|
||||||
|
obs_data_get_string(dat, "name"));
|
||||||
|
obs_source_remove(source);
|
||||||
|
obs_source_release(source);
|
||||||
|
obs_data_release(dat);
|
||||||
|
|
||||||
|
d(false);
|
||||||
|
};
|
||||||
|
|
||||||
|
std::string undo_data = obs_data_get_json(wrapper);
|
||||||
|
std::string redo_data = obs_data_get_json(wrapper);
|
||||||
|
undo_s.add_action(
|
||||||
|
QTStr("Undo.Delete").arg(obs_source_get_name(source)),
|
||||||
|
undo, redo, undo_data, redo_data, [d](bool undo) {
|
||||||
|
if (undo) {
|
||||||
|
d(true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
obs_source_remove(source);
|
||||||
|
obs_data_release(wrapper);
|
||||||
|
obs_data_release(rwrapper);
|
||||||
|
obs_data_array_release(arr);
|
||||||
|
obs_data_array_release(list_order);
|
||||||
|
|
||||||
|
if (api)
|
||||||
|
api->on_event(OBS_FRONTEND_EVENT_SCENE_LIST_CHANGED);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4330,6 +4463,7 @@ void OBSBasic::closeEvent(QCloseEvent *event)
|
|||||||
|
|
||||||
/* Clear all scene data (dialogs, widgets, widget sub-items, scenes,
|
/* Clear all scene data (dialogs, widgets, widget sub-items, scenes,
|
||||||
* sources, etc) so that all references are released before shutdown */
|
* sources, etc) so that all references are released before shutdown */
|
||||||
|
undo_s.release();
|
||||||
ClearSceneData();
|
ClearSceneData();
|
||||||
|
|
||||||
App()->quit();
|
App()->quit();
|
||||||
@ -4686,20 +4820,34 @@ void OBSBasic::on_actionAddScene_triggered()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto undo_fn = [](const std::string &data) {
|
||||||
|
obs_source_t *t = obs_get_source_by_name(data.c_str());
|
||||||
|
if (t) {
|
||||||
|
obs_source_release(t);
|
||||||
|
obs_source_remove(t);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
auto redo_fn = [this](const std::string &data) {
|
||||||
|
obs_scene_t *scene = obs_scene_create(data.c_str());
|
||||||
|
obs_source_t *source = obs_scene_get_source(scene);
|
||||||
|
SetCurrentScene(source);
|
||||||
|
obs_scene_release(scene);
|
||||||
|
};
|
||||||
|
undo_s.add_action(QTStr("Undo.Add").arg(QString(name.c_str())),
|
||||||
|
undo_fn, redo_fn, name, name, NULL);
|
||||||
|
|
||||||
obs_scene_t *scene = obs_scene_create(name.c_str());
|
obs_scene_t *scene = obs_scene_create(name.c_str());
|
||||||
source = obs_scene_get_source(scene);
|
source = obs_scene_get_source(scene);
|
||||||
SetCurrentScene(source);
|
SetCurrentScene(source);
|
||||||
|
RefreshSources(scene);
|
||||||
obs_scene_release(scene);
|
obs_scene_release(scene);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void OBSBasic::on_actionRemoveScene_triggered()
|
void OBSBasic::on_actionRemoveScene_triggered()
|
||||||
{
|
{
|
||||||
OBSScene scene = GetCurrentScene();
|
RemoveSelectedScene();
|
||||||
obs_source_t *source = obs_scene_get_source(scene);
|
|
||||||
|
|
||||||
if (source && QueryRemoveSource(source))
|
|
||||||
obs_source_remove(source);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void OBSBasic::ChangeSceneIndex(bool relative, int offset, int invalidIdx)
|
void OBSBasic::ChangeSceneIndex(bool relative, int offset, int invalidIdx)
|
||||||
@ -5109,10 +5257,11 @@ void OBSBasic::on_scenes_itemDoubleClicked(QListWidgetItem *witem)
|
|||||||
void OBSBasic::AddSource(const char *id)
|
void OBSBasic::AddSource(const char *id)
|
||||||
{
|
{
|
||||||
if (id && *id) {
|
if (id && *id) {
|
||||||
OBSBasicSourceSelect sourceSelect(this, id);
|
OBSBasicSourceSelect sourceSelect(this, id, undo_s);
|
||||||
sourceSelect.exec();
|
sourceSelect.exec();
|
||||||
if (sourceSelect.newSource && strcmp(id, "group") != 0)
|
if (sourceSelect.newSource && strcmp(id, "group") != 0) {
|
||||||
CreatePropertiesWindow(sourceSelect.newSource);
|
CreatePropertiesWindow(sourceSelect.newSource);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -5253,9 +5402,11 @@ void OBSBasic::on_actionRemoveSource_triggered()
|
|||||||
if (!items.size())
|
if (!items.size())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
auto removeMultiple = [this](size_t count) {
|
bool confirmed = false;
|
||||||
|
|
||||||
|
if (items.size() > 1) {
|
||||||
QString text = QTStr("ConfirmRemove.TextMultiple")
|
QString text = QTStr("ConfirmRemove.TextMultiple")
|
||||||
.arg(QString::number(count));
|
.arg(QString::number(items.size()));
|
||||||
|
|
||||||
QMessageBox remove_items(this);
|
QMessageBox remove_items(this);
|
||||||
remove_items.setText(text);
|
remove_items.setText(text);
|
||||||
@ -5267,21 +5418,139 @@ void OBSBasic::on_actionRemoveSource_triggered()
|
|||||||
remove_items.setWindowTitle(QTStr("ConfirmRemove.Title"));
|
remove_items.setWindowTitle(QTStr("ConfirmRemove.Title"));
|
||||||
remove_items.exec();
|
remove_items.exec();
|
||||||
|
|
||||||
return Yes == remove_items.clickedButton();
|
confirmed = remove_items.clickedButton();
|
||||||
};
|
} else {
|
||||||
|
|
||||||
if (items.size() == 1) {
|
|
||||||
OBSSceneItem &item = items[0];
|
OBSSceneItem &item = items[0];
|
||||||
obs_source_t *source = obs_sceneitem_get_source(item);
|
obs_source_t *source = obs_sceneitem_get_source(item);
|
||||||
|
|
||||||
if (source && QueryRemoveSource(source))
|
if (source && QueryRemoveSource(source))
|
||||||
obs_sceneitem_remove(item);
|
confirmed = true;
|
||||||
} else {
|
|
||||||
if (removeMultiple(items.size())) {
|
|
||||||
for (auto &item : items)
|
|
||||||
obs_sceneitem_remove(item);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
if (!confirmed)
|
||||||
|
return;
|
||||||
|
|
||||||
|
struct source_save {
|
||||||
|
std::string name;
|
||||||
|
std::string scene_name;
|
||||||
|
int pos;
|
||||||
|
bool in_group = false;
|
||||||
|
int64_t group_id;
|
||||||
|
};
|
||||||
|
vector<source_save> item_save;
|
||||||
|
|
||||||
|
obs_data_t *wrapper = obs_data_create();
|
||||||
|
obs_data_array_t *data = obs_data_array_create();
|
||||||
|
for (const auto &item : items) {
|
||||||
|
obs_sceneitem_save(item, data);
|
||||||
|
obs_source_t *source = obs_sceneitem_get_source(item);
|
||||||
|
obs_source_addref(source);
|
||||||
|
obs_source_set_hidden(source, true);
|
||||||
|
|
||||||
|
obs_sceneitem_t *grp =
|
||||||
|
obs_sceneitem_get_group(GetCurrentScene(), item);
|
||||||
|
obs_scene_t *scene = obs_sceneitem_get_scene(item);
|
||||||
|
source_save save = {
|
||||||
|
obs_source_get_name(source),
|
||||||
|
obs_source_get_name(obs_scene_get_source(scene)),
|
||||||
|
obs_sceneitem_get_order_position(item),
|
||||||
|
grp ? true : false, obs_sceneitem_get_id(grp)};
|
||||||
|
|
||||||
|
item_save.push_back(save);
|
||||||
|
}
|
||||||
|
|
||||||
|
obs_scene_t *scene = GetCurrentScene();
|
||||||
|
const char *name = obs_source_get_name(obs_scene_get_source(scene));
|
||||||
|
obs_data_set_array(wrapper, "data_array", data);
|
||||||
|
obs_data_set_string(wrapper, "name", name);
|
||||||
|
std::string undo_data(obs_data_get_json(wrapper));
|
||||||
|
|
||||||
|
auto undo_fn = [this, item_save](const std::string &data) {
|
||||||
|
obs_data_t *dat = obs_data_create_from_json(data.c_str());
|
||||||
|
obs_data_array_t *sources_data =
|
||||||
|
obs_data_get_array(dat, "data_array");
|
||||||
|
const char *name = obs_data_get_string(dat, "name");
|
||||||
|
obs_source_t *src = obs_get_source_by_name(name);
|
||||||
|
obs_scene_t *scene = obs_scene_from_source(src);
|
||||||
|
|
||||||
|
obs_sceneitems_add(scene, sources_data);
|
||||||
|
SetCurrentScene(scene);
|
||||||
|
|
||||||
|
for (const auto &save : item_save) {
|
||||||
|
obs_source_t *source =
|
||||||
|
obs_get_source_by_name(save.name.c_str());
|
||||||
|
obs_source_set_hidden(source, false);
|
||||||
|
if (save.in_group) {
|
||||||
|
obs_sceneitem_t *grp =
|
||||||
|
obs_scene_find_sceneitem_by_id(
|
||||||
|
scene, save.group_id);
|
||||||
|
obs_sceneitem_t *item =
|
||||||
|
obs_scene_sceneitem_from_source(scene,
|
||||||
|
source);
|
||||||
|
obs_sceneitem_group_add_item(grp, item);
|
||||||
|
obs_sceneitem_set_order_position(item,
|
||||||
|
save.pos);
|
||||||
|
|
||||||
|
obs_sceneitem_release(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
obs_source_release(source);
|
||||||
|
obs_source_release(source);
|
||||||
|
}
|
||||||
|
|
||||||
|
obs_source_release(src);
|
||||||
|
obs_data_array_release(sources_data);
|
||||||
|
obs_data_release(dat);
|
||||||
|
};
|
||||||
|
|
||||||
|
auto redo_fn = [item_save](const std::string &) {
|
||||||
|
for (const auto &save : item_save) {
|
||||||
|
obs_source_t *source =
|
||||||
|
obs_get_source_by_name(save.name.c_str());
|
||||||
|
obs_source_t *scene_source =
|
||||||
|
obs_get_source_by_name(save.scene_name.c_str());
|
||||||
|
obs_scene_t *scene =
|
||||||
|
obs_scene_from_source(scene_source);
|
||||||
|
if (!scene)
|
||||||
|
scene = obs_group_from_source(scene_source);
|
||||||
|
|
||||||
|
obs_sceneitem_t *item =
|
||||||
|
obs_scene_sceneitem_from_source(scene, source);
|
||||||
|
obs_sceneitem_remove(item);
|
||||||
|
obs_source_set_hidden(source, true);
|
||||||
|
|
||||||
|
obs_sceneitem_release(item);
|
||||||
|
obs_source_release(scene_source);
|
||||||
|
/* usually want to release source, but redo needs to add a reference to keep alive */
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
auto d = [item_save](bool is_undo) {
|
||||||
|
if (!is_undo)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (const auto &item : item_save) {
|
||||||
|
obs_source_t *source =
|
||||||
|
obs_get_source_by_name(item.name.c_str());
|
||||||
|
obs_source_release(source);
|
||||||
|
obs_source_release(source);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
QString action_name;
|
||||||
|
if (items.size() > 1)
|
||||||
|
action_name = QTStr("Undo.Sources.Multi")
|
||||||
|
.arg(QString::number(items.size()));
|
||||||
|
else
|
||||||
|
action_name =
|
||||||
|
QTStr("Undo.Delete")
|
||||||
|
.arg(QString(obs_source_get_name(
|
||||||
|
obs_sceneitem_get_source(items[0]))));
|
||||||
|
undo_s.add_action(action_name, undo_fn, redo_fn, undo_data, "", d);
|
||||||
|
|
||||||
|
obs_data_array_release(data);
|
||||||
|
obs_data_release(wrapper);
|
||||||
|
|
||||||
|
for (auto &item : items)
|
||||||
|
obs_sceneitem_remove(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
void OBSBasic::on_actionInteract_triggered()
|
void OBSBasic::on_actionInteract_triggered()
|
||||||
@ -5519,6 +5788,27 @@ static void RenameListItem(OBSBasic *parent, QListWidget *listWidget,
|
|||||||
|
|
||||||
obs_source_release(foundSource);
|
obs_source_release(foundSource);
|
||||||
} else {
|
} else {
|
||||||
|
auto undo = [prev = std::string(prevName)](
|
||||||
|
const std::string &data) {
|
||||||
|
obs_source_t *source =
|
||||||
|
obs_get_source_by_name(data.c_str());
|
||||||
|
obs_source_set_name(source, prev.c_str());
|
||||||
|
obs_source_release(source);
|
||||||
|
};
|
||||||
|
|
||||||
|
auto redo = [name](const std::string &data) {
|
||||||
|
obs_source_t *source =
|
||||||
|
obs_get_source_by_name(data.c_str());
|
||||||
|
obs_source_set_name(source, name.c_str());
|
||||||
|
obs_source_release(source);
|
||||||
|
};
|
||||||
|
|
||||||
|
std::string undo_data(name);
|
||||||
|
std::string redo_data(prevName);
|
||||||
|
parent->undo_s.add_action(
|
||||||
|
QTStr("Undo.Rename").arg(name.c_str()), undo, redo,
|
||||||
|
undo_data, redo_data, NULL);
|
||||||
|
|
||||||
listItem->setText(QT_UTF8(name.c_str()));
|
listItem->setText(QT_UTF8(name.c_str()));
|
||||||
obs_source_set_name(source, name.c_str());
|
obs_source_set_name(source, name.c_str());
|
||||||
}
|
}
|
||||||
@ -7762,6 +8052,16 @@ bool OBSBasic::sysTrayMinimizeToTray()
|
|||||||
"SysTrayMinimizeToTray");
|
"SysTrayMinimizeToTray");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void OBSBasic::on_actionMainUndo_triggered()
|
||||||
|
{
|
||||||
|
undo_s.undo();
|
||||||
|
}
|
||||||
|
|
||||||
|
void OBSBasic::on_actionMainRedo_triggered()
|
||||||
|
{
|
||||||
|
undo_s.redo();
|
||||||
|
}
|
||||||
|
|
||||||
void OBSBasic::on_actionCopySource_triggered()
|
void OBSBasic::on_actionCopySource_triggered()
|
||||||
{
|
{
|
||||||
copyStrings.clear();
|
copyStrings.clear();
|
||||||
|
@ -36,6 +36,7 @@
|
|||||||
#include "window-basic-about.hpp"
|
#include "window-basic-about.hpp"
|
||||||
#include "auth-base.hpp"
|
#include "auth-base.hpp"
|
||||||
#include "log-viewer.hpp"
|
#include "log-viewer.hpp"
|
||||||
|
#include "undo-stack-obs.hpp"
|
||||||
|
|
||||||
#include <obs-frontend-internal.hpp>
|
#include <obs-frontend-internal.hpp>
|
||||||
|
|
||||||
@ -166,6 +167,7 @@ class OBSBasic : public OBSMainWindow {
|
|||||||
friend class ExtraBrowsersDelegate;
|
friend class ExtraBrowsersDelegate;
|
||||||
friend class DeviceCaptureToolbar;
|
friend class DeviceCaptureToolbar;
|
||||||
friend class DeviceToolbarPropertiesThread;
|
friend class DeviceToolbarPropertiesThread;
|
||||||
|
friend class OBSBasicSourceSelect;
|
||||||
friend struct BasicOutputHandler;
|
friend struct BasicOutputHandler;
|
||||||
friend struct OBSStudioAPI;
|
friend struct OBSStudioAPI;
|
||||||
|
|
||||||
@ -608,6 +610,10 @@ public slots:
|
|||||||
void UnpauseRecording();
|
void UnpauseRecording();
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
|
|
||||||
|
void on_actionMainUndo_triggered();
|
||||||
|
void on_actionMainRedo_triggered();
|
||||||
|
|
||||||
void AddSceneItem(OBSSceneItem item);
|
void AddSceneItem(OBSSceneItem item);
|
||||||
void AddScene(OBSSource source);
|
void AddScene(OBSSource source);
|
||||||
void RemoveScene(OBSSource source);
|
void RemoveScene(OBSSource source);
|
||||||
@ -740,6 +746,7 @@ private:
|
|||||||
OBSSource prevFTBSource = nullptr;
|
OBSSource prevFTBSource = nullptr;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
undo_stack undo_s;
|
||||||
OBSSource GetProgramSource();
|
OBSSource GetProgramSource();
|
||||||
OBSScene GetCurrentScene();
|
OBSScene GetCurrentScene();
|
||||||
|
|
||||||
|
@ -28,6 +28,9 @@ struct AddSourceData {
|
|||||||
|
|
||||||
bool OBSBasicSourceSelect::EnumSources(void *data, obs_source_t *source)
|
bool OBSBasicSourceSelect::EnumSources(void *data, obs_source_t *source)
|
||||||
{
|
{
|
||||||
|
if (obs_source_is_hidden(source))
|
||||||
|
return false;
|
||||||
|
|
||||||
OBSBasicSourceSelect *window =
|
OBSBasicSourceSelect *window =
|
||||||
static_cast<OBSBasicSourceSelect *>(data);
|
static_cast<OBSBasicSourceSelect *>(data);
|
||||||
const char *name = obs_source_get_name(source);
|
const char *name = obs_source_get_name(source);
|
||||||
@ -179,7 +182,7 @@ bool AddNew(QWidget *parent, const char *id, const char *name,
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
obs_source_t *source = obs_get_source_by_name(name);
|
obs_source_t *source = obs_get_source_by_name(name);
|
||||||
if (source) {
|
if (source && parent) {
|
||||||
OBSMessageBox::information(parent, QTStr("NameExists.Title"),
|
OBSMessageBox::information(parent, QTStr("NameExists.Title"),
|
||||||
QTStr("NameExists.Text"));
|
QTStr("NameExists.Text"));
|
||||||
|
|
||||||
@ -236,6 +239,63 @@ void OBSBasicSourceSelect::on_buttonBox_accepted()
|
|||||||
if (!AddNew(this, id, QT_TO_UTF8(ui->sourceName->text()),
|
if (!AddNew(this, id, QT_TO_UTF8(ui->sourceName->text()),
|
||||||
visible, newSource))
|
visible, newSource))
|
||||||
return;
|
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);
|
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>();
|
return item->data(static_cast<int>(QtDataRole::OBSRef)).value<T>();
|
||||||
}
|
}
|
||||||
|
|
||||||
OBSBasicSourceSelect::OBSBasicSourceSelect(OBSBasic *parent, const char *id_)
|
OBSBasicSourceSelect::OBSBasicSourceSelect(OBSBasic *parent, const char *id_,
|
||||||
: QDialog(parent), ui(new Ui::OBSBasicSourceSelect), id(id_)
|
undo_stack &undo_s)
|
||||||
|
: QDialog(parent),
|
||||||
|
ui(new Ui::OBSBasicSourceSelect),
|
||||||
|
id(id_),
|
||||||
|
undo_s(undo_s)
|
||||||
{
|
{
|
||||||
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
|
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
|
||||||
|
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
#include "ui_OBSBasicSourceSelect.h"
|
#include "ui_OBSBasicSourceSelect.h"
|
||||||
|
#include "undo-stack-obs.hpp"
|
||||||
|
|
||||||
class OBSBasic;
|
class OBSBasic;
|
||||||
|
|
||||||
@ -30,6 +31,7 @@ class OBSBasicSourceSelect : public QDialog {
|
|||||||
private:
|
private:
|
||||||
std::unique_ptr<Ui::OBSBasicSourceSelect> ui;
|
std::unique_ptr<Ui::OBSBasicSourceSelect> ui;
|
||||||
const char *id;
|
const char *id;
|
||||||
|
undo_stack &undo_s;
|
||||||
|
|
||||||
static bool EnumSources(void *data, obs_source_t *source);
|
static bool EnumSources(void *data, obs_source_t *source);
|
||||||
static bool EnumGroups(void *data, obs_source_t *source);
|
static bool EnumGroups(void *data, obs_source_t *source);
|
||||||
@ -45,7 +47,8 @@ private slots:
|
|||||||
void SourceRemoved(OBSSource source);
|
void SourceRemoved(OBSSource source);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
OBSBasicSourceSelect(OBSBasic *parent, const char *id);
|
OBSBasicSourceSelect(OBSBasic *parent, const char *id,
|
||||||
|
undo_stack &undo_s);
|
||||||
|
|
||||||
OBSSource newSource;
|
OBSSource newSource;
|
||||||
|
|
||||||
|
@ -621,6 +621,9 @@ struct obs_source {
|
|||||||
* to handle things but it's the best option) */
|
* to handle things but it's the best option) */
|
||||||
bool removed;
|
bool removed;
|
||||||
|
|
||||||
|
/* used to indicate if the source should show up when queried for user ui */
|
||||||
|
bool temp_removed;
|
||||||
|
|
||||||
bool active;
|
bool active;
|
||||||
bool showing;
|
bool showing;
|
||||||
|
|
||||||
|
@ -1477,6 +1477,33 @@ obs_sceneitem_t *obs_scene_find_source_recursive(obs_scene_t *scene,
|
|||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct sceneitem_check {
|
||||||
|
obs_source_t *source_in;
|
||||||
|
obs_sceneitem_t *item_out;
|
||||||
|
};
|
||||||
|
|
||||||
|
bool check_sceneitem_exists(obs_scene_t *scene, obs_sceneitem_t *item,
|
||||||
|
void *vp_check)
|
||||||
|
{
|
||||||
|
UNUSED_PARAMETER(scene);
|
||||||
|
struct sceneitem_check *check = (struct sceneitem_check *)vp_check;
|
||||||
|
if (obs_sceneitem_get_source(item) == check->source_in) {
|
||||||
|
check->item_out = item;
|
||||||
|
obs_sceneitem_addref(item);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
obs_sceneitem_t *obs_scene_sceneitem_from_source(obs_scene_t *scene,
|
||||||
|
obs_source_t *source)
|
||||||
|
{
|
||||||
|
struct sceneitem_check check = {source, NULL};
|
||||||
|
obs_scene_enum_items(scene, check_sceneitem_exists, (void *)&check);
|
||||||
|
return check.item_out;
|
||||||
|
}
|
||||||
|
|
||||||
obs_sceneitem_t *obs_scene_find_sceneitem_by_id(obs_scene_t *scene, int64_t id)
|
obs_sceneitem_t *obs_scene_find_sceneitem_by_id(obs_scene_t *scene, int64_t id)
|
||||||
{
|
{
|
||||||
struct obs_scene_item *item;
|
struct obs_scene_item *item;
|
||||||
@ -1830,6 +1857,22 @@ void obs_sceneitem_remove(obs_sceneitem_t *item)
|
|||||||
obs_sceneitem_release(item);
|
obs_sceneitem_release(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void obs_sceneitem_save(obs_sceneitem_t *item, obs_data_array_t *arr)
|
||||||
|
{
|
||||||
|
scene_save_item(arr, item, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
void sceneitem_restore(obs_data_t *data, void *vp)
|
||||||
|
{
|
||||||
|
obs_scene_t *scene = (obs_scene_t *)vp;
|
||||||
|
scene_load_item(scene, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
void obs_sceneitems_add(obs_scene_t *scene, obs_data_array_t *data)
|
||||||
|
{
|
||||||
|
obs_data_array_enum(data, sceneitem_restore, scene);
|
||||||
|
}
|
||||||
|
|
||||||
obs_scene_t *obs_sceneitem_get_scene(const obs_sceneitem_t *item)
|
obs_scene_t *obs_sceneitem_get_scene(const obs_sceneitem_t *item)
|
||||||
{
|
{
|
||||||
return item ? item->parent : NULL;
|
return item ? item->parent : NULL;
|
||||||
@ -1977,6 +2020,24 @@ void obs_sceneitem_set_order(obs_sceneitem_t *item,
|
|||||||
obs_scene_release(scene);
|
obs_scene_release(scene);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int obs_sceneitem_get_order_position(obs_sceneitem_t *item)
|
||||||
|
{
|
||||||
|
struct obs_scene *scene = item->parent;
|
||||||
|
struct obs_scene_item *next = scene->first_item;
|
||||||
|
|
||||||
|
full_lock(scene);
|
||||||
|
|
||||||
|
int index = 0;
|
||||||
|
while (next && next != item) {
|
||||||
|
next = next->next;
|
||||||
|
++index;
|
||||||
|
}
|
||||||
|
|
||||||
|
full_unlock(scene);
|
||||||
|
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
void obs_sceneitem_set_order_position(obs_sceneitem_t *item, int position)
|
void obs_sceneitem_set_order_position(obs_sceneitem_t *item, int position)
|
||||||
{
|
{
|
||||||
if (!item)
|
if (!item)
|
||||||
@ -2385,6 +2446,11 @@ int64_t obs_sceneitem_get_id(const obs_sceneitem_t *item)
|
|||||||
return item->id;
|
return item->id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void obs_sceneitem_set_id(obs_sceneitem_t *item, int64_t id)
|
||||||
|
{
|
||||||
|
item->id = id;
|
||||||
|
}
|
||||||
|
|
||||||
obs_data_t *obs_sceneitem_get_private_settings(obs_sceneitem_t *item)
|
obs_data_t *obs_sceneitem_get_private_settings(obs_sceneitem_t *item)
|
||||||
{
|
{
|
||||||
if (!obs_ptr_valid(item, "obs_sceneitem_get_private_settings"))
|
if (!obs_ptr_valid(item, "obs_sceneitem_get_private_settings"))
|
||||||
|
@ -929,8 +929,9 @@ void obs_source_update(obs_source_t *source, obs_data_t *settings)
|
|||||||
if (!obs_source_valid(source, "obs_source_update"))
|
if (!obs_source_valid(source, "obs_source_update"))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (settings)
|
if (settings) {
|
||||||
obs_data_apply(source->context.settings, settings);
|
obs_data_apply(source->context.settings, settings);
|
||||||
|
}
|
||||||
|
|
||||||
if (source->info.output_flags & OBS_SOURCE_VIDEO) {
|
if (source->info.output_flags & OBS_SOURCE_VIDEO) {
|
||||||
os_atomic_inc_long(&source->defer_update_count);
|
os_atomic_inc_long(&source->defer_update_count);
|
||||||
@ -4283,6 +4284,16 @@ void obs_source_enum_filters(obs_source_t *source,
|
|||||||
pthread_mutex_unlock(&source->filter_mutex);
|
pthread_mutex_unlock(&source->filter_mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void obs_source_set_hidden(obs_source_t *source, bool hidden)
|
||||||
|
{
|
||||||
|
source->temp_removed = hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool obs_source_is_hidden(obs_source_t *source)
|
||||||
|
{
|
||||||
|
return source->temp_removed;
|
||||||
|
}
|
||||||
|
|
||||||
obs_source_t *obs_source_get_filter_by_name(obs_source_t *source,
|
obs_source_t *obs_source_get_filter_by_name(obs_source_t *source,
|
||||||
const char *name)
|
const char *name)
|
||||||
{
|
{
|
||||||
|
23
libobs/obs.h
23
libobs/obs.h
@ -898,6 +898,14 @@ EXPORT void obs_source_remove(obs_source_t *source);
|
|||||||
/** Returns true if the source should be released */
|
/** Returns true if the source should be released */
|
||||||
EXPORT bool obs_source_removed(const obs_source_t *source);
|
EXPORT bool obs_source_removed(const obs_source_t *source);
|
||||||
|
|
||||||
|
/** The 'hidden' flag is not the same as a sceneitem's visibility. It is a
|
||||||
|
* property the determines if it can be found through searches. **/
|
||||||
|
/** Simply sets a 'hidden' flag when the source is still alive but shouldn't be found */
|
||||||
|
EXPORT void obs_source_set_hidden(obs_source_t *source, bool hidden);
|
||||||
|
|
||||||
|
/** Returns the current 'hidden' state on the source */
|
||||||
|
EXPORT bool obs_source_is_hidden(obs_source_t *source);
|
||||||
|
|
||||||
/** Returns capability flags of a source */
|
/** Returns capability flags of a source */
|
||||||
EXPORT uint32_t obs_source_get_output_flags(const obs_source_t *source);
|
EXPORT uint32_t obs_source_get_output_flags(const obs_source_t *source);
|
||||||
|
|
||||||
@ -1578,6 +1586,21 @@ EXPORT void obs_sceneitem_release(obs_sceneitem_t *item);
|
|||||||
/** Removes a scene item. */
|
/** Removes a scene item. */
|
||||||
EXPORT void obs_sceneitem_remove(obs_sceneitem_t *item);
|
EXPORT void obs_sceneitem_remove(obs_sceneitem_t *item);
|
||||||
|
|
||||||
|
/** Adds a scene item. */
|
||||||
|
EXPORT void obs_sceneitems_add(obs_scene_t *scene, obs_data_array_t *data);
|
||||||
|
|
||||||
|
/** Saves Sceneitem into an array, arr **/
|
||||||
|
EXPORT void obs_sceneitem_save(obs_sceneitem_t *item, obs_data_array_t *arr);
|
||||||
|
|
||||||
|
/** Set the ID of a sceneitem */
|
||||||
|
EXPORT void obs_sceneitem_set_id(obs_sceneitem_t *sceneitem, int64_t id);
|
||||||
|
|
||||||
|
/** Tries to find the sceneitem of the source in a given scene. Returns NULL if not found */
|
||||||
|
EXPORT obs_sceneitem_t *obs_scene_sceneitem_from_source(obs_scene_t *scene,
|
||||||
|
obs_source_t *source);
|
||||||
|
/** Gets a sceneitem's order in its scene */
|
||||||
|
EXPORT int obs_sceneitem_get_order_position(obs_sceneitem_t *item);
|
||||||
|
|
||||||
/** Gets the scene parent associated with the scene item. */
|
/** Gets the scene parent associated with the scene item. */
|
||||||
EXPORT obs_scene_t *obs_sceneitem_get_scene(const obs_sceneitem_t *item);
|
EXPORT obs_scene_t *obs_sceneitem_get_scene(const obs_sceneitem_t *item);
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user