Просмотр исходного кода

UI: Add copying/pasting of sources/filters

Closes jp9000/obs-studio#860
cg2121 8 лет назад
Родитель
Сommit
bcd491a3d6

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

@@ -61,6 +61,14 @@ Deprecated="Deprecated"
 ReplayBuffer="Replay Buffer"
 Import="Import"
 Export="Export"
+Copy="Copy"
+Paste="Paste"
+PasteReference="Paste (Reference)"
+PasteDuplicate="Paste (Duplicate)"
+
+# copy filters
+Copy.Filters="Copy Filters"
+Paste.Filters="Paste Filters"
 
 # updater
 Updater.Title="New update available"

+ 50 - 0
UI/forms/OBSBasic.ui

@@ -892,6 +892,51 @@
      <addaction name="actionScaleCanvas"/>
      <addaction name="actionScaleOutput"/>
     </widget>
+    <action name="actionCopySource">
+     <property name="text">
+      <string>Copy</string>
+     </property>
+     <property name="shortcut">
+      <string>Ctrl+C</string>
+     </property>
+    </action>
+    <action name="actionPasteRef">
+     <property name="enabled">
+      <bool>false</bool>
+     </property>
+     <property name="text">
+      <string>PasteReference</string>
+     </property>
+     <property name="iconText">
+      <string>PasteReference</string>
+     </property>
+     <property name="toolTip">
+      <string>PasteReference</string>
+     </property>
+     <property name="shortcut">
+      <string>Ctrl+V</string>
+     </property>
+    </action>
+    <action name="actionCopyFilters">
+     <property name="text">
+      <string>Copy.Filters</string>
+     </property>
+    </action>
+    <action name="actionPasteFilters">
+     <property name="enabled">
+      <bool>false</bool>
+     </property>
+     <property name="text">
+      <string>Paste.Filters</string>
+     </property>
+    </action>
+    <addaction name="actionCopySource"/>
+    <addaction name="actionPasteRef"/>
+    <addaction name="actionPasteDup"/>
+    <addaction name="separator"/>
+    <addaction name="actionCopyFilters"/>
+    <addaction name="actionPasteFilters"/>
+    <addaction name="separator"/>
     <addaction name="transformMenu"/>
     <addaction name="orderMenu"/>
     <addaction name="scalingMenu"/>
@@ -1409,6 +1454,11 @@
     <string>Basic.MainMenu.Edit.Scale.Output</string>
    </property>
   </action>
+  <action name="actionPasteDup">
+   <property name="text">
+    <string>PasteDuplicate</string>
+   </property>
+  </action>
  </widget>
  <customwidgets>
   <customwidget>

+ 2 - 0
UI/window-basic-main-scene-collections.cpp

@@ -225,6 +225,8 @@ void OBSBasic::RefreshSceneCollections()
 
 	OBSBasic *main = reinterpret_cast<OBSBasic*>(App()->GetMainWindow());
 	main->OpenSavedProjectors();
+	main->ui->actionPasteRef->setEnabled(false);
+	main->ui->actionPasteDup->setEnabled(false);
 }
 
 void OBSBasic::on_actionNewSceneCollection_triggered()

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

@@ -3347,6 +3347,19 @@ void OBSBasic::CreateSourcePopupMenu(QListWidgetItem *item, bool preview)
 	if (addSourceMenu)
 		popup.addMenu(addSourceMenu);
 
+	ui->actionCopyFilters->setEnabled(false);
+
+	popup.addSeparator();
+	popup.addAction(ui->actionCopySource);
+	popup.addAction(ui->actionPasteRef);
+	popup.addAction(ui->actionPasteDup);
+	popup.addSeparator();
+
+	popup.addSeparator();
+	popup.addAction(ui->actionCopyFilters);
+	popup.addAction(ui->actionPasteFilters);
+	popup.addSeparator();
+
 	if (item) {
 		if (addSourceMenu)
 			popup.addSeparator();
@@ -3393,6 +3406,8 @@ void OBSBasic::CreateSourcePopupMenu(QListWidgetItem *item, bool preview)
 				SLOT(OpenFilters()));
 		popup.addAction(QTStr("Properties"), this,
 				SLOT(on_actionSourceProperties_triggered()));
+
+		ui->actionCopyFilters->setEnabled(true);
 	}
 
 	popup.exec(QCursor::pos());
@@ -5270,3 +5285,60 @@ bool OBSBasic::sysTrayMinimizeToTray()
 	return config_get_bool(GetGlobalConfig(),
 			"BasicWindow", "SysTrayMinimizeToTray");
 }
