浏览代码

UI: Implement per-scene transition overriding

Allows the ability to override what specific transition a scene may use
when transitioning to it.

(Original proposal by cg2121, reworked by Jim)

Closes jp9000/obs-studio#1052
cg2121 8 年之前
父节点
当前提交
60e1d7e90b
共有 4 个文件被更改,包括 148 次插入4 次删除
  1. 2 0
      UI/data/locale/en-US.ini
  2. 137 4
      UI/window-basic-main-transitions.cpp
  3. 5 0
      UI/window-basic-main.cpp
  4. 4 0
      UI/window-basic-main.hpp

+ 2 - 0
UI/data/locale/en-US.ini

@@ -76,6 +76,8 @@ Next="Next"
 Back="Back"
 Back="Back"
 Defaults="Defaults"
 Defaults="Defaults"
 HideMixer="Hide in Mixer"
 HideMixer="Hide in Mixer"
+TransitionOverride="Transition Override"
+None="None"
 
 
 # warning if program already open
 # warning if program already open
 AlreadyRunning.Title="OBS is already running"
 AlreadyRunning.Title="OBS is already running"

+ 137 - 4
UI/window-basic-main-transitions.cpp

@@ -127,9 +127,17 @@ void OBSBasic::InitTransition(obs_source_t *transition)
 				Qt::QueuedConnection);
 				Qt::QueuedConnection);
 	};
 	};
 
 
+	auto onTransitionFullStop = [] (void *data, calldata_t*) {
+		OBSBasic *window = (OBSBasic*)data;
+		QMetaObject::invokeMethod(window, "TransitionFullyStopped",
+				Qt::QueuedConnection);
+	};
+
 	signal_handler_t *handler = obs_source_get_signal_handler(transition);
 	signal_handler_t *handler = obs_source_get_signal_handler(transition);
 	signal_handler_connect(handler, "transition_video_stop",
 	signal_handler_connect(handler, "transition_video_stop",
 			onTransitionStop, this);
 			onTransitionStop, this);
+	signal_handler_connect(handler, "transition_stop",
+			onTransitionFullStop, this);
 }
 }
 
 
 static inline OBSSource GetTransitionComboItem(QComboBox *combo, int idx)
 static inline OBSSource GetTransitionComboItem(QComboBox *combo, int idx)
@@ -242,6 +250,27 @@ void OBSBasic::TransitionStopped()
 	swapScene = nullptr;
 	swapScene = nullptr;
 }
 }
 
 
+static void OverrideTransition(OBSSource transition)
+{
+	obs_source_t *oldTransition = obs_get_output_source(0);
+
+	if (transition != oldTransition) {
+		obs_transition_swap_begin(transition, oldTransition);
+		obs_set_output_source(0, transition);
+		obs_transition_swap_end(transition, oldTransition);
+	}
+
+	obs_source_release(oldTransition);
+}
+
+void OBSBasic::TransitionFullyStopped()
+{
+	if (overridingTransition) {
+		OverrideTransition(GetCurrentTransition());
+		overridingTransition = false;
+	}
+}
+
 void OBSBasic::TransitionToScene(OBSSource source, bool force, bool direct)
 void OBSBasic::TransitionToScene(OBSSource source, bool force, bool direct)
 {
 {
 	obs_scene_t *scene = obs_scene_from_source(source);
 	obs_scene_t *scene = obs_scene_from_source(source);
@@ -274,21 +303,43 @@ void OBSBasic::TransitionToScene(OBSSource source, bool force, bool direct)
 		source = obs_scene_get_source(scene);
 		source = obs_scene_get_source(scene);
 	}
 	}
 
 
-	obs_source_t *transition = obs_get_output_source(0);
+	OBSSource transition = obs_get_output_source(0);
+	obs_source_release(transition);
 
 
 	if (force) {
 	if (force) {
 		obs_transition_set(transition, source);
 		obs_transition_set(transition, source);
 		if (api)
 		if (api)
 			api->on_event(OBS_FRONTEND_EVENT_SCENE_CHANGED);
 			api->on_event(OBS_FRONTEND_EVENT_SCENE_CHANGED);
 	} else {
 	} else {
+		/* check for scene override */
+		OBSData data = obs_source_get_private_settings(source);
+		obs_data_release(data);
+
+		const char *trOverrideName = obs_data_get_string(data,
+				"transition");
+		int duration = ui->transitionDuration->value();
+
+		if (trOverrideName && *trOverrideName) {
+			OBSSource trOverride = FindTransition(trOverrideName);
+			if (trOverride) {
+				transition = trOverride;
+
+				obs_data_set_default_int(data,
+						"transition_duration", 300);
+
+				duration = (int)obs_data_get_int(data,
+						"transition_duration");
+				OverrideTransition(trOverride);
+				overridingTransition = true;
+			}
+		}
+
 		obs_transition_start(transition, OBS_TRANSITION_MODE_AUTO,
 		obs_transition_start(transition, OBS_TRANSITION_MODE_AUTO,
-				ui->transitionDuration->value(), source);
+				duration, source);
 	}
 	}
 
 
 	if (usingPreviewProgram && sceneDuplicationMode && !direct)
 	if (usingPreviewProgram && sceneDuplicationMode && !direct)
 		obs_scene_release(scene);
 		obs_scene_release(scene);
-
-	obs_source_release(transition);
 }
 }
 
 
 static inline void SetComboTransition(QComboBox *combo, obs_source_t *tr)
 static inline void SetComboTransition(QComboBox *combo, obs_source_t *tr)
@@ -754,6 +805,88 @@ static inline void ResetQuickTransitionText(QuickTransition *qt)
 	qt->button->setText(MakeQuickTransitionText(qt));
 	qt->button->setText(MakeQuickTransitionText(qt));
 }
 }
 
 
