Kaynağa Gözat

UI: Implement scene reordering

This simply saves/loads the actual list widget item order.

The reason why this is done is because internally, libobs doesn't have a
list of scenes, it only has a list of sources.  The list of scenes is
actually something artificially implemented by the basic window user
interface.
jp9000 10 yıl önce
ebeveyn
işleme
84567f2745
3 değiştirilmiş dosya ile 108 ekleme ve 10 silme
  1. 0 6
      obs/forms/OBSBasic.ui
  2. 101 4
      obs/window-basic-main.cpp
  3. 7 0
      obs/window-basic-main.hpp

+ 0 - 6
obs/forms/OBSBasic.ui

@@ -682,9 +682,6 @@
    </property>
   </action>
   <action name="actionSceneUp">
-   <property name="enabled">
-    <bool>false</bool>
-   </property>
    <property name="icon">
     <iconset resource="obs.qrc">
      <normaloff>:/res/images/up.png</normaloff>:/res/images/up.png</iconset>
@@ -712,9 +709,6 @@
    </property>
   </action>
   <action name="actionSceneDown">
-   <property name="enabled">
-    <bool>false</bool>
-   </property>
    <property name="icon">
     <iconset resource="obs.qrc">
      <normaloff>:/res/images/down.png</normaloff>:/res/images/down.png</iconset>

+ 101 - 4
obs/window-basic-main.cpp

@@ -200,7 +200,7 @@ static void SaveAudioDevice(const char *name, int channel, obs_data_t *parent)
 	obs_source_release(source);
 }
 
-static obs_data_t *GenerateSaveData()
+static obs_data_t *GenerateSaveData(obs_data_array_t *sceneOrder)
 {
 	obs_data_t       *saveData     = obs_data_create();
 	obs_data_array_t *sourcesArray = obs_save_sources();
@@ -214,6 +214,7 @@ static obs_data_t *GenerateSaveData()
 	SaveAudioDevice(AUX_AUDIO_3,     5, saveData);
 
 	obs_data_set_string(saveData, "current_scene", sceneName);
+	obs_data_set_array(saveData, "scene_order", sceneOrder);
 	obs_data_set_array(saveData, "sources", sourcesArray);
 	obs_data_array_release(sourcesArray);
 	obs_source_release(currentScene);
@@ -253,9 +254,25 @@ void OBSBasic::ClearVolumeControls()
 	volumes.clear();
 }
 
+obs_data_array_t *OBSBasic::SaveSceneListOrder()
+{
+	obs_data_array_t *sceneOrder = obs_data_array_create();
+
+	for (int i = 0; i < ui->scenes->count(); i++) {
+		obs_data_t *data = obs_data_create();
+		obs_data_set_string(data, "name",
+				QT_TO_UTF8(ui->scenes->item(i)->text()));
+		obs_data_array_push_back(sceneOrder, data);
+		obs_data_release(data);
+	}
+
+	return sceneOrder;
+}
+
 void OBSBasic::Save(const char *file)
 {
-	obs_data_t *saveData  = GenerateSaveData();
+	obs_data_array_t *sceneOrder = SaveSceneListOrder();
+	obs_data_t *saveData  = GenerateSaveData(sceneOrder);
 	const char *jsonData = obs_data_get_json(saveData);
 
 	if (!!jsonData) {
@@ -268,6 +285,7 @@ void OBSBasic::Save(const char *file)
 	}
 
 	obs_data_release(saveData);
+	obs_data_array_release(sceneOrder);
 }
 
 static void LoadAudioDevice(const char *name, int channel, obs_data_t *parent)
@@ -307,6 +325,35 @@ void OBSBasic::CreateDefaultScene()
 	obs_scene_release(scene);
 }
 
+static void ReorderItemByName(QListWidget *lw, const char *name, int newIndex)
+{
+	for (int i = 0; i < lw->count(); i++) {
+		QListWidgetItem *item = lw->item(i);
+
+		if (strcmp(name, QT_TO_UTF8(item->text())) == 0) {
+			if (newIndex != i) {
+				item = lw->takeItem(i);
+				lw->insertItem(newIndex, item);
+			}
+			break;
+		}
+	}
+}
+
+void OBSBasic::LoadSceneListOrder(obs_data_array_t *array)
+{
+	size_t num = obs_data_array_count(array);
+
+	for (size_t i = 0; i < num; i++) {
+		obs_data_t *data = obs_data_array_item(array, i);
+		const char *name = obs_data_get_string(data, "name");
+
+		ReorderItemByName(ui->scenes, name, (int)i);
+
+		obs_data_release(data);
+	}
+}
+
 void OBSBasic::Load(const char *file)
 {
 	if (!file) {
@@ -321,6 +368,7 @@ void OBSBasic::Load(const char *file)
 	}
 
 	obs_data_t       *data       = obs_data_create_from_json(jsonData);
+	obs_data_array_t *sceneOrder = obs_data_get_array(data, "scene_order");
 	obs_data_array_t *sources    = obs_data_get_array(data, "sources");
 	const char       *sceneName = obs_data_get_string(data,
 			"current_scene");
@@ -334,11 +382,15 @@ void OBSBasic::Load(const char *file)
 
 	obs_load_sources(sources);
 
+	if (sceneOrder)
+		LoadSceneListOrder(sceneOrder);
+
 	curScene = obs_get_source_by_name(sceneName);
 	obs_set_output_source(0, curScene);
 	obs_source_release(curScene);
 
 	obs_data_array_release(sources);
+	obs_data_array_release(sceneOrder);
 	obs_data_release(data);
 }
 