+
+void OBSBasic::on_actionCopySource_triggered()
+{
+	on_actionCopyTransform_triggered();
+
+	OBSSceneItem item = GetCurrentSceneItem();
+
+	if (!item)
+		return;
+
+	OBSSource source = obs_sceneitem_get_source(item);
+
+	copyString = obs_source_get_name(source);
+	copyVisible = obs_sceneitem_visible(item);
+
+	ui->actionPasteRef->setEnabled(true);
+	ui->actionPasteDup->setEnabled(true);
+}
+
+void OBSBasic::on_actionPasteRef_triggered()
+{
+	OBSBasicSourceSelect::SourcePaste(copyString, copyVisible, false);
+	on_actionPasteTransform_triggered();
+}
+
+void OBSBasic::on_actionPasteDup_triggered()
+{
+	OBSBasicSourceSelect::SourcePaste(copyString, copyVisible, true);
+	on_actionPasteTransform_triggered();
+}
+
+void OBSBasic::on_actionCopyFilters_triggered()
+{
+	OBSSceneItem item = GetCurrentSceneItem();
+
+	if (!item)
+		return;
+
+	OBSSource source = obs_sceneitem_get_source(item);
+
+	copyFiltersString = obs_source_get_name(source);
+
+	ui->actionPasteFilters->setEnabled(true);
+}
+
+void OBSBasic::on_actionPasteFilters_triggered()
+{
+	OBSSource source = obs_get_source_by_name(copyFiltersString);
+	OBSSceneItem sceneItem = GetCurrentSceneItem();
+
+	OBSSource dstSource = obs_sceneitem_get_source(sceneItem);
+
+	if (source == dstSource)
+		return;
+
+	obs_source_copy_filters(dstSource, source);
+}

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

@@ -119,6 +119,10 @@ private:
 	bool projectChanged = false;
 	bool previewEnabled = true;
 
+	const char *copyString;
+	const char *copyFiltersString;
+	bool copyVisible = true;
+
 	QPointer<QThread> updateCheckThread;
 	QPointer<QThread> logUploadThread;
 
@@ -413,6 +417,13 @@ private slots:
 
 	void ToggleShowHide();
 
+	void on_actionCopySource_triggered();
+	void on_actionPasteRef_triggered();
+	void on_actionPasteDup_triggered();
+
+	void on_actionCopyFilters_triggered();
+	void on_actionPasteFilters_triggered();
+
 private:
 	/* OBS Callbacks */
 	static void SceneReordered(void *data, calldata_t *params);

+ 39 - 2
UI/window-basic-source-select.cpp

@@ -93,7 +93,28 @@ static void AddSource(void *_data, obs_scene_t *scene)
 	obs_sceneitem_set_visible(sceneitem, data->visible);
 }
 
-static void AddExisting(const char *name, const bool visible)
+static char *get_new_source_name(const char *name)
+{
+	struct dstr new_name = {0};
+	int inc = 0;
+
+	dstr_copy(&new_name, name);
+
+	for (;;) {
+		obs_source_t *existing_source = obs_get_source_by_name(
+				new_name.array);
+		if (!existing_source)
+			break;
+
+		obs_source_release(existing_source);
+
+		dstr_printf(&new_name, "%s %d", name, ++inc + 1);
+	}
+
+	return new_name.array;
+}
+
+static void AddExisting(const char *name, bool visible, bool duplicate)
 {
 	OBSBasic *main = reinterpret_cast<OBSBasic*>(App()->GetMainWindow());
 	OBSScene scene = main->GetCurrentScene();
@@ -102,6 +123,17 @@ static void AddExisting(const char *name, const bool visible)
 
 	obs_source_t *source = obs_get_source_by_name(name);
 	if (source) {
+		if (duplicate) {
+			obs_source_t *from = source;
+			char *new_name = get_new_source_name(name);
+			source = obs_source_duplicate(from, new_name, false);
+			bfree(new_name);
+			obs_source_release(from);
+
+			if (!source)
+				return;
+		}
+
 		AddSourceData data;
 		data.source = source;
 		data.visible = visible;
@@ -155,7 +187,7 @@ void OBSBasicSourceSelect::on_buttonBox_accepted()
 		if (!item)
 			return;
 
-		AddExisting(QT_TO_UTF8(item->text()), visible);
+		AddExisting(QT_TO_UTF8(item->text()), visible, false);
 	} else {
 		if (ui->sourceName->text().isEmpty()) {
 			QMessageBox::information(this,
@@ -243,3 +275,8 @@ OBSBasicSourceSelect::OBSBasicSourceSelect(OBSBasic *parent, const char *id_)
 		obs_enum_sources(EnumSources, this);
 	}
 }
+
+void OBSBasicSourceSelect::SourcePaste(const char *name, bool visible, bool dup)
+{
+	AddExisting(name, visible, dup);
+}

+ 2 - 0
UI/window-basic-source-select.hpp

@@ -47,4 +47,6 @@ public:
 	OBSBasicSourceSelect(OBSBasic *parent, const char *id);
 
 	OBSSource newSource;
+
+	static void SourcePaste(const char *name, bool visible, bool duplicate);
 };