+QMenu *OBSBasic::CreatePerSceneTransitionMenu()
+{
+	OBSSource scene = GetCurrentSceneSource();
+	QMenu *menu = new QMenu(QTStr("TransitionOverride"));
+	QAction *action;
+
+	OBSData data = obs_source_get_private_settings(scene);
+	obs_data_release(data);
+
+	obs_data_set_default_int(data, "transition_duration", 300);
+
+	const char *curTransition = obs_data_get_string(data, "transition");
+	int curDuration = (int)obs_data_get_int(data, "transition_duration");
+
+	QSpinBox *duration = new QSpinBox(menu);
+	duration->setMinimum(50);
+	duration->setSuffix("ms");
+	duration->setMaximum(20000);
+	duration->setSingleStep(50);
+	duration->setValue(curDuration);
+
+	auto setTransition = [this] (QAction *action)
+	{
+		int idx = action->property("transition_index").toInt();
+		OBSSource scene = GetCurrentSceneSource();
+		OBSData data = obs_source_get_private_settings(scene);
+		obs_data_release(data);
+
+		if (idx == -1) {
+			obs_data_set_string(data, "transition", "");
+			return;
+		}
+
+		OBSSource tr = GetTransitionComboItem(ui->transitions, idx);
+		const char *name = obs_source_get_name(tr);
+
+		obs_data_set_string(data, "transition", name);
+	};
+
+	auto setDuration = [this] (int duration)
+	{
+		OBSSource scene = GetCurrentSceneSource();
+		OBSData data = obs_source_get_private_settings(scene);
+		obs_data_release(data);
+
+		obs_data_set_int(data, "transition_duration", duration);
+	};
+
+	connect(duration, (void (QSpinBox::*)(int))&QSpinBox::valueChanged,
+			setDuration);
+
+	for (int i = -1; i < ui->transitions->count(); i++) {
+		const char *name = "";
+
+		if (i >= 0) {
+			OBSSource tr;
+			tr = GetTransitionComboItem(ui->transitions, i);
+			name = obs_source_get_name(tr);
+		}
+
+		bool match = (name && strcmp(name, curTransition) == 0);
+
+		if (!name || !*name)
+			name = Str("None");
+
+		action = menu->addAction(QT_UTF8(name));
+		action->setProperty("transition_index", i);
+		action->setCheckable(true);
+		action->setChecked(match);
+
+		connect(action, &QAction::triggered,
+				std::bind(setTransition, action));
+	}
+
+	QWidgetAction *durationAction = new QWidgetAction(menu);
+	durationAction->setDefaultWidget(duration);
+
+	menu->addSeparator();
+	menu->addAction(durationAction);
+	return menu;
+}
+
 QMenu *OBSBasic::CreateTransitionMenu(QWidget *parent, QuickTransition *qt)
 QMenu *OBSBasic::CreateTransitionMenu(QWidget *parent, QuickTransition *qt)
 {
 {
 	QMenu *menu = new QMenu(parent);
 	QMenu *menu = new QMenu(parent);

+ 5 - 0
UI/window-basic-main.cpp

@@ -3470,6 +3470,11 @@ void OBSBasic::on_scenes_customContextMenuRequested(const QPoint &pos)
 		popup.addSeparator();
 		popup.addSeparator();
 		popup.addAction(QTStr("Filters"), this,
 		popup.addAction(QTStr("Filters"), this,
 				SLOT(OpenSceneFilters()));
 				SLOT(OpenSceneFilters()));
+
+		popup.addSeparator();
+
+		QMenu *transitionMenu = CreatePerSceneTransitionMenu();
+		popup.addMenu(transitionMenu);
 	}
 	}
 
 
 	popup.exec(QCursor::pos());
 	popup.exec(QCursor::pos());

+ 4 - 0
UI/window-basic-main.hpp

@@ -289,6 +289,8 @@ private:
 	void RefreshQuickTransitions();
 	void RefreshQuickTransitions();
 	void CreateDefaultQuickTransitions();
 	void CreateDefaultQuickTransitions();
 
 
+	QMenu *CreatePerSceneTransitionMenu();
+
 	QuickTransition *GetQuickTransition(int id);
 	QuickTransition *GetQuickTransition(int id);
 	int GetQuickTransitionIdx(int id);
 	int GetQuickTransitionIdx(int id);
 	QMenu *CreateTransitionMenu(QWidget *parent, QuickTransition *qt);
 	QMenu *CreateTransitionMenu(QWidget *parent, QuickTransition *qt);
@@ -317,6 +319,7 @@ private:
 	obs_hotkey_id togglePreviewProgramHotkey = 0;
 	obs_hotkey_id togglePreviewProgramHotkey = 0;
 	obs_hotkey_id transitionHotkey = 0;
 	obs_hotkey_id transitionHotkey = 0;
 	int quickTransitionIdCounter = 1;
 	int quickTransitionIdCounter = 1;
+	bool overridingTransition = false;
 
 
 	int   programX = 0,  programY = 0;
 	int   programX = 0,  programY = 0;
 	int   programCX = 0, programCY = 0;
 	int   programCX = 0, programCY = 0;
@@ -427,6 +430,7 @@ private slots:
 	void RenameTransition();
 	void RenameTransition();
 	void TransitionClicked();
 	void TransitionClicked();
 	void TransitionStopped();
 	void TransitionStopped();
+	void TransitionFullyStopped();
 	void TriggerQuickTransition(int id);
 	void TriggerQuickTransition(int id);
 
 
 	void SetDeinterlacingMode();
 	void SetDeinterlacingMode();