@@ -2045,6 +2097,7 @@ void OBSBasic::on_scenes_customContextMenuRequested(const QPoint &pos)
 	QPointer<QMenu> sceneProjectorMenu;
 
 	QMenu popup(this);
+	QMenu order(QTStr("Basic.MainMenu.Edit.Order"), this);
 	popup.addAction(QTStr("Add"),
 			this, SLOT(on_actionAddScene_triggered()));
 
@@ -2056,6 +2109,19 @@ void OBSBasic::on_scenes_customContextMenuRequested(const QPoint &pos)
 				this, SLOT(RemoveSelectedScene()),
 				DeleteKeys.front());
 		popup.addSeparator();
+
+		order.addAction(QTStr("Basic.MainMenu.Edit.Order.MoveUp"),
+				this, SLOT(on_actionSceneUp_triggered()));
+		order.addAction(QTStr("Basic.MainMenu.Edit.Order.MoveDown"),
+				this, SLOT(on_actionSceneDown_triggered()));
+		order.addSeparator();
+		order.addAction(QTStr("Basic.MainMenu.Edit.Order.MoveToTop"),
+				this, SLOT(MoveSceneToTop()));
+		order.addAction(QTStr("Basic.MainMenu.Edit.Order.MoveToBottom"),
+				this, SLOT(MoveSceneToBottom()));
+		popup.addMenu(&order);
+
+		popup.addSeparator();
 		sceneProjectorMenu = new QMenu(QTStr("SceneProjector"));
 		AddProjectorMenuMonitors(sceneProjectorMenu, this,
 				SLOT(OpenSceneProjector()));
@@ -2125,14 +2191,45 @@ void OBSBasic::on_actionRemoveScene_triggered()
 		obs_source_remove(source);
 }
 
+void OBSBasic::ChangeSceneIndex(bool relative, int offset, int invalidIdx)
+{
+	int idx = ui->scenes->currentRow();
+	if (idx == -1 || idx == invalidIdx)
+		return;
+
+	sceneChanging = true;
+
+	QListWidgetItem *item = ui->scenes->takeItem(idx);
+
+	if (!relative)
+		idx = 0;
+
+	ui->scenes->insertItem(idx + offset, item);
+	ui->scenes->setCurrentRow(idx + offset);
+	item->setSelected(true);
+
+	sceneChanging = false;
+}
+
 void OBSBasic::on_actionSceneUp_triggered()
 {
-	/* TODO */
+	ChangeSceneIndex(true, -1, 0);
 }
 
 void OBSBasic::on_actionSceneDown_triggered()
 {
-	/* TODO */
+	ChangeSceneIndex(true, 1, ui->scenes->count() - 1);
+}
+
+void OBSBasic::MoveSceneToTop()
+{
+	ChangeSceneIndex(false, 0, 0);
+}
+
+void OBSBasic::MoveSceneToBottom()
+{
+	ChangeSceneIndex(false, ui->scenes->count() - 1,
+			ui->scenes->count() - 1);
 }
 
 void OBSBasic::on_sources_currentItemChanged(QListWidgetItem *current,

+ 7 - 0
obs/window-basic-main.hpp

@@ -141,6 +141,10 @@ private:
 	void UpdateSources(OBSScene scene);
 	void InsertSceneItem(obs_sceneitem_t *item);
 
+	void LoadSceneListOrder(obs_data_array_t *array);
+	obs_data_array_t *SaveSceneListOrder();
+	void ChangeSceneIndex(bool relative, int idx, int invalidIdx);
+
 	void TempFileOutput(const char *path, int vBitrate, int aBitrate);
 	void TempStreamOutput(const char *url, const char *key,
 			int vBitrate, int aBitrate);
@@ -323,6 +327,9 @@ private slots:
 
 	void AddSourceFromAction();
 
+	void MoveSceneToTop();
+	void MoveSceneToBottom();
+
 	void EditSceneName();
 	void EditSceneItemName();