UI: Add configurable transitions
This commit is contained in:
parent
57054a237f
commit
3b1775d97f
@ -59,10 +59,17 @@ QuickTransitions.EditPropertiesTT="When editing the same scene, allows editing p
|
||||
QuickTransitions.HotkeyName="Quick Transition: %1"
|
||||
|
||||
# transitions
|
||||
Basic.AddTransition="Add Configurable Transition"
|
||||
Basic.RemoveTransition="Remove Configurable Transition"
|
||||
Basic.TransitionProperties="Transition Properties"
|
||||
Basic.SceneTransitions="Scene Transitions"
|
||||
Basic.TransitionDuration="Duration"
|
||||
Basic.TogglePreviewProgramMode="Studio Mode"
|
||||
|
||||
# transition name dialog
|
||||
TransitionNameDlg.Text="Please enter the name of the transition"
|
||||
TransitionNameDlg.Title="Transition Name"
|
||||
|
||||
# title bar strings
|
||||
TitleBar.Profile="Profile"
|
||||
TitleBar.Scenes="Scenes"
|
||||
|
@ -581,10 +581,103 @@
|
||||
<number>4</number>
|
||||
</property>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<property name="spacing">
|
||||
<number>2</number>
|
||||
<widget class="QComboBox" name="transitions">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>120</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_4">
|
||||
<property name="spacing">
|
||||
<number>4</number>
|
||||
</property>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="transitionAdd">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Maximum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>22</width>
|
||||
<height>22</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Basic.AddTransition</string>
|
||||
</property>
|
||||
<property name="accessibleName">
|
||||
<string>Basic.AddTransition</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="obs.qrc">
|
||||
<normaloff>:/res/images/add.png</normaloff>:/res/images/add.png</iconset>
|
||||
</property>
|
||||
<property name="flat">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="themeID" stdset="0">
|
||||
<string notr="true">addIconSmall</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="transitionRemove">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Maximum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>22</width>
|
||||
<height>22</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Basic.RemoveTransition</string>
|
||||
</property>
|
||||
<property name="accessibleName">
|
||||
<string>Basic.RemoveTransition</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="obs.qrc">
|
||||
<normaloff>:/res/images/list_remove.png</normaloff>:/res/images/list_remove.png</iconset>
|
||||
</property>
|
||||
<property name="flat">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="themeID" stdset="0">
|
||||
<string notr="true">removeIconSmall</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="transitionProps">
|
||||
<property name="sizePolicy">
|
||||
@ -599,6 +692,12 @@
|
||||
<height>22</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Basic.TransitionProperties</string>
|
||||
</property>
|
||||
<property name="accessibleName">
|
||||
<string>Basic.TransitionProperties</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
@ -614,16 +713,6 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="transitions">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>120</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
|
@ -18,9 +18,11 @@
|
||||
#include <QSpinBox>
|
||||
#include <QWidgetAction>
|
||||
#include <QToolTip>
|
||||
#include <QMessageBox>
|
||||
#include <util/dstr.hpp>
|
||||
#include "window-basic-main.hpp"
|
||||
#include "display-helpers.hpp"
|
||||
#include "window-namedialog.hpp"
|
||||
#include "menu-button.hpp"
|
||||
#include "qt-wrappers.hpp"
|
||||
|
||||
@ -301,9 +303,6 @@ void OBSBasic::SetTransition(obs_source_t *transition)
|
||||
SetComboTransition(ui->transitions, transition);
|
||||
obs_set_output_source(0, transition);
|
||||
obs_transition_swap_end(transition, oldTransition);
|
||||
|
||||
bool showPropertiesButton = obs_source_configurable(transition);
|
||||
ui->transitionProps->setVisible(showPropertiesButton);
|
||||
} else {
|
||||
obs_set_output_source(0, transition);
|
||||
}
|
||||
@ -314,6 +313,10 @@ void OBSBasic::SetTransition(obs_source_t *transition)
|
||||
bool fixed = transition ? obs_transition_fixed(transition) : false;
|
||||
ui->transitionDurationLabel->setVisible(!fixed);
|
||||
ui->transitionDuration->setVisible(!fixed);
|
||||
|
||||
bool configurable = obs_source_configurable(transition);
|
||||
ui->transitionRemove->setEnabled(configurable);
|
||||
ui->transitionProps->setEnabled(configurable);
|
||||
}
|
||||
|
||||
OBSSource OBSBasic::GetCurrentTransition()
|
||||
@ -327,9 +330,170 @@ void OBSBasic::on_transitions_currentIndexChanged(int)
|
||||
SetTransition(transition);
|
||||
}
|
||||
|
||||
void OBSBasic::AddTransition()
|
||||
{
|
||||
QAction *action = reinterpret_cast<QAction*>(sender());
|
||||
QString idStr = action->property("id").toString();
|
||||
|
||||
string name;
|
||||
QString placeHolderText = QT_UTF8(
|
||||
obs_source_get_display_name(QT_TO_UTF8(idStr)));
|
||||
QString format = placeHolderText + " (%1)";
|
||||
obs_source_t *source = nullptr;
|
||||
int i = 1;
|
||||
|
||||
while ((source = FindTransition(QT_TO_UTF8(placeHolderText)))) {
|
||||
placeHolderText = format.arg(++i);
|
||||
}
|
||||
|
||||
bool accepted = NameDialog::AskForName(this,
|
||||
QTStr("TransitionNameDlg.Title"),
|
||||
QTStr("TransitionNameDlg.Text"),
|
||||
name, placeHolderText);
|
||||
|
||||
if (accepted) {
|
||||
if (name.empty()) {
|
||||
QMessageBox::information(this,
|
||||
QTStr("NoNameEntered.Title"),
|
||||
QTStr("NoNameEntered.Text"));
|
||||
AddTransition();
|
||||
return;
|
||||
}
|
||||
|
||||
source = FindTransition(name.c_str());
|
||||
if (source) {
|
||||
QMessageBox::information(this,
|
||||
QTStr("NameExists.Title"),
|
||||
QTStr("NameExists.Text"));
|
||||
|
||||
AddTransition();
|
||||
return;
|
||||
}
|
||||
|
||||
source = obs_source_create_private(QT_TO_UTF8(idStr),
|
||||
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);
|
||||
CreatePropertiesWindow(source);
|
||||
obs_source_release(source);
|
||||
}
|
||||
}
|
||||
|
||||
void OBSBasic::on_transitionAdd_clicked()
|
||||
{
|
||||
bool foundConfigurableTransitions = false;
|
||||
QMenu menu(this);
|
||||
size_t idx = 0;
|
||||
const char *id;
|
||||
|
||||
while (obs_enum_transition_types(idx++, &id)) {
|
||||
if (obs_is_source_configurable(id)) {
|
||||
const char *name = obs_source_get_display_name(id);
|
||||
QAction *action = new QAction(name, this);
|
||||
action->setProperty("id", id);
|
||||
|
||||
connect(action, SIGNAL(triggered()),
|
||||
this, SLOT(AddTransition()));
|
||||
|
||||
menu.addAction(action);
|
||||
foundConfigurableTransitions = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (foundConfigurableTransitions)
|
||||
menu.exec(QCursor::pos());
|
||||
}
|
||||
|
||||
void OBSBasic::on_transitionRemove_clicked()
|
||||
{
|
||||
OBSSource tr = GetCurrentTransition();
|
||||
|
||||
if (!tr || !obs_source_configurable(tr) || !QueryRemoveSource(tr))
|
||||
return;
|
||||
|
||||
int idx = ui->transitions->findData(QVariant::fromValue<OBSSource>(tr));
|
||||
if (idx == -1)
|
||||
return;
|
||||
|
||||
for (size_t i = quickTransitions.size(); i > 0; i--) {
|
||||
QuickTransition &qt = quickTransitions[i - 1];
|
||||
if (qt.source == tr) {
|
||||
if (qt.button)
|
||||
qt.button->deleteLater();
|
||||
RemoveQuickTransitionHotkey(&qt);
|
||||
quickTransitions.erase(quickTransitions.begin() + i - 1);
|
||||
}
|
||||
}
|
||||
|
||||
ui->transitions->removeItem(idx);
|
||||
}
|
||||
|
||||
void OBSBasic::RenameTransition()
|
||||
{
|
||||
QAction *action = reinterpret_cast<QAction*>(sender());
|
||||
QVariant variant = action->property("transition");
|
||||
obs_source_t *transition = variant.value<OBSSource>();
|
||||
|
||||
string name;
|
||||
QString placeHolderText = QT_UTF8(obs_source_get_name(transition));
|
||||
obs_source_t *source = nullptr;
|
||||
|
||||
bool accepted = NameDialog::AskForName(this,
|
||||
QTStr("TransitionNameDlg.Title"),
|
||||
QTStr("TransitionNameDlg.Text"),
|
||||
name, placeHolderText);
|
||||
|
||||
if (accepted) {
|
||||
if (name.empty()) {
|
||||
QMessageBox::information(this,
|
||||
QTStr("NoNameEntered.Title"),
|
||||
QTStr("NoNameEntered.Text"));
|
||||
RenameTransition();
|
||||
return;
|
||||
}
|
||||
|
||||
source = FindTransition(name.c_str());
|
||||
if (source) {
|
||||
QMessageBox::information(this,
|
||||
QTStr("NameExists.Title"),
|
||||
QTStr("NameExists.Text"));
|
||||
|
||||
RenameTransition();
|
||||
return;
|
||||
}
|
||||
|
||||
obs_source_set_name(transition, name.c_str());
|
||||
int idx = ui->transitions->findData(variant);
|
||||
if (idx != -1)
|
||||
ui->transitions->setItemText(idx, QT_UTF8(name.c_str()));
|
||||
}
|
||||
}
|
||||
|
||||
void OBSBasic::on_transitionProps_clicked()
|
||||
{
|
||||
// TODO
|
||||
OBSSource source = GetCurrentTransition();
|
||||
|
||||
if (!obs_source_configurable(source))
|
||||
return;
|
||||
|
||||
auto properties = [&] () {
|
||||
CreatePropertiesWindow(source);
|
||||
};
|
||||
|
||||
QMenu menu(this);
|
||||
|
||||
QAction *action = new QAction(QTStr("Rename"), this);
|
||||
connect(action, SIGNAL(triggered()), this, SLOT(RenameTransition()));
|
||||
action->setProperty("transition", QVariant::fromValue(source));
|
||||
menu.addAction(action);
|
||||
|
||||
action = new QAction(QTStr("Properties"), this);
|
||||
connect(action, &QAction::triggered, properties);
|
||||
menu.addAction(action);
|
||||
|
||||
menu.exec(QCursor::pos());
|
||||
}
|
||||
|
||||
QuickTransition *OBSBasic::GetQuickTransition(int id)
|
||||
@ -875,3 +1039,51 @@ void OBSBasic::ResizeProgram(uint32_t cx, uint32_t cy)
|
||||
programX += float(PREVIEW_EDGE_SIZE);
|
||||
programY += float(PREVIEW_EDGE_SIZE);
|
||||
}
|
||||
|
||||
obs_data_array_t *OBSBasic::SaveTransitions()
|
||||
{
|
||||
obs_data_array_t *transitions = obs_data_array_create();
|
||||
|
||||
for (int i = 0; i < ui->transitions->count(); i++) {
|
||||
OBSSource tr = ui->transitions->itemData(i).value<OBSSource>();
|
||||
if (!obs_source_configurable(tr))
|
||||
continue;
|
||||
|
||||
obs_data_t *sourceData = obs_data_create();
|
||||
obs_data_t *settings = obs_source_get_settings(tr);
|
||||
|
||||
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_obj(sourceData, "settings", settings);
|
||||
|
||||
obs_data_array_push_back(transitions, sourceData);
|
||||
|
||||
obs_data_release(settings);
|
||||
obs_data_release(sourceData);
|
||||
}
|
||||
|
||||
return transitions;
|
||||
}
|
||||
|
||||
void OBSBasic::LoadTransitions(obs_data_array_t *transitions)
|
||||
{
|
||||
size_t count = obs_data_array_count(transitions);
|
||||
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
obs_data_t *item = obs_data_array_item(transitions, i);
|
||||
const char *name = obs_data_get_string(item, "name");
|
||||
const char *id = obs_data_get_string(item, "id");
|
||||
obs_data_t *settings = obs_data_get_obj(item, "settings");
|
||||
|
||||
obs_source_t *source = obs_source_create_private(id, name,
|
||||
settings);
|
||||
InitTransition(source);
|
||||
ui->transitions->addItem(QT_UTF8(name),
|
||||
QVariant::fromValue(OBSSource(source)));
|
||||
ui->transitions->setCurrentIndex(ui->transitions->count() - 1);
|
||||
obs_source_release(source);
|
||||
|
||||
obs_data_release(settings);
|
||||
obs_data_release(item);
|
||||
}
|
||||
}
|
||||
|
@ -247,6 +247,7 @@ static void SaveAudioDevice(const char *name, int channel, obs_data_t *parent,
|
||||
|
||||
static obs_data_t *GenerateSaveData(obs_data_array_t *sceneOrder,
|
||||
obs_data_array_t *quickTransitionData, int transitionDuration,
|
||||
obs_data_array_t *transitions,
|
||||
OBSScene &scene, OBSSource &curProgramScene)
|
||||
{
|
||||
obs_data_t *saveData = obs_data_create();
|
||||
@ -287,6 +288,7 @@ static obs_data_t *GenerateSaveData(obs_data_array_t *sceneOrder,
|
||||
obs_data_set_string(saveData, "name", sceneCollection);
|
||||
obs_data_set_array(saveData, "sources", sourcesArray);
|
||||
obs_data_set_array(saveData, "quick_transitions", quickTransitionData);
|
||||
obs_data_set_array(saveData, "transitions", transitions);
|
||||
obs_data_array_release(sourcesArray);
|
||||
|
||||
obs_data_set_string(saveData, "current_transition",
|
||||
@ -352,9 +354,10 @@ void OBSBasic::Save(const char *file)
|
||||
curProgramScene = obs_scene_get_source(scene);
|
||||
|
||||
obs_data_array_t *sceneOrder = SaveSceneListOrder();
|
||||
obs_data_array_t *transitions = SaveTransitions();
|
||||
obs_data_array_t *quickTrData = SaveQuickTransitions();
|
||||
obs_data_t *saveData = GenerateSaveData(sceneOrder, quickTrData,
|
||||
ui->transitionDuration->value(),
|
||||
ui->transitionDuration->value(), transitions,
|
||||
scene, curProgramScene);
|
||||
|
||||
if (!obs_data_save_json_safe(saveData, file, "tmp", "bak"))
|
||||
@ -363,6 +366,7 @@ void OBSBasic::Save(const char *file)
|
||||
obs_data_release(saveData);
|
||||
obs_data_array_release(sceneOrder);
|
||||
obs_data_array_release(quickTrData);
|
||||
obs_data_array_release(transitions);
|
||||
}
|
||||
|
||||
static void LoadAudioDevice(const char *name, int channel, obs_data_t *parent)
|
||||
@ -488,6 +492,7 @@ void OBSBasic::Load(const char *file)
|
||||
|
||||
obs_data_array_t *sceneOrder = obs_data_get_array(data, "scene_order");
|
||||
obs_data_array_t *sources = obs_data_get_array(data, "sources");
|
||||
obs_data_array_t *transitions= obs_data_get_array(data, "transitions");
|
||||
const char *sceneName = obs_data_get_string(data,
|
||||
"current_scene");
|
||||
const char *programSceneName = obs_data_get_string(data,
|
||||
@ -523,9 +528,13 @@ void OBSBasic::Load(const char *file)
|
||||
|
||||
obs_load_sources(sources);
|
||||
|
||||
if (transitions)
|
||||
LoadTransitions(transitions);
|
||||
if (sceneOrder)
|
||||
LoadSceneListOrder(sceneOrder);
|
||||
|
||||
obs_data_array_release(transitions);
|
||||
|
||||
curTransition = FindTransition(transitionName);
|
||||
if (!curTransition)
|
||||
curTransition = fadeTransition;
|
||||
|
@ -220,6 +220,8 @@ private:
|
||||
obs_source_t *FindTransition(const char *name);
|
||||
void SetTransition(obs_source_t *transition);
|
||||
OBSSource GetCurrentTransition();
|
||||
obs_data_array_t *SaveTransitions();
|
||||
void LoadTransitions(obs_data_array_t *transitions);
|
||||
|
||||
obs_source_t *fadeTransition;
|
||||
|
||||
@ -314,6 +316,8 @@ private slots:
|
||||
|
||||
void ProcessHotkey(obs_hotkey_id id, bool pressed);
|
||||
|
||||
void AddTransition();
|
||||
void RenameTransition();
|
||||
void TransitionClicked();
|
||||
void TransitionStopped();
|
||||
void TriggerQuickTransition(int id);
|
||||
@ -465,6 +469,8 @@ private slots:
|
||||
void on_actionAlwaysOnTop_triggered();
|
||||
|
||||
void on_transitions_currentIndexChanged(int index);
|
||||
void on_transitionAdd_clicked();
|
||||
void on_transitionRemove_clicked();
|
||||
void on_transitionProps_clicked();
|
||||
|
||||
void on_modeSwitch_clicked();
|
||||
|
Loading…
x
Reference in New Issue
Block a user