frontend: Replace transitions combobox direct access

This commit is contained in:
tytan652
2025-08-22 16:48:23 -04:00
committed by Ryan Foster
parent 11562b6696
commit 2962770813
5 changed files with 202 additions and 57 deletions
+4 -7
View File
@@ -74,14 +74,11 @@ void OBSStudioAPI::obs_frontend_set_current_scene(obs_source_t *scene)
void OBSStudioAPI::obs_frontend_get_transitions(struct obs_frontend_source_list *sources)
{
for (int i = 0; i < main->ui->transitions->count(); i++) {
OBSSource tr = main->ui->transitions->itemData(i).value<OBSSource>();
for (const auto &[uuid, transition] : main->transitions) {
obs_source_t *source = transition;
if (!tr)
continue;
if (obs_source_get_ref(tr) != nullptr)
da_push_back(sources->sources, &tr);
if (obs_source_get_ref(source) != nullptr)
da_push_back(sources->sources, &source);
}
}
+27 -1
View File
@@ -287,6 +287,32 @@ OBSBasic::OBSBasic(QWidget *parent) : OBSMainWindow(parent), undo_s(ui), ui(new
connect(controls, &OBSBasicControls::SettingsButtonClicked, this, &OBSBasic::on_action_Settings_triggered);
/* Set up transitions combobox connections */
connect(this, &OBSBasic::TransitionAdded, this, [this](const QString &name, const QString &uuid) {
QSignalBlocker sb(ui->transitions);
ui->transitions->addItem(name, uuid);
});
connect(this, &OBSBasic::TransitionRenamed, this, [this](const QString &uuid, const QString &newName) {
QSignalBlocker sb(ui->transitions);
ui->transitions->setItemText(ui->transitions->findData(uuid), newName);
});
connect(this, &OBSBasic::TransitionRemoved, this, [this](const QString &uuid) {
QSignalBlocker sb(ui->transitions);
ui->transitions->removeItem(ui->transitions->findData(uuid));
});
connect(this, &OBSBasic::TransitionsCleared, this, [this]() {
QSignalBlocker sb(ui->transitions);
ui->transitions->clear();
});
connect(this, &OBSBasic::CurrentTransitionChanged, this, [this](const QString &uuid) {
QSignalBlocker sb(ui->transitions);
ui->transitions->setCurrentIndex(ui->transitions->findData(uuid));
});
connect(ui->transitions, &QComboBox::currentIndexChanged, this,
[this]() { SetCurrentTransition(ui->transitions->currentData().toString()); });
startingDockLayout = saveState();
statsDock = new OBSDock();
@@ -971,7 +997,7 @@ void OBSBasic::OBSInit()
}
/* Modules can access frontend information (i.e. profile and scene collection data) during their initialization, and some modules (e.g. obs-websockets) are known to use the filesystem location of the current profile in their own code.
Thus the profile and scene collection discovery needs to happen before any access to that information (but after intializing global settings) to ensure legacy code gets valid path information.
*/
RefreshSceneCollections(true);
+19 -1
View File
@@ -1476,6 +1476,13 @@ private:
std::vector<OBSDataAutoRelease> safeModeTransitions;
QPointer<QPushButton> transitionButton;
QPointer<QMenu> perSceneTransitionMenu;
std::unordered_map<std::string, OBSSource> transitions;
// TODO: Reduce usages of an index to identify a transition
std::vector<std::string> transitionUuids;
// FIXME: Replace usages of a name to identify a transition
std::unordered_map<std::string, std::string> transitionNameToUuids;
std::string currentTransitionUuid;
obs_source_t *fadeTransition;
obs_source_t *cutTransition;
std::vector<QuickTransition> quickTransitions;
@@ -1529,6 +1536,8 @@ private:
void PasteShowHideTransition(obs_sceneitem_t *item, bool show, obs_source_t *tr, int duration);
void UpdateCurrentTransition(const std::string &uuid, bool setTransition);
public slots:
void SetCurrentScene(OBSSource scene, bool force = false);
@@ -1538,6 +1547,8 @@ public slots:
void TransitionToScene(OBSSource scene, bool force = false, bool quickTransition = false, int quickDuration = 0,
bool black = false, bool manual = false);
void SetCurrentTransition(const QString &uuid);
private slots:
void AddTransition(const char *id);
void RenameTransition(OBSSource transition);
@@ -1550,7 +1561,6 @@ private slots:
void TBarChanged(int value);
void TBarReleased();
void on_transitions_currentIndexChanged(int index);
void on_transitionAdd_clicked();
void on_transitionRemove_clicked();
void on_transitionProps_clicked();
@@ -1559,6 +1569,14 @@ private slots:
void ShowTransitionProperties();
void HideTransitionProperties();
signals:
void TransitionAdded(const QString &name, const QString &uuid);
void TransitionRenamed(const QString &uuid, const QString &newName);
void TransitionRemoved(const QString &uuid);
void TransitionsCleared();
void CurrentTransitionChanged(const QString &uuid);
public:
int GetTransitionDuration();
int GetTbarPosition();
@@ -1499,7 +1499,12 @@ void OBSBasic::ClearSceneData()
ClearListItems(ui->scenes);
ui->sources->Clear();
ClearQuickTransitions();
ui->transitions->clear();
currentTransitionUuid.clear();
transitions.clear();
transitionNameToUuids.clear();
transitionUuids.clear();
emit TransitionsCleared();
ClearProjectors();
+146 -47
View File
@@ -17,6 +17,8 @@
#include "OBSBasic.hpp"
#include <algorithm>
#include <components/MenuButton.hpp>
#include <dialogs/NameDialog.hpp>
#include <utility/display-helpers.hpp>
@@ -69,8 +71,16 @@ void OBSBasic::InitDefaultTransitions()
}
for (OBSSource &tr : defaultTransitions) {
ui->transitions->addItem(QT_UTF8(obs_source_get_name(tr)), QVariant::fromValue(OBSSource(tr)));
std::string uuid = obs_source_get_uuid(tr);
transitions.insert({uuid, OBSSource(tr)});
transitionNameToUuids.insert({obs_source_get_name(tr), uuid});
transitionUuids.push_back(uuid);
emit TransitionAdded(QT_UTF8(obs_source_get_name(tr)), QString::fromStdString(uuid));
}
UpdateCurrentTransition(transitionUuids.back(), true);
}
void OBSBasic::AddQuickTransitionHotkey(QuickTransition *qt)
@@ -198,14 +208,15 @@ obs_data_array_t *OBSBasic::SaveQuickTransitions()
obs_source_t *OBSBasic::FindTransition(const char *name)
{
for (int i = 0; i < ui->transitions->count(); i++) {
OBSSource tr = ui->transitions->itemData(i).value<OBSSource>();
if (!tr)
continue;
auto nameToUuid = transitionNameToUuids.find(name);
const char *trName = obs_source_get_name(tr);
if (strcmp(trName, name) == 0)
return tr;
if (nameToUuid != transitionNameToUuids.end()) {
auto transition = transitions.find(nameToUuid->second);
if (transition == transitions.end())
return nullptr;
return transition->second;
}
return nullptr;
@@ -377,9 +388,10 @@ void OBSBasic::SetTransition(OBSSource transition)
OBSSourceAutoRelease oldTransition = obs_get_output_source(0);
if (oldTransition && transition) {
std::string uuid = obs_source_get_uuid(transition);
obs_transition_swap_begin(transition, oldTransition);
if (transition != GetCurrentTransition())
SetComboTransition(ui->transitions, transition);
if (currentTransitionUuid != uuid)
UpdateCurrentTransition(uuid, false);
obs_set_output_source(0, transition);
obs_transition_swap_end(transition, oldTransition);
} else {
@@ -399,13 +411,12 @@ void OBSBasic::SetTransition(OBSSource transition)
OBSSource OBSBasic::GetCurrentTransition()
{
return ui->transitions->currentData().value<OBSSource>();
}
auto transition = transitions.find(currentTransitionUuid);
void OBSBasic::on_transitions_currentIndexChanged(int)
{
OBSSource transition = GetCurrentTransition();
SetTransition(transition);
if (transition == transitions.end())
return nullptr;
return transition->second;
}
void OBSBasic::AddTransition(const char *id)
@@ -424,6 +435,8 @@ void OBSBasic::AddTransition(const char *id)
name, placeHolderText);
if (accepted) {
std::string uuid;
if (name.empty()) {
OBSMessageBox::warning(this, QTStr("NoNameEntered.Title"), QTStr("NoNameEntered.Text"));
AddTransition(id);
@@ -440,8 +453,16 @@ void OBSBasic::AddTransition(const char *id)
source = obs_source_create_private(id, name.c_str(), NULL);
InitTransition(source);
ui->transitions->addItem(QT_UTF8(name.c_str()), QVariant::fromValue(OBSSource(source)));
ui->transitions->setCurrentIndex(ui->transitions->count() - 1);
uuid = obs_source_get_uuid(source);
transitions.insert({uuid, source});
transitionNameToUuids.insert({name, uuid});
transitionUuids.push_back(uuid);
emit TransitionAdded(QString::fromStdString(name), QString::fromStdString(uuid));
UpdateCurrentTransition(uuid, true);
CreatePropertiesWindow(source);
obs_source_release(source);
@@ -477,13 +498,16 @@ void OBSBasic::on_transitionAdd_clicked()
void OBSBasic::on_transitionRemove_clicked()
{
OBSSource tr = GetCurrentTransition();
auto transitionIterator = transitions.find(currentTransitionUuid);
OBSSource tr;
const char *name;
if (!tr || !obs_source_configurable(tr) || !QueryRemoveSource(tr))
if (transitionIterator == transitions.end())
return;
int idx = ui->transitions->findData(QVariant::fromValue<OBSSource>(tr));
if (idx == -1)
tr = transitionIterator->second;
if (!tr || !obs_source_configurable(tr) || !QueryRemoveSource(tr))
return;
for (size_t i = quickTransitions.size(); i > 0; i--) {
@@ -496,7 +520,15 @@ void OBSBasic::on_transitionRemove_clicked()
}
}
ui->transitions->removeItem(idx);
name = obs_source_get_name(tr);
if (name)
transitionNameToUuids.erase(std::string(name));
transitionUuids.erase(std::find(transitionUuids.begin(), transitionUuids.end(), currentTransitionUuid));
transitions.erase(currentTransitionUuid);
emit TransitionRemoved(QString::fromStdString(currentTransitionUuid));
UpdateCurrentTransition(transitionUuids.back(), true);
OnEvent(OBS_FRONTEND_EVENT_TRANSITION_LIST_CHANGED);
@@ -506,8 +538,10 @@ void OBSBasic::on_transitionRemove_clicked()
void OBSBasic::RenameTransition(OBSSource transition)
{
string name;
QString placeHolderText = QT_UTF8(obs_source_get_name(transition));
std::string name;
std::string oldName = obs_source_get_name(transition);
std::string uuid = obs_source_get_uuid(transition);
QString placeHolderText = QString::fromStdString(oldName);
obs_source_t *source = nullptr;
bool accepted = NameDialog::AskForName(this, QTStr("TransitionNameDlg.Title"), QTStr("TransitionNameDlg.Text"),
@@ -530,15 +564,19 @@ void OBSBasic::RenameTransition(OBSSource transition)
}
obs_source_set_name(transition, name.c_str());
int idx = ui->transitions->findData(QVariant::fromValue(transition));
if (idx != -1) {
ui->transitions->setItemText(idx, QT_UTF8(name.c_str()));
OnEvent(OBS_FRONTEND_EVENT_TRANSITION_LIST_CHANGED);
if (transitionNameToUuids.find(oldName) == transitionNameToUuids.end())
return;
ClearQuickTransitionWidgets();
RefreshQuickTransitions();
}
transitionNameToUuids.erase(oldName);
transitionNameToUuids.insert({name, uuid});
emit TransitionRenamed(QString::fromStdString(uuid), QString::fromStdString(name));
OnEvent(OBS_FRONTEND_EVENT_TRANSITION_LIST_CHANGED);
ClearQuickTransitionWidgets();
RefreshQuickTransitions();
}
void OBSBasic::on_transitionProps_clicked()
@@ -763,13 +801,17 @@ QMenu *OBSBasic::CreatePerSceneTransitionMenu()
int idx = action->property("transition_index").toInt();
OBSSource scene = GetCurrentSceneSource();
OBSDataAutoRelease data = obs_source_get_private_settings(scene);
auto transitionIter = transitions.find(transitionUuids[idx]);
if (idx == -1) {
obs_data_set_string(data, "transition", "");
return;
}
OBSSource tr = GetTransitionComboItem(ui->transitions, idx);
if (transitionIter == transitions.end())
return;
OBSSource tr = transitionIter->second;
if (tr) {
const char *name = obs_source_get_name(tr);
@@ -786,12 +828,17 @@ QMenu *OBSBasic::CreatePerSceneTransitionMenu()
connect(duration, (void(QSpinBox::*)(int)) & QSpinBox::valueChanged, setDuration);
for (int i = -1; i < ui->transitions->count(); i++) {
for (int i = -1; i < (int)transitionUuids.size(); i++) {
const char *name = "";
if (i >= 0) {
auto transitionIter = transitions.find(transitionUuids[i]);
OBSSource tr;
tr = GetTransitionComboItem(ui->transitions, i);
if (transitionIter == transitions.end())
continue;
tr = transitionIter->second;
if (!tr)
continue;
name = obs_source_get_name(tr);
@@ -1051,8 +1098,13 @@ QMenu *OBSBasic::CreateTransitionMenu(QWidget *parent, QuickTransition *qt)
connect(action, &QAction::triggered, this, &OBSBasic::AddQuickTransition);
}
for (int i = 0; i < ui->transitions->count(); i++) {
tr = GetTransitionComboItem(ui->transitions, i);
for (int i = 0; i < (int)transitionUuids.size(); i++) {
auto transitionIter = transitions.find(transitionUuids[i]);
if (transitionIter == transitions.end())
continue;
tr = transitionIter->second;
if (!tr)
continue;
@@ -1121,7 +1173,13 @@ void OBSBasic::AddQuickTransition()
int trIdx = sender()->property("transition_index").toInt();
QSpinBox *duration = sender()->property("duration").value<QSpinBox *>();
bool fadeToBlack = sender()->property("fadeToBlack").value<bool>();
OBSSource transition = fadeToBlack ? OBSSource(fadeTransition) : GetTransitionComboItem(ui->transitions, trIdx);
auto transitionIter = transitions.find(transitionUuids[trIdx]);
OBSSource transition;
if (!fadeToBlack && (transitionIter == transitions.end()))
return;
transition = fadeToBlack ? OBSSource(fadeTransition) : transitionIter->second;
if (!transition)
return;
@@ -1177,7 +1235,14 @@ void OBSBasic::QuickTransitionChange()
QuickTransition *qt = GetQuickTransition(id);
if (qt) {
OBSSource tr = fadeToBlack ? OBSSource(fadeTransition) : GetTransitionComboItem(ui->transitions, trIdx);
auto transitionIter = transitions.find(transitionUuids[trIdx]);
OBSSource tr;
if (!fadeToBlack && (transitionIter == transitions.end()))
return;
tr = fadeToBlack ? OBSSource(fadeTransition) : transitionIter->second;
if (tr) {
qt->source = tr;
qt->fadeToBlack = fadeToBlack;
@@ -1282,16 +1347,15 @@ obs_data_array_t *OBSBasic::SaveTransitions()
{
obs_data_array_t *transitionsData = obs_data_array_create();
for (int i = 0; i < ui->transitions->count(); i++) {
OBSSource tr = ui->transitions->itemData(i).value<OBSSource>();
if (!tr || !obs_source_configurable(tr))
for (const auto &[uuid, transition] : transitions) {
if (!transition || !obs_source_configurable(transition.Get()))
continue;
OBSDataAutoRelease sourceData = obs_data_create();
OBSDataAutoRelease settings = obs_source_get_settings(tr);
OBSDataAutoRelease settings = obs_source_get_settings(transition.Get());
obs_data_set_string(sourceData, "name", obs_source_get_name(tr));
obs_data_set_string(sourceData, "id", obs_obj_get_id(tr));
obs_data_set_string(sourceData, "name", obs_source_get_name(transition.Get()));
obs_data_set_string(sourceData, "id", obs_obj_get_id(transition.Get()));
obs_data_set_obj(sourceData, "settings", settings);
obs_data_array_push_back(transitionsData, sourceData);
@@ -1317,16 +1381,23 @@ void OBSBasic::LoadTransitions(obs_data_array_t *transitionsData, obs_load_sourc
OBSSourceAutoRelease source = obs_source_create_private(id, name, settings);
if (!obs_obj_invalid(source)) {
std::string uuid = obs_source_get_uuid(source);
InitTransition(source);
ui->transitions->addItem(QT_UTF8(name), QVariant::fromValue(OBSSource(source)));
ui->transitions->setCurrentIndex(ui->transitions->count() - 1);
transitions.insert({uuid, OBSSource(source)});
transitionNameToUuids.insert({name, uuid});
transitionUuids.push_back(uuid);
emit TransitionAdded(QT_UTF8(name), QString::fromStdString(uuid));
if (cb)
cb(private_data, source);
} else if (safe_mode || disable_3p_plugins) {
safeModeTransitions.push_back(std::move(item));
}
}
UpdateCurrentTransition(transitionUuids.back(), true);
}
OBSSource OBSBasic::GetOverrideTransition(OBSSource source)
@@ -1361,3 +1432,31 @@ int OBSBasic::GetTransitionDuration()
{
return ui->transitionDuration->value();
}
void OBSBasic::UpdateCurrentTransition(const std::string &uuid, bool setTransition)
{
auto transitionIter = transitions.find(uuid);
if (currentTransitionUuid == uuid || transitionIter == transitions.end())
return;
currentTransitionUuid = uuid;
if (setTransition)
SetTransition(transitionIter->second);
emit CurrentTransitionChanged(QString::fromStdString(uuid));
}
void OBSBasic::SetCurrentTransition(const QString &uuid)
{
auto transitionIter = transitions.find(uuid.toStdString());
if (currentTransitionUuid == uuid.toStdString() || transitionIter == transitions.end())
return;
currentTransitionUuid = uuid.toStdString();
SetTransition(transitionIter->second);
emit CurrentTransitionChanged(uuid);
}